Why are files not found from parallel folders CMake - c++

To have my .cpp and .h files a little bit sorted up pending on their responsibilitie I decided to put them into seperate folders
I used the following structure:
root
|
-CMakeLists.txt [rootCmakeList]
src
|
-main.cpp
.......|
....... math
.......|
.......-CMakeLists.txt[mathCmakeList]
.......-Algebra.h
.......-Algebra.cpp
.......XML[xmlCmakeList]
.......|
.......-CMakeLists.txt
.......-AwesomeXML.h
.......-AwesomeXML.cpp
The [rootCmakeList] looks:
cmake_minimum_required(VERSION 3.11.3)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS_DEBUG "-g")
project(myProject)
#add exectuable
add_executable(myProject src/main.cpp)
target_include_directories(myProject PUBLIC "${src/XML}")
target_include_directories(myProject PUBLIC "${src/math}")
add_subdirectory(src/XML)
add_subdirectory(src/math)
target_link_libraries(myProject xml)#needed?
target_link_libraries(myProject math)#needed?
The [mathCmakeList] looks:
include_directories(${myProject}src/math)
add_library(math Algebra.cpp)
The [xmlCmakeList] looks:
include_directories(${myProject}src/xml)
add_library(xml AwesomeXML.cpp)
So far so good and no problems. But if I want to #include Algebra.h into
AweseomeXML.cpp I can not find the file.
To being honest I am not even sure if the cmake command add_library and target_link_libraries makes really sense here because I do not want to create own libraries of it just want to tidy up a little bit my files pending on their topic.

myProject doesn't seem to be a variable you set. Furthermore if you properly set up the library targets, you won't need to add any of the include directories to myProject manually.
First set up the CMakeLists.txt file for math, since it doesn't depend on other projects. I recommend moving headers linking libraries use to a subdirectory. I myself usually use include and any path that you want the linking library to use in #includes starts there. Set the include dirs in a way that adds them to the INTERFACE_INCLUDE_DIRECTORIES target property of math.
add_library(math Algebra.cpp
include/Algebra.h # for IDEs
)
target_include_directories(math # should be static here, since you don't want to deploy the lib by itself
PUBLIC include # available to both math and linking libs
PRIVATE . # only available to math; only necessary, if there are "private" headers
)
Then do the same thing for xml, but since you're using functionality from math, you need to link it giving you access to its include dirs automatically, since they are available via INTERFACE_INCLUDE_DIRECTORIES:
add_library(xml STATIC
AwesomeXML.cpp
include/AwesomeXML.h
)
target_include_directories(xml PUBLIC include)
target_link_libraries(xml PRIVATE math) # change PRIVATE to PUBLIC, if Algebra.h is included in a public header
Now at the toplevel we should make sure that any dependencies of a target are available before the target is defined. Also linking a lib gives you access to their respective public include directories and the public include dirs of dependencies linked publicly:
cmake_minimum_required(VERSION 3.11.3)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS_DEBUG "-g")
project(myProject)
add_subdirectory(src/math)
add_subdirectory(src/XML)
#add exectuable
add_executable(myProject src/main.cpp)
target_link_libraries(myProject PRIVATE math xml)

Related

how to write cmake with 1 executable and multiple subdirectories

I have a project with many sub-directories that each 1 of them include both header and source files. I want 1 executable which include all my src files.
I managed to write the cmake so it compiles successfully,
but Im dealing with 2 problems, I dont now how to solve:
1 - The compile time is very slow, probably somthing I'm doing wrong.
2 - I have few flags like DEBUG, RELEASE that I couldnt make it define/ undefine in any of the CMakeLists.txt files.
I need this because I have some of my source files :
#ifndef RELEASE /DEBUG #endif
My project stracture looks similar to this:
root/ (project root)
3rd_party/
spdlog/ ...
src/
CMakeLists.txt
main.cpp (contains main method)
logger/
log.c
logger.cpp
logger.hpp
CMakeLists.txt
first/
first_c.h
first.cpp
first.hpp
CMakeLists.txt
second/
second.cpp
second.hpp
CMakeLists.txt
control/
control.cpp
control.hpp
control_2.hpp
CMakeLists.txt
some more sub directories/...
build/
... (executable)
This is part from what I currently have :
in src/CMakeLists.txt:
cmake_minimum_required(VERSION 3.18)
project(integration LANGUAGES CXX)
set(src_main main.cpp)
add_subdirectory(first)
add_subdirectory(second)
add_subdirectory(third)
add_subdirectory(control)
add_subdirectory(logger)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../3rd_party/spdlog ${CMAKE_CURRENT_BINARY_DIR}/spdlog)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
add_executable(${PROJECT_NAME} ${src_main})
target_link_libraries(${PROJECT_NAME} control first second third logger)
target_compile_definitions(${PROJECT_NAME} PUBLIC RELEASE) # not working???
in src/control/CMakeLists.txt:
set(control_source_files
control.cpp
control.hpp
)
add_library(control SHARED ${control_source_files})
find_library(LIB paho-mqtt3c ${PROJECT_SOURCE_DIR}/lib)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(control PUBLIC Threads::Threads)
target_link_libraries(control PUBLIC ${LIB})
target_include_directories(robot_control PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../second)
target_include_directories(robot_control PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../third)
in src/first/CMakeLists.txt:
set(first_source_files
first_c.h
first.cpp
first.hpp
)
add_library(first SHARED ${first_source_files})
target_include_directories(motor PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../second)
target_include_directories(motor PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../logger)
target_include_directories(motor PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../3rd_party/date/include/)
Im not sure if I need target_include_directories I did it becuase in first.hpp there are icludes for headers in those subdirectories.
any help to do the compile time faster and define right the flags ??
1 - The compile time is very slow, probably somthing I'm doing wrong.
There might be many reasons.
Main cause is usually to many includes in header files. Froward declarations in as many places as possible of header files is very effective cure for that issue. There is even a tool which helps to clean up existing project Include What You Use (IWYU).
2 - I have few flags like DEBUG, RELEASE that I couldnt make it
define/ undefine in any of the CMakeLists.txt files. I need this
because I have some of my source files :
target_compile_definitions(${PROJECT_NAME} PUBLIC RELEASE) # not working???
You are doing that wrong. Depending on generator you use (if it supports multiple configuration or not), you can control this in configuration step or in build step, by passing extra parameters:
In case if generator do not have mtuple configurations you configure this this way:
cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
cmake --build .
See doc
If generator supports multiple configurations then:
cd build
cmake ..
cmake --build . --config Debug
target_include_directories(robot_control PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../second)
target_include_directories(robot_control PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../third)
This is wrong. target_include_directories defines which paths are important for given target (library). Now when something is PUBLIC then any target which will do target_link_libraries(someTarget PUBLIC sourceTarget) where sourceTarget is your library will be impacted by this path. someTarget will inherit include paths from public (or interface) of source target so you don't have to add them explicitly.
So basically this quted lines are obsolete (if second and third targets have this include paths defined as PUBLIC).

Integrating GTest with existing CMake Project: share the same target_sources

I have a large C++ library, and want to do some testing with GTest.
At the moment, the build is handled with CMake, in particular there is one CMakeLists.txt file in the root directory like the following
make_minimum_required(VERSION 3.13.0)
project(mylib)
find_package(PkgConfig REQUIRED)
set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
set(CMAKE_INSTALL_RPATH "${CMAKE_CURRENT_SOURCE_DIR}/lib/protobuf/src/.libs/")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
SET(BASEPATH "${CMAKE_SOURCE_DIR}")
INCLUDE_DIRECTORIES("${BASEPATH}")
add_executable(mylib run.cpp)
add_subdirectory(src)
add_subdirectory(proto)
target_include_directories(mylib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/lib/math
${CMAKE_CURRENT_SOURCE_DIR}/lib/protobuf/src
... some dirs ...
)
target_link_directories(mylib PRIVATE
... some libs ..
)
target_link_libraries(mylib
${CMAKE_CURRENT_SOURCE_DIR}/lib/math
${CMAKE_CURRENT_SOURCE_DIR}/lib/protobuf/src
.....
)
target_compile_options(mylib PUBLIC -D_REENTRANT -fPIC)
Then in the src directory and every sub-directory there is a CMakeLists.txt file, for example this is in src/
target_sources(mylib
PUBLIC
includes.hpp
)
add_subdirectory(algorithms)
add_subdirectory(collectors)
add_subdirectory(hierarchies)
add_subdirectory(mixings)
add_subdirectory(runtime)
add_subdirectory(utils)
My question here is the following: what is the least painful way to integrate GTest in the current project? I was thinking of having a test/ subdirectory, like I've seen here: Adding Googletest To Existing CMake Project
However this example requires that for each executable you manually list all the files it includes. Is there a quicker way to use the sources that are already added to 'mylib'?
You can split the current mylib executable target into two targets
mylib, a library target that is very much like the current mylib target, but without the run.cpp file
mylib_exe an executable target that compiles run.cpp and links to mylib
Now your test files can link to mylib.

Cmake issue with building a small library

I am currently trying to deepen my understanding regarding CMake. I try to use http://libqglviewer.com/introduction.html]LibQGLViewer as a Third-Party library in a C++ Project of mine.
The CMakeLists.txt in the associated subdirectory looks like the following where the part, I have questions is the add_libary section and some header and source files were omitted for clarity
cmake_minimum_required (VERSION 3.5.1 FATAL_ERROR)
set(target_name QGLViewerQt5)
project(${target_name})
message(STATUS "BUILDING QGLViewer-2.7.0 FROM SOURCE!")
set(BASE_DIR QGLViewer)
set(VRENDER_DIR VRender)
set(CMAKE_AUTOMOC ON)
set(QGLheaders
${BASE_DIR}/camera.h
${BASE_DIR}/config.h
${BASE_DIR}/${VRENDER_DIR}/AxisAlignedBox.h
${BASE_DIR}/${VRENDER_DIR}/Exporter.h
)
set(QGLsources
${BASE_DIR}/camera.cpp
${BASE_DIR}/${VRENDER_DIR}/Exporter.cpp
)
add_library(${target_name} ${QGLsources} ${QGLheaders})
target_include_directories(${target_name}
PUBLIC .
)
target_link_libraries(${target_name}
${OPENGL_LIBRARIES}
Qt5::Core
Qt5::Widgets
Qt5::Xml
Qt5::OpenGL
)
set(CMAKE_AUTOMOC OFF)
install(TARGETS ${target_name} DESTINATION lib)
My Application runs and everything is fine.
However, I read that one should only include the source files with add_library and then use target_include_directories to consider the associated header files. So I changes the above part to
add_library(${target_name} SHARED ${QGLsources})
target_include_directories(${target_name}
PUBLIC
${PROJECT_SOURCE_DIR}/QGLViewer
${PROJECT_SOURCE_DIR}/QGLViewer/VRender
)
but now, I get an error trying to make my project
fatal error: QGLViewer/qglviewer.h: No such file or directory
compilation terminated.
can you please tell me
What exactly does PUBLIC . do? I know what PUBLIC does but what does the point mean?
Why does it not work as before?
thank you in advance
PS: The folder structure is as follows
Firts one, target_include_directories() has following syntax according official docs target_include_directories(<target> [SYSTEM] [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...]) as you see there few keywords might be used:
PRIVATE: adds directories to INCLUDE_DIRECTORIES property of <target>
INTERFACE: adds directories to INTERFACE_INCLUDE_DIRECTORIES property of <target>
PUBLIC: adds directories to INCLUDE_DIRECTORIES and INTERFACE_INCLUDE_DIRECTORIES properties of <target>
What about those properties:
INCLUDE_DIRECTORIES - contains list of directories to search header files you used in project
INTERFACE_INCLUDE_DIRECTORIES - contains list of directories to search header files too, but it has transitivity, that means you able to inherit your include directories to project linked through target_link_libraries()
Second one, your code doesn't work because you are using another include folders paths, your source file must be contain something like #include <QGLViewer/qglviewer.h> but since you do not include root folder anymore (. in your previous code), but linking QGLViewer directly - you must type #include <qglviewer.h>. Fix it for each #include you are using or add ${PROJECT_SOURCE_DIR} to target_include_directories instead.

CMake Add (Test) Executable

I would like to create two executables: one executable for the application, and one for the testing of the application. To that end, I have the following in my CMakeLists.txt file:
include_directories(include)
file(GLOB SOURCE "src/*.cc")
file(GLOB TEST "test/*.cc")
add_executable(interest_calc ${SOURCE})
add_executable(interest_calc_test "src/interest_calc.cc" ${TEST})
Since both src and test directories contain main functions, I have to manually add source files to the "test" executable. Is there another, non-manual, way to add required source files to the "test" executable?
Further, is there a better way to test functionality than creating a separate test executable? If so, what/how?
One way to improve your process would be to pull the guts of your executable into a library, then have a nominal "main" executable which just calls into your library and a "test" executable which exercises the library however you want to test it.
This way, any changes you need to make go into the library and the executable build process is untouched.
Edit to show CMake with your example:
include_directories(include)
file(GLOB SOURCE "src/*.cc")
# Remove main from library, only needed for exec.
list(REMOVE_ITEM SOURCE "main.cc")
file(GLOB TEST "test/*.cc")
add_library(interest_calc_lib STATIC ${SOURCE})
add_executable(interest_calc "main.cc")
target_link_libraries(interest_calc interest_calc_lib)
add_executable(interest_calc_test ${TEST})
target_link_libraries(interest_calc_test interest_calc_lib)
There are already some good answers from Soeren and mascoj but I would like to give a more concrete recommendation.
When you already have a CMakeLists.txt for your executable and you like to add testing, I recommend adding a static dummy library. This library can have all the sources of the executable except the main method (it may be easiest to single out the main method in a separate file if you do not have that already). Using a static library will give you two benefits:
The final executable will behave exactly as your current one, so there is no need to deal with distribution of a new, shared library
You do not need to deal with exporting symbols or throwing exceptions across shared object boundaries
The changes to your CMakeLists.txt can be quite small. I will give an example here, assuming you use cmake 3.0 or newer. First, an example of CMakeLists.txt before adding the dummy library:
project(MyProject)
set(SOURCES src/First.cc src/Second.cc src/Third.cc)
add_executable(${PROJECT_NAME} ${SOURCES} src/Main.cc)
target_include_directories(${PROJECT_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR})
target_compile_options(${PROJECT_NAME}
$<$<CXX_COMPILER_ID:GNU>:-Wall;-pedantic)
target_compile_definitions(${PROJECT_NAME}
$<$<CONFIG:Debug>:DEBUG;_DEBUG>)
set_target_properties(${PROJECT_NAME}
PROPERTIES CXX_STANDARD 14)
target_link_libraries(${PROJECT_NAME}
Threads::Threads)
To add the dummy library and testing, you need to introduce a new target with a different name. I choose here to use ${PROJECT_NAME}_lib because this will be very non-intrusive on the CMakeLists.txt. Here is the updated version. Notice the use of ${PROJECT_NAME}_lib in place of ${PROJECT_NAME} in almost all places. Most properties are now passed down to the executable by making them PUBLIC. Only calls to set_target_properties() are not transitive and must be duplicated for library and executable.
project(MyProject)
set(SOURCES src/First.cc src/Second.cc src/Third.cc)
add_library(${PROJECT_NAME}_lib STATIC ${SOURCES})
add_executable(${PROJECT_NAME} src/Main.cc)
target_include_directories(${PROJECT_NAME}_lib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR})
target_compile_options(${PROJECT_NAME}_lib PUBLIC
$<$<CXX_COMPILER_ID:GNU>:-Wall;-pedantic)
target_compile_definitions(${PROJECT_NAME}_lib PUBLIC
$<$<CONFIG:Debug>:DEBUG;_DEBUG>)
set_target_properties(${PROJECT_NAME}_lib
PROPERTIES CXX_STANDARD 14)
set_target_properties(${PROJECT_NAME}
PROPERTIES CXX_STANDARD 14)
target_link_libraries(${PROJECT_NAME}
${PROJECT_NAME}_lib
Threads::Threads)
Now you can link your tests against ${PROJECT_NAME}_lib with a different main method.
You could do like this :
In the current CMakeLists.txt, put these lines :
add_subdirectory(src)
add_subdirectory(test)
and then, in each directories add a CMakeLists.txt that link correctly sources to each files.
About test, I've heard that CMake can do test automation, but I don't really know how it works.
In my opinion the best solution is to create a library (shared or static) and two executables (one for the main program and one for the test main). After that you should link the library against the two applications.
In this answer I write down a explanation with a little example how you could managed the project with cmake.

Right way of creating a library, installing it and linking to another project using CMake

I have a set of files that I want to make into a library and then use that library in another project. This it how it looks like right now
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
SET(CMAKE_CXX_FLAGS "-std=c++11 -fopenmp -fPIC")
add_library (helperlibs lib1.cpp lib2.cpp lib3.cpp lib4.cpp )
INSTALL(TARGETS helperlibs
DESTINATION "${HOME}/lib"
)
INSTALL(FILES lib1.h lib2.h lib3.h lib4.h helperheader.h
DESTINATION "${HOME}/include/helperlibs"
)
In this code Lib4 depends on Lib1-3 and Lib3 depends on Lib1-2 and Lib2 depends on Lib1. Each of these cpp files also depend on a helperheader.h file that contains some definitions and structs.
In my project I have the following CMake file
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
SET( CMAKE_CXX_FLAGS "-std=c++11 -fopenmp -fPIC")
SET(MYINCS ${HOME}/include/helperlibs)
SET(MYLIBDIR ${HOME}/lib)
SET(MYLIBS ${MYLIBDIR}/libhelperlibs.a )
include_directories(${MYINCS})
add_executable(main main.cpp)
target_link_libraries(main ${MYLIBS})
So what I am wondering if you want to create a static library and link to from a another project using cmake is this the way you should write?
Embed the search paths into the library target as properties and create an export.
This way executables in the same build tree will find the library and its include files without you having to specify paths (they become implicit).
I needed to read the cmake documentation carefully a few times before it dawned on me how it should work.
http://www.cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html#creating-packages
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
excerpt from a live example:
add_library(trustportal-util ${CMAKE_CURRENT_LIST_FILE} ${_source_files} ${_disabled_source_files} )
target_link_libraries(trustportal-util ${Boost_LIBRARIES})
if(APPLE)
find_library(SECURITY_FRAMEWORK Security)
target_link_libraries(trustportal-util ${SECURITY_FRAMEWORK})
else()
find_library(LIB_SSL ssl)
find_library(LIB_CRYPTO crypto)
target_link_libraries(trustportal-util ${LIB_SSL} ${LIB_CRYPTO})
endif()
target_compile_definitions(trustportal-util PUBLIC BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE)
target_include_directories(trustportal-util PUBLIC ${Boost_INCLUDE_DIRS})
target_include_directories(trustportal-util PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_include_directories(trustportal-util SYSTEM PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
install(TARGETS trustportal-util
EXPORT trustportal-utilExport
DESTINATION lib
INCLUDES DESTINATION include
)
INSTALL(EXPORT trustportal-utilExport DESTINATION lib)
One option is to do what you are currently doing where you place the includes and libs in a common location, perhaps /usr/include and /usr/lib on linux, or ${HOME} on both Windows/Linux, up to you.
Another option is available if you use git. You can include the project inside another using submodules. Then use include_directory(${submodule}) and build and link directly for every project. The advantage of this approach is that dependencies are more localised. One problem with this method is if you recursively do this, you may end up with duplicates of some projects and cmake will complain that two libraries have the same name.