Makefile:动态库的编译链接与使用(六)

1、动态链接库

动态链接库:不会把代码编译到二进制文件中,而是运行时才去加载,所以只需要维护一个地址

  • 动态:运行时才去加载,即所谓的动态加载
  • 连接:指库文件和二进制程序分离,用某种特殊的手段维护二者之间的关系
  • 库:Windows下为.dll库文件,Linux下为.so库文件

动态链接库文件的好处是程序和库文件分离,可以分别发行,库文件可以被多处共享

2、动态库的制作与使用
2.1、制作一个动态库
  • 首先生成一个SoTest.h、SoTest.cpp分别存放类声明和定义

    // 声明一个抽象类,因为有纯虚函数
    class SoTest {
    public:
        void func1();
        virtual void func2();
        virtual void func3() = 0;
    };
    
    
    
    // 实现
    #include "SoTest.h"
    #include <iostream>
    
    void SoTest::func1() {
        std::cout << "func1()" << std::endl;
    }
    
    void SoTest::func2() {
        std::cout << "func2()" << std::endl;
    }
    
  • 执行编译命令生成一个动态链接库

    g++ -shared -fPIC SoTest.cpp -o libSoTest.so
    

    此时当前目录下会生成一个 libSoTest.so的文件表示动态库

    • -shared指令:表示这是一个共享库
    • -fPIC指令:PIC(Position Independent Code)地址无关代码,加入这个指令后生成的动态库不需要进行任何的修改被加载到任意内存地址都是能够正常运行的。(后面在展开说)
    • 动态库的命名规则很奇葩,其实在/user/local/lib等Linux的文件夹下经常可以看到libxxx.so的文件
      • lib是一种大家默认的命名规范,但是最后加载的时候又会去掉这个lib,只能说很奇葩
      • .so是表示这是一个动态库
    • -l(小写L):指定动态库的文件的名称,名称需要去掉lib和.so,如上!
    • -I(大写i):指定头文件目录,默认为当前目录
    • -L:手动指定动态库库文件搜索目录,默认只链接共享目录(系统的lib动态库),运行的时候还需要指定一次
2.2、编写程序使用动态库
  • 首先准备一个main.cpp引入SoTest.h头文件,对SoTest进行继承并且重写几个函数

    #include <iostream>
    #include "SoTest.h"
    
    class Test: public SoTest{
    public:
        void func2() override {
            std::cout << "Test::func2()" << std::endl;
        }
    
        void func3() override {
            std::cout << "Test::func3()" << std::endl;
        }
    };
    
    int main() {
        Test test;
        test.func1();
        test.func2();
        test.func3();
        std::cout << "Hello, World!" << std::endl;
        return 0;
    }
    
  • 使用下面的指令进行编译

    g++ main.cpp -o main -L ./ -l SoTest
    
2.3、运行时动态库的连接
  • Linux默认动态库路径配置文件:
/etc/ld.so.conf       /etc/ld.so.conf.d/*.conf

/lib/*        /usr/lib        /usr/local/lib
...

上面的指令只是在编译时对这个动态库进行了链接,但是运行时是找不到的了,因此运行的时候会报错,报错原因:

  • 链接器:工作于链接阶段,工作时需要-l和-L分别指定库名和动态库路径
  • 动态链接器:工作与程序运行阶段,工作时需要提供动态库所在目录位置,而动态库加载,程序是默认从几个系统指定的位置加载这个libSoTest.so文件。
  • 当前位置的加载,因此需要给给定一个路径使得系统能够加载到动态库,通过ldd main可以看到找不到这个库
    在这里插入图片描述
2.4、解决方法

解决方法其实还是蛮多的,大概有3-4种的样子

  • 方案一:
    export LD_LIBRARY_PATH=./(动态库路径),这是临时环境变量,关闭bash就不会有了
  • 方案二:
    将动态库路径写入环境变量.bashrc作为永久环境变量(bash启动就有)
  • 方案三:
    拷贝自定义动态库到系统/lib或者其他一些指定的系统加载lib下
  • 方案四:
    sudo vim /etc/ld.so.conf
    写入绝对路径
    sudo ldconfig -v 使得配置文件生效

不管上面那种写法,最后lld main都能看到对应的libSoTest.so的路径在哪

2.5、Makefile
main: libSoTest.so
	${CXX} main.cpp -o main -L ./ -lSoTest
	sudo cp libSoTest.so /lib/
	lld main

libSoTest.so:
	${CXX} -shared -fPIC SoTest.cpp -o $@

clean:
	${RM} *.so main
	sudo rm -rf /lib/libSoTest.so

在这里插入图片描述

  • 14
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值