分类: LINUX
2011-05-16 18:44:48
automake & libtool
一直搞不清automake跟libtool啥关系,以为后者是前者一部分,今天总算搞清楚它俩可完全独立使用。
libtool的官方手册说它的作用是为创建不同平台下的库文件(包括动态和静态)提供统一使用接口。我现在写的库还没考虑到不同平台移植,不过发现在处理一个静态库依赖许多其它静态库,而后者又嵌套地依赖别的库时,特别轻松。设想如下需求:
libtop.a依赖libsub1.a和libsub2.a,而libsub1.a和libsub2.a同时依赖libcom.a。我们希望libsub1.a和libsub2.a的人不需要知道libcom.a,也就是在链接时不需要给出libcom.a;libtop.a的使用者无需知道libsub1.a和libsub2.a,更无需知道libcom.a。
对于libsub[12].a的使用者,我们得将libcom.a中的.o文件也打包到libsub[12].a中,也就是“合并静态库”。对于此需求无论百度或google都给出先用ar x解出libcom.a中的.o,然后ar aru加入libsub[12].a中。这个过程手工做还好,问题是如何让makefile自动做?我想出一个丑陋的hack办法,在libsub[12].a的Makefile.am中新加一个target:
DEP_LIBS=libcom.a
sub1dist: libsub1.a
mkdir -p .tmp.o && cd .tmp.o && \
for alib in $(DEP_LIBS); do \
rm -f *.o; ar x ../$$alib; \
ar q ../libsub1.a *.o; done
rm -rf .tmp.o; ranlib libsub1.a
然后make之后还得make sub1dist,这样生成的libsub1.a在使用才无需链接libcom.a。
这个办法相当丑陋,让人不爽。后者仔细地google之,发现有人说libtool可以帮助合并依赖的静态库,办法是先将libcom.a使用libtool编译成convenience library。通常编译一个libtool静态库语法是:
lib_LTLIBRARIES = libcom.la
libcom_la_SOURCES = xx.cpp
为了编译成convenience library,需要将第一行的lib_LTLIBRARIES改成noinst _LTLIBRARIES。然后在生成libsub1.a时加上一行
libsub1_la_LIBADD = libcom.la
这样生成的libsub1.a(默认在.libs/下)就包含了libcom.a里的.o文件。可以从生成过程打印的信息看出libtool也是先将libcom.a用ar x解到特定目录下,然后添加到libsub1.a中,在添加时如果有重名的.o文件,它会重命名一个,例如加上lt1-前缀。
好了,libsub[12].a的使用者无需知道libcom.a了。那是否同样可以将libsub[12].a也编译成convenience library,并生成libtop.a时加上:libtop_la_LIBADD = libsub1.la libsub2.la,从而libtop.a的使用者也无需知道libsub[12].a呢?一路编译下来确实没什么问题。但最后使用libtop.a时,问题来了:
所有关于libcom.a中定义的符号,通通报出multiple definition of XXX的错误来!
显然libtop.a中包括了多份libcom.a的内容。原因应该是很明显的,解决办法是什么?Google之,一篇02年文章说这是libtool的一个bug,当时的解决办法是修改libtool脚本。但我现在是用的最新版本,在libtool中也没发现所要修改的代码。
痛苦的寻索过程说出来总是一句话:不要用LIBADD,而是用LDFLAGS,例如生成libsub1.a:
libsub1_la_LDFLAGS=-I$(com_dir) -lcom
同样的方法生成libsub2.a和libtop.a之后,libtop.a的使用者就真的不需知道其依赖关系了。