Exporting a static data member of a class for dll using MSVC

Since past couple of days I have been searching and experimenting with the right way to export a static data member of a class for dynamic linkage in Windows using MSVC solution generated by CMake.

The CMake hierarchy is as follows:

DLLLinkingExperiment
-CMakeLists.txt    
-SubDirectory 
  -CMakeLists.txt    
  -LibraryDummy.cpp
  -LibraryDummy.h
-ExternalLibrary
  -CMakeLists.txt    
  -Executable.cpp

With bare minimum, the C++ code is as follows

LibraryDummy.h/.cpp

// LibraryDummy.h
#pragma once
#include <iostream>

namespace Rachel
{
	class  Retrospect
	{
	public:
		static void Status();
		static Retrospect* ReturnStaticPointer() { return s_Ret; }
	private:
		static Retrospect* s_Ret;
	};
}
----------------------------------------------------------------------------------------------
// LibraryDummy.cpp
#include "LibraryDummy.h"

namespace Rachel 
{
	Rachel::Retrospect* Retrospect::s_Ret = nullptr;
	void Retrospect::Status()
	{
		std::cout << "I am Xan!";
	}
}

and corresponding CMakeLists.txt is

project(LibraryDummy VERSION 1.0)

#add a library that runs
# Building the project (STATIC or DYNAMIC (SHARED))
if (BUILD_SHARED_LIBS)
    add_library(LibraryDummy SHARED LibraryDummy.cpp LibraryDummy.h)
else()
    add_library(LibraryDummy STATIC LibraryDummy.cpp LibraryDummy.h)
endif()

target_include_directories(LibraryDummy
    PRIVATE
        # where the library itself will look for its internal headers
        ${CMAKE_CURRENT_SOURCE_DIR}
    PUBLIC
        # where top-level project will look for the library's public headers
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
        # where external projects will look for the library's public headers
        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)

target_compile_definitions(LibraryDummy PUBLIC LibraryDummy)

Now Executable.cpp is

#include "LibraryDummy.h"

int main()
{
	Rachel::Retrospect::Status();
	Rachel::Retrospect::ReturnStaticPointer();
	return 0;
}

with CMakeLists.txt as follows

add_executable(External Executable.cpp)

Finally the top level CMakeLists.txt is as follows

# Here top level

cmake_minimum_required(VERSION 3.23)


# First we specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")


# Setting some options
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)


project(DllExternal VERSION 1.0)

# Build the test library
add_subdirectory(SubDirectory)


add_subdirectory(ExternalLibrary)


target_link_libraries(External PUBLIC LibraryDummy)

Visual Studio linker is complaining as follows

I have done some research, searched .def files and assembly files (given I am junior in reading assembly code), I can’t find any way for graceful linking in Windows.

Note: This issue never arises in Mac or Linux using gcc or clang!

Look into the GenerateExportHeader module.

See also the following talk which covers symbol visibility in general, including the GenerateExportHeader module Ben mentioned:

1 Like