1.为何会出现undefinedreferenceto'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拿来包含头文件,但通常情况下包含头文件都在源码里用#includexxxxxx实现,-include参数极少用。-I参数是拿来指定头文件目录,/usr/include目录通常是不用指定的,gcc晓得去哪里找,而且倘若头文件不在/usr/include里我们就要用-I参数指定了,例如头文件置于/myinclude目录里,那编译命令行就要加上-I/myinclude参数了,若果不加你会得到一个"xxxx.h:Nosuchfileordirectory"的错误。-I参数可以用相对路径,例如头文件在当前目录,可以用-I.来指定
4.几个相关的环境变量
PKG_CONFIG_PATH:拿来指定pkg-config用到的pc文件的路径,默认是/usr/lib/pkgconfig,pc文件是文本文件linux include 头文件,扩充名是.pc,上面定义开发包的安装路径linux include 头文件,Libs参数和Cflags参数等等。
CC:拿来指定c编译器。
CXX:拿来指定cxx编译器。
LIBS:跟前面的--libs作用差不多。
CFLAGS:跟前面的--cflags作用差不多。
CC,CXX,LIBS,CFLAGS自动编译时通常用不上,在做configure时有时用到,通常情况下不用管。
环境变量设定方式:exportENV_NAME=xxxxxxxxxxxxxxxxx
==============================================================================
[相关介绍]
应用程序(Applications)
应用程序一般都有固定的文件夹,系统通用程序置于/usr/bin,日后系统管理员在本地计算机安装的程序一般置于/usr/local/bin或则/opt文件夹下。不仅系统程序外,大部份个人用到的程序都置于/usr/local下,所以保持/usr的整洁非常重要。当升级或则重装系统的时侯,只要把/usr/local的程序备份一下就可以了。
一些其他的程序有自己特定的文件夹,例如XWindow系统,一般安装在/usr/X11中,或则/usr/X11R6。GNU的编译器GCC,一般放置在/usr/bin或则/usr/local/bin中,不同的Linux版本可能位置稍有不同。
头文件(HeadFiles)
在C语言和其他语言中,头文件申明了系统函数和库函数,而且定义了一些常量。对于C语言,头文件基本上洒落于/usr/include和它的子文件夹下。其他的编程语言的库函数分布在编译器定义的地方,例如在一些Linux版本中,XWindow系统库函数分布在/usr/include/X11,GNUC++的库函数分布在/usr/include/g++。这种系统库函数的位置对于编译器来说都是“标准位置”,即编译器才能手动搜救这种位置。
假如想引用坐落标准位置之外的头文件,我们须要在调用编译器的时侯加上-I标志,来显式的说明头文件所在文件夹。例如,
$gcc-I/usr/openwin/includehello.c
会告诉编译器不仅标准位置外,还要去/usr/openwin/include瞧瞧有没有所需的头文件。详尽情况见编译器的使用指南(mangcc)。
库函数(LibraryFiles)
库函数就是函数的库房,它们都经过编译,重用性不错。一般,库函数互相合作,来完成特定的任务。例如操控屏幕的库函数(cursers和ncursers库函数),数据库读取库函数(dbm库函数)等。
系统调用的标准库函数通常坐落/lib以及/usr/lib。C编译器(精确点说,联接器)须要晓得库函数的位置。默认情况下,它只搜索标准C库函数。
库函数文件一般开头字母是lib。前面的部份标识库函数的用途(例如C库函数用c标示,物理库函数用m标识),小数点后的后缀表明库函数的类型:
去/usr/lib看一下linux操作系统版本,你会发觉,库函数都有动态和静态两个版本。
查看动态库函数工具:ldd*.so
与头文件一样,库函数一般置于标准位置,但我们也可以通过-L标示符,来添加新的搜索文件夹,-l指定特定的库函数文件。诸如
$gcc-ox1111fred-L/usr/openwin/libx11fred.c-lX11
上述命令都会在编译期间,链接坐落/usr/openwin/lib文件夹下的libX11函数库,编译生成x1111fred。
静态链接库(StaticLibraries)
最简单的函数库就是一些函数的简单集合。调用库函数中的函数时,须要在调用函数中include定义库函数的头文件。我们用-l选项添加标准函数库之外的函数库。
静态函数库,亦称为archives,一般以后缀.a结尾。
我们也可以创建维护自己的静态链接库函数。下边就介绍一下:
我们创建的库函数包括两个函数,之后在前面的实例中调用其中之一。两个库函数名子分别是fred和bill,仅仅是输出字符串。
首先,我们分别编撰两个源文件(fred.c和bill.c),源文件如下:
/*fred.c*/#includevoidfred(intarg){printf(“fred:youpassed%dn”,arg);}/*bill.c*/#includevoidbill(char*arg){printf(“bill:youpassed%sn”,arg);}
/*fred.c*/#includevoidfred(intarg){printf(“fred:youpassed%dn”,arg);}/*bill.c*/#includevoidbill(char*arg){printf(“bill:youpassed%sn”,arg);}
2.接出来,我们将这两个源文件编译为两个独立的目标文件。这儿要用到GCC的-c选项。命令如下所示:
$gcc-cfred.cbill.c
$ls*.o
bill.ofred.o
3.之后,写一个调用bill的测试函数,在此之前,最好为库函数构建一个头文件。头文件中有对库函数的申明。倘若其他函数要调用库函数,必须在其代码中包含头文件。也可以在fred.c和bill.c中包含该头文件,有利于编译器发觉错误。头文件lib.h的内容如下所示:
/*Thisislib.h.Itdeclaresthefunctionsfredandbillforusers*/voidbill(char*);voidfred(int);
/*Thisislib.h.Itdeclaresthefunctionsfredandbillforusers*/voidbill(char*);voidfred(int);
4.测试函数program.c比较简单,代码如下:
#include“lib.h”intmain(){bill(“HelloWorld”);exit(0);}
#include“lib.h”intmain(){bill(“HelloWorld”);exit(0);}
5.如今我们可以编译测试一下程序了:
$gcc-cprogram.c
$gcc-oprogramprogram.obill.o
$./program
bill:wepassedHelloWorld
6.接出来,我们要创建一个函数库。借助ar函数构建归档文件(archive),之后将目标文件加入其中。
$arcrvlibfoo.abill.ofred.o
a-bill.o
a-fred.o
7.如今可以使用函数库中的函数了。我们用-l指定函数库的名子。由于该函数库没有在标准文件夹中,我们还须要用-L将当前文件夹"."添加到搜索路径中。编译命令如下所示:
$gcc-oprogramprogram.o-L.-lfoo
共享链接库(SharedLibraries)
静态链接库的一个缺点是,假如我们同时运行了许多程序,但是它们使用了同一个库函数,这样,在显存中会大量拷贝同一库函数。这样,还会浪费好多珍稀的显存和储存空间。使用了共享链接库的Linux就可以避开这个问题。
共享函数库和静态函数在同一个地方,只是后缀有所不同。例如,在一个典型的Linux系统,标准的共享数序函数库是/usr/lib/libm.so。
当一个程序使用共享函数库时,在联接阶段并不把函数代码联接进来,而只是链接函数的一个引用。当最终的函数导出显存开始真正执行时,函数引用被解析,共享函数库的代码才真正导出到显存中。这样,共享链接库的函数就可以被许多程序同时共享小型linux系统,而且只需储存一次就可以了。共享函数库的另一个优点是,它可以独立更新,与调用它的函数毫不影响。