文档章节

Linux的makefile中的选项

zhangyujsj
 zhangyujsj
发布于 2014/12/13 22:43
字数 2491
阅读 72
收藏 1

1 大体的理解

关于linux编程中库的问题,我们先来点整体上的理解:CFLAGS: 指定头文件(.h文件)的路径,如:CFLAGS=-I/usr/include -I/path/include。同样地,安装一个包时会在安装路径下建立一个include目录,当安装过程中出现问题时,试着把以前安装的包的 include目录加入到该变量中来。

LDFLAGS:gcc 等编译器会用到的一些优化参数,也可以在里面指定库文件的位置。用法:LDFLAGS=-L/usr/lib -L/path/to/your/lib。每安装一个包都几乎一定的会在安装目录里建立一个lib目录。如果明明安装了某个包,而安装另一个包时,它愣是 说找不到,可以抒那个包的lib路径加入的LDFALGS中试一下。

LIBS:告诉链接器要链接哪些库文件,如LIBS = -lpthread -liconv

简单地说,LDFLAGS是告诉链接器从哪里寻找库文件,而LIBS是告诉链接器要链接哪些库文件。不过使用时链接阶段这两个参数都会加上,所以你即使将这两个的值互换,也没有问题。

有时候LDFLAGS指定-L虽然能让链接器找到库进行链接,但是运行时链接器却找不到这个库,如果要让软件运行时库文件的路径也得到扩展,那么我们需要增加这两个库给"-Wl,R":

LDFLAGS = -L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib

如果在执行./configure以前设置环境变量export LDFLAGS="-L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib" ,注意设置环境变量等号两边不可以有空格,而且要加上引号(shell的用法)。那么执行configure以后,Makefile将会设置这个选项,链 接时会有这个参数,编译出来的可执行程序的库文件搜索路径就得到扩展了。

2 从理论上深入地解释下

本文详细介绍了linux gcc头文件指定方法,以及搜索路径顺序的问题。另外,还总结了,gcc动态链接的方法以及路径指定,同样也讨论了搜索路径的顺序问题。本文包含了很多的例子,具有很强的 操作性,希望读者自己去走一遍。

.#include <>#include “”

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

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

 

.gcc指定头文件的三种情况:

1.会在默认情况下 指定到/usr/include文件夹(更深层次的是一个相对路径,gcc可执行程序的路径是/usr/bin/gcc,那么它在实际工作时指定头文件头径是一种相对路径方法,换算成绝对路径就是加上/usr/include,如#include <stdio.h>就是包含/usr/include/stdio.h)

 

2.GCC还使用了-I指定路径的方式,即

gcc -I 头文件所在文件夹(绝对路径或相对路径均可)   源文件

举一个例子:

设当前路径为/root/test,其结构如下:

include_test.c

include/include_test.h

有两种方法访问到include_test.h

1. include_test.c#include “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也可

 

3. 参数:-nostdinc使编译器不再系统缺省的头文件目录里面找头文件,一般和-I联合使用,明确限定头文件的位置。

 

在编译驱动模块时,由于非凡的需 求必须强制GCC不搜索系统默认路径,也就是不搜索/usr/include要用参数-nostdinc,还要自己用-I参数来指定内核头文件路径,这个时候必须在Makefile中指定。

 

头文件搜索顺序:

1.由参数-I指定的路径(指定路径有多个路径时,按指定路径的顺序搜索)

 

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

/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

 

.Linux指定动态库路径

 

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

 

 

1.在配置文件/etc/ld.so.conf中指定动态库搜索路径。

可以通过编辑配置文件/etc/ld.so.conf来指定动态库的搜索路径,该文件中每行为一个动态库搜索路径。每次编辑完该文件后,都必须运行命令ldconfig使修改后的配置生效。

 

举一个例子:

所有源文件:

源文件1: lib_test.c

#include <stdio.h>

void prt()

{

     printf("You found me!!!\n");

}

源文件2: main.c

void prt();

int main()

{

      prt();

      return 0;

}

操作过程:

我们通过以下命令用源程序lib_test.c来创建动态库 lib_test.so

# gcc –o lib_test.o -c lib_test.c

# gcc -shared -fPIC -o lib_test.so  lib_test.o

#

或者直接一条指令:

#gcc –shared –fPIC –o lib_test.so  lib_test.c

#

 

注意:

-fPIC参数声明链接库的代码段是可以共享的,

-shared参数声明编译为共享库。请注意这次我们编译的共享库的名字叫做

lib_test.so,这也是Linux共享库的一个命名的惯例了:后缀使用so,而名称使用libxxxx格式。

 

接着通过以下命令编译main.c,生成目标程序main.out

# gcc -o main.out  -L. –l_test  main.c

#

请注意为什么是-l_test?

 

然后把库文件移动到目录/root/lib中。

# mkdir /root/lib

# mv lib_test.so /root/lib/ lib_test.so

#

 

最后编辑配置文件/etc/ld.so.conf,在该文件中追加一行/root/lib

 

运行程序main.out:

# ./main.out

./main.out: error while loading shared libraries: lib_test.so: cannot open shared object file: No such file or directory

#

出错了,系统未找到动态库lib_test.so。找找原因,原来在编辑完配置文件/etc/ld.so.conf后,没有运行命令ldconfig,所以刚才的修改还未生效。我们运行ldconfig后再试试。

 

# ldconfig

# ./main.out

You found me!!!

#

程序main.out运行成功,并且打印出正确结果。

 

2.通过环境变量LD_LIBRARY_PATH指定动态库搜索路径。

通过设定环境变量LD_LIBRARY_PATH也可以指定动态库搜索路径。当通过该环境变量指定多个动态库搜索路径时,路径之间用冒号":"分隔。下面通过例2来说明本方法。

 

举一个例子:

这次我们把上面得到的文件lib_test.so移动到另一个地方去,如/root下面,然后设置环境变量LD_LIBRARY_PATH找到lib_test.so。设置环境变量方法如下:

# export LD_LIBRARY_PATH=/root

#

然后运行:

#./main.out

You found me!!!

#

注意:设置环境变量LD_LIBRARY_PATH=/root是不行的,非得export才行。

 

3.在编译目标代码时指定该程序的动态库搜索路径。

还可以在编译目标代码时指定程序 的动态库搜索路径。-Wl,表示后面的参数将传给link程序ld(因为gcc可能会自动调用ld)。这里通过gcc 的参数"-Wl,-rpath,"指定

举一个例子:

这次我们还把上面得到的文件lib_test.so移动到另一个地方去,如/root/test/lib下面,

因为我们需要在编译目标代码时指 定可执行文件的动态库搜索路径,所以需要用gcc命令重新编译 源程序main.c(见程序2)来生成可执行文件main.out

# gcc -o main.out   -L.   –l_test  -Wl,-rpath,/root/test/lib    main.c

#

 

运行结果:

# ./main.out

You found me!!!

#

 

程序./main.out运行成功,输出的结果正是main.c中的函数prt的运行结果。因此程序main.out搜索到的动态库是/root/test/lib/lib_test.so

 

关于-Wl,rpath的使用方法我再举一个例子,应该不难从中看出指定多个路径的方法:

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

 

以上介绍了三种指定动态库搜索路 径的方法,加上默认的动态库搜索路径/lib/usr/lib,共五种动态库的搜索路径,那么它们搜索的先后顺序是什么呢?读者可以用下面的方法来试验一下:

(1)       用前面介绍的方法生成5lib_test.so放在5个不同的文件夹下面,要求每一个lib_test.so都唯一对应一个搜索路径,并注意main.out程序输出的不同。

(2)       运行main.out,即可看 出他是那个搜索路径下的,然后删除这个路径下的lib_test.so,然后再运行。依此类推操作,即可推出搜索顺序。

 

可以得出动态库的搜索路径搜索的 先后顺序是:

 

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

 

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

 

3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;

 

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

 

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

 

在上述123指定动态库搜索路径时,都可指定多个动态库搜索路径,其搜索的先后顺序是按指定路径的先后顺序搜索 的。有兴趣的读者自己验证。


本文转载自:blog.chinaunix.net/uid-23215128-id-2521319.html

zhangyujsj
粉丝 24
博文 358
码字总数 224241
作品 0
广州
私信 提问
加载中

评论(1)

程序手艺人
程序手艺人
写的简单易懂,非常棒:bowtie:
如何编译一个嵌入式的linux内核

1. 配置系统的基本结构 Linux内核的配置系统由三个部分组成,分别是: Makefile:分布在 Linux 内核源代码中的 Makefile,定义 Linux 内核的编译规则; 配置文件(config.in):给用户提供配...

LiSteven
2012/07/25
300
0
Linux下用C语言最基本的程序开发与调试

1.建一个目录 2.写代码,建一个hello.c文件 代码: view plain copy to clipboard print ? #include "stdio.h" main() { printf("Hello Linux.\n") } 记得最后一定要换行 3.编译 gcc -o hel......

晨曦之光
2012/03/09
2.5K
0
探索 Linux 内核:Kconfig/kbuild 的秘密

深入理解 Linux 配置/构建系统是如何工作的。 自从 Linux 内核代码迁移到 Git 以来,Linux 内核配置/构建系统(也称为 Kconfig/kbuild)已存在很长时间了。然而,作为支持基础设施,它很少成...

作者: Cao Jin
08/15
0
0
用qmake生成Makefile

1.简介:   qmake是Trolltech公司创建的用来为不同的平台和编译器书写Makefile的工具。是qt工具包的一部分.在Unix&linux上写程式的人大概都碰过Makefile。用 make来开发和编译程式的确很方便...

openthings
2015/01/22
3.6K
0
编写驱动的makefile使要

一般在编译linux驱动时,我们需要在交叉编译环境中进行编译,所以要在编译环境中搭建交叉编译环境。编写驱动的makefile使需要制定驱动依赖的内核的路径,makefile写法如下: KERN_DIR = /xx...

天王盖地虎626
2018/12/11
7
0

没有更多内容

加载失败,请刷新页面

加载更多

崛起于Springboot2.X之5分钟解决单点登陆(53)

SpringBoot2.X心法总纲 1、pom文件依赖 <dependency> <groupId>com.majiaxueyuan</groupId> <artifactId>sso-core</artifactId> <version>1.2.2</version></dependency> 2、......

木九天
4分钟前
0
0
面向对象和面向过程的区别

面向过程 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。 缺点:没有面向对...

无名氏的程序员
5分钟前
0
0
OpenStack大事记

2010年7月19日,Rackspace、NASA、Citrix、Dell共同开发并发布OpenStack第一个版本。 2011年10月,Rackspace放弃OpenStack控制权,交由OpenStack藕色 2012年5月NASA宣布退出OpenStack的开发。...

大别阿郎
5分钟前
0
0
面向对象的简单应用—以交通工具(Vehicle)为列

请定义一个交通工具(Vehicle)的类其中有: 属性: 速度(speed)、 体积(size)等,方法:移动(move())、设置速度(setSpeed(int speed))、加速 speedUp()、减速 speedDown()等。最后在测试类 Ve...

INEVITABLE
16分钟前
1
0
通往艺术家之路

通往艺术家之路 并发编程中,开发者往往需要权衡锁的颗粒粗细,锁住的代码块太大呢会导致可能的线程堵塞,锁的颗粒太细呢又会因为频繁地加锁解锁导致系统用户态内核态的转换从而消费很多时间...

StupidZhe
17分钟前
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部