首页 > 系统相关 >Linux用g++编译生成动态连接库.so的方法及连接

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

时间:2023-09-22 23:45:04浏览次数:39  
标签:文件 动态 ++ so cpp lib64 main 连接

  • 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/

标签:文件,动态,++,so,cpp,lib64,main,连接
From: https://www.cnblogs.com/hhddd-1024/p/17723697.html

相关文章

  • 20230922学习总结java连接HBASE
    连接条件:1、所有虚拟机上运行hadoop集群、运行zookeeper进程守护 2、向项目中导入即hbase安装目录下的conf文件夹中的两个文件 3、添加maven依赖<dependencies><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-server</ar......
  • Comparison between top diagnostic tools
    Intoday'srapidlyadvancingautomotiveindustry,diagnostictoolsplayacrucialroleinefficientlyidentifyingandresolvingissueswithvehicles.Withanabundanceofdiagnosticsoftwareavailableinthemarket,itcanbeoverwhelmingtochooset......
  • C++笔记(细碎小知识点)1
    1.内联:写在类内或外部声明inline(编译器判断是否内联,不是满足上述条件就一定内联),优点更快2.protected:派生类可以直接调用基类的protected成员3.class类内默认private,struct内默认public4.构造函数最优写法,用初始化(只有构造函数有)效率比在函数中写更高(因编译器先进行初始化再执行......
  • 思科 显示连接的端口号
    1点击选项中的Options2选择Preferences3选择PortLabelsAlwaysShown(端口标签总是显示)4其他选项AnimationSound动画声ShowLinkLights显示链接灯HideDeviceLabel隐藏设备标签PortLabelsAlwaysshown端口标签总是显示......
  • Fallible point in C/C++
    Operator[]Theperformanceof[]inCandC++isdifferent.e.g.,whenyouexcuteA[index]IfAisaobject,itwillcalltheoperator[]IfAisapointer,itisequivalenttoA+indexSo,operatoroverloadingisinvalidtopointer.......
  • C语言学习-- ~ 按二进制取位 前置后置++ 关系操作符 逻辑操作符
    #include<stdio.h>//~按二进制取位intmain(){inta=10;intb=~a;/*~按二进制取位如101--~=010*/printf("%d\n%d\n",a,b);/*运行a=10b=-11在二进制里的最高位表示符号位,0为正1为负(3=000…………011)源码......
  • C语言学习-- ~ 按二进制取位 前置后置++ 关系操作符 逻辑操作符
    #include<stdio.h>//~按二进制取位intmain(){inta=10;intb=~a;/*~按二进制取位如101--~=010*/printf("%d\n%d\n",a,b);/*运行a=10b=-11在二进制里的最高位表示符号位,0为正1为负(3=000…………011)源码......
  • C++ 的cout.tellp()和cout.seekp()语法介绍
    无论是使用cout输出普通数据,用cout.put()输出指定字符,还是用cout.write()输出指定字符串,数据都会先放到输出流缓冲区,待缓冲区刷新,数据才会输出到指定位置(屏幕或者文件中)。值得一提的是,当数据暂存于输出流缓冲区中时,我们仍可以对其进行修改。ostream类中提供有tellp()和se......
  • Ubuntu20.04 ping Temporary failure in name resolution问题
    解决步骤vi/etc/systemd/resolved.conf将DNS的注释取消掉并改成8.8.8.8即可参考:https://blog.csdn.net/weixin_43354181/article/details/105352203......
  • [ARC165D] Substring Comparison
    ProblemStatementForanintegersequence$X=(X_1,X_2,\dots,X_n)$,let$X[L,R]$denotetheintegersequence$(X_L,X_{L+1},\dots,X_{R})$.Youaregivenintegers$N$and$M$,and$M$quadruplesofintegers$(A_i,B_i,C_i,D_i)$.Determineifthereisaninte......