[关闭]
@babydragon 2016-01-09T11:44:40.000000Z 字数 2209 阅读 2760

静态编译expect以及大坑

未分类


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

编译tcl静态库

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

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

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

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

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

编译expect

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

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

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

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

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

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

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

  1. gcc \
  2. -pipe -O2 -fomit-frame-pointer -Wall \
  3. -Wl,--export-dynamic \
  4. -o expect exp_main_exp.o \
  5. -L/alidata1/6080/source/expect5.45 -lexpect5.45 \
  6. -L/alidata1/6080/source/target/lib -ltcl8.6 \
  7. -ldl -lieee -lm \
  8. -Wl,-rpath,/alidata1/6080/source/target/lib \
  9. -Wl,-rpath,/alidata1/6080/source/target/lib/expect5.45

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

  1. gcc \
  2. -pipe -O2 -fomit-frame-pointer -Wall \
  3. -Wl,--export-dynamic \
  4. -o expect exp_main_exp.o \
  5. -L/alidata1/6080/source/expect5.45 -lexpect5.45 \
  6. -L/alidata1/6080/source/target/lib -ltcl8.6 \
  7. -ldl -lieee -lm \
  8. -Wl,-rpath,/alidata1/6080/source/target/lib \
  9. -Wl,-rpath,/alidata1/6080/source/target/lib/expect5.45 -ltclstub8.6 -lpthread

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

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

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

最终将编译命令修改成:

  1. gcc \
  2. -pipe -O2 -fomit-frame-pointer -Wall \
  3. -Wl,--export-dynamic \
  4. -o expect exp_main_exp.o \
  5. -L/alidata1/6080/source/expect5.45 -lexpect5.45 \
  6. -L/alidata1/6080/source/target/lib -ltcl8.6 \
  7. -ldl -lieee -lm \
  8. -Wl,-rpath,/alidata1/6080/source/target/lib \
  9. -Wl,-rpath,/alidata1/6080/source/target/lib/expect5.45 -ltclstub8.6 -lpthread -lutil

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

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

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

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

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注