linux编译指定库、头⽂件的路径问题
1. 为什么会出现undefined reference to 'xxxxx'错误?
⾸先这是链接错误,不是编译错误,也就是说如果只有这个错误,说明你的程序源码本⾝没有问题,是你⽤编译器编译时参数⽤得不对,你没有指定链接程序要⽤到得库,⽐如你的程序⾥⽤到了⼀些数学函数,那么你就要在编译参数⾥指定程序要链接数学库,⽅法是在编译命令⾏⾥加⼊-lm。
2.-l参数和-L参数
-l参数就是⽤来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库⽂件名有什么关系呢?就拿数学库来说,他的库名是m,他的库⽂件名是libm.so,很容易看出,把库⽂件名的头lib和尾.so去掉就是库名了。
-L参数跟着的是库⽂件所在的⽬录名。再⽐如我们把libtest.so放在/aaa/bbb/ccc⽬录下,那链接参数就是-L/aaa/bbb/ccc -ltest另外,⼤部分libxxxx.so只是⼀个链接
3. -include和-I参数
-include⽤来包含头⽂件,但⼀般情况下包含头⽂件都在源码⾥⽤#include xxxxxx实现,-include参数很
少⽤。-I参数是⽤来指定头⽂件⽬录,/usr/include⽬录⼀般是不⽤指定的,gcc知道去那⾥,但是如果头⽂件不在/usr/include⾥我们就要⽤-I参数指定了,⽐如头⽂件放在/myinclude⽬录⾥,那编译命令⾏就要加上-I/myinclude参数了,如果不加你会得到⼀个"xxxx.h: No such file or directory"的错误。-I参数可以⽤相对路径,⽐如头⽂件在当前⽬录,可以⽤-I.来指定
4.⼏个相关的环境变量
PKG_CONFIG_PATH:⽤来指定pkg-config⽤到的pc⽂件的路径,默认是 /usr/lib/pkgconfig,pc⽂件是⽂本⽂件,扩展名是.pc,⾥⾯定义开发包的安装路径,Libs参数和Cflags参数等等。
CC:⽤来指定c编译器。
CXX:⽤来指定cxx编译器。
LIBS:跟上⾯的--libs作⽤差不多。
CFLAGS:跟上⾯的--cflags作⽤差不多。
CC,CXX,LIBS,CFLAGS⼿动编译时⼀般⽤不上,在做configure时有时⽤到,⼀般情况下不⽤管。
环境变量设定⽅法:export ENV_NAME=xxxxxxxxxxxxxxxxx
==============================================================================
[相关介绍]
应⽤程序(Applications)
应⽤程序通常都有固定的⽂件夹,系统通⽤程序放在/usr/bin,⽇后系统管理员在本地计算机安装的程序通常放在/usr/local/bin或者/opt⽂件夹下。除了系统程序外,⼤部分个⼈⽤到的程序都放在/usr /local下,所以保持/usr的整洁⼗分重要。当升级或者重装系统的时候,只要把/usr/local的程序备份⼀下就可以了。
⼀些其他的程序有⾃⼰特定的⽂件夹,⽐如X Window系统,通常安装在/usr/X11中,或者/usr/X11R6。GNU的编译器GCC,通常放置在/usr/bin或者/usr/local/bin中,不同的Linux版本可能位置稍有不同。
头⽂件(Head Files)
在C语⾔和其他语⾔中,头⽂件声明了系统函数和库函数,并且定义了⼀些常量。对于C语⾔,头⽂件
基本上散落于/usr/include和它的⼦⽂件夹下。其他的编程语⾔的库函数分布在编译器定义的地⽅,⽐如在⼀些Linux版本中,X Window系统库函数分布在/usr/include/X11,GNU C++的库函数分布在/usr/include/g++。这些系统库函数的位置对于编译器来说都
是“标准位置”,即编译器能够⾃动搜寻这些位置。
如果想引⽤位于标准位置之外的头⽂件,我们需要在调⽤编译器的时候加上-I标志,来显式的说明头⽂件所在⽂件夹。⽐如,
$ gcc -I/usr/openwin/include hello.c
会告诉编译器除了标准位置外,还要去/usr/openwin/include看看有没有所需的头⽂件。详细情况见编译器的使⽤⼿册(man gcc)。
库函数(Library Files)
库函数就是函数的仓库,它们都经过编译,重⽤性不错。通常,库函数相互合作,来完成特定的任务。⽐如操控屏幕的库函数(cursers和ncursers库函数),数据库读取库函数(dbm库函数)等。
系统调⽤的标准库函数⼀般位于/lib以及/usr/lib。C编译器(精确点说,连接器)需要知道库函数的位置。默认情况下,它只搜索标准C库函数。
库函数⽂件通常开头字母是lib。后⾯的部分标⽰库函数的⽤途(⽐如C库函数⽤c标识, 数学库函数⽤m标⽰),⼩数点后的后缀表明库函数的类型:.a 指静态链接库
.so 指动态链接库
去/usr/lib看⼀下,你会发现,库函数都有动态和静态两个版本。
查看动态库函数⼯具: ldd *.so
与头⽂件⼀样,库函数通常放在标准位置,但我们也可以通过-L标识符,来添加新的搜索⽂件夹,-l指定特定的库函数⽂件。⽐如
$ gcc -o x11fred -L/usr/openwin/lib x11fred.c -lX11
gnu编译器上述命令就会在编译期间,链接位于/usr/openwin/lib⽂件夹下的libX11函数库,编译⽣成x11fred。
静态链接库(Static Libraries)
最简单的函数库就是⼀些函数的简单集合。调⽤库函数中的函数时,需要在调⽤函数中include定义库函数的头⽂件。我们⽤-l选项添加标准函数库之外的函数库。
静态函数库,也称为archives ,通常以后缀.a结尾。
我们也可以创建维护⾃⼰的静态链接库函数。下⾯就介绍⼀下:
我们创建的库函数包括两个函数,然后在后⾯的实例中调⽤其中之⼀。两个库函数名字分别是fred和bill,仅仅是输出字符串。
1. ⾸先,我们分别编写两个源⽂件(fred.c和bill.c),源⽂件如下:
1. /* fred.c */
2. #include <stdio.h>
3. void fred(int arg)
4. {
5. printf(“fred: you passed %d\n”, arg);
6. }
7. /* bill.c */
8. #include <stdio.h>
9. void bill(char *arg)
10. {
11. printf(“bill: you passed %s\n”, arg);
12. }
/* fred.c */ #include <stdio.h> void fred(int arg) { printf(“fred: you passed %d\n”, arg); } /* bill.c */ #include <stdio.h> void bill(char *arg) { printf(“bill: you passed %s\n”, arg); }
2. 接下来,我们将这两个源⽂件编译为两个独⽴的⽬标⽂件。这⾥要⽤到GCC的-c选项。命令如下所⽰:
$ gcc -c fred.c bill.c
$ ls *.o
bill.o fred.o
3. 然后,写⼀个调⽤bill的测试函数,在此之前,最好为库函数建⽴⼀个头⽂件。头⽂件中有对库函数的声明。如果其他函数要调⽤库函数,必须在其代码中包含头⽂件。也可以在fred.c 和bill.c中包含该头⽂件,有利于编译器发现错误。头⽂件lib.h的内容如下所⽰:
1. /*
2. This is lib.h. It declares the functions fred and bill for users
3. */
4. void bill(char *);
5. void fred(int);
/* This is lib.h. It declares the functions fred and bill for users */ void bill(char *); void fred(int);
4. 测试函数program.c⽐较简单,代码如下:
1. #include “lib.h”
2. int main()
3. {
4. bill(“Hello World”);
5. exit(0);
6. }
#include “lib.h” int main() { bill(“Hello World”); exit(0); }
5. 现在我们可以编译测试⼀下程序了:
$ gcc -c program.c
$ gcc -o program program.o bill.o
$ ./program
bill: we passed Hello World
6. 接下来,我们要创建⼀个函数库。利⽤ar函数建⽴归档⽂件(archive),然后将⽬标⽂件加⼊其中。
$ ar crv libfoo.a bill.o fred.o
a - bill.o
a - fred.o
7. 现在可以使⽤函数库中的函数了。我们⽤-l指定函数库的名字。因为该函数库没有在标准⽂件夹中,我们还需要⽤-L将当前⽂件夹"."添加到搜索路径中。编译命令如下所⽰:
$ gcc -o program program.o -L. -lfoo
共享链接库(Shared Libraries)
静态链接库的⼀个缺点是,如果我们同时运⾏了许多程序,并且它们使⽤了同⼀个库函数,这样,在内存中会⼤量拷贝同⼀库函数。这样,就会浪费很多珍贵的内存和存储空间。使⽤了共享链接库的Linux就可以避免这个问题。
共享函数库和静态函数在同⼀个地⽅,只是后缀有所不同。⽐如,在⼀个典型的Linux系统,标准的共享数序函数库是/usr/lib/libm.so。
当⼀个程序使⽤共享函数库时,在连接阶段并不把函数代码连接进来,⽽只是链接函数的⼀个引⽤。当最终的函数导⼊内存开始真正执⾏时,函数引⽤被解析,共享函数库的代码才真正导⼊到内存中。这样,共享链接库的函数就可以被许多程序同时共享,并且只需存储⼀次就可以了。共享函数库的另⼀个优点是,它可以独⽴更新,与调⽤它的函数毫不影响。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论