【问题标题】:Code::Blocks and boost 1.55: static library is not used when dynamic library is presentCode::Blocks and boost 1.55: 存在动态库时不使用静态库
【发布时间】:2014-02-06 16:33:39
【问题描述】:

我已经使用以下命令构建了 boost 1.55 序列化库:

b2 --build-dir=build toolset=gcc --with-serialization --layout=tagged link=static threading=multi stage

并在我的stage/lib 目录中获得了libboost_serialization-mt.alibboost_wserialization-mt.a - 很好。然后我将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,但我现在想静态链接。我该怎么做?

我也不太了解库命名:我的lib 文件夹中有一些libboost_wserialization... 库,并且serializationw 前缀在当前@987654322 的库命名部分中没有描述@。


您的回答让我对发生的事情有了更好的了解 - 现在我知道 boost_wserialization 库的来源。我发现,在进行第二次构建后,所有 现有的库都被共享了,而静态库被覆盖了。这就是为什么我对那些以前确实是静态的库的“额外”.so 文件感到困惑。

【问题讨论】:

    标签: c++ gcc boost linker codeblocks


    【解决方案1】:

    好的,第一个问题:

    为什么会有boost_serializationboost_wserialization 库?

    wserialization 库是面向 wchar_t 的。放入一个单独的库,因为它实际上可能不需要。

    为什么会有多个共享/静态库?

    您看到所有这些额外共享库的原因是因为您使用link=static,shared 调用b2,它指示boost 构建共享库以及静态库。此外,添加thread=multi 会导致构建mt 库,这些库应该在链接到多线程应用程序时使用。

    为什么我会收到关于 libboost_serialization.so.1.55.0 的运行时链接错误?

    默认情况下,大多数 unix/linux 系统在链接时更喜欢使用共享库而不是静态库,因此当您尝试链接时,它会更喜欢使用共享库而不是静态库。如果你想强制链接静态库而不是共享库,你可以告诉编译时链接器这样做,使用:

    -Wl,-Bstatic -lboost_serialization -Wl,-Bdynamic
    

    这将导致链接器查找boost_serialization 库的静态变体,而不是动态变体。

    现在,因为您使用的是 code::blocks,所以我必须逐个查找如何指定这些标志,但最明智的做法是使用 @ 清理 boost 构建987654331@ 然后重新构建,只指定link=static,那么你应该只得到.a 文件,这将再次生成独立的可执行文件。

    如果要为code::blocks 指定此选项,则需要将它们放入项目的Build Settings -> Linker settings -> Other Linker Options 字段中。简单地在库字段中指定库不适用于这种情况。此外,忘记传递-Wl,-Bdynamic 选项将导致它尝试链接某些平台库的静态版本,如果相关库不存在,这可能会导致构建失败。

    如果您想避免必须设置LD_LIBRARY_PATH 来运行二进制文件,您可以将选项-Wl,-rpath,/path/to/boost/libraries 添加到链接器标志中,这将导致编译程序在尝试解析库的位置时搜索该目录.

    【讨论】:

    • 在阅读此答案时,我对我告诉 boost 的构建系统要做的事情以及我真正需要的事情的理解增长得最多,因此我将其标记为已接受。原来我上面问的问题没有一个“正确答案”,因为我同时面临着多重误解。
    【解决方案2】:

    令我困惑的是,每个库都有一个 .so 文件,甚至 那些应该是静态的。为什么会在那里?它有什么用?

    您显然正在使用其他人的 make 文件。我自己写的。我的构建命令不会创建“.so”(共享对象库)。它只创建“.a”(存档库)。链接器知道如何使用其中任何一个。

    见 man 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 对每个需要加载或映射的 .so 都有一些小的性能影响。我的桌面有 4 GB,桌面从未感到“拥挤”。它的交换从未被使用过(afaik)。所以我一般用.a的。

    注意:当链接器可以访问存档 (.a) 和共享对象 (.so) 文件时,链接器将使用 .so(并忽略 .a)。可能您可以覆盖该偏好,但我没有尝试过。我发现将存档 (.a) 移动到单独的(从 .so 的)目录中并通过 -L 构建选项通知链接器更容易。

    【讨论】:

    • 我没有使用 makefile,而是 Code::Block 的构建系统完全不同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-13
    • 2014-11-23
    • 2013-05-25
    相关资源
    最近更新 更多