代码::块和boost 1.55:当存在动态库时,不使用静态库
Code::Blocks and boost 1.55: static library is not used when dynamic library is present
我用以下命令构建了boost 1.55串行化库:
b2 --build-dir=build toolset=gcc --with-serialization --layout=tagged link=static threading=multi stage
并且在我的CCD_ 3目录中得到了CCD_ 1和CCD_。然后,我将boost_serialization
添加到我的C::B项目的链接库列表中,并编译了boost序列化示例,它从命令行运行良好。然后,我使用额外构建了动态和单线程变体
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
,但我现在想静态链接。我该怎么做?
我也不太理解库的命名:我的lib
文件夹中有一些libboost_wserialization...
库,而当前boost入门页面的库命名部分中没有描述libboost_serialization-mt.a
1的w
前缀。
你的回答让我更好地了解了发生了什么——现在我知道了boost_wserialization
库的来源。我发现,在进行第二次构建后,所有当前库都被共享,并且静态库被覆盖。这就是为什么我对那些以前确实是静态的库的"额外".so
文件感到困惑。
好的,第一个问题:
为什么有
boost_serialization
和boost_wserialization
库?
wserialization库是面向wchar_t的。放入一个单独的库中,因为实际上可能并不需要它。
为什么有多个共享/静态库?
您之所以看到所有这些额外的共享库,是因为您使用link=static,shared
调用b2
,它指示boost构建共享库和静态库。此外,在thread=multi
中添加会导致mt
库的构建,这些库在链接到多线程应用程序时应该使用。
为什么我收到关于
libboost_wserialization-mt.a
0的运行时链接错误?
默认情况下,大多数unix/linux系统在链接时更喜欢使用共享库而不是静态库,因此当您尝试链接时,它更喜欢使用分享库而不是静止库。如果你想强制静态库的链接而不是共享库的链接,你可以告诉编译时链接器这样做,使用:
-Wl,-Bstatic -lboost_serialization -Wl,-Bdynamic
这将导致链接器查找boost_serialization
库的静态变体,而不是动态变体。
现在,因为您使用的是code::blocks
,所以我必须逐个查找如何指定这些标志,但最明智的做法是使用./b2 clean
清理提升构建,然后重新生成,只指定link=static
,然后您应该只得到.a
文件,这将再次生成独立的可执行文件。
如果要为code::blocks
指定此选项,则需要将它们放入项目的Build Settings
->Linker settings
->Other Linker Options
字段中。在这种情况下,简单地在库字段中指定库是不起作用的。此外,忘记传入stage/lib
0选项会导致它尝试链接某些平台库的静态版本,如果有问题的库不存在,则可能导致构建失败。
如果您想避免必须将LD_LIBRARY_PATH
设置为运行二进制文件,可以将选项-Wl,-rpath,/path/to/boost/libraries
添加到链接器标志中,这将导致编译后的程序在尝试解析库的位置时搜索该目录。
让我困惑的是,每个库都有一个.so文件,甚至那些应该是静态的。为什么它在那里?它需要什么?
您显然在使用他人的make文件。我自己写的。我的构建命令不会创建".so"(共享对象库)。它只创建".a"(归档库)。链接器知道如何使用这两种方法。
参见手册ar。实用程序ar建立档案
见手册ld。实用程序ld可以构建共享对象。
您可以在构建序列中查找这些实用程序调用,或者询问某人它们在哪里,并注释ld的使用,因为您很可能不需要两者(同时构建两者会不必要地延长构建时间)。或者,您可以暂时重命名ld命令,然后尝试构建。当它找不到ld命令时,您可能会得到一个有用的提示,提示在哪里调用ld。
在我的make文件中,命令如下所示。注释字符是行开头的#。(字符串扩展$(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而变小,随着.a而变大,但.so的每个文件都有一些小的性能打击。因此需要加载或映射。我的桌面上有4 GB,桌面从未感到"拥挤"。它的交换从未被使用过(afaik)。所以我通常使用.a的
注意:当链接器同时访问存档(.a)和共享对象(.so)文件时,链接器将使用.so(并忽略.a)。您可能可以覆盖该首选项,但我尚未尝试。我发现简单地将归档文件(.a)移到一个单独的(与.so的)目录中,并通过-L构建选项通知链接器更容易。
- 检查编译时是否存在静态函数
- 为什么即使存在此静态成员,也不会构造它?
- 使用C ,使用SFINAE测试静态成员的存在,返回错误的值
- 在不存在的对象上调用静态成员函数
- 代码::块和boost 1.55:当存在动态库时,不使用静态库
- 存在静态常量成员时的赋值运算符
- 静态库中未定义的符号,但在同一 VS 解决方案中存在
- 静态元组类成员的 constexpr 存在链接器错误
- 如何检查SFINAE是否存在静态常量成员
- 静态方法的Xcode中存在C++链接器错误
- 使用Visual Studio将静态构建的库链接到共享库可能存在内存风险
- 在静态初始化期间,pthread线程变量何时开始存在
- 为什么我的静态方法的返回值与定义的构造函数(在 c++ 中)之间存在类型不匹配?
- 在C++中,一个静态变量可以在没有类的情况下存在吗
- 是否存在类型的静态向量
- 是否存在阻止内置具有静态成员的技术限制
- 确保全局范围的静态变量在任何地方都存在
- 可能存在编译器错误,本地结构从模板参数(phew)访问函数中的静态变量
- 如何检测具有特定签名的静态成员函数的存在
- 静态链接失败,尽管名称存在