Based on this stackoverflow answer to a similar question (Cmake include header only target from header only target), I am creating a header only library and trying to use it in an executable.
My folder structure is below:
├── CMakeLists.txt // root folder CMake file
├── srcs // this is the hdr only library
│ ├── src1.hpp
│ ├── CMakeLists.txt
│ ├── src2.hpp
│ └── src3.hpp
│ └── ...
└── test // this is the executable project
├── CMakeLists.txt
└── main.cpp
Root level CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project (MyProj CXX)
add_subdirectory(srcs)
add_subdirectory(test)
src level CMakeLists.txt (for header only library)
add_library(MyLib INTERFACE)
target_sources(MyLib INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/src1.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src2.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src3.hpp"
)
target_include_directories(MyLib
INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
add_subdirectory(plugins)
CMake file for executable test project
add_executable(MyTest main.cpp)
target_sources(MyTest
PRIVATE main.cpp
)
target_include_directories(MyTest PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
target_link_libraries(MyTest PUBLIC MyLib)
Though this configures cmake without warnings/error, running the make fails, indicating that the executable project is unable to find the header file(s) from library.
/.../nettu2/test/main.cpp:6:10: fatal error: src1.hpp: No such
file or directory #include "src1.hpp"
^~~~~~~~~~~~~~~~ compilation terminated. test/CMakeFiles/MyTest.dir/build.make:62: recipe for target
'test/CMakeFiles/MyTest.dir/main.cpp.o' failed make[2]: *
[test/CMakeFiles/MyTest.dir/main.cpp.o] Error 1
CMakeFiles/Makefile2:126: recipe for target
'test/CMakeFiles/MyTest.dir/all' failed make[1]: *
[test/CMakeFiles/MyTest.dir/all] Error 2 Makefile:129: recipe for
target 'all' failed make: *** [all] Error 2
I am sure that I am missing some crucial but trivial thing here, but yet unable to figure out, what is going wrong here. How can I get this build working?
You have a minor mistake in this line:
target_include_directories(MyLib
INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
The include directory you specify for MyLib expands to the build directory corresponding to srcs, i.e. it results in an invocation like
clang++ /path/to/build/test/test.cpp -I /path/to/build/srcs ...
but you want to pass the actual source directory to the preprocessor. To fix this, try
target_include_directories(MyLib
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
Related
I am working on a C project as of recently and want to learn how to use CMake properly.
The project consists of the following directory structure (as of now):
.
└── system
├── collections
│ ├── bin
│ ├── build
│ ├── includes
│ └── src
└── private
└── corelib
├── bin
├── build
├── includes
└── src
Every directory including 'bin' sub-directories is a separate library. They contain a CMakeLists.txt each.
The plan is to link the libraries in such a way that, during development, no manual recompilation of 'corelib' should be required to receive updated code from it, while also ensuring that dependencies would be resolved once all libraries get compiled as SHARED libraries and put in a place such as 'usr/local/lib' or similar.
I have a dependency of library 'corelib' in library 'collections'.
Trying to resolve said dependency, I have come up with the following CMakeLists.txt in 'collections':
cmake_minimum_required(VERSION 3.0.0)
project(collections VERSION 0.1.0 LANGUAGES C)
set(LIBRARY_OUTPUT_PATH ../bin)
add_subdirectory(../private/corelib ${LIBRARY_OUTPUT_PATH})
include_directories(./includes)
aux_source_directory(./src SOURCES)
add_library(collections SHARED ${SOURCES} main.c)
However, this does not produce the result I am looking for, as I get the following output on build:
[main] Building folder: collections
[build] Starting build
[proc] Executing command: /usr/bin/cmake --build /home/codeuntu/Repositories/netcore-c/src/system/collections/build --config Debug --target all -j 6 --
[build] gmake[1]: *** No rule to make target '../bin/all', needed by 'all'. Stop.
[build] gmake[1]: *** Waiting for unfinished jobs....
[build] Consolidate compiler generated dependencies of target collections
[build] [ 50%] Built target collections
[build] gmake: *** [Makefile:91: all] Error 2
[build] Build finished with exit code 2
It seems this is the wrong way to go about it. Any help is greatly appreciated.
This is the CMakeLists.txt for 'corelib':
cmake_minimum_required(VERSION 3.0.0)
project(corelib VERSION 0.1.0 LANGUAGES C)
include_directories(./includes)
aux_source_directory(./src SOURCES)
set(LIBRARY_OUTPUT_PATH ../bin)
add_library(corelib SHARED ${SOURCES} main.c)
Binary directory has to be a subdirectory of current dir, it can't be above ../bin. Use:
add_subdirectory(../private/corelib some_unique_name)
Overall, let's fix some issues. A more advanced CMake might look like this:
# system/CmakeLists.txt
add_subdirectory(private EXCLUDE_FROM_ALL)
add_subdirectory(collections)
# system/collections/CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(collections VERSION 0.1.0 LANGUAGES C)
file(GLOB_RECURSE srcs *.c *.h)
add_library(collections ${srcs})
# Use only target_* intefaces
target_include_directories(collections PUBLIC
./includes
)
target_link_libraries(collections PRIVATE
corelib
)
# system/private/CMakeLists.txt
add_subdirectory(corelib)
# system/private/corelib/CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(corelib VERSION 0.1.0 LANGUAGES C)
file(GLOB_RECURSE srcs *.c *.h)
add_library(corelib ${srcs})
target_include_directorieS(corelib PUBLIC ./includes)
# system/CMakePresets.json
{
... see documentation ...
"configurePresets": [
{
...
"cacheVariables": {
"BUILD_SHARED_LIBS": "1",
"ARCHIVE_OUTPUT_DIRECTORY": "${binaryDir}/bin",
"LIBRARY_OUTPUT_DIRECTORY": "${binaryDir}/bin",
"RUNTIME_OUTPUT_DIRECTORY": "${binaryDir}/bin"
}
}
I.e. overall, I do not think every project inside system wants to compile his own separate instance of corelib, rather one corelib should be shared. Just add corelib once, from anywhere. Note that it doesn't have to be in order - you can target_link_libraries on targets before they are defined.
I am trying to first create a static library and then link it to an executable using CMake. My project file structure looks like this:
├── CMakeLists.txt
├── build
├── lib
│ ├── CMakeLists.txt
│ ├── build
│ ├── include
│ │ └── Point.hpp
│ └── src
│ └── Point.cpp
└── mainApp.cpp
I first build the library like so.
cmake_minimum_required(VERSION 2.8.9)
project(CAST3)
set(CMAKE_BUILD_TYPE Release)
include_directories(include)
file(GLOB SOURCES "src/*.cpp")
add_library(CAST3 STATIC ${SOURCES})
However, when i try to link the library to my executable I get an error.
This is my executable
#include"Point.hpp"
int main(int argc, char *argv[]){
Point p = Point(1,2,3);
return 0;
}
This is my CMake file to link the library to the executable.
cmake_minimum_required(VERSION 2.8.9)
project (CAST3)
set ( PROJECT_LINK_LIBS libCAST3.a )
link_directories( ${CMAKE_CURRENT_SOURCE_DIR}/lib/build)
add_executable(libtest mainApp.cpp)
target_link_libraries(libtest ${PROJECT_LINK_LIBS} )
When I run that I get the this error
/mainApp.cpp:1:9: fatal error: 'Point.hpp' file not found
#include"Point.hpp"
^~~~~~~~~~~
1 error generated.
make[2]: *** [CMakeFiles/libtest.dir/mainApp.cpp.o] Error 1
make[1]: *** [CMakeFiles/libtest.dir/all] Error 2
make: *** [all] Error 2
What am I missing?
What am I missing?
You are missing target_include_directories(CAST3 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) inside lib/CMakeLists.txt.
You are missing add_subdirectory(lib) from root CMakeLists.txt.
The set ( PROJECT_LINK_LIBS libCAST3.a ) and target_link_libraries(libtest ${PROJECT_LINK_LIBS} ) and link_directories( ${CMAKE_CURRENT_SOURCE_DIR}/lib/build) could be removed. Then you are missing just target_link_libraries(libtest PUBLIC CAST3). Cmake will automatically find the proper .a file and propagate include paths with target_link_libraries.
So your lib/CMakeLists.txt could look like this:
cmake_minimum_required(VERSION 3.0) # I would advise to update
project(CAST3)
include_directories(include)
file(GLOB sources src/*.cpp) # upper case variable names reserved for exported variables by convention
add_library(CAST3 ${sources}) # STATIC by default
target_include_directories(CAST3 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
And root CMakeLists.txt could look like this:
cmake_minimum_required(VERSION 3.0) # I would advise to update
project(CAST3)
add_subdirectory(lib)
add_executable(libtest mainApp.cpp)
target_link_libraries(libtest CAST3)
./dir/
├── bot_example
│ ├── CMakeLists.txt
│ └── example0.cpp
├── CMakeLists.txt
├── README.md
└── sleepy_discord
├── attachment.cpp
├── attachment.h
├── channel.cpp
├── etc...
I am refactoring a project that was purely visual studio into CMake in order to make it cross-platform. I am not extensively experienced in CMake, however this structure worked in a test project to the end of debugging the problem. It fails at including the first header file (attachment.h and I can't seem to get it to recognize it. I've searched around for other answers with the same problem but to no avail. Any and all help is appreciated.
EDIT: I should mention this works under windows, which is why I'm confused and reaching out to Stack Exchange.
Top Level CMakeLists.txt
# Project Initialization
CMAKE_MINIMUM_REQUIRED(VERSION 3.5)
Project("Sleepy-Discord")
# Component Initialization
add_subdirectory(sleepy_discord)
add_subdirectory(bot_example)
./sleepy_discord/CMakeLists.txt
# Initialize API
cmake_minimum_required(VERSION 3.5)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
SET(BOOST_MIN_VERSION "1.58.0")
FIND_PACKAGE(Boost ${BOOST_MIN_VERSION} REQUIRED)
FIND_PACKAGE(CURL)
SET (sleepy_discord_SOURCES
./attachment.cpp
./attachment.h
./channel.cpp
./channel.h
./client.cpp
./client.h
./common.cpp
./common.h
./default_functions.cpp
./discord_object_interface.cpp
./discord_object_interface.h
./embed.cpp
./embed.h
./error.h
./experimental.cpp
./experimental.h
./json.c
./json.h
./json_wrapper.cpp
./message.cpp
./message.h
./sd_error.cpp
./server.cpp
./server.h
./sleepy_discord.h
./user.cpp
./user.h
)
if(Boost_FOUND)
add_library(sleepy_discord ${sleepy_discord_SOURCES})
target_include_directories(sleepy_discord INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
"$<BUILD_INTERFACE:${Boost_INCLUDE_DIRS}>"
"$<BUILD_INTERFACE:${CURL_INCLUDE_DIR}>"
"$<BUILD_INTERFACE:>${OPENSSL_INCLUDE_DIR}"
"$<BUILD_INTERFACE:>${CPR_INCLUDE_DIR}"
)
else()
message(STATUS "Boost library not found.")
endif()
./bot_example/CMakeLists.txt
# Initialize Bot
cmake_minimum_required(VERSION 3.5)
set(bot_example_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/example0.cpp
)
add_executable(bot_example ${bot_example_SOURCES})
target_link_libraries(bot_example sleepy_discord)
Terminal output:
Scanning dependencies of target sleepy_discord
[ 5%] Building CXX object sleepy_discord/CMakeFiles/sleepy_discord.dir/attachment.cpp.o
/home/bleugamer/Development/bots/sleepy_discord/sleepy_discord/attachment.cpp:1:24: fatal error: Attachment.h: No such file or directory
compilation terminated.
sleepy_discord/CMakeFiles/sleepy_discord.dir/build.make:62: recipe for target 'sleepy_discord/CMakeFiles/sleepy_discord.dir/attachment.cpp.o' failed
make[2]: *** [sleepy_discord/CMakeFiles/sleepy_discord.dir/attachment.cpp.o] Error 1
CMakeFiles/Makefile2:85: recipe for target 'sleepy_discord/CMakeFiles/sleepy_discord.dir/all' failed
make[1]: *** [sleepy_discord/CMakeFiles/sleepy_discord.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
On Unix-like systems (well, on EXT, UFS and other "Unixy" filesystems, to be precise) file accesses are case sensititive. Change
#include "Attachment.h"
to
#include "attachment.h"
I am learning to use cmake for a project using a shared library, but I keep getting this error:
Linking CXX executable test/test/robot_test
/usr/bin/ld: cannot open output file test/test/robot_test: No such file or directory
collect2: error: ld returned 1 exit status
make[2]: *** [test/test/robot_test] Error 1
make[1]: *** [CMakeFiles/test/robot_test.dir/all] Error 2
make: *** [all] Error 2
Here is my CMake file:
cmake_minimum_required(VERSION 2.8.12)
project("Particle Filter")
set(CMAKE_BUILD_TYPE Release)
include_directories(include)
set(LIB_SOURCES src/robot.cc src/sampler.cc src/general.cc)
set(LIB_HEADERS include/robot.h include/sampler.h include/general.h)
add_library(my_lib SHARED ${LIB_SOURCES} ${LIB_HEADERS})
install(TARGETS my_lib DESTINATION lib)
set(APP_SOURCES test/robot_test.cc test/sampler_test.cc)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test")
foreach(test ${APP_SOURCES})
#cut off .cc of src files using empty string
string(REPLACE ".cc" "" testname ${test})
add_executable(${testname} ${test})
target_link_libraries(${testname} my_lib)
endforeach(test ${APP_SOURCES})
add_definitions(
-std=c++11 # Or -std=c++0x
# Other flags
)
Here is my tree (excluding the build directory that contains a lot of this such as my makefile,.so and .a file):
├── CMakeLists.txt
├── driver.cc
├── include
│ ├── general.h
│ ├── robot.h
│ └── sampler.h
├── lib
├── notes
├── src
│ ├── general.cc
│ ├── robot.cc
│ └── sampler.cc
└── test
├── robot_test.cc
└── sampler_test.cc
Also, the .so or .a files are not getting saved to my lib folder after sudo make install, how do I fix this?
The first parameter for command add_executable is not a filename but a name of target. Target's name shouldn't contain special symbols like slash ("/").
You may control output directory of executables created by setting variable CMAKE_RUNTIME_OUTPUT_DIRECTORY:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test")
...
# Relative path to executable will be 'test/robot_test'.
add_executable(robot_test robot_test.cc)
First: I'm a total newbie in using cmake especially with Qt5. So my explanations might sound a little weird to you, but I'll try my best.
At the moment I'm about to set up my project using cmake, Qt5 and mingw.
My project structure is the following:
Cmake (my project name)
├── headers
│ ├── Controller
│ │ └── Controller.h
│ └── IUI
│ └── mainwindow.h
└── source
├── Controller
│ └── Controller.cpp
│ └── cmakelists.txt
└── IUI
├── main.cpp
├── mainwindow.cpp
└── mainwindow.ui
└── cmakelists.txt
This is the cmakelists.txt located in source/IUI
cmake_minimum_required(VERSION 2.8.11)
project(CellAnalyser)
find_package (Qt5Widgets)
set (CellAnalyserLib_src ${PROJECT_SOURCE_DIR}/source/IUI/mainwindow.cpp)
set (CellAnalyserLib_hdr ${PROJECT_SOURCE_DIR}/header/IUI/mainwindow.h)
set (CellAnalyserLib_ui ${PROJECT_SOURCE_DIR}/source/IUI/mainwindow.ui)
set (CellAnalyserBin_src ${PROJECT_SOURCE_DIR}/source/IUI/main.cpp)
set (Source ${CellAnalyserLib_src} ${CellAnalyserBin_src})
qt5_wrap_cpp(CellAnalyserLib_hdr_moc ${CellAnalyserLib_hdr})
qt5_wrap_ui (CellAnalyserLib_ui_moc ${CellAnalyserLib_ui})
include_directories (${PROJECT_SOURCE_DIR})
include_directories (${PROJECT_BINARY_DIR})
add_library (CellAnalyserLib SHARED
${CellAnalyserLib_src}
${CellAnalyserLib_hdr_moc}
${CellAnalyserLib_ui_moc}
)
add_executable(CellAnalyser ${Source}
${CellAnalyserLib_hdr}
${CellAnalyserLib_src}
${CMAKE_SOURCE_DIR}/header/Controller/Controller.h
${CMAKE_SOURCE_DIR}/source/Controller/Controller.cpp
)
target_link_libraries (CellAnalyserLib Qt5::Widgets)
target_link_libraries (CellAnalyser ${ITK_LIBRARIES})
target_link_libraries(CellAnalyser ${OPENGL_LIBRARIES})
target_link_libraries (CellAnalyser CellAnalyserLib)
So thats been the important part you need to know. Now the question is: why am I not able to include the Header "controller.h" in mainwindow.cpp? The include in main.cpp works fine and I am able to instantiate the controller-class and call functions. But if I try the same exact thing in mainwindow.cpp I get the following as output:
CMakeFiles\CellAnalyserLib.dir/objects.a(mainwindow.cpp.obj):mainwindow.cpp:(.text+0x820): undefined reference to `_imp___ZN6itksys18SystemToolsManagerD1Ev'
CMakeFiles\CellAnalyserLib.dir/objects.a(mainwindow.cpp.obj):mainwindow.cpp:(.text+0x859): undefined reference to `_imp___ZN6itksys18SystemToolsManagerC1Ev'
CMakeFiles\CellAnalyserLib.dir/objects.a(mainwindow.cpp.obj):mainwindow.cpp:(.data+0xfffff740): undefined reference to `itk::NiftiImageIOFactoryRegister__Private()'
C:/PROGRA~2/MINGW-~1/I686-4~1.2-P/mingw32/bin/../lib/gcc/i686-w64-mingw32/4.9.2/../../../../i686-w64-mingw32/bin/ld.exe: CMakeFiles\CellAnalyserLib.dir/objects.a(mainwindow.cpp.obj): bad reloc address 0x0 in section `.data'
collect2.exe: error: ld returned 1 exit status
source\IUI\CMakeFiles\CellAnalyserLib.dir\build.make:134: recipe for target 'source/IUI/libCellAnalyserLib.dll' failed
mingw32-make[2]: *** [source/IUI/libCellAnalyserLib.dll] Error 1
CMakeFiles\Makefile2:263: recipe for target 'source/IUI/CMakeFiles/CellAnalyserL
ib.dir/all' failed
mingw32-make[1]: *** [source/IUI/CMakeFiles/CellAnalyserLib.dir/all] Error 2
makefile:82: recipe for target 'all' failed
mingw32-make: *** [all] Error 2
So what am I doing wrong?
First of all, including controller.h appears to work fine, if the error messages you provided were complete. Only the linking fails, when CellAnalyserLib is being linked.
The reason for this is that you are using functions obtained from controller.cpp, but you are not including controller.cpp in any way in your linkage (neither directly as source, nor indirectly through another library). In addition, you are not linking ITK with your CellAnalyserLib.
A possible fix would be to ditch the shared library altogether (replace your add_* and target_link_libraries statements):
add_executable(CellAnalyser ${Source}
${CellAnalyserLib_hdr}
${CellAnalyserLib_src}
${CellAnalyserLib_hdr_moc}
${CellAnalyserLib_ui_moc}
${CMAKE_SOURCE_DIR}/header/Controller/Controller.h
${CMAKE_SOURCE_DIR}/source/Controller/Controller.cpp
)
target_link_libraries (CellAnalyser Qt5::Widgets)
target_link_libraries (CellAnalyser ${ITK_LIBRARIES})
target_link_libraries(CellAnalyser ${OPENGL_LIBRARIES})
If ditching the shared library is not an option, you need to clean up your linkage, by not having the same source in two different objects (again, replace your add_* and target_link_libraries statements):
add_library (CellAnalyserLib SHARED
${CellAnalyserLib_src}
${CellAnalyserLib_hdr_moc}
${CellAnalyserLib_ui_moc}
${CMAKE_SOURCE_DIR}/source/Controller/Controller.cpp
)
add_executable(CellAnalyser ${CellAnalyserBin_src}
)
target_link_libraries (CellAnalyserLib ${ITK_LIBRARIES})
target_link_libraries(CellAnalyserLib ${OPENGL_LIBRARIES})
target_link_libraries (CellAnalyserLib Qt5::Widgets)
target_link_libraries (CellAnalyser CellAnalyserLib)
Adding headers to add_* is not neccessary.