1.基础知识
对于以压缩包发布的软件,在它的目录下通常都有一个配置脚本configure,它的作用确定编译参数(比如头文件位置、连接库位置等),然后生成Makefile以编译程序。可以进入该软件的目录,执行"./configure --help"命令查看使用帮。
一个程序能正确编译、链接、运行需要满足3个条件:预处理时能找到头文件,连接时能找到库,运行时能找到库。下面分别介绍:
1.1指定头文件位置
在程序中常用两种方法来包含头文件:
#include <headerfile.h>
#include "headerfile.h"
两者区别是,对于第二种方法,首先在源文件当前目录下查找头文件,如果找不到,再像第一种方法一样去编译命令指定、系统预设的目录去找。这些"指定的"、"预设的"目录在什么地方呢?
- "指定的"头文件目录是编译程序时使用"-I"指定目录,
- "预设的"头文件目录是由编译器自己决定的。
通过一个例子可以看到这点,执行一下命令:
mkdir -p /work/AAA/include /*临时目录,测试用*/
mkdir -p /work/BBB/include /*临时目录,测试用*/
export C_INCLUDE_PATH=/work/AAA/include
echo 'main() {}' | arm-linux-gcc -I/work/BBB/include -E -v -
得到以下输出内容,从中可以看到查找头文件时的路径及优先顺序:
...
#include "....." search starts here:
#include <.....> search starts here:
/work/BBB/include
/work/AAA/include
...
可以总结出头文件的查找路径及优先顺序。
1.如果源文件中使用双引号来包含头文件,则首先在源文件当前目录查找头文件。
2.如果编译时使用"-I/some/dir",则在/some/dir中查找。
3.如果设置了环境变量C_INCLUDE_PATH,则在指定的目录中查找。
4.最后在编译器预设的路径中查找,这是不需要指定的。
所以,编译程序时如果出现了找不到头文件的错误,可以通过设置C_INCLUDE_PATH或给编译器设置"-I"选线来指定头文件目录,这可以在执行配置命令configure之前设置C_INCLUDE_PATH或CFLAGS,如果不设置CFLAGS,它的默认值为"-g -O2",比如:
export C_INCLUDE_PATH="/some/dir/1:/some/dir/2"
export CFLAGS = "-g -O2 -I/some/dir" #如果设置了C_INCLUDE_PATH,就可以不设置CFLAGS
./configure
还有更好的方法,当明确知道要使用哪个动态库时,可以通过pkg-config命令获知要使用这个库时编译时的参数、连接时的参数。
先执行一下命令体验一下:
export PKG_CONFIG_PATH=/work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib/pkgconfig
pkg-config --cflags uuid
-I/work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/include
1.2.交叉编译时库的搜索路径
1.“-L”指定连接时库的搜索路径,这些库使用"-l"来显示指定,比如"-labc"表示的库文件为libabc.so
2."-rpath-link"比"-L"多一项功能,它指定的目录还可以用于搜索依赖库。
3."-rpath"比"-rpath-link"多一项功能,它指定的目录会被编译进程序中,当程序运行时,首先从这些目录中寻找库。
怎样指定"-rpath-link"呢?连接器arm-linux-ld通常是由arm-linux-gcc间接启动的,而arm-linux-gcc并不认识"-rpath-link"选项,所以需要在前面加上关键字"-Wl",表示选项用于连接器。在执行配置命令configure之前设置LDFLAGS即可,比如:
export LDFLAGS="-Wl,-rpath-link-Wl,/work/crossbuild/X/lib -Wl,-rpath-link-Wl,/work/corssbuild/GTK/lib"
./configure
1.3.指定运行时库的位置
运行库时的查找路径及优先顺序如下:
1.编译时使用"-rpath"指定目录。
2.环境变量LD_LIBRARY_PATH指定的目录(它可以指定多个目录,以冒号分隔)。
3.默认路径:/lib、/usr/lib.
注意:
通过设定环境变量LD_LIBRARY_PATH可以指定动态库搜索路径。当通过该环境变量指定多个动态库搜索路径时,路径之间用冒号":"分隔。
不过LD_LIBRARY_PATH的设定作用是全局的,过多的使用可能会影响到其他应用程序的运行,所以多用在调试。
通常情况下推荐使用gcc的-R或-rpath选项来在编译时就指定库的查找路径,并且该库的路径信息保存在可执行文件中,运行时它会直接到该路径查找库,避免了使用LD_LIBRARY_PATH环境变量查找。
1.4.扩充知识
库的链接时路径和运行时路径
现代连接器在处理动态库时将链接时路径(Link-time path)和运行时路径(Run-time path)分开,用户可以通过-L指定连接时库的路径,通过-R(或-rpath)指定程序运行时库的路径,大大提高了库应用的灵活性。
比如我们做嵌入式移植时#arm-linux-gcc $(CFLAGS) –o target –L/work/lib/zlib/ -llibz-1.2.3 (work/lib/zlib下是交叉编译好的zlib库),将target编译好后我们只要把zlib库拷贝到开发板的系统默认路径下即可。或者通过-rpath(或-R )、LD_LIBRARY_PATH指定查找路径。