[CMake] Newbie question: Static linking

Sanatan Rai sanatan at gmail.com
Mon May 23 14:42:54 EDT 2011


On 23 May 2011 17:46, Michael Hertling <mhertling at online.de> wrote:
> On 05/23/2011 05:09 PM, Sanatan Rai wrote:
>> On 23 May 2011 16:00, Michael Wild <themiwi at gmail.com> wrote:
>>> Everything that relies on static/global initialization to register
>>> factories is an implicit scheme. An explicit scheme is where the
>>> dependent code (e.g. the main() function) calls a function to do the
>>> registration.

<snipped>

>
> # CMakeLists.txt:
> CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
> PROJECT(GLOBALS CXX)
> SET(CMAKE_VERBOSE_MAKEFILE ON)
> ADD_LIBRARY(helper STATIC helper.cxx)
> ADD_EXECUTABLE(main main.cxx)

<snipped>

>  helper *helperCreator()
>  {
>    return (new helper());
>  }
>  const bool helperRegistered = registerhelper("helper", helperCreator);
> }
>
> If I'm not mistaken, this is roughly what you do in your project.

  Indeed.

<snipped>
> // helper.cxx:
> #include <iostream>
>
> int h;  // <-- For external reference.
>
> class helper {};
>
> namespace {
>
>  bool registerhelper(const char *ident, helper *(*creator)())
>  {
>    std::cout << ident << "=" << (void *)creator << std::endl;
>  }
>
>  helper *helperCreator()
>  {
>    return (new helper());
>  }
>  const bool helperRegistered = registerhelper("helper", helperCreator);
> }
>
> // main.cxx:
> extern int h;
> int h0 = h;
> int main(void){return 0;}
>
> Now, the entities from helper.cxx.o are included in the final binary,
> i.e. you'll see the "ident=..." message. Of course, the same happens
> when you include helper.cxx.o immediately in the main executable by
> mentioning helper.cxx among main's source files, i.e. a monolithic
> build. However, be aware that advanced linkers and, in particular,
> optimising compiler back-ends may feel free to remove entities that
> seem to be unnecessary for the program to run, as David has remarked
> in the meantime.

Absolutely.

> Michael's advice to explicitly register your factory classes means that
> there will be an external reference to the concerned object files, so
> they'll be included and the registration will be done via the boolean
> constants' initialisation, and that's what I'd advise, too. ATM, you
> try to have some actions performed in your program without referring
> to these actions by any means, and this simply does not work.
>
> Besides, when using --[no-]whole-archive in order to force the linker
> to include all of a static library's object files - be aware of the
> already mentioned limitations and the fact that you will get *all*
> object files, not just the ones you need - you might intersperse
> these flags immediately in TARGET_LINK_LIBRARIES() without -L/-l:
>
> target_link_libraries(myTarget
>    -Wl,--whole-archive helper1 helper2 -Wl,--no-whole-archive)
>

Yup, interspersing these flags is the approach I am taking at the moment.

>>    As I mentioned earlier, I did this a little more explicitly in a
>> .NET project in the following
>> manner:
>>
>>   * I had a factory object, whose job it was to hold creator functions
>> for objects of classes
>>     derived from a base class of interest.

<snipped>

> If the object file holding the factory is placed in a static library,
> and if there's no reference to any of this object file's entities from
> anywhere, the above-noted approach would also fail on *nix, but you say
> "...a static method that could be called.": Calling this method *is* a
> reference to the factory's object file from outside, so it would be
> included in the final binary, and everything works fine.

Quite.

> In summary, this whole issue is not related to C++ or even to CMake,
> but to the manner static libraries are handled: The linker - at least
> the GNU one - picks out entire object files, or drops them if they are
> not referred to. This is something one must keep in mind, particularly
> when dealing with global objects for initialisation purposes. BTW, also
> keep in mind that the order of initialisations, i.e. constructor calls,
> among global objects is unspecified; this might become important when
> such global objects refer to each other.

I do realise that it was off-topic, but people very kindly offered suggestions!
So one had to go on!

Many thanks to all for a careful and useful discussion.

Unfortunately, I am stuck with the paradigm of having to kludge loading an
entire library. For various reasons the one may not have a reference to
the hosted object in main, which must remain agnostic. Indeed, in my particular
line of business (finance), this happens to be a `standard' pattern.
Whether good or bad is a discussion that'd be too off topic...(though am happy
to continue the discussion off/on list if people are so inclined!).

--Sanatan


More information about the CMake mailing list