1,LDFLAGS的问题:
一般的工程目录会有src、test、include、lib四个目录,src是自己的源码目录,而test是单元(或功能)测试的目录,include是工程需要引用别人的头文件所在的目录,lib则是工程需要引用别人提供的库文件所在的目录。
当别人只提供头文件和库文件给你的时候,一般把头文件会发在$(top_srcdir)/include下,库文件放在$(top_srcdir)/lib下,如果是32或者64位平台,可分目录存放,比如64位平台的rhel5.4,则库文件目录可以为$(top_srcdir)/lib/x86_64/RHEL5_4,当我们在src的源文件则有两种方式来做:
(1)什么也不做,只要将src目录的源文件引用了头文件,但不告之链接的依赖关系,然后生成库文件;这样做的后果是,如果需要另外产生可执行文件,则需要指明依赖关系,且一般可执行文件会动态加载外部依赖库;
(2)对其说明依赖关系,使用libxxx_la_LDFLAGS说明外部的链接关系,然后生成库文件,在libxxx.la文件中能看到依赖的具体关系,这样做可以使可执行文件不需要动态在外部依赖的库,但是有个不好的地方是,在libxxx.la中会存在着libxxx_la_LDFLAGS的路径,比如$(top_srcdir)/lib/x86_64/RHEL5_4,然而一旦编译到系统,当工程目录删除,会造成别人对这个库依赖的查找的失败,虽然自己的应用不受影响,周末好好的想了一下,目前也没有特别好的解决办法。
2,库到处安装的问题
虽然此问题不是autoconf的问题,但是由于工程人员不熟悉,经常./configure后,然后make && make install,会导致库默认安装到/usr/local下,有的工程人员则制定路径./configure --prefix=/usr,导致多种库因为不同的人形成不同的版本,对调试造成了一定了影响。
这个问题其实可以得到解决,默认大家规范从项目层次上规范,或者从制度上规范。不要将不成熟的库安装到系统(/usr)或者应用(/usr/local)目录,一般可以指定./configure --prefix=/tmp/$HOME/usr来确定不同的路径,这样确保系统的干净环境,不会受到不同版本的库污染。另外,对make 和 make install要有清楚的认识,一般来说,对于编译、调试可以使用make出来的结果,而make install主要用于部署,所以不要在调试的时候make install,当然特殊测试除外。
3,两种动态指定依赖库的问题
引用外部库,经常会看到./configure --with-xxx=/tmp/xxx类似的配置,这是一种引用外部库的途径,当外部库的安装没有标准安装或者不属于GNU规范时,都可以通过编写m4文件达到动态配置依赖头文件和库的目的,但是这种途径有一个缺点,就是当依赖的库特别多的时候,我们需要编写大量的m4文件来配置大量的--with--foo信息,这种方法是相对比较落后的方法。
另外一种比较先进的方法是一个标准,我们为自己的工程创建pc文件,这样我们可以使用pkg-config命令很方便的指定我们工程的头文件路径和目标链接路径和库名称,当然如果每个库都按照这个标准,那么动态依赖则不是问题,我们只需要使用pkg-config --cflags foo和pkg-config --libs foo就能指定头文件的CFLAGS值和库所依赖的LDFLAGS;如果是特定的路径,可以使用PKG_CONFIG_PATH环境变量指定pc文件的路径。像开源的很多软件都遵循这样的标准,更有大型的软件,比如mysql、libxml2都实现了自己的pkgconfig,比如mysql_config和xml2-config等等。
4,libxxx_SOURCES引发的问题
好多人认为在写libxxx_SOURCES的时候,只需要加上.cpp文件就可以了,因为可以编译通过,其实忽略了当前的头文件,那么在make dist以及make install的时候就会产生头文件不在dist包或者头文件丢失的问题,libxxx_SOURCES的理解可以理解成.h的头文件也算源文件;或许这样比较繁琐,但是在linux环境的添加应该十分的容易吧?在提供给外部的头文件时,路径可以使用变量libxxxincludedir来赋值,头文件则使用libxxxinclude_HEADERS来赋值即可。
5,lib_LIBRARIES和lib_LTLIBRARIES的关系
很多人经常使用lib_LIBRARIES来生成静态库,但是对于动态库不知道怎么生成?其实lib_LTLIBRARIES就是用libtool来生成一个libxxx.la文件,由./configure指定参数来控制生成动态库还是静态库。也许虽然好多人从事C/C++工作很多年,甚至写过Makefile很多年,但是对于动态库和静态库的作用还是没有弄得很清楚:
(1)静态库一般不依赖于应用依赖,但是依赖于系统依赖,比如依赖libc,如果系统依赖版本不同,可能静态库不能使用,如果系统依赖版本接口不同,则静态库肯定不能使用;动态库一般二者都依赖,缺失任何依赖都不能正常作用,依赖库一般版本不同,可以使用软连接后,如果符号定义能找到,则能够使用,否则不能正常使用;由于静态库依赖比动态库少,所以一般静态库比动态库大很多。
(2)从进程空间来看,一般静态库或者静态可执行文件运行,会发现内存占用比动态库文件或动态可执行文件运行大的多。静态库包含了所有依赖的库信息,进程启动后,锁依赖的库信息都会加载到这个进程空间,独立运行,因此如果依赖库或路径出现问题,不会对静态库或静态执行文件产生影响,因为依赖库已经放置到静态库或静态执行文件当中了;而动态库则根据符号表查找符号链接(ld.so.cache),很多依赖的库占用共同的内存空间,但是这样会有一个问题,就是依赖库发生变化会对进程本身造成影响(除非进程本身不需要重新加载);由于静态库和动态库占用进程的空间不同,所以要区别对待使用。
其实,经过autoconf自动化编译还会有很多的问题,这些都是很多人问过,然后我总结出来的一些注意点,希望对已经入门的学者有所帮助。