I have the following CMakeLists.txt
file to generate my project based on Qt:
cmake_minimum_required(VERSION 2.8.12)
project(MyProject)
find_package(Qt5Widgets)
set(MyProjectLib_src ${PROJECT_SOURCE_DIR}/gui.cpp)
set(MyProjectLib_hdr ${PROJECT_SOURCE_DIR}/gui.h)
set(MyProjectLib_ui ${PROJECT_SOURCE_DIR}/gui.ui)
set(MyProjectBin_src ${PROJECT_SOURCE_DIR}/main.cpp)
qt5_wrap_cpp(MyProjectLib_hdr_moc ${MyProjectLib_hdr})
qt5_wrap_ui (MyProjectLib_ui_moc ${MyProjectLib_ui})
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_BINARY_DIR})
add_library(MyProjectLib SHARED
${MyProjectLib_src}
${MyProjectLib_hdr_moc}
${MyProjectLib_ui_moc}
)
target_link_libraries(MyProjectLib Qt5::Widgets)
add_executable(MyProject ${MyProjectBin_src})
target_link_libraries(MyProject MyProjectLib)
When I try to compile the generated project, I got the following error:
error LNK1104: cannot open file 'Debug\MyProjectLib.lib'
The corresponding directory Debug
contains:
MyPtojectLib.dll
MyProjectLib.ilk
MyProjectLib.pdb
You declared MyProjectLib
as a shared library, so unless you exported all or part of the symbols of the library, you will only have a .dll
designed to be loaded at runtime, and no .lib
to link against at compile time as you're trying to do.
A quick solution may be to declare MyProjectLib
as a static library:
add_library(MyProjectLib STATIC ...)
Another option could be to use "new" cmake features to export all symbols (see this article):
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
You can also use the "traditional" way by explicitly declaring the symbols to be exported, like in this answer (the long answer). You will first need to declare some API macro somewhere in your code:
#ifdef MyProjectLib_EXPORTS
#define MyProjectLib_API __declspec(dllexport)
#else
#define MyProjectLib_API __declspec(dllimport)
#endif
Note that MyProjectLib_EXPORTS
is automatically generated by cmake for shared libraries: you don't need to care about this. Then for each of your class in your code, use the macro in the declaration:
class MyProjectLib_API MyClass { /* ... */ };
MyClass
will be an exported symbol when compiling MyProjectLib
because MyProjectLib_EXPORTS
will be defined, and MyProjectLib_API will expand to __declspec(dllexport)
. So it will be exported in a .lib
file.
It will be an imported symbol when linking against MyProjectLib
because MyProjectLib_EXPORTS
will be undefined, and MyProjectLib_API
will expand to __declspec(dllimport)
.
You may also improve your cmake file like this:
qt5_wrap_cpp(MyProjectLib_hdr_moc ${MyProjectLib_hdr})
qt5_wrap_ui (MyProjectLib_ui_moc ${MyProjectLib_ui})
You may use AUTOMOC
and AUTOUIC
instead to let cmake automatically handle the call to Qt's utilities.
include_directories (${PROJECT_SOURCE_DIR})
include_directories (${PROJECT_BINARY_DIR})
PROJECT_SOURCE_DIR
is an include directory by default, and I can't see why you need to add PROJECT_BINARY_DIR
here: just remove these lines.
Once cleaned, your cmake file may become something like this:
cmake_minimum_required(VERSION 2.8.12)
project(MyProject)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt5Widgets)
set(MyProjectLib_src
${PROJECT_SOURCE_DIR}/gui.cpp
${PROJECT_SOURCE_DIR}/gui.h
${PROJECT_SOURCE_DIR}/gui.ui
)
add_library(MyProjectLib STATIC
${MyProjectLib_src}
)
target_link_libraries(MyProjectLib Qt5::Widgets)
set(MyProjectBin_src ${PROJECT_SOURCE_DIR}/main.cpp)
add_executable(MyProject
${MyProjectBin_src}
)
target_link_libraries (MyProject MyProjectLib)
TLDR: Make sure you have source files, not just headers!
For web searchers who arrive here and may not have the OP's problem, I just encountered a very similar linking error that occurred because I had split libraries and left one of them without any source files, a header-only library:
add_library(hsm STATIC
StateAbstract.hpp # header-only
StateMachineAbstract.hpp # header-only
StateMachineBase.hpp # header-only
)
My fix was to insert a cpp file pending restoration of class implementation files:
add_library(hsm STATIC
Placeholder.cpp # this file causes hsm.lib to get generated on Windows
StateAbstract.hpp # header-only
StateMachineAbstract.hpp # header-only
StateMachineBase.hpp # header-only
)
This may seem like it would be obvious, but I'm doing Linux/QNX development on this project and gcc creates a nearly empty library:
$ wc -c build/lib/libhsm.a
8 build/lib/libhsm.a
$ strings build/lib/libhsm.a
!<arch>
That library links quite happily. It was only later when the project was building the Windows version on a build server that I saw the error:
[4/6] cmd.exe /C "cd . && C:\PROGRA~2\MICROS~2\2017\COMMUN~1\VC\Tools\MSVC\1413~1.261\bin\Hostx64\x64\link.exe /lib /nologo /machine:x64 /out:build\lib\hsm.lib && cd ."
[5/6] ...
[6/6] cmd.exe /C "cd . && "C:\Program Files\CMake\bin\cmake.exe" -E vs_link_exe ... /out:build\gtest\hsm_test.exe ... build\lib\hsm.lib ...
LINK : fatal error LNK1104: cannot open file 'build\lib\hsm.lib'
Since I saw the command to create the lib file in the build server output, I could not initially figure out why hsm.lib would not be there (and I cannot get on the build server). Fortunately, as I read the other answer and triple-checked that it was statically linked, I noticed it was a header-only library - whew! I feel lucky!