perl-全面編譯(轉)
文章分類:綜合技術
資迅 論壇 教程 雜志 SNS 搜尋
-
Linux教程
Linux
Linux程式設計
C/C++程式設計
Python程式設計
Perl程式設計
PHP程式設計
shell
程式設計技術
kernel
html技術
zope
java/jsp
discuz
Linux寶庫 Linux教程 Linux Linux程式設計 Perl程式設計
06/14 2008 Perl語言全面編譯 分類:Perl程式設計 | Linux 作者:Linux寶庫 來自:Linux教程 釋出時間:2008年06月14日 您是本文的第5640位讀者
-
本文來自:Linux教程 -- http://doc.linuxpk.com/3089.html
如有不明白之處,歡迎參加社群讨論
簡
述
本文将詳細講述Perl的編譯方法,獻給所有熱愛、喜歡Perl的程式員們。
Perl自從面世以來1.0版本到現今的5.6版本,一直都有編譯程式,主要因為國内的中文資料很少,大多數人不願意去看或者不懂得英文資料,所造成不知道器編譯方法。即使是很多Perl界高手也同樣有此類問題。Perl編譯方法五花八門,各種編譯方法都有其重要的意義和弱點。另一方面Perl編譯方法不能流行的原因是,本身Perl就是一個免費的東西,人們不希望Perl成為編譯的商品,但是在國内也是是以而拖累了Perl的發展步伐。但在此我不贊成也不推崇Perl程式的編譯,Perl編譯有小些局限性,但是仍然可以完成所有任務,想要達到良好的編譯效果,需要高超的程式設計技術和相關經驗,重要的是對OOP(面向對象的程式設計)的了解,将會使得你的Perl程式更加易于編譯,運作速度更快,相容性更廣等特性。
以前我寫過Perl在可嵌入式技術方面技術文章。它的優勢和其它嵌入語言無法比拟的相容性,Perl不但擁有PHP的可嵌入HTML技術,也同樣支援用PerlScript寫ASP的。但是如果你希望你的程式可以編譯執行,那麼可嵌入式方法顯然是不可能的。我幾乎不用ePerl、 mod_perl等可嵌入式Perl
HTML
頁,但是我更不贊成很多人把HTML置入程式之中,這兩種方法都有其好處以及壞處。我推崇模闆方式的編寫方法,大家可能也用過模闆方式,可能認為它在頁面量處理方面有很多問題?但是,那些都是陳舊古老的方式,也是說明你并未精通Perl語言,采用模闆方式調入HTML頁是相當好的方法,幾乎可以達到所有可嵌入式技術的功效,也可以像HTML程式内置方式的靈活操縱性。我覺得程式員和HTML制作員是不同的,如果我們采用ePerl、PHP、ASP,那麼你就不是一個真正的程式員,那隻是HTML技術的伺服器處理部分罷了,真正的程式是程式本身,而不附帶任何其它特性。
我認為好的教學文章,應該讓讀者充分了解内容,充分擴充層面。諸如編寫一個Httpd程式,有很多傳統的程式員根本不了解
http的通訊協定,即使講了很多内容,但是仍然搞得半懂不懂。本文将會充分擴充層面,讓讀者了解更多的技術資料,而不必看完本文後又要去尋找關聯技術資料。同樣國内目前有很多技術性書籍,都是來自國外的譯本,但是很多譯者并非此技術專家,在翻譯的時候很多東西無法充分了解,帶來的時間上的障礙。我希望國内的程式設計專家能夠寫一些有用的技術文章和書籍,因為我看過很多國人自己寫的文章都容易了解和操作。但是問題在于都偏向與基礎教學,目前急切地需要有更深層次的技術資料。
内容大綱:
1)
PerlApp和PerlSvc編譯方法
New!
Easy!
2)
Perl2Exe
編譯方法
3)
PerlCC
編譯方法
4)
PerlCC之Bytecode
編譯解析法——Just
Like
Java
Program!
New!
Cool!
5)
OOP面向對象的程式之為編譯而設計
6)
HTML模闆程式設計方式——真正的WEB程式(Program)
Good!
7)
聯合編譯以及執行個體
Advanced!
說明:如何選擇閱讀以上内容是很重要的,以上内容并非适合各個階層的Perl程式員。PerlApp和PerlSvc适合在 Windows2000環境下程式設計初學者和一般的Perl程式設計人員,Perl2Exe适合在非Windows和Windows95/98/Me
環境下程式設計初學者和一般的Perl程式設計人員。PerlCC适合與任何作業系統平台,但是操作複雜,适合于中級程式員和進階程式員開發大宗商業化軟體(公衆客戶)使用。ByteCode是一種新型的編譯方式,類似Java,它需要Perl解析器的支援,但是它是靈活性最高的編譯方式,适合中級程式員和進階程式員開發大宗商業化軟體(服務商)使用。如果你希望你可以編寫出一個出色的Perl編譯的程式,那麼你必須閱讀第4節,它将告訴你如何使用面向對象的程式設計技術來實作Perl編譯程式的高效良好的開發環境和模式。
第一節
PerlApp和PerlSvc編譯方法
PerlApp和PerlSvc是ActiveState
公司開發的,它屬于
Active
Perl
Dev
Kit(PDK)産品。本編譯方法隻适合于Windows2000上運作,其它系統均無法正常使用,編譯程式必須是标準Perl和ActivePerl。
PDK下載下傳位址:http://ftp.tanshuai.net/pub/
ftp://ftp.tanshuai.net/pub/
PerlApp和PerlSvc,前者是标準的應用程式,後者是Windows2000的服務程式(類似與IIS,一開機就啟動的服務程式,而且無法中斷它的運作)。他們有兩種運作模式:依靠(Dependent)和獨立(Freestanding),“依靠”模式程式運作的系統上必須有Perl 解析器和相關子產品,這樣的程式相對較小;“獨立”模式,Perl解析器等相關子產品都會完全嵌入在程式之中,這樣的程式在任何Windows2000作業系統上都可以順利運作,而不需要額外的支援,但是程式相對較大。
使用方法:
标準使用方法(“依靠”模式):
perlapp
這樣程式就會建立一個以腳本名命名的可執行檔案
“獨立”模式:
perlapp(或者perlsvc)
–f
定義輸出可執行檔案名:
perlapp(或者perlsvc)
–e=tanshuai.exe
test.pl
它将會把test.pl檔案輸出的可執行檔案名改為“tanshuai.exe”。
設定程式屬性:
perlapp(或者perlsvc)
-i=
類表名
目标項目
Filenumber
檔案号碼
Productnumber
産品号碼
Productname
産品名稱
Legaltrademarks
合法商标
Filedescription
檔案說明
Originalfilename
原檔案名
Fileversion
檔案版本
Comments
注解
Productversion
産品版本
Companyname
公司名稱
Internalname
内部名稱
Legalcopyright
版權
?≌飧鍪焙蛴行┤絲贍懿淮竺靼祝飧鍪歉墒裁從玫摹H绻阍嘈垂齏in32程式,那就會知道,它是Windows程式的版本說明(如圖1)。
圖1
Perl.exe檔案的版本說明
名稱與數值用“;”分開。而且所有項目值都需小寫。
清理PerlCtrl
的DLL:
perlapp(或者perlsvc)
–c
添加子產品:
perl(或者perlsvc)
–a=
如:perlapp
tanshuai.pl
–a=IO:Socket;XML::Parser;Tanshuai::Http;MP3;
這樣子產品IO:Socket,XML::Parser,Tanshuai::Http和MP3就被置入程式内。
Perl圖形界面:
perlapp(或者perlsvc)
–g
如果你的程式非指令行或者CGI,是T/K圖形界面的話,就需要采取這個指令。
排除
Perl56.dll:
perlapp(或者perlsvc)
–x
Perl56.dll是PerlApp執行的關鍵,但是如果你不希望他和你的程式在一起,你可以把它排除,另行安置,但是主意,一定要保證它的存在否則就無法正确運作
添加額外檔案:
perlapp(或者perlsvc)
–b=
如果你希望在程式内部打開檔案,請使用這個指令。
如:open(FILE,“./PerlAPP.TXT“);@FILE=;close(FILE);
這樣就必須打開“PerlAPP.TXT“檔案,但是你如果把它置入程式,它将會在記憶體中打開。(無法寫入)
報告嵌入子產品錯誤:
perlapp(或者perlsvc)
-r
一些子產品無法嵌入,使用該指令可以得出相關資訊。
輸出詳細資訊:
perlapp(或者perlsvc)
-v
如:perlapp
tanshuai.pl
–v
輸出:
Using
myScript.pl
for
script
name
Input
script
name:
tanshuai.pl
Output
exe
name:
tanshuai.exe
Exe
Mode:
Perl
Dependent
Creating
dependent
executable
解釋:PerlApp
和PerlSvc無法在Windows95/98/ME
PerlApp使用的部分Win32
API函數未被支援。
第二節
Perl2EXE
編譯方法
Perl2EXE
可以在大多數流行系統上編譯運作,但是我幾乎不用它,我認為它是“最低級”編譯。而且它也是最容易被反編譯的程式。是以我不推崇它,也不願意用它。不過适合很多初學者。
它的原理很簡單,知識把原來的Perl代碼放入程式中和内置的解析其共同運作,而且速度不如PerlAPP。
Perl2EXE
同樣可以在
http://ftp.tanshuai.net/pub
和
ftp://ftp.tanshuai.net/pub/
下載下傳。
标準方法:
perl2exe
Perl解析器選項值設定:
perl2exe
–perloption=““
參數主要就是perl解析器的參數如:-w
–X
–e
等等。
共享dll庫:
perl2exe
–small
如果你是多個程式編譯,那麼使用這個指令,比較“劃算“,你隻要把它們的共享dll庫,複制到共同的執行目錄下,即可。共享DLL庫:p2xdll.dll或者p2x560.dll。
啟動圖形界面:
perl2exe
–gui
和perlapp是同樣的作用。
設定執行程式的圖示:
perl2exe
–icon=
設定輸出檔案名:
perl2exe
-o=
設定運作系統平台:
perl2exe
–platform=
如:Sun作業系統
perl2exe
–platform=sun
program.pl
Linux作業系統
perl2exe
–platform=linux
program.pl
第三節
PerlCC
編譯方法
PerlCC是Perl的最好最優秀最強的得編譯器,而且是免費的。但是它的調試與運作是比較方“煩”人的?L乇鹗竊谖⑷淼腤indows就更令人頭疼。
PerlCC編譯器的原理是分析Perl原代碼,然後根據标準轉換方式,轉換成C語言,當然這裡的C全部采用Perl的頭檔案(Header),也就是全部采用Perl的函數,即使你隻有一行的
“hello
world”;”都需要無數行的定義後才會出現這樣的效果。但是令人驚奇的是perl編譯後的這個“hello
world”比C/C++的編譯後的可執行檔案還要小。采用PerlCC轉換出來的C源代碼幾乎是不可讀(不可了解)的,幾乎比彙編語言還令人費解。是以這樣的程式即使被反編譯出來,它的源代碼也是會令人無法琢磨,但是這種程式根本幾乎無法反編譯,至少目前是,我相信隻要Windows未被反編譯那麼它編譯出來的Perl可執行程式也同樣無法反編譯。
如果使用PerlCC是大家最關心的事情,在Unix-Style系統是,凡是安裝perl5.0以上版本的都可以使用PerlCC,編譯程式,但是必須有C編譯器。這個我就不必太多說了。因為這個方法不大适合初學者,一般中級程式員對Unix-Style系統應該是較為了解的。
在Windows中,一定要安裝VC6.0(也可以是GCC,但是安裝複雜)否則仍然無法編譯,安裝VC6.0是簡單的事情,隻要找到微軟VC6的CD光牒,安裝。
然後,下載下傳Perl源代碼(位址:http://ftp.tanshuai.net/pub/
),下來後解開壓縮(Windows可以用Winzip)。
UNIX-Style
指令行模式下:
#cd
#make
#make
test
~可選
#make
install
~完成安裝
#export
PATH=$PATH;/;
~設定變量
Windows
指令行(Command.com
CMD.COM)模式下:
C:/>cd
C:
nmake
C:
nmake
test
~可選
C:
nmake
install
Windows
95/98/Me
在
AutoExec.Bat檔案中設定路徑。
Windows
Nt/2000
在“控制台”-〉“系統”-〉“進階”-〉“環境變量”中設定
注意:千萬不要使用AtivePerl,而且最好在安裝标準編譯Perl後,删除AtivePerl,AtivePerl“不支援” PerlCC,雖然它也有帶perlcc
但是至少我是永遠都無法編譯成功的,我也不知道為什麼,我也不想知道為什麼,因為很多程式是在Unix- Style
上運作的,大多數都是标準Perl,是以建議大家為了相容所有作業系統,請盡量用标準Perl編寫和解析程式。
好啦,一切安裝、設定就緒後,重新啟動計算機後。我們進入我們想要編譯的檔案目錄中,輸入“perlcc
”(注意:這裡的程式擴充名稱必須是.pl
.bat
.p
.pm,.cgi也不行,你可以修改perlcc.bat檔案來支援其它擴充名)。
輸入以上指令後,會出現一大堆你可能看不懂的指令(這些你并不需要關心)
例如我要編譯一個内容為:
“ok”;
的Perl程式,該檔案名:abc.pl。
輸入:
perlcc
abc.pl
PerlCC輸出内容:
------------------------------------------------------------------------------
Compiling
abc.pl:
-------------------------------------------------------------------------------
Making
C(abc.pl.c)
for
abc.pl!
C:/perl/5.6.0/bin/MSWin32-x86/perl.exe
-IC:/perl/5.6.0/lib/MSWin32-x86
-IC:/perl
/5.6.0/lib
-IC:/perl/site/5.6.0/lib/MSWin32-x86
-IC:/perl/site/5.6.0/lib
-I.
-MB
::Stash
-c
abc.pl
C:/perl/5.6.0/bin/MSWin32-x86/perl.exe
-IC:/perl/5.6.0/lib/MSWin32-x86
-IC:/perl
/5.6.0/lib
-IC:/perl/site/5.6.0/lib/MSWin32-x86
-IC:/perl/site/5.6.0/lib
-I.
-MO
=C,-l2000,-umain,-uattributes,-uDB,-uWin32
abc.pl
Starting
compile
Walking
?ree
Prescan
Saving
methods
Bootstrap
attributes
abc.pl
Writing
output
Loaded
B
Loaded
IO
Loaded
Fcntl
abc.pl
syntax
OK
Compiling
C(abc)
for
abc.pl!
C:/perl/5.6.0/bin/MSWin32-x86/perl.exe
-IC:/perl/5.6.0/lib/MSWin32-x86
-IC:/perl
/5.6.0/lib
-IC:/perl/site/5.6.0/lib/MSWin32-x86
-IC:/perl/site/5.6.0/lib
-I.
E:/
DOCUME~1/ADMINI~1/LOCALS~1/Temp/abc.pl.tst
Couldn't
open
E:DOCUME~1ADMINI~1ocals~1temp/abc.pl.val
cl
-Od
-MD
-DNDEBUG
-DWIN32
-D_CONSOLE
-DNO_STRICT
-DPERL_MSVCRT_READFIX
-Od
-
MD
-DNDEBUG
-Ic:/perl/5.6.0/lib/MSWin32-x86/CORE
-o
abc
abc.pl.c
/link
-nologo
-nodefaultlib
-release
-libpath:"c:/perl/5.6.0/lib/MSWin32-x86/CORE"
-machine:
x86
-libpath:c:/perl/5.6.0/lib/MSWin32-x86/CORE
c:/perl/5.6.0/lib/MSWin32-x86/CO
RE/perl56.lib
oldnames.lib
kernel32.lib
user32.lib
gdi32.lib
winspool.lib
com
dlg32.lib
advapi32.lib
shell32.lib
ole32.lib
oleaut32.lib
netapi32.lib
uuid.lib
wsock32.lib
mpr.lib
winmm.lib
version.lib
odbc32.lib
odbccp32.lib
msvcrt.lib
abc.pl.c
然後再輸入:abc.exe,如果輸出結果與abc.pl一樣,那麼編譯就成功了。這個程式是使用Visual
C++的CL.EXE
C/C++編譯程式編譯的。在Unix-Style下是使用CC或者GCC編譯的。
子產品編譯注意事項:
目前PerlCC标準編譯方式可以支援大多數程式的子產品使用,但是我推薦盡量使用内部指令來完成相應任務,諸如IO::Socket子產品可以使用 socket
内部函數。因為
IO::Socket是無法在PerlCC下面編譯成功的,為什麼?
大家知道Perl很多的子產品是本身Perl的語言和内部函數編寫的。但是有一部分包括IO::Socket
DBD
DBI等這些常用的子產品,由于Perl本身内置函數限制,采用了PerlXS接口通過C
程式達到目的的。這些是通過第三方程式達到目的子產品是無法成功的編譯。是以我建議盡量使用非含有第三方程式的子產品程式設計。有人可能會說了,我使用了DBI
DBD來操作資料庫,難道讓我放棄嗎?不,我覺得任何事情都是有它的解決方法,Perl也一樣。Perl
Bytecode将會解決這一問題(詳情情看第4節)。
程式設計方式注意事項:我為什麼要在開頭說OOP
等相關技術以及在本文中提及了OOP的編寫?因為PerlCC編譯有一定的局限性,如果采用 OOP就可以避免這個局限性,而且會更好的發揮,衆所周知,OOP是程式設計發式的有一革命,你遲早都會涉及的,是以早一點總比晚一點好。我們經常編寫程式的時候用“require”指令來引用其它Perl程式檔案。然而這種方式不是PerlCC不支援,PerlCC當然支援,這個指令,但是問題在于它無法被編譯入PerlCC的主程式内,也就是說主程式被編譯了,然而外部引用的這個沒有被編譯,這樣會造成很多問題,首先是暴露了原始代碼,其次它人可以随意修改,肯能導緻很多量(比如密碼)被套出,也可以修改程式運作的模式。但是這也是有點,最後一節将會詳盡講述。
第四節
PerlCC之Bytecode
編譯解析法
Bytecode
是
PerlCC的另一編譯方法,必須在Perl5.6以後版本才有得支援。它的原理就好像Java一樣,它會把Perl檔案編譯成二進制令人費解的亂碼檔案,它是采用類似MD5這樣的反向加密編碼,幾乎不可能反編譯,和可執行程式一樣複雜,但是它不可以直接執行哦。想要執行它,必須用Perl解析器,就好像
Java
編譯後必須有Java解析器,否則就無法執行。我習慣成為編譯解析法,有的時候就說Just
Like
Java
Progam!
它的編譯方法也不難,但是竟然有很多人都不知道,我問過很多Perl前輩,他們也不大了解這一方法。而且很多我也從來見過誰寫過這樣的程式(難道我是國内第一個知道的嗎?:)
使用方法:perlcc
–b
編譯後它會輸出一個檔案,你打開它看,定會吃驚。而且這種檔案最小是180KB,比perlcc
C語言轉換編譯多了很多。
它的好處在于,一處編譯到處使用。但是對于CGI就不大好處理。是以還是建議在各個平台進行編譯。
例如我ByteCode編譯上節的abc.pl程式檔案:
輸入:
perlcc
–b
abc.pl
Perlcc
–B
輸出
----------------------------------------------------------------------------
Compiling
abc.pl:
----------------------------------------------------------------------------
Making
Bytecode(abc.plc)
for
abc.pl!
C:/perl/5.6.0/bin/MSWin32-x86/perl.exe
-IC:/perl/5.6.0/lib/MSWin32-x86
-IC:/perl
/5.6.0/lib
-IC:/perl/site/5.6.0/lib/MSWin32-x86
-IC:/perl/site/5.6.0/lib
-I.
-MB
::Stash
-c
abc.pl
C:/perl/5.6.0/bin/MSWin32-x86/perl.exe
-IC:/perl/5.6.0/lib/MSWin32-x86
-IC:/perl
/5.6.0/lib
-IC:/perl/site/5.6.0/lib/MSWin32-x86
-IC:/perl/site/5.6.0/lib
-I.
-MO
=Bytecode,-umain,-uattributes,-uDB,-uWin32
abc.pl
abc.pl
syntax
OK
好了,然後perl
abc.plc
就可以執行了。
執行注意事項:
使用Bytecode
編譯後的檔案,你一般需要更名回原來的檔案名,否則容易在運作程式後出現警告資訊“Attempt
to
free
unreferenced
scalar.”雖然它對程式沒有本質影響,但是不美觀嘛,另一種解決方法就是使用
perl
–X
,關閉所有警告消息,警告不等同與錯誤,是以一般情況下,某些警告是不必要的。
同樣ByteCode
編譯程式可以被引用(require)但是不能調用(use),可以作為對象程式設計的對象。這是一個很靈活的東西,如果你希望你的子產品被大家使用,但是不想讓大家知道其中的操作,那麼你就是用ByteCode,但是你的子產品将永遠不會被納入CPAN。這種方法就好像OCX控件。
但是注意,但是使用某個子產品的時候,你必須保證使用該程式的機器上有這個子產品,最簡單的方法你可以把子產品一起複制使用,但是有些第三方程式子產品需要重新編譯,你如果不希望其它人操作子產品或者是看到引用的子產品,也可以使用 Bytecode。但是注意,一定要用require方法調用加密子產品啊。這個世界總是這樣,總會有些遺憾的,這樣的話就不能用一些子產品和OOP。
不知道你了解Python這個語言否?它Perl很相像,比Perl還有簡單呢。但是我認為很多東西都是抄Perl的,包括它得二進制編譯方法,就和Perl
Bytecode沒有任何差別。反正大家也都知道PHP也是抄了Perl不少東西。
--------------------------------------------------------------------------------
第五節
OOP面向對象的程式之為編譯而設計
面向對象的程式設計已經不是什麼新穎的話題和技術了。它在C++和Java中,尤為重要,哎,我覺得在寫大宗程式的時候會很有幫助,但是在小程式裡面反而麻煩,還不如普通的函數使用。OOP大多數基本的Perl教程都有說明,是以這裡也不多講“廢話”,主要講述OOP在編譯Perl程式中的應用以及Perl
OOP編寫的技巧,是以值得一看。
前面說過在PerlCC編譯可執行程式的時候,不要使用require函數,這是沒有錯的。但是有很多人寫require習慣了,而且不經常接觸OOP模式,是以不習慣。
其實使用use比require
好很多,還有很多人用require引入變量,這是大大錯誤,這是一種程式上編寫的失誤,是以建議以後大家不要用這種方式。編譯的時候也不要用這種放式?那麼用什麼方式?如果你是一個有經驗的Perl程式員,你應該知道。使用OPEN函數,傳送變量值。這是編譯Perl程式的關鍵,一些定量(不變的量),最好放在程式内部,變量以及客戶所需要設定的量使用我先前說的那種方式。具體實踐方法:
Tanshuai
OpenConf
函數代碼:
sub
Open_Conf
{
open(FILE,
"$_[0]");#打開~調用函數的檔案名
my
@Conf_Info
=
;#賦予~檔案内容到@Conf_Info數組中
close(FILE);#關閉~檔案
my
$Conf_Infos
;定義~局部變量
foreach
$Conf_Infos
(@Conf_Info)
{#循環
($name,
$value)
=
split(/=/,
$Conf_Infos);#區分~名稱和數值
($value,
$dot)
=
split(/;/,
$value);#區分~結束符
$value=~s"'""gi;#删除~不必要的符号
$CFG{$name}
=
$value;#複制~參數到散列變量
}
}
配置檔案原形:
Port='81';
IP="127.0.0.1";
Listen='5';
調用方法:
Open_Conf('../Conf/httpd.cfg');#../Conf/httpd.cfg為路徑和檔案名
$port
=
$CFG{'Port'};#将檔案原型的Port量複制到$port上,當然你可以不必這樣做,可以直接引HASH
$ip
=
$CFG{'IP'};#和上面的一樣
這樣就解決了配置變量的問題,我想這個函數對某些人一定會有很重要的意義。
在這裡OOP就是use
方式的調用。
現在我們要着重讨論OOP問題了,如果你不想把一大堆的程式代碼寫在一個檔案中,那麼使用OOP就最好了,原來是可以使用require,但這裡不可一。OOP在Perl的好處顯而易見,首先可以編譯,即使不編譯,它也同require有明顯差異。
OOP是在程式需要時調入,不需要時自動消失(通常說破壞對象)。require則不然,一旦調入一直存在,除非你使用exit
函數,是以在某些方面影響了程式的效率。
例如我們要寫一個Shell程式,一共需要一下部分:輸入/輸出(I/O)、指令判斷(CMD)、System(系統操作)。
我們平時也可以使用require,在編譯的時候就好了,同樣我們雖然可以按照子程式放在一個程式裡面,但是在這裡隻是例子,但是在大宗商業項目中,這樣做是顯然費時費力的,會增加維護成本,無法聯合開發等多種弊端。
我們把他們分為4個檔案3個子產品一個主程式(編譯):IO.pm、CMD.pm、System.pm、Shell.pl。
首先要構造對象:
Tanshuai
對象構造方法:
package
;
my
%IN;#定義~包(對象)内部的散列
sub
new
{#構造函數名
my
$class
=
shift;
%IN=
@_;#将調用對象的數值傳入散列IN中
my
$self={};
bless
$self,$class;
return
$self;
}
雖然上面的構造有些不好的地方,但是它是通用對象的構造方法,利于調試,如果你認為沒程式上的問題,就可以“封包”,适當修改變量傳引方式。
這裡的所有對象隻有是一個單一函數,隻包括:構造對象和操作對象的兩個部分,這是一個簡單的對象引用,但是這種應用在實際的開發總是相當無畏的,在這裡是為了友善教大家,是以不要什麼程式都要對象。
IO.pm:
package
IO;
my
%IN;
sub
new
{
my
$class
=
shift;
%IN
=
@_;
my
$self={};
bless
$self,$class;
return
$self;
?
sub
do
{#操作對象函數
my
$self=shift;
defined
($_
=
);#啟動Shell得取輸入資訊
chomp;#去掉無用的字元
s/^/s+//;#過濾危險字元
my
$cmd
=
$_;#複制量
return
$cmd;#傳回量
}
1;
CMD.pm:
package
CMD;
my
%IN;
sub
new
{
my
$class
=
shift;
%IN
=
@_;
my
$self={};
bless
$self,$class;
return
$self;
}
sub
do
{#操作對象函數
my
$self=shift;
my
$cmd
=
@_
;#傳入調用程式的指令
while
(){#執行循環,直到退出
if
($cmd
eq
'ver')
{
"Tanshuai
Command
Shell
v.1.0.0.001225b/n";
"(C)Copyright
Tanshuai.Com
1997-2001/n";
'EMAIL:[email protected]';
"/n";
&do;
}
elsif
($cmd
eq
""){
&do;
exit;
}
elsif
($cmd
eq
'exit'){
"Exit
System";
exit;
}
elsif
($cmd
eq
‘dir'){
use
System;#使用包System
my
$sys
=
System
::new
;#建立基于System包的對象$sys
$sys->do($cmd)
;#操作對象sys傳送指令
&do;
}
else
{
"
Command
Not
Found
";
&do;
}
}
}
}
1;
System.pm:
Package
System;
my
%IN;
sub
new
{
my
$class
=
shift;
%IN
=
@_;
my
$self={};
bless
$self,$class;
return
$self;
}
sub
do
{#操作對象函數
my
$self=shift;
my
$cmd
=
@_
;
system($cmd)
;#使用System函數作業系統,啟動dir指令
1;
以上各個子產品(對象)已經建立完畢,我們現在隻需要設計一個簡單的操作對象程式。這個時候你發現搞對象原始是如此簡單:)
Shell.pl
主程式:
use
IO;#調用~子產品(對象)
IO.pm
use
CMD;#調用~子產品(對象)
CMD.pm
my
$IO
=
IO::new;#建立對象~$IO
my
$CMD
=
CMD::new;#建立對象~$CMD
my
$GetInput
=
$IO->do;#從對象IO得到輸入資訊;
$CMD->do("$GetInput");#将得到的輸入資訊發送給對象$CMD,進行分析操作。
exit
;
這樣就完成了,你可能問為什麼沒有使用對象System
?那是因為在對象CMD中繼承對象System,是以我們不需要在程式中使用System,要不然就累了。
當你看到shell.pl程式時候,你有何感想?是不是覺得搞對象簡單了很多呢?給我的想法就是,以後程式員會越來越多,因為對象程式設計太簡單了,而我們呢?哎,我們就去做對象。以後程式設計和做對象的人可能要區分開來了。
現在編譯shell.pl後,把這些對象删除,看看能否使用?當然能,假如你使用require就出現無法執行的緻命錯誤。
哎呀,好累了。我就要吐血了
#[email protected],還沒有吃晚飯呢。明日繼續吧。
這裡告訴大家編譯Perl在較大或者較複雜的程式項目中,使用對象,會有很好的作用。你可能會問,用對象編譯出來的程式如此之大,是否會影響效率?肯定會,但是它并非明顯,就好像一個小小的15KB的程式,在運作的時候可能占用超過100MB的記憶體。由于它會整個被記憶體啟動,但是并不會有較大幅度的效率下降。如果還想使用類似require的方法,就要看最後一章了。
第六節
HTML模闆程式設計方式——真正的WEB程式
什麼是真正的程式(Program)?我們平時使用ASP、PHP這些都不屬于程式,它們隻是一種頁(Page),動态頁面(Dynamic
Page),但是我們一般稱作頁面程式設計(Web
Programming),但這種說法不确切(并非不正确)。程式就是程式,并非所有的語言都叫做程式或程式設計語言。很多權威的書籍、文章和網站(例如:Yahoo!)都沒有将ASP、PHP當作程式(程式設計語言)來解釋。ASP是一種語言媒體,PHP在 Yahoo的定義頁隻是類似于SSI。他們說要做的東西頂多就是一個“背景(伺服器端)的HTML(或者說是Script)”,可以想象,頁(Page)和程式(Program)的差異,至少可以說頁是由程式來解析輸出結果的。那麼也就是說,頁想要做的事情比程式要局限得多。PHP不是一種程式,如果用 ASP或PHP做一個Http伺服器,你會有什麼感覺?你見過嗎?你見過ASP、PHP做的非Web“程式”嗎?我想你沒有見過。你相信用ASP、PHP 編制出類似于Windows的圖形(GUI)界面程式嗎?那是一種什麼感覺呢?是以,做程式和頁面是兩種不同的概念,在國内不知道是翻譯的時候錯誤,還是大家都是這樣了解的。
如果你要寫一個Web頁,做一些小動作,用ASP、PHP、ePerl等未嘗不可。但是它不是來給你做大宗Web項目或者軟體而設計的。至少我是這樣認為。而且我覺得Perl目前在程式中直接使用HTML是一種不好的習慣或者行為。它将增加維護成本,降低工作效率等諸多不便因素。其實我覺得外制式的模闆方式的HTML套入法是适合時代潮流以及未來軟體更新擴充的。至少可以讓客戶在不觸及程式核心的前提下,随意修改界面,可以得到個性化、特性化的設定——未來趨勢。而且我們可以降低很大維護的成本,同時某些不變的(諸如:版權、聲明、标示)内容仍然可以使用内置式或者在套入模闆的過程中進行相應修改等。如果你真的不喜歡他人修改模闆,那麼你可以使用加密方式,對模闆檔案進行加密,可以達到程式操作目的,和降低維護成本,而禁止他人修改的目的(推薦使用:Crypt::RC4)。
本章将會着重講述在Perl程式中(不但隻是為了編譯Perl)使用套入法,套入模闆HTML,并且進行靈活的HTML操作。
以下是标準的内置式和外制式的HTML操作:
内置式HTML程式:
#!perl
$Var="HELLO
WORLD";
$Var
HTML
exit;
外置式HTML程式:
#!perl
$Var="HELLO
WORLD";
open
(HTML,"../HelloWorld.html");#打開HelloWorld.html檔案
@HTML=;
close
(HTML);
Content-type
:text/html
;
foreach
(@HTML)
{#循環
$_
=~
s//*Var/$Var/g;#替換Hellworld.html
檔案中*Var的内容為變量$Var的内容
"$_";#輸出
}
exit;
外置式HTML檔案
HellWorld.html:
*Var
上面的例子都是現實操作中廣泛(流行)用法,大家可能感覺到外置式有些複雜,其實不然,你隻要把它做成一個函數或者對象就相當容易了。
關鍵問題在于,變量的替換,若使用上面的方法,有些不妥,因為默寫模闆頁面不一定是适合的那些變量,如果你把所有的變量都放在foreach裡面,那麼勢必對于程式運作資源造成極大浪費,而且得?懷ナВ跋煨省U庋龀梢桓龊蛘叨韻螅曰嵊脅煌ㄓ玫奈侍狻?
是以建立一個靈活的分析方法,對于模闆HTML處理提供良好的快捷的運作模式。
這個時候我們就要利用Perl強大的文法分析,來做一個自己的HTML語言分析語句了。這個語句看似簡單缺令人頭疼。
我們現在以“*”符号作為模闆中的變量(類似于Perl
中的$),這樣有助于辨析。那麼我想要把所有以“*”開頭的變量,自動變換成程式内的對應變量,例如:要把*abc成為内部的$abc。一般情況我們需要逐個設定,這樣大大浪費了時間,我們現在需要做一個通用的方法,無論什麼的量都自動轉換。這個文法很簡單:
$_
=~
//*(/w+)/;
看似簡單的一局話,卻有很大的作用,這句就是把以*開頭的字元的名找出來,但是有趣的是,你不需要進行太複雜的,隻要遇到空格或者其它非标準字元,就會自動排除。
現在我們要把找到的字元名(即HTML的自定義變量)發給一個臨時變量中(該步驟可以不做):$tmp
=
$1
;
現在要做的就是把這個*abc換成量$abc的值:
$_
=~
s//*$tmp/$Html{"$tmp"}/g
這裡的$Html是散列變量(HASH),為了友善和容易了解,我在這裡采用HASH,這樣對應的$Html{‘abc’}就被提出來,換掉*abc了。
下面就是我做的模闆套用函數與例子。
打開檔案的函數RTF:
#!perl
sub
RTF{
open(READTXTFILE,"$_[0]");
@readtxtfile=;
close(READTXTFILE);
return
@readtxtfile;
}
分析模闆的函數PHF:
#!perl
sub
PHF
{
my
$file
=
"$_[0]";
@HtmlFileMessages=&RTF("$file");#Open
File;
foreach
(@HtmlFileMessages)
{
$_
=~
//*(/w+)/;
#替換網頁的變量,批量處理,尋找“*
--------------------------------------------------------------------------------
第七節
聯合編譯以及執行個體
本章至關重要,你已經知道Perl的兩種最好的編譯方法。但是他們都有利弊,隻要稍動腦筋,就可以實作“強強聯合”,這樣可以盡量避免那些缺憾。
聯合編譯的道理很簡單,但操作起來也不那樣一帆風順,其中有很多地方值得注意。聯合編譯主要有一個主程式和多個子程式(FILE)組成。它們之間是使用require函數連接配接。主程式隻做連接配接等分析工作,子程式做細節工作,包括對象操作,子產品引用。我們采用PerlCC
翻譯C的方式來編譯主程式成為一個可以執行的檔案,在把子程式用Bytecode方式編譯,這樣即可免去無法使用部分子產品的問題,也可以直接使用Perl程式,隻要在主程式的前面定義一下子產品引用路徑,方法:
use
lib
‘’;
這樣就可以了,把那些需要調入的子產品,放在制定路徑中就好了。而且在CGI或者Socket的網絡程式設計和頁面程式設計中,使用該模是有助于提高效率,降低資源占用率。如果使用整體編譯方法,那麼每次啟動必然會耗費相當大的記憶體,同樣這個程式要重複關閉啟動,做Fast
CGI也是相當不友善的,這也是 Fast
CGI在Perl中的最好的方法。根據不同的請求套入不同的子程式。
首先我們使用
cgi-lib.pl得去POST和GET資料(這個時候有些人會問,為什麼不使用cgi.pm,我不是不想用它,而是cgi.pm在perlcc的任何編譯模式都會有問題)
然後根據不同的請求,我在這裡設定為action。
例如:
require
“cgi-lib”;
if
($in{‘action’}
eq
“”)
{
require
“display.pl”;
&display;
exit;#可選
}elsif
($in{‘action’
}eq
“love”)
{
require
“love.pl”;
&love;
exit;#可選
}
這樣是很好的。我們使用perlcc
标準編譯方法編譯它,然後用-b模式編譯display.pl和love.pl。然後把它們的名字改回.pl。
注意在使用perlcc編譯程式的時候,編譯出來的程式必須帶有應用程式擴充檔案,如dll和so。因為你的程式還需它們支援,這個檔案在 Perl的解析軟體目錄下,例如perl5.6就是perl56.dll,必須把它拷貝到執行檔案目錄地下。在Linux下是.so。你最好在一個沒有 Perl
平台解析器的環境下進行測試,把那些需要使用的包也包括在裡面。即使是VC等軟體編譯出來的程式,都需要在純環境下測試,這是必要的。這樣就可以測試出程式的一些不必要的問題。
另外perlcc
的任何模式對文法都是很挑剔的,是以你最好使用比較正規的編寫方法,而且單個perl程式如果程式量太大,必須截取到另一個檔案中,否則編譯後容易出現記憶體溢出現象。
大家要知道如果你的子程式使用了ByteCode編譯,但是他人仍然可以把你的子程式改成源代碼形式,這樣就好像我說的會被套出很多量。最好的的方法,是采用ByteCode
編譯的程式寫入一個Auth認證函數。當然最保險的方法是使用檔案内容驗證,但是效率影響,我認為不大必要。
主程式:
#
!perl
require
“cgi-lib”;
if
($in{‘action’}
eq
“”)
{
auth
(“display.pl”);
&display;
exit;#可選
}elsif
($in{‘action’
}eq
“love”)
{
auth
(“love.pl”);
&love;
exit;#可選
}
sub
auth
{
require
"$_[0]
"
;
$auth
=
&check
;
if
($auth
ne
"checkabcdefg
"){
exit
;
}
}
Display.pl
#
!perl
sub
check
{
$check=
"checkabcdefg
"
;
return
$check
;
}
sub
display
{
"content-type
:text/html
/n/n"
;
"hello
baby
"
;
}
上面是一種簡單的,不過也會造成一些問題,是以下面是一個麻煩(并非複雜)方法,但是很安全。
檢查編譯程式是否真實:
#
!perl
open
(FILE,"./print.pl");
@FILE=;
close
(FILE);
foreach
(@FILE)
{
if
($_
=~/程式編譯後的部分代碼/){
}else
{exit
;}
}
首先把程式進行bytecode編譯,然後截取部分獨特的其它程式沒有的代碼,放入其中,來檢查引入程式是否正确合法。
你可以把bytecode的程式改名成.dll等,這樣其它人就不知道是怎麼回事啦。
結束語
Perl是一個強大的而且是最早的解析性程式語言,它的編譯程式是B子產品,大家可以詳細常見,它有多種編譯方式,都是采用反向編譯(BackEnd)不同于反編譯。是以經本上是不可能被反編譯。我認為本文對所有的Perl程式員都有很大的幫助。
Perl還有很多其它方式的編譯、加密方法,但是我覺得本文介紹的幾種方式都是最好的(相容性和運作效率),有一些人,把寫的程式進行部分字元亂碼或者是取消縮近的書寫格式(把所有程式寫在一行上),我認為這些方法是“愚蠢的”,是以建議大家不要花那麼多時間去研究這些“無謂”的東西。
部分字元編碼例子——原本:
#
!perl
sub
Hello
{
$hello=abc
;
$hello
;
}
&hello
;
部分字元編碼例子——編碼後
#
!perl
sub
adfjierei123489dkajd_dfefnkdj
{
$iernvmdnvcjnaldffgh=abc;
$iernvmdnvcjnaldffgh;
}
&adfjierei123489dkajd_dfefnkdj;
我希望通過本文促使Perl在國内的商業發展,也同樣加快了Perl技術在國内的發展速度。但是我仍然希望大家可以寫更多的公開源代碼的程式出來,這樣可以讓初學者有較快的提高速度。
如果你有任何問題和想法都可以通過電子郵件([email protected],
[email protected],
[email protected])或者ICQ:25856530
OICQ:66552聯絡我,其它資料可以到我的網站查詢http: //www.tanshuai.net
http://www2.tanshuai.net
本文來自:Linux教程 -- http://doc.linuxpk.com/3089.html
如有不明白之處,歡迎參加社群讨論