I have a setup that does not work, and I have no idea what I am doing wrong here - I am trying to convert a project from handcrafted Makefiles to autotools, and I think I have most of it set up correctly, as the application and all its convenience libraries builds and links correctly, but there is some trouble with the global state initializers of the convenience libraries.
Some of the libraries follow a pattern like this in the code:
// in global scope of somemodule.cpp
namespace {
bool registered = ModuleShare::registerModule<SomeModule>("SomeModule");
}
this code, along with the actual module source, is compiled into a convenience library using libtool
// libsomething Makefile.am
noinst_LTLIBRARIES = libsomething.la
libsomething_la_SOURCES = \
[ ... ]
moduleshare.cpp moduleshare.h \
somemodule.cpp somemodule.h \
[ ... ]
and this library is built, and referenced in the application Makefile.am as follows:
// someapp Makefile.am
bin_PROGRAMS = someapp
someapp_SOURCES = someapp.c someapp.h
someapp_CPPFLAGS = -I ${top_srcdir}/something
someapp_LDADD = ${top_srcdir}/something/libsomething.la
I have modified ModuleShare::registerModule to verify it is not called:
template<typename T>
static bool registerModule(const std::string &module){
printf("%s\n", module.c_str());
[ ... ]
return true;
}
What could be the reason for this?
EDIT:
At this point, I have figured out that this problem is related to the linker that is allowed to remove unused symbols during linkage. If I link manually using --whole-archive
, everything works as expected.
Coming from a C background, I also tried
static void
__attribute__((constructor))
register (void)
{
ModuleShare::registerModule<SomeModule>("SomeModule");
}
but that also does not produce the behaviour that I expected, which is wierd, considering that I rely on this construct a lot in my private C projects.
At this point, I am open to suggestions in any direction. I know that libtool does not provide per-library flags in LDADD, and I can't, and simply don't want to compile everything with --whole-archive just to get rid of these symptoms. I have only limited control over the codebase, but I think what I really need to ask here is, what is a good and reliable way to initialize program state in a convenience library using autotools?
EDIT2:
I think I am a step closer - it seems that the application code has no calls to the convenience library, and hence the linker omits it. The application calls into the library only via a templated function defined in a header file of SomeModule
, which relies on the static initializers called in the convenience libraries.
This dependency reversion is screwing over the whole build.
Still, I am unsure how to solve this :/
Thanks, Andy
registered
ever used in the real code? Does it work in the handcrafted Makefiles? IIRC, convenience libs are statically linked by libtool. Ifregistered
isn't used, the linker might be throwing out the initialization code as well. – Agretharegistered
not used anywhere. However, referencing it in the module code does not help. I also added a function declared__attribute__((constructor))
which is not called as well. – Ernaernaldxxx_LDFLAGS
variable for-Wl,--whole-archive
. – Merilyn