Search code examples
cmakedllstatic-librariesclionundefined-reference

Undefined reference when trying to link to static pre-built library Noesis in Cmake (c++, CLion, windows)


I am trying to start using the GUI library Noesis in my game, and am currently in the process of integrating it into my project. Unfortunately, during linking, all of the Noesis functions I have used so far say "undefined reference" For example:

[0/1] Re-running CMake...
-- 
-- Configuring done (0.3s)
-- Generating done (0.1s)
-- Build files have been written to: C:/projects/Curse of Elliah/cmake-build-debug
[1/2] Linking CXX executable Curse_of_Elliah.exe
FAILED: Curse_of_Elliah.exe 
C:\WINDOWS\system32\cmd.exe /C "cd . && C:\Users\wilto\AppData\Local\Programs\CLion\bin\mingw\bin\g++.exe -g  @CMakeFiles\Curse_of_Elliah.rsp -o Curse_of_Elliah.exe -Wl,--out-implib,libCurse_of_Elliah.dll.a -Wl,--major-image-version,0,--minor-image-version,0 && cd ."
C:\Users\wilto\AppData\Local\Programs\CLion\bin\mingw\bin/ld.exe: CMakeFiles/Curse_of_Elliah.dir/libs/Noesis/NoesisGL/GLRenderDevice.cpp.obj: in function `NoesisApp::GLRenderDevice::GLRenderDevice(bool)':
C:/projects/Curse of Elliah/libs/Noesis/NoesisGL/GLRenderDevice.cpp:154: undefined reference to `Noesis::RenderDevice::RenderDevice()'

Noesis is a pre-built static library that includes header files (.h), as well as a .lib file and a .dll file. Somehow, the definitions inside the .dll file are not able to be reached, and I have scoured the internet looking for a solution, and have tried many different things, but nothing seems to change.

In Noesis integration tutorial, it says this:

/Bin: this is the directory where dynamic libraries, one folder per architecture, can be found. Your executable must be able to reach this path. The easiest way is by copying it here in a post-build step.
/Include: directory for public headers. You must add this path to the Additional Include Directories of your project
/Lib: object libraries to link against with are stored in this directory, one folder per architecture. You must add this path to you Additional Libraries Directory and also link with the corresponding library.

Because of this, I put the headers into the project's lib folder, and there have not been a problem using them, as I just included it in CMake. Then, I put the .lib file into another subfolder in my libs folder: libs/Noesis/Lib/windows_x86_64/Noesis.lib, I have used this path in many different ways together with target_link_libraries, and have verified that CMake is able to reach the file with a message(STATUS). Then there is the .dll file. I have put the dll file in yet another subfolder to lib, and added the subfolder it is located in to the environment variables in windows. This did not seem to do anything. I also have put the .dll file inside of the build folder, cmake-build-debug. I have tried to place it in multiple different subfolders inside of that place, but even when it is next to the .exe file, nothing changes.

I have tried to just include it as you would a normal library, with include_directories and target_link_libraries as simple as possible. I have tried using add_library:

add_library(noesis SHARED IMPORTED)
set_target_properties(noesis PROPERTIES
        INTERFACE_INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/libs/Noesis"
        IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/libs/Noesis/Bin/windows_x86_64/Noesis.dll"
        IMPORTED_IMPLIB "${PROJECT_SOURCE_DIR}/libs/Noesis/Lib/windows_x86_64/Noesis.lib"
        #INTERFACE_LINK_LIBRARIES "\$<LINK_ONLY:gdi32>"
)

in both this manner and changing IMPORTED_LOCATION to the .lib file and omitting IMPORTED_IMPLIB. This also did not work. I am wondering if I am doing something wrong, and what the actual proper way to import a static, pre-built library is? I also do not really have any official support from Noesis side, since they are not supporting CMake. I have spent an entire day on fixing this simple problem, and I feel like I have run out of options.

Edit: I created a minimal project with just Noesis, using MSVC and the Visual Studio 2022 generator. Here is my cmake code:

cmake_minimum_required(VERSION 3.29)
project(untitled)

set(CMAKE_CXX_STANDARD 23)

include_directories("${CMAKE_CURRENT_SOURCE_DIR}/libs/Noesis")
link_directories("${CMAKE_CURRENT_SOURCE_DIR}/libs/Noesis/Bin/windows_x86_64")

add_library(noesis SHARED IMPORTED)
set_target_properties(noesis PROPERTIES
        INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/libs/Noesis"
        IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/libs/Noesis/Bin/windows_x86_64/Noesis.dll"
        IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/libs/Noesis/Lib/windows_x86_64/Noesis.lib"
        #INTERFACE_LINK_LIBRARIES "\$<LINK_ONLY:gdi32>"
)

add_executable(untitled main.cpp)
target_link_libraries (untitled ${noesis})

and this is my structure:

untitled

  • cmake-build-debug
  • libs
  • Noesis
  • Bin - windows_x86_64
    • Noesis.dll
  • Lib - windows_x86_64
    • Noesis.lib
  • Noesis header files
  • CMakeList.txt
  • main.cpp

Unfortunately, I still have the same issue, where it says:

main.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) void __cdecl Noesis::Init(void)" (__imp_?Init@Noesis@@YAXXZ) referenced in function main [C:\projects\untitled\cmake-build-debug\untitled.vcxproj]
C:\projects\untitled\cmake-build-debug\Debug\untitled.exe : fatal error LNK1120: 1 unresolved externals [C:\projects\untitled\cmake-build-debug\untitled.vcxproj]

Edit 2:

Actually, I am dumb. I changed ${noesis} to just noesis in the target_link_libraries, and now it says Process finished with exit code -1073741515 (0xC0000135). This appears to be because the .exe cannot find the .dll. I think I have placed Noesis.dll next to the .exe, but I might have to do some testing

Edit 3: Actually, I managed to get it working! MSVC just places the .exe in a subfolder!


Solution

  • You're trying to link against MSVC compiled C++ DLL with MinGW, and that's the problem — you can't do it that easy. MSVC compiler uses different rules to mangle C++ function's names than GCC, that's why you got the “undefined reference to” error. Use MSVC instead, it should work, in my case it works without a hitch.