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!