linux下gcc/g++创建一个共享库项目以及创建一个可执行项目动态链接该共享库

Silentdoer / 2023-08-19 / 原文

1.先确保有g++命令

2.创建一个c++项目目录,并cd到该目录

3.创建共享库头文件:dynamic_so.h

#ifndef __TEST__
#define __TEST__

int testFun(int a, int b);

#endif

4.创建对应共享库的实现文件:dynamic_so.cpp

#include "dynamic_so.h"

int testFun(int a, int b)
{
    return a + b;
}

5.编译共享库:g++ dynamic_so.cpp -fPIC -shared -o libtest.so
此时可以看到在项目根目录下多了一个叫libtest.so的文件,这里注意,共享库要以lib开头.so结尾

 

6.开始写主程序:main.cpp

#include <iostream>
#include "dynamic_so.h"

using namespace std;

int main()
{
    cout << testFun(10, 20) << endl;

    return 0;
}

可以看到这个程序也引用了这个头文件,用于后面代码编写不会报错

7.编译成可执行文件main:g++ main.cpp -L. -ltest -o main【这里的-ltest的test就是上面的共享库去掉前缀lib和后缀.so的名字,最后的main就是可执行文件名】
可以看到在项目根目录下也多出了一个main文件

8.执行main文件:./main会发现找不到动态链接库,我们用ldd main会发现libtest.so链接的是not found

解决方式为将libtest.so放到公共目录,比如/usr/lib目录下,这个时候再用ldd main就可以看到libtest.so是链接的/usr/lib/libtest.so了

此时再执行就会输出30;

 

9.如果想编译时就让main可以从程序所在目录(而非工作目录)里搜索libtest.so呢?可以这么编译:g++ main.cpp -L. -Wl,-z,origin -Wl,-rpath='$ORIGIN' -ltest -o main
此时ldd main可以看到libtest.so链接的就是main文件当前所在目录的libtest.so文件;(libtest.so => /home/silentdoer/Projects/CppProjs/cpp_test/./libtest.so

还可以切换到上一层用./cpp_test/main来执行一下,发现确实可以输出30

10.如果是希望libtest.so链接的是main文件同级目录下的lib目录里的libtest.so文件呢?可以这样写:g++ main.cpp -L. -Wl,-z,origin -Wl,-rpath='$ORIGIN/lib' -ltest -o main

这种情况下,编译要求libtest.so在main.cpp所在目录,但是执行main时要求libtest.so在main所在目录的lib目录下;

【注意,一个库或可执行程序只有一个rpath,所以不存在给main依赖的共享库a设置搜索路径是'$ORIGIN/lib1',而依赖的共享库b的搜索路径是'$ORIGIN/lib2'】

 

11.通过命令,将已经编译好的可执行文件的修改其rpath:patchelf --set-rpath '$ORIGIN/lib/ttt' main
这个时候我们再用ldd main会发现not found了,可以将lib下的libtest.so移动到lib/ttt目录下,再ldd main就能看到了;

 

【总结1,rpath的出现,可以解决这样的问题,可执行程序a依赖了库libfoo版本是1,名字是libfoo,可执行程序b依赖了libfoo版本是2,名字也是libfoo,

那如果libfoo是安装在全局共享库目录,则a和b是无法一起安装的,这个时候就可以将a设置rpath,将版本是1的libfoo放到其rpath里即可】

 

12.但是如果有这样的情况:程序a依赖libfoo库版本是1和依赖了libkk库版本是1,程序2依赖了libfoo版本是2和依赖了libkk版本是2,那么这个时候应该要把libfoo v1和libkk v1都复制到程序a的rpath里,但是libfoo v1库又依赖了库libbar版本是1,而libkk v1依赖的libbar版本确是v2,那么这个时候显然libbar的v1和v2不能放共享库目录,但是放到程序a的rpath里也有冲突,因为程序a依赖的libfoo和libkk它们自己就有冲突,所以又要给程序a rpath里的libfoo v1自己也设置rpath,然后把libbar的v1放libfoo v1的rpath目录里即可解决,其他类似的冲突都可以用这种方式去解决】

 

13.如果一个库没有任何依赖,会是这样:

ldd /usr/lib64/ld-linux-x86-64.so.2
        statically linked