When linking, is there something between "grab what you need" and "grab all" (-Wl,--whole-archive)?
Asked Answered
S

1

5

I have this library which involves some static initialization code which needs to run before main(). It all works well if you just compile all of the translation units together, but it doesn't work if I provide a static library (.a file) and have users link their application against it - the linker simply ignores the symbols which do my static initialization.

Alternatively, I can make the linker pick up everything in the static library, if I specify the -Wl,--whole-archive option to GCC, i.e. specify the --whole-archive option to GNU link.

But is there some middle ground? Can I mark some symbols and make the linker always pick them up for the executable, while the rest of the symbols are added only when needed?

Motivation: I use some static blocks to register classes in a factory; I want to make my code available as a (non-dynamic) library, without the user code having to perform any "magic incantation" for the factory to be populated.

Some related questions:

Sputter answered 18/4, 2017 at 11:36 Comment(3)
Did you ever find an alternative to --whole-archive?Bridging
@tmm1: No, I sort of gave up on it.Sputter
I guess --undefined is the only other solution. More details in https://mcmap.net/q/267351/-is-there-a-way-to-force-c-compiler-to-not-optimize-out-specific-static-objects-in-a-static-libraryBridging
G
2

You can force the linker to keep a given function (and naturally, all code that is called from this function). Add -u my_function to the link command. Many build systems let static libraries to 'export' the build settings to those who use them. E.g., for Android ndk-build framework, you can specify something like

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)

in your module Android.mk. People reuse it by adding to their Android.mk the simple statement

$(call import-module,third_party/the_best_static_library)

N.B. For this approach to work, my_function() cannot be declared static. If some symbol is declared as static at the file scope, then the linker guess not know it by name at all. Luckily, if it is referenced in some code that the linker decides to keep, then it will also not get stripped off. Furthermore, unless you make a special effort, the linker will strip or keep whole compilation units (a.k.a. C files). Thus, it is usually enough to "anchor" a dummy function to keep many functions and data.

Grania answered 10/5, 2017 at 15:0 Comment(2)
(1) What part of this example is specific to Android? Does GNU ld respect all these flags? (2) about static - you mean not declaring it static at file scope, right? That would actually be problematic for me... but still, +1 for now and when I get a chance to try it I'll accept.Sputter
I expanded the answer about statuc. Regarding the linker flag, it is available on any gcc based toolchain, as far as I know. The Android specific stuff is how you distribute the knowledge to users of your static library. How do you help them to access your header files? How do you teach them that your code depends on some third party prebuilt libraries?Grania

© 2022 - 2024 — McMap. All rights reserved.