1

I am converting a large Windows C++ application from a large set of source files to a smaller core application linked to several static libraries (to which many of the original source files are moved).

Each library requires access to a 'registration method' in the core application. Each library should call that method during global initialization, but that is not happening. That is my problem.

The code works fine in the original form where libraries are not used. I guess I am omitting a necessary link option for the libraries, but I don't know which.

I have created a minimal, workable example. I developed this on Windows 10 using:

CMake 3.14.5
MSVC 2019

Here's CMakeLists.txt:

cmake_minimum_required(VERSION 2.8.9)
project (CMakeLinkTest)
add_library(myLibrary STATIC MyStar.cpp)
add_executable(CMakeLinkTest StarFactory.cpp main.cpp)
target_link_libraries(CMakeLinkTest myLibrary)

The application contains main.cpp:

#include <iostream>

int main(int argc, char *argv[]){
   std::cout << "Hello World!" << std::endl;
   return 0;
}

and a singleton class called StarFactory.

StarFactory.h:

#include<string>

class StarFactory
{
public:

    static StarFactory* instance();
    ~StarFactory() {};

    std::string registerStarType(std::string a_type);

private:

    StarFactory() {};

    static StarFactory* mp_instance;   // Singleton instance 
};

StarFactory.cpp:

#include <iostream>
#include "StarFactory.h"

StarFactory* StarFactory::mp_instance = 0;

StarFactory* StarFactory::instance()
{
    if ( mp_instance==0 )
        mp_instance = new StarFactory;

    return mp_instance;
}

std::string StarFactory::registerStarType(std::string a_type)
{
    std::cout << "registerStarType: " << a_type << std::endl;
    return a_type;
}

Finally, a static library contains class MyStar which registers itself with the singleton at global initialisation.

MyStar.cpp:

#include<string>
#include "StarFactory.h"

class MyStar
{
public:
    MyStar() {
        StarFactory* s = StarFactory::instance();
        //s->registerStarType("MyStar");
    };
};

MyStar myStar;
std::string starName = StarFactory::instance()->registerStarType("MyStar");

Now for what happens. If I link MyStar.cpp directly into the application I see:

>CMakeLinkTest.exe
registerStarType: MyStar
Hello World!

If link MyStar.cpp into MyLibrary.lib and link that to the application I see:

>CMakeLinkTest.exe
Hello World!

So, the library's call (last line of MyStar.cpp) to the application's singleton is not working.

Can anyone explain this please?

DavidA
  • 2,053
  • 6
  • 30
  • 54

2 Answers2

1

As stated by engf-010, if a symbol defined in your static library is not used, the linker won't put it in the final binary.

One way to solve the problem using CMake would be to use an OBJECT library instead of a STATIC library.

1

The default behavior for linker is to not include static library that is not referenced.

You can either:

  • force linker to include the library anyway - you can use cmake's add_link_options or equivalent
  • not use a static library - just link the object like as in your first example
  • reference the code in static library
  • use a shared object (dynamic library) instead
Zaffy
  • 16,801
  • 8
  • 50
  • 77
  • Thanks for your answer, which is no doubt correct. However, I've chosen to accept the other answer as it's an elegant solution when using CMake. – DavidA Nov 08 '19 at 13:28