现在的位置: 首页 > 综合 > 正文

Linux下gcc编译中关于头文件与库文件搜索路径相关问题

2018年05月13日 ⁄ 综合 ⁄ 共 10746字 ⁄ 字号 评论关闭

zz http://liuleijsjx.javaeye.com/blog/452061

其他链接 When should I set LD_LIBRARY_PATH?


 

关键字: 如何指定gcc的默认头文件路径

在交叉编译的时候我们需要用到其他的库,在
config

时候可以通过
“-I”

来指定头文件目录,但是每次都需要设置的话难免有些麻烦,找到一个简单的方法。看下文的红色部分。


有大量的环境变量可供设置以影响
GCC

编译程序的方式。利用这些变量的控制也可使用合适的命令行选项。一些环境变量设置在目录名列表中。这些名字和
PATH

环境变量使用的格式相同。特殊字符
PATH_SEPARATOR

(安装编译程序的时候定义)用在目录名之间。在
UNIX

系统中,分隔符是冒号,而
Windows

系统中为分号。




C_INCLUDE_PATH



编译
C

程序时使用该环境变量。该环境变量指定一个或多个目录名列表,查找头文件,就好像在命令行中指定
-isystem

选项一样。会首先查找
-isystem

指定的所有目录。


==>


也见
CPATH


CPLUS_INCLUDE_PATH


OBJC_INCLUDE_PATH



COMPILER_PATH



该环境变量指定一个或多个目录名列表,如果没有指定
GCC_EXEC_PREFIX

定位子程序,编译程序会在此查找它的子程序。


==>


也见
LIBRARY_PATH


GCC_EXEC_PREFIX


-B

命令行选项。

CPATH



编译
C


C++


Objective-C

程序时使用该环境变量。该环境变量指定一个或多个目录名列表,查找头文件,就好像在命令行中指定
-l

选项一样。会首先查找
-l

指定的所有目录。


==>


也见
C_INCLUDE_PATH


CPLUS_INCLUDE_PATH


OBJC_INCLUDE_PATH




CPLUS_INCLUDE_PATH



编译
C++

程序时使用该环境变量。该环境变量指定一个或多个目录名列表,查找头文件,就好像在命令行中指定
-isystem

选项一样。会首先查找
-isystem

指定的所有目录。


==>


也见
CPATH


C_INCLUDE_PATH


OBJC_INCLUDE_PATH



DEPENDENCIES_OUTPUT



为文件名设置该环境变量会让预处理程序将基于依赖关系的
makefile

规则写入文件。不会包括系统头文件名字。




如果环境变量设置为单名,被看作是文件名字,而依赖关系规则的名字来自源文件名字。如果定义中有两个名字,则第二个名字是用作依赖关系规则的目标名。

设置该环境变量的结果和使用命令行选项
-MM


-MF


-MT

的组合是一样的。


==>

也见
SUNPRO_DEPENDENCIES



GCC_EXEC_PREFIX



如果定义了该环境变量,它会作为编译程序执行的所有子程序名字的前缀。例如,如果将变量设置为
testver

而不是查找
as

,汇编器首先会在名字
testveras

下查找。如果在此没有找到,编译程序会继续根据它的普通名进行查找。可在前缀名中使用斜线指出路径名。

GCC_EXEC_PREFIX


的默认设置为
prefix

/lib/gcc-lib/

,这里的

prefix

是安装编译程序时
configure

脚本指定的名字。该前缀也用于定位标准连接程序文件,包含进来作为可执行程序的一部分。




如果使用
-B

命令行选项,会重写该设置。


==>

也见
COMPILER_PATH



LANG


该环境变量用于指出编译程序使用的字符集,可创建宽字符文字、串文字和注释。




定义
LANG


C-JIS

,指出预处理程序将多字节字符按照
JIS

(日语工业标准)字符进行解释。
C-SJIS

可用来指出
Shift -JIS

字符而
C-EUCJP

指出日文
EUC






如果没有定义
LANG

,或定义为不可识别,函数
mblen()

被用来确定字符宽度,而
mbtowc()

用来将多字节序列转换为宽字符。


LC_ALL


如果设置,该环境变量的值重写
LC_MESSAGES


LC_CTYPE

的所有设置。


LC_CTYPE


该环境变量指出引用串中定义的多字节字符的字符分类。主要用于确定字符串的字符边界,字符编码需要用引号或转义符,可被错误地解释为字符串的结尾或特殊字

符串。对
Australian English

,可将它设置为
en_AU




Mexican Spanish

,可将它设置为
es_MX

。如果没有设置该变量,默认为
LANG

变量的值,或如果没有设置
LANG

,那就使用
C

英语行为。也见
LC_ALL




LC_MESSAGES


该环境变量指出编译程序使用何种语言发出诊断消息。对
Australian English

,可设置为
en_AU




MexicanSpanish

,可设置为
es_MX

。如果变量没有设置,使用
LANG

变量的默认值,或如果没有设置
LANG

,那就使用
C

英语行为。也见
LC_ALL




LD_LIBRARY_PATH


该环境变量不会影响编译程序,但程序运行的时候会有影响。变量指定一个目录列表,程序会查找该列表定位共享库。只有当未在编译程序的目录中找到共享库的时候,执行程序必须设置该变量。


LD_RUN_PATH


该环境变量不会影响编译程序,但程序运行的时候会有影响。该变量在运行时指出文件的名字,运行的程序可由此得到它的符号名字和地址。地址不会重新载入,因而可能符号引用其他文件中的绝对地址。这和
ld

工具使用
-R

选项完全一样。

LIBRARY_PATH



该环境变量可设置为一个或多个目录名字列表,连接程序会搜寻该目录,以查找特殊连接程序文件,和由
-l

(字母
l



)命令行选项指定名字的库。



-L

命令行选项指定的目录在环境变量的前面,首先被查找。


==>

也见
COMPILER_PATH



OBJC_INCLUDE_PATH



在编译
Objective-C

程序的时候使用该环境变量。一个或多个目录名的列表由环境变量指定,用来查找头文件,就好像在命令行中指定
-isystem

选项一样。所有由
-isystem

选项指定的目录会首先被查找。


==>


也见
CPATH


CPLUS_INCLUDE_PATH


C_INCLUDE_PATH



SUNPRO_OUTPUT



为文件名设置该环境变量会令预处理程序将基于依赖关系的
makefile

规则写入文件。会包含系统头文件名。

如果环境变量被设置为单个名字,它将会被当作文件名,依赖关系规则中的名字将由源文件的名字中获得。如果定义中有两个名字,第二个名字就是依赖关系规则中的目标名。

设置该环境变量的结果与在命令行中使用参数
-M


-MF


-MT

的效果一样。


==>

参见
DEPENDENCIES_OUTPUT



TMPDIR



这个变量包含了供编译程序存放临时工作文件的目录的路径名。这些文件通常在编译过程结束时被删除。这种文件的一个例子就是由预处理程序输出并输入给编译程序的文件。

linux

默认的
include

在哪
?


#include <linux/module.h>

中的
module.h

默认是在哪个目录下呢?我在
/usr/include/linux

下并没有找到这个文件。


另外想问一下,不同内核版本的
linux

头文件是不是一样的。比如:我在
2.6.20

内核的系统上,用
2.6.10

的头文件会不会有问题。

 

网友回复
:

1

我的
module.h

是在

内核编译好了的目录下的,不是在
/usr/include/linux

下,


2


2.6.20

内核的系统上,用
2.6.10

的头文件应该会有问题,内核的头文件和

当前系统运行的内核不一致。

 

网友回复
:

你引用的是内核下的头文件
.

不在
/usr/include


.


: /usr/src/kernels/2.6.18-8.el5-x86_64/include/linux/module.h

下面
...

中间的版本号是不一样的
...

你选你的就行了
..

 

网友回复
:

请问楼上为什么是在
/usr/src/kernels/2.6.18-8.el5-x86_64/include/linux/module.h

呢?我查了一下环境变量,没有看到关于头文件的环境变量。
gcc

是如何知道头文件的位置的?

 

网友回复
:

这个问题很好,


你需要看看
linux kernel


Makefile

文件了。在什么地方找头文件,它说了算。:)

 

网友回复
:

你的程序是驱动之类的内核层的吧?


它调用的头文件就应该是内核源码里面的
include

了。一般的系统都把内核源码放在
/usr/src

下面,假如是自己编译的内核的话,也可以放在别处的。

至于
gcc

到哪里去找头文件,就看
makefile

了,或者直接用
gcc

命令的话,要加上
-I

来指定目录。

 

网友回复
:

楼上,可是我的
makefile

里没有指定
include

呀,
gcc

是怎么找到头文件的?

 

网友回复
:gcc

是怎么找到头文件的?


================================

回答了这个问题,
LZ

就明白了一切了,
GCC

找头文件有三种策略:


1.

会在默认情况下指定到
/usr/include

文件夹
(

更深层次的是一个相对路径,
GCC

可执行程序的路径是
/usr/bin

,那么它在实际工作时指定头文件头径是一种相对路径方法,换算成绝对路径就是
/usr/include)

2.GCC

还使用了
-I

指定路径的方式,这一点大家都知道


3.

还可以使用一个参数来指示
GCC

不搜索系统默认路径,这个参数我忘了,你搜一下就知道了


 

在编译驱动模块时,由于非凡的需求必须强制
GCC

不搜索系统默认路径,也就是不搜索
/usr/include

,要自己用
-I

参数来指定内核头文件路径,这个时候必须在
Makefile

中指定两个参数,一个是内核头文件路径,一个是强制
GCC

不搜索系统默认路径。在编译内核时,必须使用一个参数
(

强制
GCC

不搜索系统默认路径
)

,否则就会引起混乱。

 

==

 

关键字: linux指定动态库路径

Linux

指定动态库路径

 

众所周知,
Linux

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


/usr/lib

。动态库被创建后,一般都复制到这两个目录中。当程序执行时需要某动态库,

并且该动态库还未加载到内存中,则系统会自动到这两个默认搜索路径中去查找相应的动态库文件,然后加载该文件到内存中,这样程序就可以使用该动态库中的函

数,以及该动态库的其它资源了。在
Linux

中,动态库的搜索路径除了默认的搜索路径外,还可以通过以下三种方法来指定。

 

方法一:在配置文件
/etc/ld.so.conf


中指定动态库搜索路径。


 

可以通过编辑配置文件
/etc/ld.so.conf

来指定动态库的搜索路径,该文件中每行为一个动态库搜索路径。每次编辑完该文件后,都必须运行命令

ldconfig


使修改后的配置生效

。我们通过例
1

来说明该方法。


1


我们通过以下命令用源程序
pos_conf.c

(见程序
1

)来创建动态库
libpos.so

,详细创建过程请参考文
[1]


# gcc -c pos_conf.c
         # gcc -shared -fPCI -o libpos.so pos_conf.o
         #

 

#include <stdio.h>
         void pos()
         {
                 printf("/root/test/conf/lib/n");
          }
         


程序
1: pos_conf.c

 

接着通过以下命令编译
main.c

(见程序
2

)生成目标程序
pos


# gcc -o pos main.c -L. -lpos
  #

void pos();
        int main()
        {
             pos();
              return 0;
         }
       


程序
2: main.c

然后把库文件移动到目录
/root/test/conf/lib

中。

# mkdir -p /root/test/conf/lib
         # mv libpos.so /root/test/conf/lib
          #

最后编辑配置文件
/etc/ld.so.conf

,在该文件中追加一行
"/root/test/conf/lib"


运行程序
pos

试试。

# ./pos
         ./pos: error while loading shared libraries: libpos.so: cannot open shared object file: No such file or directory
          #

出错了,系统未找到动态库
libpos.so

。找找原因,原来在编辑完配置文件
/etc/ld.so.conf

后,没有运行命令
ldconfig

,所以刚才的修改还未生效。我们运行
ldconfig

后再试试。

# ldconfig
         # ./pos
          /root/test/conf/lib
           #

程序
pos

运行成功,并且打印出正确结果。

 

方法二:通过环境变量
LD_LIBRARY_PATH


指定动态库搜索路径。


 

通过设定环境变量
LD_LIBRARY_PATH

也可以指定动态库搜索路径。当通过该环境变量指定多个动态库搜索路径时,路径之间用冒号
"


"

分隔。下面通过例
2

来说明本方法。


2


我们通过以下命令用源程序
pos_env.c

(见程序
3

)来创建动态库
libpos.so


# gcc -c pos_env.c
         # gcc -shared -fPCI -o libpos.so pos_env.o
          #

#include <stdio.h>
        void pos()
         {
               printf("/root/test/env/lib/n");
          }
       


程序
3: pos_env.c

测试用的可执行文件
pos

可以使用例
1

中的得到的目标程序
pos

,不需要再次编译。因为
pos_conf.c

中的函数
pos


pos_env.c

中的函数
pos

函数原型一致,且动态库名相同,这就好比修改动态库
pos

后重新创建该库一样。这也是使用动态库的优点之一。

然后把动态库
libpos.so

移动到目录
/root/test/conf/lib

中。

# mkdir -p /root/test/env/lib
         # mv libpos.so /root/test/env/lib
          #

我们可以使用
export

来设置该环境变量,在设置该环境变量后所有的命令中,该环境变量都有效。

例如:

# export LD_LIBRARY_PATH=/root/test/env/lib
         #

但本文为了举例方便,使用另一种设置环境变量的方法,既在命令前加环境变量设置,该环境变量只对该命令有效,当该命令执行完成后,该环境变量就无效了。如下述命令:

# LD_LIBRARY_PATH=/root/test/env/lib ./pos
        /root/test/env/lib
         #

程序
pos

运行成功,并且打印的结果是
"/root/test/env/lib"

,正是程序
pos_env.c

中的函数
pos

的运行结果。因此程序
pos

搜索到的动态库是
/root/test/env/lib/libpos.so


 

方法三:在编译目标代码时指定该程序的动态库搜索路径。

 

还可以在编译目标代码时指定程序的动态库搜索路径。
-Wl,

表示后面的参数将传给
link

程序
ld

(因为
gcc

可能会自动调用
ld

)。这里通过
gcc

的参数
"-Wl,-rpath,"

指定(如例
3

所示)。当指定多个动态库搜索路径时,路径之间用冒号
"


"

分隔。


3


我们通过以下命令用源程序
pos.c

(见程序
4

)来创建动态库
libpos.so


# gcc -c pos.c
         # gcc -shared -fPCI -o libpos.so pos.o
          #

#include <stdio.h>
        void pos()
         {
               printf(".//n");
         }
        


程序
4: pos.c

因为我们需要在编译目标代码时指定可执行文件的动态库搜索路径,所以需要用
gcc

命令重新编译源程序
main.c(

见程序
2)

来生成可执行文件
pos


# gcc -o pos main.c -L. -lpos -Wl,-rpath,./
         #

再运行程序
pos

试试。

# ./pos
         ./
          #

程序
pos

运行成功,输出的结果正是
pos.c

中的函数
pos

的运行结果。因此程序
pos

搜索到的动态库是
./libpos.so


example:

gcc -Wl,-rpath,/home/arc/test,-rpath,/lib/,-rpath,/usr/lib/,-rpath,/usr/local/lib test.c

以上介绍了三种指定动态库搜索路径的方法,加上默认的动态库搜索路径
/lib


/usr/lib

,共五种动态库的搜索路径,那么它们搜索的先后顺序是什么呢?

在介绍上述三种方法时,分别创建了动态库
./libpos.so


/root/test/env/lib/libpos.so


/root/test/conf/lib/libpos.so

。我们再用源程序
pos_lib.c

(见程序
5

)来创建动态库
/lib/libpos.so

,用源程序
pos_usrlib.c

(见程序
6

)来创建动态库
/usr/lib/libpos.so


#include <stdio.h>
         void pos()
          {
                 printf("/lib/n");
           }
         


程序
5: pos_lib.c

#include <stdio.h>
        void pos()
         {
                printf("/usr/lib/n");
         }
       


程序
6: pos_usrlib.c



样我们得到五个动态库
libpos.so

,这些动态库的名字相同,且都包含相同函数原型

的公用函数
pos

。但存储的位置不同和公用函数
pos

打印的结果不同。每个动态库中的公用函数
pos

都输出该动态库所存放的位置。这样我们可以通过执行例
3

中的可执行文件
pos

得到的结果不同获知其搜索到了

哪个动态库,从而获得第
1

个动态库搜索顺序,然后删除该动态库,再执行程序
pos

,获得第
2

个动态库搜索路径,再删除第
2

个被搜索到的动态库,如此往复,

将可得到
Linux


搜索动态库的先后顺序。

程序
pos

执行的输出结果和搜索到的动态库的对应关系如表
1

所示:

程序
pos

输出结果

使用的动态库

对应的动态库搜索路径指定方式

./

./libpos.so

编译目标代码时指定的动态库搜索路径

/root/test/env/lib

/root/test/env/lib/libpos.so

环境变量
LD_LIBRARY_PATH

指定的动态库搜索路径

/root/test/conf/lib

/root/test/conf/lib/libpos.so

配置文件
/etc/ld.so.conf

中指定的动态库搜索路径

/lib

/lib/libpos.so

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

/usr/lib

/usr/lib/libpos.so

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


1:

程序
pos

输出结果和动态库的对应关系

创建各个动态库,并放置在相应的目录中。测试环境就准备好了。执行程序
pos

,并在该命令行中设置环境变量
LD_LIBRARY_PATH


# LD_LIBRARY_PATH=/root/test/env/lib ./pos
          ./
          #

根据程序
pos

的输出结果可知,最先搜索的是编译目标代码时指定的动态库搜索路径。然后我们把动态库
./libpos.so

删除了,再运行上述命令试试。

# rm libpos.so
        rm: remove regular file `libpos.so'? y
        # LD_LIBRARY_PATH=/root/test/env/lib ./pos
        /root/test/env/lib
        #

根据程序
pos

的输出结果可知,第
2

个动态库搜索的路径是环境变量
LD_LIBRARY_PATH

指定的。我们再把
/root/test/env/lib/libpos.so

删除,运行上述命令。

# rm /root/test/env/lib/libpos.so
         rm: remove regular file `/root/test/env/lib/libpos.so'? y
        # LD_LIBRARY_PATH=/root/test/env/lib ./pos
        /root/test/conf/lib
        #


3

个动态库的搜索路径是配置文件
/etc/ld.so.conf

指定的路径。删除动态库
/root/test/conf/lib/libpos.so

后再运行上述命令。

# rm /root/test/conf/lib/libpos.so
        rm: remove regular file `/root/test/conf/lib/libpos.so'? y
        # LD_LIBRARY_PATH=/root/test/env/lib ./pos
        /lib
        #


4

个动态库的搜索路径是默认搜索路径
/lib

。我们再删除动态库
/lib/libpos.so

,运行上述命令。

# rm /lib/libpos.so
        rm: remove regular file `/lib/libpos.so'? y
        # LD_LIBRARY_PATH=/root/test/env/lib ./pos
        /usr/lib
        #

最后的动态库搜索路径是默认搜索路径
/usr/lib


综合以上结果可知,动态库的搜索路径搜索的先后顺序是:

1.

编译目标代码时指定的动态库搜索路径;

2.

环境变量
LD_LIBRARY_PATH

指定的动态库搜索路径;

3.

配置文件
/etc/ld.so.conf

中指定的动态库搜索路径;

4.

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


5.

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


在上述
1


2


3

指定动态库搜索路径时,都可指定多个动态库搜索路径,其搜索的先后顺序是按指定路径的先后顺序搜索的。对此本文不再举例说明,有兴趣的读者可以参照本文的方法验证。

 

===

 

关键字: linux操作系统的头文件和库文件搜索路径

Include


header

文件
,

动态链接库,系统定义,总共有下列来源指定
gcc

去那里找。

当初在编译时指定的
(


~gcc/gcc/collect2.c:locatelib()

写在
specs

内的

,内定的,这是当初
compile gcc

时写在程序内的。

后来用
-D -I -L

指定的

gcc

环境变量设定
(

编译的时候
)

ld.so

的环境变量
(

这是
run time

的时候)

 

一、头文件


gcc

在编译时如何去寻找所需要的头文件:

※所以
header file

的搜寻会从
-I

开始

※然后找
gcc

的环境变量
C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH

※再找内定目录

/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

 

二、库文件


cos()

等函式库的选项要多加
-lm

编译的时候
:


gcc

会去找
-L

※再找
gcc

的环境变量
LIBRARY_PATH

※再找内定目录
/lib /usr/lib /usr/local/lib

这是当初
compile gcc

时写在程序内的

 

三、运行时动态库的搜索路径


1

、在配置文件
/etc/ld.so.conf

中指定动态库搜索路径

2

、通过环境变量
LD_LIBRARY_PATH

指定动态库搜索路径(当通过该环境变量指定多个动态库搜索路径时,路径之间用冒号
"


"

分隔)

3

、在编译目标代码时指定该程序的动态库搜索路径(还可以在编译目标代码时指定程序的动态库搜索路径。

这是通过
gcc

的参数
"-Wl,-rpath,"

指定(如例
3

所示)。当指定多个动态库搜索路径时,路径之间用冒号
"


"

分隔)

4

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

5

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

可以通过执行可执行文件
pos

得到的结果不同获知其搜索到了哪个动态库,从而获得第
1

个动态库搜索顺序,然后删除该动态库,

再执行程序
pos

,获得第
2

个动态库搜索路径,再删除第
2

个被搜索到的动态库,

如此往复,将可得到
Linux

搜索动态库的先后顺序。

程序
pos

执行的输出结果和搜索到的动态库的对应关系如表
1

所示

程序
pos

输出结果

使用的动态库

对应的动态库搜索路径指定方式

./ ./libpos.so

编译目标代码时指定的动态库搜索路径

/root/test/env/lib /root/test/env/lib/libpos.so

环境变量
LD_LIBRARY_PATH

指定的动态库搜索路径

/root/test/conf/lib /root/test/conf/lib/libpos.so

配置文件
/etc/ld.so.conf

中指定的动态库搜索路径

/lib /lib/libpos.so

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

/usr/lib /usr/lib/libpos.so

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

综合以上结果可知,动态库的搜索路径搜索的先后顺序是:

1.

编译目标代码时指定的动态库搜索路径;

2.

环境变量
LD_LIBRARY_PATH

指定的动态库搜索路径;

3.

配置文件
/etc/ld.so.conf

中指定的动态库搜索路径;


4.

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



5.

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


抱歉!评论已关闭.