我正在尝试构建一些使用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
库。
但为什么它在dinamic环境中起作用?
答案 0 :(得分:3)
使用静态链接时,您还必须静态链接到要链接的库所依赖的任何库。
答案 1 :(得分: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提升不是其中之一。
如何自动完成此过程?好吧,你没有。您只需包含所需内容并按照链接器错误发现更多需求。
您可以找到哪个静态库包含符号类似的符号:
$ 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()
答案 2 :(得分:0)
但为什么它在dinamic环境中起作用?
我的大多数make文件都有以下注释(从我需要时找到答案后...抱歉,我不知道我在哪里找到它。)
注意 - 当使用'-l'的构建找到该库的.so版本(所以 - 共享对象)并且同样存在.a存档时,g ++优先于.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链接,请注意,这不会将整个lib拉入当前构建目标。相反,在运行时,.so被加载到内存中,如果它还没有。程序启动后会发生这种情况。对于大多数应用程序,当程序调整其内存映射(在后台自动化)时,这被视为“小”启动性能。我相信我曾经发现应用程序本身可以控制何时加载.so。
使用.so将整个库拉入内存(如果尚未安装)。因此,在上面的xxx vs yyy场景中,没有任何遗漏符号,.so会拉出所有符号,无论是否使用。
再一次,当尝试使用“-lxxx_i686”加载xxx时,即使libxxx_i686.a位于同一目录中,链接器也更喜欢引入libxxx_i686.so。