Linux C头文件查找与动态库搜索

一、编译程序时,头文件路径搜索

本文介绍在linux中头文件的搜索路径,也就是说你通过include指定的头文件,linux下的gcc编译器它是怎么找到它的呢。在此之前,先了解一个基本概念。

头文件是一种文本文件,使用文本编辑器将代码编写好之后,以扩展名.h保存就行了。头文件中一般放一些重复使用的代码,例如函数声明、变量声明、常数定义、宏的定义等等。当使用#include语句将头文件引用时,相当于将头文件中所有内容,复制到#include处。#include有两种写法形式,分别是:

#include <> : 直接到系统指定的某些目录中去找某些头文件。

#include “” : 先到源文件所在文件夹去找,然后再到系统指定的某些目录中去找某些头文件。

#include文件可能会带来一个问题就是重复应用,如a.h引用的一个函数是某种实现,而b.h引用的这个函数却是另外一种实现,这样在编译的时候将会出现错误。所以,为了避免因为重复引用而导致的编译错误,头文件常具有:

#ifndef LABEL

#define LABEL

//代码部分

#endif

的格式。其中LABEL为一个唯一的标号,命名规则跟变量的命名规则一样。常根据它所在的头文件名来命名。

例如,如果头文件的文件名叫做hardware.h,那么可以这样使用:

#ifndef __HARDWARE_H__

#define __HARDWARE_H__

//代码部分

#endif

这样写的意思就是,如果没有定义__HARDWARE_H__,则定义__HARDWARE_H__,并编译下面的代码部分,直到遇到#endif。这样当重复引用时,由于__HARDWARE_H__已经被定义,则下面的代码部分就不会被编译了,这样就避免了重复定义。

一句话,头文件事实上只是把一些常用的命令集成在里面,你要用到哪方面的命令就载入哪个头文件就可以了。

gcc寻找头文件的路径(按照1->2->3的顺序)

1. 在gcc编译源文件的时候,通过参数-I指定头文件的搜索路径,如果指定路径有多个路径时,则按照指定路径的顺序搜索头文件。命令形式如:“gcc -I /path/where/theheadfile/in sourcefile.c“,这里源文件的路径可以是绝对路径,也可以是相对路径。

eg:设当前路径为/root/test,include_test.c如果要包含头文件“include/include_test.h“,有两种方法:

1) include_test.c中#include “include/include_test.h”或者#include "/root/test/include/include_test.h",然后gcc include_test.c即可

2) include_test.c中#include <include_test.h>或者#include <include_test.h>,然后gcc –I include include_test.c也可

2. 通过查找gcc的环境变量C_INCLUDE_PATH/CPLUS_INCLUDE_PATH/OBJC_INCLUDE_PATH来搜索头文件位置。

3. 再找内定目录搜索,分别是

/usr/include

/usr/local/include

/usr/lib/gcc-lib/i386-linux/2.95.2/include

最后一行是gcc程序的库文件地址,各个用户的系统上可能不一样。

gcc在默认情况下,都会指定到/usr/include文件夹寻找头文件。

gcc还有一个参数:-nostdinc,它使编译器不再系统缺省的头文件目录里面找头文件,一般和-I联合使用,明确限定头文件的位置。在编译驱动模块时,由于非凡的需求必须强制GCC不搜索系统默认路径,也就是不搜索/usr/include要用参数-nostdinc,还要自己用-I参数来指定内核头文件路径,这个时候必须在Makefile中指定。

4. 当#include使用相对路径的时候,gcc最终会根据上面这些路径,来最终构建出头文件的位置。如#include <sys/types.h>就是包含文件/usr/include/sys/types.h

二、编译程序时,动态库文件路径搜索

编译的时候:

1)gcc会去找-L指定的路径,例如

-L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk

2)再找gcc的环境变量LD_LIBRARY_PATH

3)再找内定目录 /lib:/usr/lib: /usr/local/lib:这是当初compile gcc时写在程序内的

二、运行程序时,Linux动态库文件搜索路径

linux共享库链接器ld.so有五种方法查找已经编译好的库libbase.so的位置,分别为:

1)ELF可执行文件中动态段中DT_RPATH所指定的路径。即在编译目标代码时, 对gcc加入链接参数“-Wl,-rpath”指定动态库搜索路径,eg:gcc -Wl,-rpath,/home/arc/test,-rpath,/lib/,-rpath,/usr/lib/,-rpath,/usr/local/lib test.c

2)环境变量LD_LIBRARY_PATH 指定的动态库搜索路径

3)/etc/ld.so.cache中所缓存的动态库路径,这个可以通过先修改配置文件/etc/ld.so.conf中指定的动态库搜索路径,然后执行ldconfig命令使其立即生效。

4)默认的动态库搜索路径/lib

5)默认的动态库搜索路径/usr/lib

另外:在嵌入式Linux系统的实际应用中,1和2被经常使用,也有一些相对简单的的嵌入式系统会采用4或5的路径来规范动态库,3在嵌入式系统中使用的比较少, 因为有很多系统根本就不支持ld.so.cache。

那么,动态链接器ld.so在这五种路径中,是按照什么样的顺序来搜索需要的动态共享库呢?答案这里先告知就是按照上面的顺序来得,即优先级是:1-->2-->3-->4-->5。我们可以写简单的程序来证明这个结论。

首先,写成5个函数,这5个函数名称都叫pt,但是里面的内容不一样:

pt1.c

#include <stdio.h>

void pt(){

printf("1 path on the gcc give \n");

}

pt2.c

#include <stdio.h>

void pt(){

printf("2 path on the LD_LIBRARY_PATH \n");

}

pt3.c

#include <stdio.h>

void pt(){

printf("3 path on the /etc/ld.so.conf \n");

}

pt4.c

#include <stdio.h>

void pt(){

printf("4 path on the /lib \n");

}

pt5.c

#include <stdio.h>

void pt(){

printf("5 path on the /usr/lib \n");

}

然后,分别编译这5个函数,然后将它们分别移到上面5种情况对应的5个不同目录下:

gcc -fPIC -c pt1.c -o pt.o

gcc -shared pt.o -o libpt.so

mv libpt.so /tmp/st/1/

gcc -fPIC -c pt2.c -o pt.o

gcc -shared pt.o -o libpt.so

mv libpt.so /tmp/st/2/

gcc -fPIC -c pt3.c -o pt.o

gcc -shared pt.o -o libpt.so

mv libpt.so /tmp/st/3/

gcc -fPIC -c pt4.c -o pt.o

gcc -shared pt.o -o libpt.so

mv libpt.so /lib/

gcc -fPIC -c pt5.c -o pt.o

gcc -shared pt.o -o libpt.so

mv libpt.so /usr/lib/

再次,编写一个main函数m,让它来调用函数pt:

m.c

#include <stdio.h>

int main(){

printf("start....\n");

pt();

printf("......end\n");

return 0;

}

最后,准备环境,让ld都知道这5个路径:

(a) 往/etc/ld.so.conf总增加一行,内容:/tmp/st/3,然后执行 ldconfig 命令

(b) export LD_LIBRARY_PATH=/tmp/st/2

另外3中路径,ld都可以得到,请接着看下面。

之后测试:

gcc m.c -o m1 -L/tmp/st/1 -lpt -Wl,-rpath,/tmp/st/1

./m1

start....

1 path on the gcc give

......end

这里在可执行文件中动态段中DT_RPATH所指定的路径,因此需要在编译m.c的时候就指定路径,由于其他路径都也告诉了ld,很明显,此种方法优先级最高了。

gcc m.c -o m -L/tmp/st/1 -lpt

./m

start....

2 path on the LD_LIBRARY_PATH

......end

这里很显然调用了LD_LIBRARY_PATH指定了路径中的共享库,因此此种情况优先级第二。

mv /tmp/st/2/libpt.so /tmp/st/2/libpt2.so

/m

start....

3 path on the /etc/ld.so.conf

......end

这里是调用了/etc/ld.so.cache中所缓存的动态库路径中的共享库,因此此种情况优先级第三。

mv /tmp/st/3/libpt.so /tmp/st/3/libpt3.so

./m

start....

4 path on the /lib

......end

这里是调用/lib中的共享库,优先级第四。

rm /lib/libpt.so

./m

start....

5 path on the /usr/lib

......end

这里是调用/lib中的共享库,优先级第五。

故证明这五种路径指定方法的优先级是1-->2-->3-->4-->5!

引用自:http://blog.csdn.net/huangjm_13/article/details/21160445

时间: 2024-12-24 20:25:24

Linux C头文件查找与动态库搜索的相关文章

cmake中设置ELF文件加载动态库的位置

1. 三个文件 1. world.c #include<stdio.h> void world(void) { printf("world.\n"); } 2. hello.c #include <stdio.h> void world(void); void hello(void) { printf("hello\n"); world(); } 3. main.c void main(void) { hello(); } 2. 编译动态库

linux下把log4cxx封装成so动态库文件(一)

这是一个经常遇到的问题,在软件开发过程中,需要将某些功能封装成一个独立的模块,这样维护升级也很方便.现在我们就要把开源日志库log4cxx封装成so动态加载库文件. 在上一篇文章<log4cxx日志库RedHat下安装>中,我们已经将log4cxx安装在home/mac/log4cxx/log4cxx下了,那么接下来的操作我们就继续在这个路径下进行. 还是先tree一下/home/mac/log4cxx这个目录吧 log4cxx ---apr ---apr-util ---log4cxx 那再

Linux学习笔记——例说makefile 头文件查找路径

0.前言 从学习C语言开始就慢慢开始接触makefile,查阅了很多的makefile的资料但总感觉没有真正掌握makefile,如果自己动手写一个makefile总觉得非常吃力.所以特意借助博客总结makefile的相关知识,通过例子说明makefile的具体用法. 例说makefile大致分为4个部分 1.只有单个C文件 2.含有多个C文件 3.需要包括头文件路径 4.一个较为复杂的例子 [代码仓库]--makefile-example 代码仓库位于bitbucket,可借助Tortoise

linux常用头文件及说明

linux常用头文件及说明 1. Linux中一些头文件的作用: <assert.h>:ANSI C.提供断言,assert(表达式)<glib.h>:GCC.GTK,GNOME的基础库,提供很多有用的函数,如有数据结构操作函数.使用glib只需要包含<glib.h><dirent.h>:GCC.文件夹操作函数.struct dirent,struct DIR,opendir(),closedir(),readdir(),readdir64()等 <c

GCC、头文件查找顺序总结

GCC笔记 The History of GCC -------------------------------------------------------------------------------- 1984年,Richard Stallman发起了自由软件运动,GNU (Gnu's Not Unix)项目应运而生,3年后,最初版 的GCC横空出世,成为第一款可移植.可优化.支持ANSI C的开源C编译器. GCC最初的全名是GNU C Compiler,之后,随着GCC支持的语言越

linux下添加动态链接库路径、动态库加载等方法

linux下添加动态链接库路径的方法 2017年01月20日 10:08:17 阅读数:5596 Linux共享库路径配置 Linux下找不到共享库文件的典型现象为明明已经安装某个软包(如libnet,MySQL),编译连接可以正常进行,但是在运行时出现如"error while loading shared libraries: libnet.so.1:cannot open shared object file :No such file or directory"的错误提示. 原

Linux动态库搜索路径的技巧

众所周知,Linux动态库的默认搜索路径是/lib和/usr/lib.动态库被创建后,一般都复制到这两个目录中.当程序执行时需要某动态库,并且该动态库还未加载到内存中,则系统会自动到这两个默认搜索路径中去查找相应的动态库文件,然后加载该文件到内存中,这样程序就可以使用该动态库中的函数,以及该动态库的其它资源了.在Linux 中,动态库的搜索路径除了默认的搜索路径外,还可以通过以下三种方法来指定. 方法一:在配置文件/etc/ld.so.conf中指定动态库搜索路径. 可以通过编辑配置文件/etc

linux驱动程序头文件

1.编写任何驱动程序都必须带的头文件 #include <linux/module.h>:在编写任何模块都需要包含此头文件.该头文件自动包含了 <linux/version.h>头文件,该头文件包含了宏                                                                                                  MODULE_LICENSE("GPL")的定义. #include

linux c 头文件

1 //1.Linux中一些头文件的作用: 2 #include <assert.h> //ANSI C.提供断言,assert(表达式) 3 #include <glib.h> //GCC.GTK,GNOME的基础库,提供很多有用的函数,如有数据结构操作函数 4 #include <dirent.h> //GCC.文件夹操作函数 5 #include <ctype.h> //ANSI C.字符测试函数.isdigit(),islower()等 6 #inc