perl教程

当前位置:首页>Perl>perl教程>Perl语言全面编译(三)

Perl语言全面编译(三)

时间:2015-07-14 11:03来源:网络整理 作者:KKWL 点击:
第四节 PerlCC之Bytecode 编译解析法 Bytecode 是 PerlCC的另一编译方法,必须在Perl5.6以后版本才有得支持。它的原理就好像java一样,它会把Perl文件编译成二进制令人费解的乱码文件,它是采

第四节 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') { 

                   print "Tanshuai Command Shell v.1.0.0.001225b\n"; 

                   print "(C)Copyright Tanshuai.Com 1997-2001\n"; 

                   print 'EMAIL:tanshuai@BIGFOOT.COM'; 

                   print "\n"; 

                   &do; 

         } 

         elsif ($cmd eq ""){ 

                   &do; 

                   exit; 

         } 

         elsif ($cmd eq 'exit'){ 

                   print "Exit System"; 

                   exit; 

         } 

         elsif ($cmd eq ‘dir'){ 

                   use System;#使用包System 

my $sys = System ::new ;#建立基于System包的对象$sys 

$sys->do($cmd) ;#操作对象sys传送命令 

                   &do; 

                   } 

         else { 

          print " 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就出现无法执行的致命错误。 
哎呀,好累了。我就要吐血了 #$@,还没有吃晚饭呢。明日继续吧。  
这里告诉大家编译Perl在较大或者较复杂的程序项目中,使用对象,会有很好的作用。你可能会问,用对象编译出来的程序如此之大,是否会影响效率?肯定会,但是它并非明显,就好像一个小小的15KB的程序,在运行的时候可能占用超过100MB的内存。由于它会整个被内存启动,但是并不会有较大幅度的效率下降。如果还想使用类似require的方法,就要看最后一章了。 

------分隔线----------------------------