我使用以下命令构建了boost 1.55序列化库:
b2 --build-dir=build toolset=gcc --with-serialization --layout=tagged link=static threading=multi stage
并在libboost_serialization-mt.a
目录中获得libboost_wserialization-mt.a
和stage/lib
- 很好。然后我将boost_serialization
添加到我的C :: B项目的链接器库列表中并编译了boost serialization example,它从命令行运行良好。然后,我使用
b2 --build-dir=build toolset=gcc --with-serialization --layout=tagged link=static,shared threading=multi,single stage
并按预期在我的stage/lib
目录中获得了更多库。让我感到困惑的是,每个库都有一个.so
文件,即使是那些应该是静态的文件。为什么会这样?需要什么?
当我现在编译项目时,可执行文件抱怨:
error while loading shared libraries: libboost_serialization.so.1.55.0: cannot open shared object file: No such file or directory
库绝对存在,我可能只需要将它的路径添加到LD_LIBRARY_PATH
,但我想暂时静态链接。我怎么能这样做?
我也不太了解库命名:我的libboost_wserialization...
文件夹中有一些lib
库,而w
中的serialization
前缀未在当前boost getting started page的库命名部分。
您的回答让我更好地了解了发生的事情 - 现在我知道了boost_wserialization
图书馆的来源。我发现在完成第二次构建后,所有存在的库被共享,并且静态库被覆盖。这就是为什么我对那些以前确实是静态的库的“额外”.so
文件感到困惑。
答案 0 :(得分:2)
好的,第一个问题:
为什么有
boost_serialization
和boost_wserialization
库?
wserialization库是面向wchar_t的。放入一个单独的库,因为实际上可能不需要它。
为什么有多个共享/静态库?
您看到所有这些额外共享库的原因是因为您使用b2
调用link=static,shared
,它指示boost构建共享库以及静态库。此外,添加thread=multi
会导致构建mt
库,这些库是链接到多线程应用程序时应使用的库。
为什么我收到有关
libboost_serialization.so.1.55.0
的运行时链接错误?
默认情况下,大多数unix / linux系统在链接时更喜欢使用共享库而不是静态库,所以当你尝试链接时,它更喜欢使用共享库而不是静态库。如果要强制使用静态库而不是共享库的链接,可以使用以下命令告诉编译时链接器执行此操作:
-Wl,-Bstatic -lboost_serialization -Wl,-Bdynamic
这将导致链接器查找boost_serialization
库的静态变体,而不是动态变体。
现在,因为你正在使用code::blocks
,我必须查找如何根据具体情况指定这些标志,但最明智的做法是清理boost构建使用./b2 clean
然后重建,仅指定link=static
,那么您最终只能使用.a
个文件,这将再次生成独立的可执行文件。
如果您要为code::blocks
指定此选项,则需要将它们放入Build Settings
- > Linker settings
- >项目的Other Linker Options
字段。只需在库字段中指定库就不适用于这种情况。此外,忘记传入-Wl,-Bdynamic
选项将导致它尝试链接某些平台库的静态版本,如果相关库不存在,这可能导致构建失败。
如果要避免必须设置LD_LIBRARY_PATH
来运行二进制文件,可以将选项-Wl,-rpath,/path/to/boost/libraries
添加到链接器标志,这将导致编译程序在尝试解析时搜索该目录图书馆的位置。
答案 1 :(得分:1)
让我感到困惑的是,每个图书馆都有一个.so文件,甚至 那些应该是静态的。为什么会这样?需要什么?
你显然正在使用别人的make文件。我写了自己的。我的构建命令不会创建“.so”(共享对象库)。它只创建“.a”(存档库)。链接器知道如何使用它们。
见男人ar。实用程序ar建立档案 见男士ld。实用程序ld可以构建共享对象。
您可能会在构建序列中查找这些实用程序调用,或者询问某人他们在哪里并注释掉ld的使用,因为您很可能不需要两者(并且构建两者都会不必要地延长构建时间)。或者,您可以暂时重命名ld命令,然后尝试构建。当找不到ld命令时,您可能会获得有关调用ld的位置的有用提示。
在我的make文件中,命令如下所示。注释char是#行的开头。 (字符串扩展$(AR)和$(LD)允许使用非标准实用程序。)
$(TARGET_ARCHIVE): $(OBJ)
@echo R10: $(TARGET_ARCHIVE) :from: $(OBJ)
$(AR) crs $(TARGET_ARCHIVE) $(OBJ)
# $(TARGET_OLB) : $(OBJ)
# @echo R00: $(TARGET_OLB) :from: $(OBJ)
# $(LD) -o $(TARGET_OLB) -r $(OBJ)
存档(.a)在使用时直接链接到您的可执行文件并包含在您的可执行文件中。加载可执行文件时,.a的所有引用符号都已包含在其中。 (未引用的符号和代码未链接)
共享对象(.so)没有直接链接,而是您的可执行文件获取.so的句柄(或可能是文件名)。我相信,当您的可执行文件加载时,.so不会立即加载。直到您的可执行文件第一次引用.so中的符号时才会加载.so。在该加载时,您的应用程序将遇到延迟,但对于大多数应用程序来说,这种延迟加载可能是合理的。
在激活过程之前,.so也可能已加载到系统内存中。在这种情况下,当你的可执行文件首先引用.so中的一个符号时,一些系统代码会将现有的内存.so映射到你的应用程序 - 可能比加载它更快,但我认为最大的好处是.so由许多进程使用/引用只需要加载一次,从而节省了内存空间。加载的.so具有所有符号,即使您的应用程序不需要所有符号。
在任何一种情况下,你的可执行文件都会更小,但是.so更大,但是.so的每个.so都有一些小的性能损失,需要加载或映射。我的桌面有4 GB,桌面从未感到“拥挤”。它的交换从未使用过(afaik)。所以我一般都使用.a's。
注意:当链接器可以访问存档(.a)和共享对象(.so)文件时,链接器将使用.so(并忽略.a)。可能你可以覆盖这个偏好,但我还没试过。我发现将归档文件(.a)简单地移动到一个单独的(从.so的)目录中更容易,并通过-L build选项通知链接器。