CMake building Shared library error but Static is fine [duplicate] - c++

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!

Related

How to create a static library (not executable) in CMake?

I'm new to cmake and I was wondering how to create a static library. In gcc, it can be done by:
ar rsv
Well, how do you do it using CMake?
add_library(mylib STATIC file1.cpp file2.cpp)
add_executable(myexe main.cpp)
target_link_libraries(myexe mylib)
This generates a static library (.a file) but how do you compile it without adding an executable?
if I remove add_executable(myexe main.cpp), it gives me an error. I only want this file:
mylib.a
and NOT
myexe.exe
mylib.a
add_library can be used by itself, without using add_executable at all. Simply remove line 2 to get rid of the executable. The error is most likely caused by line 3, which needs myexe to function. Line 3 should also be removed, because you are only building the library and not linking it.
My bad, I just need to remove:
add_executable(myexe main.cpp)
target_link_libraries(myexe mylib)
and this will work.

CMAKE static library builds well but shared library linking fails [duplicate]

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!

CMake: target_include_directories() can't find header files

At the top of my main.cpp file, No such file or directory is thrown at #include <sqlite3.h>.
Building the code manually by g++ -I"C:\Libraries\64_bit\SQLite3\include\" -L"C:\Libraries\64_bit\SQLite3\bin\" -lsqlite3 main.cpp Class1.cpp Class1.h Class2.cpp Class2.h -o main throws no errors.
CMake cannot seem to find the header, even though I've explicitly described where it is located in my file-system. According to the documentation for target_include_directories(), that should be enough:
Specified include directories may be absolute paths or relative paths. Repeated calls for the same append items in the order called.
Why is the target_include_directories() function not finding the headers, even though I've provided the exact absolute path?
I'm developing on a 64-bit Windows 10 machine, and CLion is set-up to compile with the MinGW-w64 g++ compiler.
I've downloaded the 64-bit Windows pre-compiled binary, sqlite3.dll and stored it locally in C:\Libraries\64_bit\SQLite3\bin\.
In order to access SQLite C++ functions I've also downloaded SQLite3's amalgamated source code and stored all source files in C:\Libraries\64_bit\SQLite3\include\.
I built my project in CLion, which is essentially a fancy GUI-wrapper for CMake. In my CMakeLists.txt, I've included SQLite3's headers and linked sqlite3 as follows:
cmake_minimum_required(VERSION 3.7)
project(My_Project)
set(CMAKE_CXX_STANDARD 11)
set(INCLUDE_DIRS C:\\Libraries\\64_bit\\SQLite3\\include\\)
set(LIBRARIES sqlite3.dll)
# My project's source code
set(SOURCE_FILES main.cpp Class1.cpp Class1.h Class2.cpp Class2.h)
add_executable(My_Project ${SOURCE_FILES})
# For compiler warnings
target_compile_options(My_Project PRIVATE -Wall)
# Including SQLite3's headers
target_include_directories(My_Project PRIVATE ${INCLUDE_DIRS})
# Linking against sqlite3.dll
target_link_libraries(My_Project ${LIBRARIES})
You can run into problems if you don't put paths between quotes.
Thus it is a good idea to write:
set(INCLUDE_DIRS "C:\\Libraries\\64_bit\\SQLite3\\include\\")
or, rather:
set(INCLUDE_DIRS "C:/Libraries/64_bit/SQLite3/include/")
Additionally, the CMakeLists.txt as it currently stands won't be able to find -lsqlite3. Thankfully, CMake makes finding libraries easy:
# Optionally, add 'PATHS "C:/Libraries/64_bit/SQLite3/bin/"'
find_library(SQLITE3_LIBRARY NAMES sqlite3)
If the library is discover-able on your system, the above command will return the path to the library and store that path in SQLITE3_LIBRARY. All that remains to do is link the project against the SQLite3 library:
# Link project to the SQLite3 library
target_link_libraries(MSP_Tool ${SQLITE3_LIBRARY})

Error LNK1104: cannot open file 'Debug\MyProjectLib.lib'

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!

Cmake configuration for multiple sub-libraries in a "packages" directory

Here is a sample project I am trying to build with a "Packages" directory which includes all the libraries to be used in the main code.
I am trying to keep my root cmake file as clean as possible and avoid relative path such as
include_directory(packages/lib1)
but I am struggling. Is there a way of including sub-directories of a directory for the purposes of header inclusion.
First a few minor remarks:
always name the CMake configuration files CMakeLists.txt (because of)
bookmark the documentation on CMake: https://cmake.org/documentation/
Sometimes it's not that easy to read, but very specific once you adopt your head to the "CMake world" ;-)
make yourself comfortable with the scope of CMake variables
include_directories(DIR1 [DIR2 [...]])
Tells CMake where the compiler should look for header files, i.e. -IDIR1 -IDIR2 ....
add_library(NAME [STATIC|SHARED] SOURCES)
This command creates the required compiler commands to create a static or shared library out of a given list of source files. No need to add in the header files. The make target will be called NAME and the library target is known to CMake as NAME.
add_subdirectory(DIR)
Tells CMake to look into DIR and parse the included CMakeLists.txt with all its content.
target_link_libraries(TARGET LIB1 [LIB2 [...]])
Tells CMake to instruct the linker to link LIB1, LIB2, etc. to the TARGET, i.e. -LLIB1 -LLIB2 .... TARGET is a CMake/make target previously defined/created with a call to add_{library,executable,custom_target}.
CMakeLists.txt:
include_directories(libraries)
# a header file in `libraries/lib1/foo.hpp` can be included
# in the whole CMake project by `#include "lib1/foo.hpp"`.
add_subdirectory(libraries)
add_subdirectory(tests)
libraries/CMakeLists.txt:
add_subdirectory(lib1)
add_subdirectory(lib2)
libraries/lib1/CMakeLists.txt:
add_library(lib1 STATIC ${LIB1_SOURCES})
libraries/lib2/CMakeLists.txt:
add_library(lib2 STATIC ${LIB2_SOURCES})
tests/CMakeLists.txt:
add_executable(tests ${TEST_SOURCES})
target_link_libraries(tests lib1 lib2)