CMake doesn't link the actual object to the resulting dll

I created a C++ library in visual studio and all is fine. However, I’m trying to convert the projects to CMake so I can build them on linux as well.
The library in question is implemented as pimple (dont know if it makes any difference though just saying) and it looks like this :

#ifndef BLINKER_H
#define BLINKER_H

/* If we are we on Windows, we want a single define for it.*/
#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__))
#define _WIN32
#endif /* _WIN32 */

#if defined(_WIN32) && defined(_BLINKER_BUILD_DLL)
/* We are building DETECTOR as a Win32 DLL */
#define BLINKER_API __declspec(dllexport)
#elif defined(_WIN32) && defined(BLINKER_DLL)
/* We are calling DETECTOR as a Win32 DLL */
#define BLINKER_API __declspec(dllimport)
#elif defined(__GNUC__) && defined(_BLINKER_BUILD_DLL)
/* We are building DETECTOR as a shared / dynamic library */
#define BLINKER_API __attribute__((visibility("default")))
#else
/* We are building or calling DETECTOR as a static library */
#define BLINKER_API
#endif

#include <iostream>
#include <sstream>

#include <opencv2/core.hpp>
#include <opencv2/opencv.hpp>

using namespace std::chrono_literals;
typedef std::chrono::system_clock Time;

const int COUNT_VJ = 3;
const int ILS_DSM = 30;
const int ILS_DSM_EXT = 600;
const cv::Size ILF_SIZE = { 34, 26 };
const cv::Size ILF_SIZE_PROCESSED = { 41, 32 };
 
struct Info
{
	void CheckStatus()
	{
		//...
	}
    //...
};

class BlinkerImpl;

class BLINKER_API Blinker
{
public:
	Blinker(std::string path = "", std::string netPath = "");
	void main_op(cv::Mat& imgOrig, Info& inf, std::string sme = "IDLS_E5", bool show_debug_info = true);
	
	~Blinker();

private:
	BlinkerImpl* blinker;
};


#endif // !BLINKER_H


this is the cmake that I have written so far:

cmake_minimum_required(VERSION 3.11)
project(Blinker)

set(CMAKE_CXX_STANDARD 17)

find_package(Torch REQUIRED)
find_package(OpenCV REQUIRED)

include_directories(D:/Codes/cpp/port/LibtorchPort/Dependencies/include ${TORCH_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS})

# http://dlib.net/examples/CMakeLists.txt.html
add_subdirectory(C:/Users/User/Downloads/dlib-19.21_for_cmake/dlib-19.21 C:/Users/User/Downloads/dlib-19.21_for_cmake/dlib-19.21/build)     

set(BLINKER_SRC  D:/Codes/cpp/port/LibtorchPort/Dependencies/include/Blinker/Blinker.cpp
)

add_library(
    Blinker_static
    ${BLINKER_SRC}
)
add_library(
    Blinker_dynamic
    SHARED
    ${BLINKER_SRC}
)

set(LIBS ${LIBS} ${TORCH_LIBRARIES} ${OpenCV_LIBS} dlib::dlib )
# Link
target_link_libraries(Blinker_static  ${TORCH_LIBRARIES} ${OpenCV_LIBS} dlib::dlib)
target_link_libraries(Blinker_dynamic  ${TORCH_LIBRARIES} ${OpenCV_LIBS} dlib::dlib)

When I run the cmake like this :

cmake -DCMAKE_PREFIX_PATH="$(python -c 'import torch.utils; print(torch.utils.cmake_prefix_path)');D:\External Libs\Opencv3.4.10_vc14_vc15\opencv3.4" ..

and then open the visual studio project and try to build everything, the build goes on smoothly and generates 4 files :
Blinker_dynamic.dll
Blinker_dynamic.exp
Blinker_dynamic.lib
Blinker_static.lib.

However, when I try to link a test application with the Blinker_dynamic.dll for example, I get linker errors as if the actual Blinker implementation is no where to be found:

Severity	Code	Description	Project	File	Line	Suppression State
Error	LNK2019	unresolved external symbol "public: void __cdecl Blinker::main_op(class cv::Mat &,struct Info &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,bool)" (?main_op@Blinker@@QEAAXAEAVMat@cv@@AEAUInfo@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_N@Z) referenced in function "int __cdecl test1(void)" (?test1@@YAHXZ)	Blinker_dynamic_test	D:\Codes\cpp\port\LibtorchPort\Blinker_Test\build\Blinker_Test.obj	1	
Error	LNK2019	unresolved external symbol "public: __cdecl Blinker::Blinker(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0Blinker@@QEAA@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0@Z) referenced in function "int __cdecl test1(void)" (?test1@@YAHXZ)	Blinker_dynamic_test	D:\Codes\cpp\port\LibtorchPort\Blinker_Test\build\Blinker_Test.obj	1	
Error	LNK2019	unresolved external symbol "public: __cdecl Blinker::~Blinker(void)" (??1Blinker@@QEAA@XZ) referenced in function "int __cdecl test1(void)" (?test1@@YAHXZ)	Blinker_dynamic_test	D:\Codes\cpp\port\LibtorchPort\Blinker_Test\build\Blinker_Test.obj	1	
Error	LNK1120	3 unresolved externals	Blinker_dynamic_test	D:\Codes\cpp\port\LibtorchPort\Blinker_Test\build\Release\Blinker_dynamic_test.exe	1	

And when inspecting the dll itself, you can indeed see, there is no trace of the actual Blinker.cpp in it.

For the reference here is the Blinker.dll created inside visual studio:
enter image description here

and here is the dll created using this cmake I posted above:

I must be doing something wrong, but I cant seem to figure it out! what am I missing here?

Rather than manually implementing all that logic for working out whether you need to export the class symbols or not, I recommend you consider using the GenerateExportHeader module instead. It makes handling these things very straightforward and has the added benefit of broad platform/compiler support too. You can get a good introduction to this from the first part of my CppCon talk from last year:

In your case, I think you’ll find that BLINKER_API is not being defined to what you expect when building your library. The logic for the preprocessor paths that would define it all rely on either _BLINKER_BUILD_DLL or BLINKER_DLL being defined, but I don’t see either of those being defined in your CMake source. Again, the GenerateExportHeader module takes care of that aspect for you too, so take a look at that and it should simplify this for you considerably.

2 Likes

Thanks a lot greatly appreciate your kind help.
God bless you