对于以压缩包发布的软件,在它的目录下通常都有一个配置脚本configure,它的作用确定编译参数(比如头文件位置、连接库位置等),然后生成Makefile以编译程序。可以进入该软件的目录,执行"./configure --help"命令查看使用帮。
一个程序能正确编译、链接、运行需要满足3个条件:预处理时能找到头文件,连接时能找到库,运行时能找到库。下面分别介绍:
1.指定头文件位置
在程序中常用两种方法来包含头文件:
#include
#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.“-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.编译时使用"-rpath"指定目录。
2.环境变量LD_LIBRARY_PATH指定的目录(它可以指定多个目录,以冒号分隔)。
3.默认路径:/lib、/usr/lib.
头文件的查找方式和库的搜索路径