前言
实际上我从来没有使用过Perl语言,我对它的认知,也仅限于它能干很多事情,但核心功能是处理正则表达式,那么为什么会想要编译它呢?因为我是一个命令行工具收集控,我收集命令行工具的原则是单个exe文件,直接就能运行,不依赖于任何第三方库,也不会往我的电脑上乱写东西(比如写注册表,往AppData目录里写文件等等)。
本来是想把GNU的工具集(比如cat
, ls
, cp
, tee
, grep
, sed
……)收集过来的,然而据说这些工具都依赖于POSIX特性,在Windows下必须有POSIX模拟层(比如cygwin1.dll
一类的东东)才能正常工作,否则就是各种残缺不全。这就违背了我的“不依赖第三方库”的原则(而且,也许正是这个原因,好多移植到Windows的工具都已经长年无人维护,版本老旧了。)
啊哦,那么grep
,sed
,gawk
这些都收集不到了。同为正则表达式软件, perl
怎么样呢?可惜官网一搜,只有安装包,没有单文件版的exe.怀着最后一点希望,我们找到了它的源码。
准备编译环境
编译perl.exe
可以用MinGW或者VC++.
用MinGW时,除了把MinGW的bin
子目录添加到PATH
变量以外,还要在搜索路径下建立一个批处理gmake.bat
,内容为:
:: gmake.bat
mingw32-make %*
原因稍后就会解释(如果用VC++,也许不需要这个步骤)。
下载、解压源码
到官网 https://www.cpan.org/src/README.html 下载源码。
如果有wget
工具,那么可以直接输入命令:
wget https://www.cpan.org/src/5.0/perl-5.30.2.tar.gz
否则,可以把wget
后面的URL复制到浏览器地址栏里下载(此贴发表时,最新版本为5.30.2
)
解压缩需要用到第三方压缩软件。比如可以用 7-zip .当然,各种“国产”压缩软件也都能用。
解压后会产生一个目录,比如perl-5.30.2
,里面就是源码。
编译
进入源码目录后,建议先阅读顶层目录的README.win32
文件。里面会提到,官方建议使用的make工具是dmake
或gmake
.gmake
就是GNU make,而MinGW自带的mingw32-make
虽然也是GNU make,但它们的文件名不相同,如果直接敲命令mingw32-make
进行编译,到某个时点就会报错说找不到gmake
命令,这就是之前要建立gmake.bat
的原因,它让makefile可以找到gmake
命令,而其中实际调用mingw32-make
来工作。
接下来进入win32
子目录,打开GNUmakefile
这个文件(如果用VC++,那就打开Makefile
文件),它的顶部是一些参数定义,其中大部分都可以不用理会,需要关心的只是如下几个参数:
USE-NO-REGISTRY := define # 取消注册表支持,如果没有这个选项,perl会读取注册表
CCTYPE := GCC # 所采用的编译器,如用VC++编译,那么应该选取CCTYPE:=MSVCxxx,xxx为版本号
BUILD_STATIC := define # 静态编译生成 perl-static.exe 文件
ALL_STATIC := define # 把所有核心模块编译到 perl-static.exe 中去
CCHOME := C:\TDM-GCC-64 # 编译器的安装目录(下面应该有bin\等子目录)。
# 通常为C:\MinGW,因为我安装的是TDM-GCC版本所以是这个值
对于上面所列的参数值,可以直接改动GNUmakefile
来设置,但直接改makefile不是好习惯(万一这个makefile是由软件自动生成的,那么当下一次生成时,你做的修改就都丢失了),我们用命令行的方式把这些参数值传到makefile中,为此,建立一个批处理build.bat
:
:: build.bat
gmake USE-NO-REGISTRY:=define CCTYPE:=GCC BUILD_STATIC:=define ALL_STATIC:=define CCHOME:=C:\TDM-GCC-64 %*
接下来就是在命令行敲入build.bat
,泡杯茶喝着慢慢等的事情了。编译完成,会在顶层目录生成一个大小有10多M的perl-static.exe
文件,这就是我们想要的,棒棒哒!
生成文档
如果你想生成Perl的一份本地文档,以便没有网络的时候查阅,那么可以继续敲入build.bat doc
,在win32
子目录下就会生成一个html
目录,把这个目录的东西全部拷出来就行了。
补充说明
最初我以为perl-static.exe
已经可以独立工作,不需要其它额外的东西,然而后来发现这货还是得靠外部脚本库(不是.dll
之类的二进制库)才能正常工作,如果只把perl-static.exe
拷贝到另一个目录,而不连带着脚本库一起拷贝出来,那就连简单的perl-static -V
命令都会报错。
所以最后还需要一个步骤,那就是把Perl源代码顶层目录下的lib
子目录拷贝出来,把它跟perl-static.exe
放在一起,示意图如下:
c:\perl\demo\dir
│
│ perl-static.exe
│ perl.bat
│
└───lib
│ _charnames.pm
│ ..........
├───App
│ Cpan.pm
│ ..........
├───Archive
├───..........
调用的时候,要在perl-static
的后面跟一个参数-I<incpath>
来指定脚本库所在的目录,比如上图就是:
c:\perl\demo\dir\perl-static.exe -Ic:\perl\demo\dir\lib [其他参数]
当然,可以写个批处理perl.bat
把这个命令包装一下。由于perl-static.exe
需要包装,最好不要把它放在系统搜索路径中,而只把包装的perl.bat
加入路径即可。
由于perl-static.exe
不需要二进制库的支持,可以进入lib
子目录中清理掉编译过程中生成的静态二进制库:
del /s /q *.o *.a
这样可以适当缩小体积。
个人感言:其实这多少已经违背了我的“单文件独立运行”的要求,不过Perl毕竟是个强大的工具,一个能顶好几个Unix命令(cat
,sed
,grep
,awk
,sort
……),相比之下,这点小缺点也是可以容忍滴