c++ 动态库与静态库编译

460 阅读1分钟

1 代码文件

  • hello.h

    //hello.h #pragma once

    #include

    class Hello { public: Hello(); void SayHello(); };

  • hello.cpp

    #include "hello.h"

    Hello::Hello() {}

    void Hello::SayHello() { std::cout << "hello" << std::endl; }

  • main.cpp

    #include "hello.h"

    int main() { Hello h; h.SayHello(); }

2 编译libhello.so 动态链接库

将hello.cpp编译成动态链接库libhello

  • --shared 表示生成动态库

  • -fPIC 表示生成的动态库是位置无关的。关于fPIC选项的区别可以参考gcc 编译参数 -fPIC 作用

    g++ --shared -fPIC hello.cpp -o libhello.so

查看libhello中定义的函数符号

zhuorui@zhuorui:~/code/test$ nm libhello.so | grep "Hello"
000000000000118a T _ZN5Hello8SayHelloEv
000000000000117a T _ZN5HelloC1Ev
000000000000117a T _ZN5HelloC2Ev

可以看到libhello.so中有我们定义的SayHello函数,位于代码段中。

3 编译main.cpp并链接libhello.so动态库

zhuorui@zhuorui:~/code/test$ g++ main.cpp
/usr/bin/ld: /tmp/ccoUTiMv.o: in function `main':
main.cpp:(.text+0x23): undefined reference to `Hello::Hello()'
/usr/bin/ld: main.cpp:(.text+0x2f): undefined reference to `Hello::SayHello()'
collect2: error: ld returned 1 exit status

执行g++ main.cpp会编译报错,找不到Hello相关的函数定义。这是因为main.cpp调用了相关的函数,但链接器ld找不到相关的函数定义。

g++ main.cpp  -lhello -L.

再次执行以上命令,编译通过了。

  • -l告诉链接器去找libhello.so这个动态库,main.cpp里面依赖的外部符号去这个动态库寻找。

  • -L告诉链接器将当前目录加入动态库的搜索目录。

我们尝试运行可执行文件

zhuorui@zhuorui:~/code/test$ ./a.out
./a.out: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

报错说明未找到libhello.so这个动态库。我们使用ldd命令查找a.out的动态库依赖

zhuorui@zhuorui:~/code/test$ ldd a.out
        linux-vdso.so.1 (0x00007ffdb55e7000)
        libhello.so => not found
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff961ed0000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff961cde000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff961b8f000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ff9620f6000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff961b74000)

发现libhello.so确认没有找到。这是因为libhello.so库文件所在的目录没有加入环境变量LD_LIBRARY_PATH导致的。我们执行以下命令,将当前目录加入到动态库的搜索目录。

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`pwd`

再次运行可执行程序,发现成功运行起来了。

4 编译libhello.a静态库

将hello.cpp编译成目标文件,执行以下,目录下会生成hello.o文件

g++ -c hello.cpp

将.o目标文件打包成静态库

ar crsv libhello.a hello.o

nm 确认libhello.a中有我们定义的符号

nm libhello.a

5 编译main.cpp并链接libhello.a静态库

编译生成a.out可执行文件

g++ main.cpp -lhello -L.

查看a.out动态库依赖,可以看到并没有hello相关的库依赖,这是因为我们是静态编译的。

zhuorui@zhuorui:~/code/test$ ldd a.out
        linux-vdso.so.1 (0x00007ffcf2720000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fbccbd6e000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbccbb7c000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fbccba2d000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fbccbf94000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fbccba12000)

本文使用 markdown.com.cn 排版