静态编译expect以及大坑

expect是脚本处理有交互命令的利器,但是这货依赖tcl,并且默认没有安装。为了方便分发到测试服务器上,尝试了下静态编译。结果以失败告终。下面是整个编译的过程。

编译tcl静态库

由于expect依赖tcl,必须先编译一个静态版本的tcl库。tcl的源码可以从阿里云镜像下载:

wget http://mirrors.aliyun.com/gentoo/distfiles/tcl-core8.6.4-src.tar.gz

编译的方式和编译普通应用类似,唯一需要注意的是,我们只需要编译出静态库即可。

tar vxf tcl-core8.6.4-src.tar.gz 
cd tcl8.6.4/unix/
./configure --disable-shared --prefix=$HOME/source/target
make
make install

这里我们直接安装到指定的路径,并且关闭动态链接库的编译。这样在$HOME/source/target里面,就会tcl的静态库。

编译expect

首先还是从镜像下载expect源码。

wget http://mirrors.aliyun.com/gentoo/distfiles/expect5.45.tar.gz

然后运行configure的时候,需要指定tcl的路径,并且关闭动态链接。

tar vxf expect5.45.tar.gz 
./configure --with-tcl=$HOME/source/target --disable-shared
make

这里遇到了很多链接的问题。首先是

expect.c:(.text+0xbc):对‘tclStubsPtr’未定义的引用
exp_main_sub.c:(.text+0x6fb):对‘tclIntStubsPtr’未定义的引用
tclUnixThrd.c:(.text+0x31):对‘pthread_key_delete’未定义的引用

这些符号无法找到,无法进行链接。向上查找这些错误对应的编译命令,发现已经在链接最终的expect命令了。此时的编译命令为:

gcc 
     -pipe -O2 -fomit-frame-pointer -Wall  
     -Wl,--export-dynamic  
    -o expect exp_main_exp.o 
    -L/alidata1/6080/source/expect5.45 -lexpect5.45 
    -L/alidata1/6080/source/target/lib -ltcl8.6 
    -ldl  -lieee -lm 
    -Wl,-rpath,/alidata1/6080/source/target/lib 
    -Wl,-rpath,/alidata1/6080/source/target/lib/expect5.45

查阅了tcl的faq,前面遇到无法链接的符号在tclstub库中,同时还发现少了pthread库的一些符号。加上这些之后,编译命令变成:

gcc 
     -pipe -O2 -fomit-frame-pointer -Wall  
     -Wl,--export-dynamic  
    -o expect exp_main_exp.o 
    -L/alidata1/6080/source/expect5.45 -lexpect5.45 
    -L/alidata1/6080/source/target/lib -ltcl8.6 
    -ldl  -lieee -lm 
    -Wl,-rpath,/alidata1/6080/source/target/lib 
    -Wl,-rpath,/alidata1/6080/source/target/lib/expect5.45 -ltclstub8.6 -lpthread

此时tcl和一些基础库的链接失败消失,但是出现了

pty_termios.c:(.text+0x116):对‘openpty’未定义的引用

这个错误。同样需要去查找这个函数实现的库,最终定位到了libutil。

最终将编译命令修改成:

gcc 
     -pipe -O2 -fomit-frame-pointer -Wall  
     -Wl,--export-dynamic  
    -o expect exp_main_exp.o 
    -L/alidata1/6080/source/expect5.45 -lexpect5.45 
    -L/alidata1/6080/source/target/lib -ltcl8.6 
    -ldl  -lieee -lm 
    -Wl,-rpath,/alidata1/6080/source/target/lib 
    -Wl,-rpath,/alidata1/6080/source/target/lib/expect5.45 -ltclstub8.6 -lpthread -lutil

终于能够正常编译出静态编译的expect命令了。

就在以为完事大吉的时候,发现这个静态编译的expect命令,虽然已经静态链接了tcl库,但是在其他没有tcl的机器上运行的时候,会提示:

Tcl_Init failed: Can't find a usable init.tcl in the following directories

原来为了支持扩展,tcl会要求初始化的时候执行这个初始化脚本。查阅了tcl的文档,要编译一个完全不依赖机器上tcl库的程序比较麻烦。最终,找到了一个简单的命令empty来处理命令的交互。

One Reply to “静态编译expect以及大坑”

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据