您的位置:首页 > 运维架构 > Linux

【基础知识】linux c 编译链接运行、动态链接库

2013-03-14 16:42 330 查看
编译链接时:

使用pkg-config xxx --libs --cflags,完成和库xxx的链接

链接时易出现 multiple definition of xx:

头文件的作用就是被其他的.cpp包含进去的。它们本身并不参与编译,但实际上,它们的内容却在多个.cpp文件中得到了 编译。通过“定义只能有一次”的规则,我们很容易可以得出,头文件中应该只放变量和函数的声明,而不能放它们的定义。因为一个头文件的内容实际上是会被引 入到多个不同的.cpp文件中的,并且它们都会被编译。放声明当然没事,如果放了定义,那么也就相当于在多个文件中出现了对于一个符号(变量或函数)的定 义,纵然这些定义都是相同的,但对于编译器来说,这样做不合法。所以,应该记住的一点就是,.h头文件中,只能存在变量或者函数的声明,
而不要放定义
。即,只能在头文件中写形如:extern int a;和void f();的句子。这些才是声明。如果写上int a;或者void f() {}这样的句子,那么一旦这个头文件被两个或两个以上的.cpp文件包含的话,编译器会立马报错。

这个头文件规则是有三个例外的:reference

1. 头文件中可以写const/static对象的定义。因为全局的const对象默认是没有extern的声明的,所以它只在当前文件中有效。另外包含了头文件的源文件中的这个const对象的值是相同的,可谓一举两得。

2. 头文件中可 以写内联函数(inline)的定义。因为inline函数是需要编译器在遇到它的地方根据它的定义把它内联展开的,而并非是普通函数那样可以先声明再链 接的(内联函数不会链接),所以编译器就需要在编译时看到内联函数的完整定义才行。如果内联函数像普通函数一样只能定义一次的话,这事儿就难办了。因为在 一个文件中还好,我可以把内联函数的定义写在最开始,这样可以保证后面使用的时候都可以见到定义;但是,如果我在其他的文件中还使用到了这个函数那怎么办 呢?这几乎没什么太好的解决办法,因此C++规定,内联函数可以在程序中定义多次,只要内联函数在一个.cpp文件中只出现一次,并且在所有的.cpp文
件中,这个内联函数的定义是一样的,就能通过编译。那么显然,把内联函数的定义放进一个头文件中是非常明智的做法。

3. 头文件中可以写类 (class)的定义。因为在程序中创建一个类的对象时,编译器只有在这个类的定义完全可见的情况下,才能知道这个类的对象应该如何布局,所以,关于类的 定义的要求,跟内联函数是基本一样的。所以把类的定义放进头文件,在使用到这个类的.cpp文件中去包含这个头文件,是一个很好的做法。在这里,值得一提 的是,类的定义中包含着数据成员和函数成员。数据成员是要等到具体的对象被创建时才会被定义(分配空间),但函数成员却是需要在一开始就被定义的,这也就 是我们通常所说的类的实现。一般,我们的做法是,把类的定义放在头文件中,而把函数成员的实现代码放在一个.cpp文件中。这是可以的,也是很好的办法。
不过,还有另一种办法。那就是直接把函数成员的实现代码也写进类定义里面。在C++的类中,如果函数成员在类的定义体中被定义,那么编译器会视这个函数为 内联的。因此,把函数成员的定义写进类定义体,一起放进头文件中,是合法的。注意一下,如果把函数成员的定义写在类定义的头文件中,而没有写进类定义中, 这是不合法的,因为这个函数成员此时就不是内联的了。一旦头文件被两个或两个以上的.cpp文件包含,这个函数成员就被重定义了。

运行时:

  动态库的搜索路径搜索的先后顺序是:

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

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

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

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

  如果运行时缺少库失败:

  使用ldd查看需要哪些库,其中缺少的库会指向not found:


  ldd a

  linux-gate.so.1 =>  (0x001c9000)

  libxx_xx.so.x.x => not found 

  1 库没有安装,安装相应dev包

  2 库没有添加到系统动态库搜索路径,或者虽然加进来了,但是还没被系统索引。


  vi /etc/ld.so.conf

  加入:/path to xx/lib

  执行ldconfig

  ldd:怎么知道可执行文件运行时需要哪些库:

  ldd <可执行文件名>       查看可执行文件链接了哪些  系统动态链接库

  nm <可执行文件名>       查看可执行文件里面有哪些符号

  strip <可执行文件名>      去除符号表可以给可执行文件瘦身

  如果我们想从可执行程序里面提取出来一点什么文本信息的话,还可以用strings命令

  strings <可执行文件名>

linux操作系统上面的动态共享库大致分为三类:

1、操作系统级别的共享库和基础的系统工具库

2、应用程序级别的系统共享库

以上两类的动态共享库,应用程序会自动寻找到他们,并不需要你额外的设置和担心。这是为什么呢? 因为以上这些目录默认就被加入到动态链接程序的搜索路径里面了。Linux的系统共享库搜索路径定义在/etc/ld.so.conf这个配置文件里面。 

假设我们自己编译安装的ImageMagick图形库在/usr/local/ImageMagick目录下面,并且希望其他应用程序都可以使用 ImageMagick的动态共享库,那么我们只需要把/usr/local/ImageMagick/lib目录加入/etc/ld.so.conf文 件里面,然后执行:ldconfig 命令即可。

3、应用程序独享的动态共享库

有很多共享库只被特定的应用程序使用,那么就没有必要加入系统库路径,以免应用程序的共享库之间发生版本冲突。因此Linux还可以通过设置环境变 量LD_LIBRARY_PATH来临时指定应用程序的共享库搜索路径,就像我们上面举的那个例子一样,我们可以在应用程序的启动脚本里面预先设置 LD_LIBRARY_PATH,指定本应用程序附加的共享库搜索路径,从而让应用程序找到它。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: