[SOLVED] How to ensure that the constructors in a lib.a are called?

The test routines for our library are a load of functions which take advantage of GCC __attribute__((constructor)); each of our test functions carry this attribute (buried inside a macro) so that they get called during C library initialization and add themselves to a linked-list of test functions that can later be called by our test application, once we’ve got into main(). This is the same mechanism that Espressif’s test system uses and it works fine on all of the native environments we support (Zephyr/West, STM32Cube, nRF5SDK, ESP-IDF, Arduino, etc.); I now need to make it work under PlatformIO.

PlatformIO happily compiles all of our test code, and our core code, and puts the lot into a single lib.a, however none of the tests run. When I look at the .map file, none of our code has been linked. This is likely because none of the constructors that are those test functions in lib.a are being called, so the entire thing is being dumped at the link stage.

Can anyone suggest a way to make the linker call the constructors inside a lib.a file (without adding a load of dummy functions to call the tests, which kind of defeats the object)? I’ve tried the sledgehammer of passing -Wl,-whole-archive in as a build flag but the link stage then fails complaining of many, many duplicated C library functions, so that is likely not the answer.

Or is there a way to make PlatformIO compile all files directly into one thing, rather than multiple libraries? Any way forward will do; otherwise we can’t run any tests.

Dass adding the used attribute on top of constructor not help in this case?

Thanks for the swift reply: I’d look at that but unfortunately it does not help, as explained here:

…that (and I think all attributes) only affect the compiler, not the linker. I did try it anyway, of course, but it doesn’t alter the outcome; all of our code is being compiled but none of our code is being linked into the image.

Does the result differ when you set lib_archive = no in the platformio.ini?

1 Like

That’s interesting - with that added I’m getting a linker error which might be an indication that it is including the relevant code and I’ve missed a reference out of the build somewhere. Let me fix that and get back here with a conclusion.

Thanks for all this help so late on a Friday night!

Yup, you da MAN! That does indeed fix it: our constructors are now being called and so our tests are being collated into our linked-list and our code is being linked/called. Thanks, again.