库链接的问题

编译:

编译过程是以每个.cpp文件为独立的编译单位的,生成一个个.obj

编译过程,将引用文件在.cpp文件中展开,并检查是否有正确的声明。如果该函数没有定义,编译器认为在连接过程可以在其他.obj文件中找到。

头文件路径是通过编译器默认设置以及用户通过-I选项添加的,默认的include路径,可以通过指令来查看

echo | g++ -v -x c++ -E -

连接过程,将上面没有定义的函数,在其他.obj中查找定义,如果没有找到,则会报undefine reference的问题。

而查找链接库时所用的路径是,通过变量LIBRARY_PATH设置,但是变量LIBRARY_PATH只是在编译期间使用,作为查找动态链接库时指定查找共享库的路径。

执行

在可执行文件执行时,会通过LD_LIBRARY_PATH查找动态链接库的。

LD_LIBRARY_PATH环境变量用于在程序加载运行期间查找动态链接库时指定除了系统默认路径之外的其他路径。

注意

LD_LIBRARY_PATH中指定多个的路径,查找动态库的时候会按序查找

举个例子,如果我们make了opencv的debug版本,和opencv的release版本,这两个版本在程序中都会用到,所以需要将两个版本的lib的路径,都添加到环境变量LD_LIBRARY_PATH中,假如我们将debug版本的路径放在release版本的前面,那么程序执行运行时,如果需要用到opencv库,那么都会先查找debug的路径,即都执行的是debug的lib,无论用户本意如何。

那么问题来了,这时就涉及为什么要设置两次library path?LIBRARY_LIB设置的路径在运行时不能使用么?

答:开发时,设置LIBRARY_PATH,以便gcc能够找到编译时需要的动态链接库。

发布时(执行时),设置LD_LIBRARY_PATH,以便程序加载运行时能够自动找到需要的动态链接库,如果更改LD_LIBRARY_PATH,不需要重新编译也可以完成更新。

即LIBRARY_PATH只是为了编译时能够确定是否存在连接函数的定义,即obj;而,当编译结束后,可执行文件具执行的时候,是通过LD_LIBRARY_PATH来查找obj的)

所以,是的,LIBRARY_PATH设置的路径不能再运行时使用。

但是我还有个问题

因为是在运行的时候连接,会不会影响速度?因为得查找所有的 动态链接库文件,而编译的时候就可以执行lib目录下的那些库文件

静态链接库,连接时注意事项:

使用静态连接库时,在链接命令中给出所依赖的库时,需要注意库之间的依赖顺序,依赖其他库的库一定要放到被依赖库的前面,这样才能真正避免undefined reference的错误,完成编译链接。

动态链接库不存在这个问题。

动态链接库和静态链接库的区别

静态连接库就是把(lib)文件中用到的函数代码直接链接进目标程序,程序运行的时候不再需要其它的库文件;动态链接就是把调用的函数所在文件模块(DLL)和调用函数在文件中的位置等信息链接进目标程序,程序运行的时候再从DLL中寻找相应函数代码,因此需要相应DLL文件的支持。

静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了。但是若使用 DLL,该 DLL 不必被包含在最终 EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与 EXE 独立的 DLL 文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。

我们遇到的问题是:

1.

从别的机器上拷贝过来的工程代码,更新库路径。

但是运行的时候出现段错误。

这是系统安装的opencv库的问题。

2.

我们重新安装了一个debug版本的opencv,并想用这个库。

具体操作如下,make之后(并没有install),将-I,-L路径都连接到信的目录,但是编译的时候出错,错误如下:

这是因为,我们的debug库是未安装的,include下头文件不全,所以报这样的错,然后我们将-I路径换为系统的opencv的include,就编译通过了。

3.

但是然后很奇怪的事情发生了,如果直接登录我的账号,执行,会出现段错误,如果李同学从他的账户su到我的账户,执行,就正常。

这是因为我们的~/.bashrc文件不同

他在~/.bashrc中直接将LD_LIBRARY_PATH中的路径赋值为$USER_OPENCV_HOME/lib,而他这个USER_OPENCV_HOME是自己安装的lib,

而我是这样添加的

export LD_LIBRARY_PATH = $LD_LIBRARY_PATH: $USER_OPENCV_LIB/lib

这样,查找动态连接库时,会直接先查找usr/local下的opencv库,而这个库有问题,所以就出现了上述情况。

改为这样就可以了

export LD_LIBRARY_PATH = $USER_OPENCV_LIB/lib: $LD_LIBRARY_PATH

另外,我的.bashrc文件只能通过新开一个会话,才能有更新,用source不行,不知道为什么

另外,调用cv::getBuildInformation()函数,可查看可执行文件当前使用的库的信息,库信息,跟所调用的库有关,即跟LD_LIBRARY_PATH有关。


补充

linux静态链接库与动态链接库的区别及动态库的创建(转)

一、引言

通常情况下,对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象文件(object file)与牵涉到的函数库(library)被链接合成一个可执行文件(executable file)。程序在运行时,与函数库再无瓜葛,因为所有需要的函数已拷贝到自己门下。所以这些函数库被成为静态库(static libaray),通常文件名为“libxxx.a”的形式。

其实,我们也可以把对一些库函数的链接载入推迟到程序运行的时期(runtime)。这就是如雷贯耳的动态链接库(dynamic link library)技术。

二、动态链接库的特点与优势

首先让我们来看一下,把库函数推迟到程序运行时期载入的好处:

  1. 可以实现进程之间的资源共享。

    什么概念呢?就是说,某个程序的在运行中要调用某个动态链接库函数的时候,操作系统首先会查看所有正在运行的程序,看在内存里是否已有此库函数的拷贝了。如果有,则让其共享那一个拷贝;只有没有才链接载入。这样的模式虽然会带来一些“动态链接”额外的开销,却大大的节省了系统的内存资源。C的标准库就是动态链接库,也就是说系统中所有运行的程序共享着同一个C标准库的代码段。

  2. 将一些程序升级变得简单。用户只需要升级动态链接库,而无需重新编译链接其他原有的代码就可以完成整个程序的升级。Windows 就是一个很好的例子。
  3. 甚至可以真正坐到链接载入完全由程序员在程序代码中控制。

    程序员在编写程序的时候,可以明确的指明什么时候或者什么情况下,链接载入哪个动态链接库函数。你可以有一个相当大的软件,但每次运行的时候,由于不同的操作需求,只有一小部分程序被载入内存。所有的函数本着“有需求才调入”的原则,于是大大节省了系统资源。比如现在的软件通常都能打开若干种不同类型的文件,这些读写操作通常都用动态链接库来实现。在一次运行当中,一般只有一种类型的文件将会被打开。所以直到程序知道文件的类型以后再载入相应的读写函数,而不是一开始就将所有的读写函数都载入,然后才发觉在整个程序中根本没有用到它们。

三、动态链接库的创建

由于动态链接库函数的共享特性,它们不会被拷贝到可执行文件中。在编译的时候,编译器只会做一些函数名之类的检查。在程序运行的时候,被调用的动态链接库 函数被安置在内存的某个地方,所有调用它的程序将指向这个代码段。因此,这些代码必须实用相对地址,而不是绝对地址。在编译的时候,我们需要告诉编译器, 这些对象文件是用来做动态链接库的,所以要用地址不无关代码(Position Independent Code (PIC))。

对gcc编译器,只需添加上 -fPIC 标签,如:

gcc -fPIC -c file1.c

gcc -fPIC -c file2.c

gcc -shared libxxx.so file1.o file2.o

注意到最后一行,-shared 标签告诉编译器这是要建立动态链接库。这与静态链接库的建立很不一样,后者用的是 ar 命令。也注意到,动态链接库的名字形式为 “libxxx.so” 后缀名为 “.so”

2、动态库的链接

在1、中,我们已经成功生成了一个自己的动态链接库libtest.so,下面我们通过一个程序来调用这个库里的函数。程序的源文件为:test.c。

test.c:

#include “so_test.h”

int main()

{

test_a();

test_b();

test_c();

return 0;

}

l 将test.c与动态库libtest.so链接生成执行文件test:

$ gcc test.c -L. -ltest -o test

l 测试是否动态连接,如果列出libtest.so,那么应该是连接正常了

$ ldd test

l 执行test,可以看到它是如何调用动态库中的函数的。

3、编译参数解析

最主要的是GCC命令行的一个选项:

-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件

l -fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

l -L.:表示要连接的库在当前目录中

l -ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称

l LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。

l 当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,不过如果没有root权限,那么只能采用输出LD_LIBRARY_PATH的方法了。



undefined reference问题总结(转)

http://ticktick.blog.51cto.com/823160/431329

1. 链接时缺失了相关目标文件(.o)

测试代码如下

//main.c
int main()
{
test();
}
//test.c
#include <stdio.h>
void test()
{
printf("test!\n");
}

然后编译

gcc -c test.c
gcc -c main.c

得到两个 .o 文件,一个是 main.o,一个是 test.o ,然后我们链接 .o 得到可执行程序:

gcc -o main main.o

这时,你会发现,报错了:

这就是最典型的undefined reference错误,因为在链接时发现找不到某个函数的实现文件,本例中test.o文件中包含了test()函数的实现,所以如果按下面这种方式链接就没事了。

gcc -o main main.o test.o

2….

时间: 2024-10-28 23:20:15

库链接的问题的相关文章

三种标准库链接方式

Linux 应用程序因为 Linux 版本的众多与各自独立性,在工程制作与使用中必须熟练掌握如下两点才能有效地工作和理想地运行.1.Linux 下标准库链接的三种方式(全静态 , 半静态 (libgcc,libstdc++), 全动态)及其各自利弊.2.Linux 下如何巧妙构建 achrive(*.a),并且如何设置链接选项来解决 gcc 比较特别的链接库的顺序问题.全静态:1.-static -pthread -lrt -ldl2.不会发生应用程序在 不同 Linux 版本下的标准库不兼容问

解决遇到动态库链接静态库

场景: 二进制Link-->动态库-->第三方静态库 Linux环境中需要动态库链接第三方的静态库 错误: /usr/bin/ld: ../../3rdpart/x64/muduo/lib/libbase.a(AsyncLogging.o): relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC ../../3rdpart/x64/mu

静态库链接时的依赖关系和先后顺序

1 静态库链接时的依赖关系 静态库之间是有依赖关系的,比如A.lib依赖于B.lib.C.lib.D.lib.E.lib,因为A会使用B.C.D.E中的函数. 2 使用静态库时的先后顺序 是不是B.C.D.E一定要放在A的后面?或者说,如果自己依赖于某个库,那么自己就要放在这个库的后面? 如果是的话,为什么会这样?是所有的链接器都是这样的吗? MSVC++12.0编译器是不管这个顺序的,gcc的未知. 3 使用静态库时必须注意依赖关系 也就是说,要使用一个lib时,要把它依赖的所有的lib都加上

ubuntu系统下,gsl 库链接问题 -undefined reference to `cblas_xxx`

今天在ubuntu系统下进行程序调试的时候出现以下错误信息: [ 10%] Linking CXX executable ../test_coco /usr/local/lib/libgsl.so: undefined reference to `cblas_ztrsv' /usr/local/lib/libgsl.so: undefined reference to `cblas_scasum' /usr/local/lib/libgsl.so: undefined reference to

linux共享库链接过程

一 与静态库链接 1 符号解析(symbol resolution) 将符号的引用与定义联系在一起.#引用信息和定义信息在哪儿,怎么联系在一起的 1)内部符号解析-编译器 2)外部符号解析-连接器 与静态库链接: 链接器维护三个集合(E:可执行文件集合(U:未解析的符号集合(D:已定义的符号集合对于每一个输入的目标文件,通过里面的符号引用与定义信息来修改U.D中的值.对于库文件,若库中的文件成员m中含有对之前 U 中未解析符号的定义,则将m类似目标文件执行操作,直到U.D不再发生变化(如何判断)

JDBC--数据库链接及相关方法的封装

使用的是MySQL数据库,首先导入驱动类,然后根据数据库URL和用户名密码获得数据的链接.由于使用的是MySQL数据库,它的URL一般为,jdbc:mysql://主机地址:端口号/库名. 下面是封装的具体类,用到了泛型和反射,不过还存在些问题,就是对使用的泛型对象有些限制,只能用于泛型类对象属性名与数据库表中列名相同的对象,而且初始化对象的方法必须为set+属性名的方法.本来想通过返回值类型,参数列表来确定该属性初始化方法的,然而可能是目前学到的还是太少,只学了三周,所以并没有实现,感觉这个方

浅析静态库链接原理

静态库的链接基本上同链接目标文件.obj/.o相同,但也有些不同的地方.本文简要描述linux下静态库在链接过程中的一些细节. 静态库文件格式 静态库远远不同于动态库,不涉及到符号重定位之类的问题.静态库本质上只是将一堆目标文件进行打包而已.静态库没有标准,不同的linux下都会有些细微的差别.大致的格式wiki上描述的较清楚: Global header ----------------- +------------------------------- File header 1 --->

makefile与动态链接库案例分析——动态库链接动态库

http://blog.csdn.net/huqinwei987/article/details/50517780 背景:效率考虑,要重用把服务器主备机方案,以库Libmdpha(高可用)的形式加进主工程dds(调度数据服务器). 有源代码,打算直接编译Libmdpha.so.xxx,加入主工程dds.复制动态库libmdpha.so.xxx到主工程相关路径,并改makefile,makefile中主要加复制命令和建立软连接的命令,库名注意统一: 引用库中加入Libmdpha 同时加 cp -f

解决Boost库链接出错问题

安装完最新的Boost库 官方说明中有一句话: Finally, $ ./b2 install will leave Boost binaries in the lib/ subdirectory of your installation prefix. You will also find a copy of the Boost headers in the include/ subdirectory of the installation prefix, so you can hencefo

linux下的库链接

linux下的编译一般都是需要一些头文件或者库文件的支持,头文件或者库文件一般的默认路径是在/usr/include/ 和/usr/lib/下的,但是当你需要的文件没有在默认的路径下,该怎么办尼,这里提供了几种链接到的方法: 1.$ gcc foo.c -I /home/liuru/include -o foo                                               链接到/home/liuru/include 下的头文件,使用-I选项 2.$ gcc foo