【问题标题】:Order of libraries in static and dynamic linking静态和动态链接中的库顺序
【发布时间】:2016-05-27 17:57:51
【问题描述】:

我正在尝试构建一些使用 boost 库的示例 C++ 代码。我使用this 作为静态链接的参考示例。

当我使用动态库构建时,一切都很好。

g++  -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include  -c -o src/main.o src/main.cpp
g++  -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include  -c -o src/ThreadExample.o src/ThreadExample.cpp
g++  -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include  -c -o src/Utils.o src/Utils.cpp
g++ src/main.o src/ThreadExample.o src/Utils.o -lboost_thread -lboost_filesystem -lboost_system -lboost_timer -o ThreadExampleBinary

但是当我使用静态库时,我会收到很多 undefined reference 错误:

g++  -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include  -c -o src/main.o src/main.cpp
g++  -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include  -c -o src/ThreadExample.o src/ThreadExample.cpp
g++  -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include  -c -o src/Utils.o src/Utils.cpp
g++ -static src/main.o src/ThreadExample.o src/Utils.o -lboost_thread -lboost_filesystem -lboost_system -lboost_timer -o ThreadExampleBinary

/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::cpu_timer::start()':
(.text+0x7fd): undefined reference to `boost::chrono::steady_clock::now()'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::cpu_timer::stop()':
(.text+0x94c): undefined reference to `boost::chrono::steady_clock::now()'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::cpu_timer::elapsed() const':
(.text+0xa59): undefined reference to `boost::chrono::steady_clock::now()'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::cpu_timer::resume()':
(.text+0xb60): undefined reference to `boost::chrono::steady_clock::now()'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::auto_cpu_timer::auto_cpu_timer(std::ostream&, short)':
(.text+0xca5): undefined reference to `boost::chrono::steady_clock::now()'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o):(.text+0xd4e): more undefined references to `boost::chrono::steady_clock::now()' follow
collect2: error: ld returned 1 exit status
make: *** [ThreadExampleBinary] Error 1

似乎可以通过添加额外的-lboost_chrono 库来解决此问题。 但为什么它在动态环境中起作用?

【问题讨论】:

    标签: c++ boost linker g++ static-linking


    【解决方案1】:

    使用静态链接,您还必须静态链接到所链接的库所依赖的任何库。

    【讨论】:

    • 如何自动化这个过程?如何通过检查错误找到所需的静态库并不明显,例如:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libopencv_core。 a(gl_core_3_1.cpp.o):在函数IntGetProcAddress(char const*)': (.text._ZL17IntGetProcAddressPKc+0x15): undefined reference to glXGetProcAddressARB'
    • 正确答案,但我认为可以通过更多关于库依赖链的细节来改进它。
    • @mrgloom,没有通用的自动化。您可以重复该过程直到成功(添加更多库,或使用 libtool 链接您的文件 - 这取决于 .la 文件存在,我不确定 boost 是否提供它们。
    【解决方案2】:

    不同之处在于共享库在 ELF 标头中有一个条目,称为 NEEDED,其中列出了在您链接此共享库时要包含的其他共享库。

    您可以使用以下命令查看它们:

    $ objdump -p /usr/lib/libboost_timer.so | grep NEEDED
      NEEDED               libboost_chrono.so.1.60.0
      NEEDED               libboost_system.so.1.60.0
      NEEDED               librt.so.1
      NEEDED               libstdc++.so.6
      NEEDED               libgcc_s.so.1
      NEEDED               libc.so.6
    

    但是对于静态库,没有这样的系统,因为它们只是目标文件的集合。

    值得注意的是,共享对象中的NEEDED 条目完全是可选的,如果它们不可用,那么它们的行为将与静态条目完全相同。但大多数共享库都包含它们。

    许多库使用 pkg-config 基础架构来提供所需的完整命令行,但 AFAIK boost 不是其中之一。

    如何自动化这个过程?好吧,你没有。您只需包含需要的内容并按照链接器错误来发现更多需求。

    您可以找到哪个静态库包含如下符号:

    $ nm --print-file-name --defined-only --demangle /usr/lib/*.a  2> /dev/null | \
               grep -q 'boost::chrono::steady_clock::now()'
    /usr/lib/libboost_chrono.a:chrono.o:0000000000000090 T boost::chrono::steady_clock::now()
    

    【讨论】:

      【解决方案3】:

      但为什么它在动态环境中起作用?

      我的大部分 make 文件都有以下注释(从我在需要时找到答案时......对不起,我不知道我在哪里找到它。)


      注意 - 当使用 '-l' 的构建找到该库的 .so 版本(so - 共享对象)并且相同的 .a 存档也在那里时,g++ 更喜欢 .so 而不是 .a。


      但是,您仍然可以通过完全指定 .a 的路径来实现静态链接。

      例子:

      $(CC) $(CC_FLAGS)  $<  /usr/local/lib/libboost_chrono.a  -o $@  ...
      #                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      

      有时,存档代码引用另一个存档中的符号。

      即-lyyy_i686 使用了 -lxxx_i686 中的一些函数,并且 xxx 在构建命令中首先列出。符号可能仍未解析,链接器可能会失败。

      发生这种情况时,请尝试再次将 xxx 添加到存档列表的末尾

         from:      -lxxx_i686   -lyyy_i686  -lrt -pthread
      
         becomes    -lxxx_i686   -lyyy_i686  -lrt -pthread -lxxx_i686
                     ^^^^^^^^^_____________________________^^^^^^^^^^
      

      前面假设只有 .a 库是可找到的(没有 xxx.so)


      另一种选择,您可以命令链接器多次搜索存档

                              -lyyy_i686  -lrt -pthread       -(-lxxx_i686-)
      tell gcc to link this library as many times as needed __^^__________^^
      

      同样,只有 .a 是可找到的


      最后,如果您选择与 .so 链接,请注意这不会将整个库拉入当前构建目标。相反,在运行时,如果 .so 不存在的话,它会被加载到内存中。这发生在程序启动后。对于大多数应用程序来说,这被认为是对启动性能的“小”影响,因为程序会调整其内存映射(自动在幕后)。我相信我曾经发现应用程序本身可以控制何时加载.so。


      .so 的使用将整个库拉入内存(如果尚未安装)。因此,不会有任何缺失的符号,在我上面的 xxx vs yyy 场景中,.so 会提取所有符号,无论是否使用。

      再一次,当尝试使用“-lxxx_i686”加载 xxx 时,链接器更喜欢拉入 libxxx_i686.so,即使 libxxx_i686.a 位于同一目录中。

      【讨论】:

        猜你喜欢
        • 2010-10-04
        • 2010-09-15
        • 1970-01-01
        • 2018-01-23
        • 2011-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-05
        相关资源
        最近更新 更多