关于build系统

    使用autoconf以来,的确带来了不少的方便之处,但是autoconf存在下面这样的一些问题。

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自动化编译还会有很多的问题,这些都是很多人问过,然后我总结出来的一些注意点,希望对已经入门的学者有所帮助。 

Monthly Archives

Pages

Powered by Movable Type 7.7.2

About this Entry

This page contains a single entry by Cnangel published on July 17, 2010 10:25 PM.

distcc 介绍 was the previous entry in this blog.

尖椒炒肉绝招 is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.