本文翻译自libtool的官方使用手册的部分内容,翻译不当之处请多指教,转载清注明出处!
1.简介
以前,如果你是一名源代码包开发者,你想要利用共享库带来的优势,你需要为每一种平台编写特定的代码以使你的代码可以运行。同时你可能需要设计一个配置文件接口,所以包的安装者可以选择哪些库需要安装。
GNU Libtool 简化上述工作,其将平台相关的特性和用户接口封装到了一个脚本文件中。GNU Libtool设计的目的为:每一个编译环境的本地功能特性都是通过一个统一的接口管理,所有的问题都被软件开发者隐藏了。
GNU Libtool所包含的接口是令人欣慰的,用户不需要为了使他们想要的源码包编译成共享库而去阅读晦涩难懂的文档。他们仅仅需要执行包的configure脚本,剩下的事情就都交给libtool来完成了。
本文都是围绕构建libhllo库展开的。libhello也能为共享库,也可能为静态库,或者两者都是,只要是libtool已经移植到了目标系统上,就能按照系统所支持的库存在方式生成库的正确模式。
2.使用libtool
下面例子中所使用的源码文件都是来自libtool发行源码包的test/demo子文件夹,假设我们需要依赖foo.c和main.c构建‘libhllo'库文件。需要注意的是foo.c文件使用到了cos数学函数,所以我们需要在链接命令中使用-lm选项。
我们使用两中平台完成libhello的创建过程:
a23’: Ultrix 4.2 platform 只支持静态库。
‘burger’:NetBSD/i386 1.2 platform 同时支持静态库和共享库。
2.1 创建目标文件
一般的目标文件创建方式为:
burger$ gcc -g -O -c main.c
burger$
该命令将会产生一个名为main.o的目标文件。大部分的系统在生成静态库的目标文件时使用下面的命令:
burger$ gcc -g -O -c foo.c
burger$ gcc -g -O -c hello.c
burger$
生成共享库时需要向编译器传递PIC(position-independent code)而不是position-dependent代码,libtool隐藏了编译器复杂的共享库编译选项,同时使用分离的库文件存储文件(PIC 库保存在.libs子目录下,静态库存储在当前目录下)。在不支持共享库的OS上,PIC库是不会存在的。
为了创建‘foo.c和hello.c’库文件,将标准的编译器选项传递给libtool即可,具体命令如下:
a23$:libtool --mode=compile gcc -g -O -c foo.c
gcc -g -O -c foo.c -o foo.o
a23$ libtool-- mode = compile gcc - g - O - c hello.c
gcc -g -O -c hello.c -o hello.o
a23$
注意:libtool会额外的创建libtool专用的控制文件。'.lo'文件就是libtool生成的目标文件,用于libtool决定那些目标文件可能被组装成共享库。由于‘a23’平台只支持静态库,所以其下的库目标文件如下:
# foo.lo - a libtool object file
# Generated by ltmain.sh (GNU libtool) 2.2.6b
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
# Name of the PIC object.
pic_object=none
# Name of the non-PIC object.
non_pic_object='foo.o'
在支持共享库的OS上,libtool会自动的产生额外的PIC目标文件,命令执行情况如下:
burger$ libtool --mode=compile gcc -g -O -c foo.c
mkdir .libs
gcc -g -O -c foo.c -fPIC -DPIC -o .libs/foo.o
gcc -g -O -c foo.c -o foo.o >/dev/null 2>&1
burger$
注意:libtool会自动创建.libs目录用于存放PIC库目标文件
‘burger'系统下的库目标文件内容如下:
# foo.lo - a libtool object file
# Generated by ltmain.sh (GNU libtool) 2.2.6b
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
# Name of the PIC object.
pic_object='.libs/foo.o'
# Name of the non-PIC object.
non_pic_object='foo.o'
注意到第二行的gcc命令会将其所有的输出丢弃。其目的是避免编译器产生烦人的重复警告信息,可以是使用-no-suppress选项关闭选项:
burger$ libtool --mode=compile gcc -no-suppress -g -O -c hello.c
gcc -g -O -c hello.c -fPIC -DPIC -o .libs/hello.o
gcc -g -O -c hello.c -o hello.o
burger$
2.2 链接库文件
如果不使用,一般的静态库制作方式如下:
burger$ ar cru libhello.a hello.o foo.o
burger$
许多系统还需要执行ranlib命令,来使静态库产生符号的索引,如下:
burger$ ranlib libhello.a
burger$
对于静态库的创建,libtool只是简单的ar和ranlib的封装,其执行效果如下:
a23$ libtool --mode=link gcc -g -O -o libhello.la foo.o hello.o
*** Warning: Linking the shared library libhello.la against the
*** non-libtool objects foo.o hello.o is not portable!
ar cru .libs/libhello.a
ranlib .libs/libhello.a
creating libhello.la
(cd .libs && rm -f libhello.la && ln -s ../libhello.la libhello.la)
a23$
上述警告信对于只支持静态库的OS来说没有问题,但是对于支持共享库的OS 来说至关重要。
重新运行libtool,这次使用库目标文件,运行效果如果下:
a23$ libtool --mode=link gcc -g -O -o libhello.la foo.lo hello.lo \
-rpath /usr/local/lib -lm
ar cru .libs/libhello.a foo.o hello.o
ranlib .libs/libhello.a
creating libhello.la
(cd .libs && rm -f libhello.la && ln -s ../libhello.la libhello.la)
a23$
编译共享库时我们需要指定共享库安装的位置,例如/usr/local/lib,libtool使用-vpath选项实现该功能。
burger$ libtool --mode=link gcc -g -O -o libhello.la foo.lo hello.lo \
-rpath /usr/local/lib -lm
rm -fr .libs/libhello.a .libs/libhello.la
ld -Bshareable -o .libs/libhello.so.0.0 .libs/foo.o .libs/hello.o -lm
ar cru .libs/libhello.a foo.o hello.o
ranlib .libs/libhello.a
creating libhello.la
(cd .libs && rm -f libhello.la && ln -s ../libhello.la libhello.la)
burger$
太酷了,只需简单一条命令就同时创建了共享库和静态库,这是libtool的魅力所在。.libs子目录下为创建好的静态库 和共享库
2.3链接可执行文件
不使用libtool链接可执行文件的命令如下:
burger$ gcc -g -O -o hell.old main.o libhello.a -lm
burger$
在编写该命令时我们需要记住-lm选项,而使用libtool则完全没有必要这样,例如:
a23$ libtool --mode=link gcc -g -O -o hell main.o libhello.la
gcc -g -O -o hell main.o ./.libs/libhello.a -lm
a23$
基于共享库的可执行文件链接可能需要记住很多链接选项,而使用libtool则完全没有必要,例如:
burger$ libtool --mode=link gcc -g -O -o hell main.o libhello.la
gcc -g -O -o .libs/hell main.o -L./.libs -R/usr/local/lib -lhello -lm
creating hell
burger$
如果‘libhello.la’已经安装,这时你需要链接它生成新的程序,例如:
burger$ gcc -g -O -o test test.o -L/usr/local/lib -lhello -lm
但是,除非‘/usr/local/lib'在标准的共享库搜索路径上,否则test不会正确运行。而libtool会链接到已经安装的libool 目标文件,而该文件会为你做好一切:
burger$ libtool --mode=link gcc -g -O -o test test.o \
/usr/local/lib/libhello.la
gcc -g -O -o .libs/test test.o -Wl,--rpath \
-Wl,/usr/local/lib /usr/local/lib/libhello.a -lm
creating test
burger$