连接时,在“仅获取所需”和“全部获取”(-Wl,--whole-archive)之间是否有其他选项?

5
我有一个涉及一些静态初始化代码的库,需要在main()之前运行。如果只编译所有翻译单元,则所有内容都正常工作,但是如果我提供一个静态库(.a文件)并让用户链接它们的应用程序,则链接器会忽略执行我的静态初始化的符号。
或者,如果我使用-Wl,--whole-archive选项指定GNU编译器集合(GCC)选项,则可以使链接器拾取静态库中的所有内容,即指定--whole-archive选项。
但是是否有折衷方案?我能否标记一些符号并使链接器始终将它们拾取到可执行文件中,而仅在需要时添加其余符号?
动机:我使用一些静态块在工厂中注册类;我希望将我的代码作为(非动态)库提供,而用户代码无需执行任何“魔法咒语”即可填充工厂。
一些相关问题:
  • 如何强制从C++(MSVC 11)的静态库中包含静态对象
  • 如何强制gcc链接未引用的静态C++对象
  • 如何强制gcc链接未使用的静态库

  • 你有没有找到--whole-archive的替代方案? - tmm1
    @tmm1:不,我有点放弃了。 - einpoklum
    我猜 --undefined 是唯一的其他解决方案。更多细节请参见 https://dev59.com/VKbja4cB1Zd3GeqPi5uQ#47186765 - tmm1
    1个回答

    2
    你可以强制链接器保留给定的函数(以及自然地,从该函数调用的所有代码)。在链接命令中添加 -u my_function。许多构建系统允许静态库将构建设置“导出”给使用它们的人。例如,对于 Android 的ndk-build框架,你可以指定类似以下的内容。
    include $(CLEAR_VARS)
    LOCAL_MODULE := the_best_static_library
    LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libfoo.a
    LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
    LOCAL_EXPORT_LDFLAGS := -u my_function
    include $(PREBUILT_STATIC_LIBRARY)
    

    在你的模块中的 Android.mk 文件。人们可以通过在他们的 Android.mk 文件中添加一个简单的语句来重用它。
    $(call import-module,third_party/the_best_static_library)
    

    注意:为了使此方法起作用,my_function() 不能被声明为 static。如果某个符号在文件作用域内被声明为 static,则链接器将根本不知道它的名称。幸运的是,如果它在一些链接器决定保留的代码中被引用,则它也不会被剥离。此外,除非你做出特殊努力,否则链接器将剥离或保留整个编译单元(即 C 文件)。因此,通常足够通过“锚定”一个虚拟函数来保持许多函数和数据。


    1
    (1) 这个例子中哪一部分是特定于Android的?GNU ld是否支持所有这些标志? (2) 关于“static” - 你的意思是在文件范围内不声明它为静态,对吧?那对我来说实际上会有问题...但现在还是点赞+1,等我有机会尝试后再接受。 - einpoklum
    我扩展了关于statuc的答案。关于链接器标志,据我所知,在任何基于gcc的工具链上都可以使用。Android特定的内容是如何向您的静态库用户分发知识的问题。您如何帮助他们访问您的头文件?您如何教他们您的代码依赖于某些第三方预构建库? - Alex Cohn

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接