|
写过很多程序,编译过很多程序,也运行过很多程序,对一个程序的从生到死,感觉很简单,也就没有做更多的或者说深入的思考与研究。也许我们习惯了在windows环境下的编程,在这里我们有很好的IDE,它能把一个工程组织得很好,直接点编译生成一个可执行文件,然后直接双击这个.exe文件或者创建一个快捷方式运行这个程序。以前可能我们也听说过,源码先要编译,然后链接,然后装载、运行,可我们很少去考虑这背后到底都发生了些什么,似乎也不用考虑那么多,因为我们的IDE实在是太智能了,因为我们已经很习惯了使用windows环境,因为在windows下安装个软件,我们几乎只需要点击下一步就可以了。
这段时间在做linux系统下opencv2.0到ARM开发板的移植,在这里,我有很多问题不得不考虑,问题如下:
程序在编译时,源码所需要的库及头文件编译器是去哪找的?(库及头文件的查找)
当输入一个命令时,系统时如何找到这个命令的?(命令的查找)
程序在运行时,它所需要的库是去哪找的?(动态链接库的查找)
这就是一个程序的由生到死的过程中需要考虑的几个问题!
在linux系统下,我们常常要自己通过源码安装一些库,装一些软件,第一件事该想到的,编译生成后的头文件,库或者程序我们该放到哪,是放到/lib /usr/lib /usr/include /usr/bin /usr/local/lib /usr/local/include /usr/local/bin等目录下吗?可能有些书会说自己安装的程序一般放在/usr/local目录下,放到这下面我可以省心的不用去一些环境变量或文件了,但接下来我们可能会想,要是我以后想删除我前面安装的软件呢?你还能想起你以前安装这个软件时它到底安装了哪些文件了吗?几乎不可能吧!
所以当我想安装一个软件时我希望像在windows下一样,把这个软件安装在一个单独的目录下,比如说我要安装opencv2.0,那么我就在/usr/local目录下创建一个目录opnecv2.0,然后把所有相关的都安装到/usr/local/opencv2.0目录下,这样如果我以后不想要这个库时我就可以直接删掉这个文件夹就可以了。可在这里我们就有些问题不得不考虑了:如果我们把opencv安装到了/usr/local/opencv2.0这个目录下了,那编译器在编译包含有opencv2.0的库或头文件时,编译器能找着这些头文件和库吗?如果这是一个可运行文件,我在其它目录下运行这个文件,系统能找到这个文件吗?它是如何找到这个文件的呢?当其它包含有opencv有关函数的程序时,它是如何找到这些库的呢?由这就引发了我上面提到的三个问题。
下面我们先来看第一个问题:程序在编译时,源码所需要的库及头文件编译器是去哪找的?在这里,其实有库的查找,和头文件的查找,下面先来讲头文件的查找。
我们在写一个比较大型的程序时,总是喜欢把这些函数还有一些数据结构的声明放在一个文件中,我们把这种文件称为头文件,文件名以.h后缀结尾。在一些源文件里,我们可能要包含自己写的头文件,还有一些标准库的头文件比如说stdio.h等等。在编译的预处理阶段,预处理程序会将这些头文件的内容插到相应的include指令处,现在的问题是编译器是如何找到这些头文件的。
1.在编译时,我们可以用-I(i的大写)选项来指定头文件所在的目录,如:
test.h内容如下:
Struct student
{
Int age;
};
main.c 内容如下:
#include<stdio.h>
#include<test.h>
int main()
{
struct student st;
st.age = 25;
printf(“st.age=%d\n”,st.age);
return 0;
}
可以把test.h放在与main.c同一个目录下,编译命令如下:
xgy@ubuntu:~/tmp/workSpace/testincludedir$ gcc main.c -I./
如果把test.h放在/usr/include/xgytest目录下,注意,xgytest是我自己建的一个目录
编译命令如下:
xgy@ubuntu:~/tmp/workSpace/testincludedir$ gcc main.c –I/usr/include/xgytest
注意:在-I后可以有空格也可以没有空格,另外也可以指定多个目录,例如,tesh.h放在当前文件夹下,还有一个teacher.h放在 ./include目录下,则可以这样编译:
xgy@ubuntu:~/tmp/workSpace/testincludedir$ gcc main.c -I ./ -I ./include/
2.设置gcc的环境变量C_INCLUDE_PATH、CPLUS_INCLUDE_PATH 、CPATH。
C_INCLUDE_PATH 编译 C 程序时使用该环境变量。该环境变量指定一个或多个目录名列表,查找头文件,就好像在命令行中指定 -isystem 选项一样。会首先查找 -isystem 指定的所有目录。
CPLUS_INCLUDE_PATH 编译 C++ 程序时使用该环境变量。该环境变量指定一个或多个目录名列表,查找头文件,就好像在命令行中指定 -isystem 选项一样。会首先查找 -isystem 指定的所有目录。
CPATH 编译 C 、 C++ 和 Objective-C 程序时使用该环境变量。该环境变量指定一个或多个目录名列表,查找头文件,就好像在命令行中指定 -l 选项一样。会首先查找 -l 指定的所有目录。
假设test.h放在/usr/include/xgytest,则对C_INCLUDE_PATH做如下设置:
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/include/xgytest
详细请况可以参考如下文章:
http://blog.csdn.net/katadoc360/article/details/4151286
3.查找默认的路径/usr/include /usr/local/include等
总结一下gcc在编译源码时是如何寻找所需要的头文件的:
1.首先gcc会从-I选项指定的路径查找
2.然后找gcc的环境变量:C_INCLUDE_PATH、CPLUS_INCLUDE_PATH 、CPATH等。
3.然后再按照下面列出的顺序查找内定的目录:
/usr/include
/usr/local/include
/usr/lib/gcc-lib/i386-linux/2.95.2/include
/usr/lib/gcc-lib/i386-linux/2.95.2/../../../../include/g++-3
/usr/lib/gcc-lib/i386-linux/2.95.2/../../../../i386-linux/include
但是如果安装gcc的时候,是有给定的prefix的话,那么就是
/usr/include
prefix/include
prefix/xxx-xxx-xxx-gnulibc/include
prefix/lib/gcc-lib/xxxx-xxx-xxx-gnulibc/2.8.1/include
程序在编译时,编译器又是如何查找所需要的库的呢?这里的库既包括静态库又包括动态库。在这里,我们得先了解两个概念:库的链接时路径和运行时路径。
现代连接器在处理动态库时将链接时路径(Link-time path)和运行时路径(Run-time path)分开,用户可以通过-L指定连接时库的路径,通过-R(或-rpath)指定程序运行时库的路径,大大提高了库应用的灵活性。
我们来看几个例子:
pos.c文件的内容如下:
#include<stdio.h>
void pos()
{
printf("the directory is .//n");
}
main.c文件的内容如下:
#include<stdio.h>
int main()
{
pos();
return 0;
}
接下来看如下执行的命令:
由于是第一次发贴,还不会,也不知道乍样在贴中插入图片,而下面的一些命令我是以截图的形式给出的,所以下面的内容就请到我的博客看吧:http://blog.csdn.net/dlutxie/article/details/6776936 |
|