Linux用g++编译生成动态连接库.so的方法及连接

发布时间 2023-09-22 23:39:50作者: 黄河大道东
  • Linux动态库默认搜索路径

/lib64、/usr/lib64、/lib、/usr/lib

  • 系统头文件目录

/usr/include

  • 常用命令

ldd main:查看二进制可执行文件链接的动态链接库信息,例如ldd nginx

g++ -c main.cpp:以单个xx.cpp源文件为单位只编译出xx.o的二进制文件(称为:目标文件)

g++ xx.o yy.o -o main:链接所有相关的目标文件连同用到的静态库、动态库、运行时库到最终独立的可执行文件

file main:查看文件格式信息

readelf -h main:查看ELF文件的基本信息(ELF文件是Linux系统可执行文件的通用格式,windows系统的可执行文件通用格式为PE,二者非常相似,但是不兼容,都是对二进制代码的一种封装)

readelf -S main:查看程序的区块,包含机器代码,与程序的数据

objdump -s -d main.o/main :查看ELF文件中的内容

objdump -r main.o:查看目标文件的重定位表,用于查看哪些函数需要被重定位,以及被重定位位置的偏移量

1、编译动态库.so文件

这里用到4个文件测试,它们分别为:SoDemoTest.h、one.cpp、two.cpp、three.cpp

vim SoDemoTest.h

#ifndef __SO_DEMO_TEST_HEADER__   
#define __SO_DEMO_TEST_HEADER__   
#include <iostream>   
using namespace std;  
void one();  
void two();  
void three();  
#endif 

vim one.cpp

#include "SoDemoTest.h"
void one(){cout << "call one() function." << endl;}

vim two.cpp

#include "SoDemoTest.h"
void two(){cout << "call two() function." << endl;}

vim three.cpp

#include "SoDemoTest.h"
void three(){cout << "call three() function." << endl;}

将这几个文件编译成动态库libtest.so的命令如下:

g++ one.cpp two.cpp three.cpp -fPIC -shared -o libtest.so

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

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

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

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

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

2、链接动态库

现在用一个程序来调用上面生成的动态链接库。

vim main.cpp

#include "SoDemoTest.h"
int main(){
    one();
    two();
    three();
    return 0;
}

main.cpplibtest.so链接成一个可执行文件main命令如下:

g++ main.cpp -L. -ltest -o main

测试可执行程序main是否已经链接动态库libtest.so,如果列出libtest.so的链接信息,就说明正常链接。可以执行以下命令:

[root@test ~]# ldd main
	linux-vdso.so.1 =>  (0x00007ffd913fa000)
	libtest.so => /lib64/libtest.so (0x00007f3feaa8e000)   // 此处即为链接成功
	libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f3fea786000)
	libm.so.6 => /lib64/libm.so.6 (0x00007f3fea484000)
	libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f3fea26e000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f3fe9ea0000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f3feac90000)

3、注意的问题

调用动态库的时候有几个问题会经常碰到,有时,明明已经将库的头文件所在目录通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,
但通过ldd命令察看时,就是找不到指定链接的.so动态库文件,这时要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。

LD_LIBRARY_PATH: 动态库的查找路径

设置:

方法一: export LD_LIBRARY_PATH=/xx/.so文件存放目录这种方法只是针对当前这个bash实例生效

方法二: 修改~/.bashrc或~/.bash_profile或系统级别的/etc/profile

vim /etc/profile
export LD_LIBRARY_PATH=/xx/.so文件存放目录
source /etc/profile

方法三:这个没有修改LD_LIBRARY_PATH但是效果是一样的实现动态库的查找,

1、vim /etc/ld.so.conf
在第1行:include ld.so.conf.d/*.conf内容的下方填入.so文件存放的目录全路径
例如:/xx/.so文件存放目录
2、保存过后ldconfig一下(ldconfig 命令的用途,主要是在默认搜寻目录(/lib、/lib64和/usr/lib、/usr/lib64)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库(格式如前介绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件.缓存文件默认为/etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表.)
3、一般会将自己编译的动态库与头文件放到/usr/local/include与/usr/local/lib目录中

方法三设置稍微麻烦,好处是比较不受用户的限制。

通常这样就可以解决库无法链接的问题。

原文:https://codeleading.com/article/43326414671/