Simple multiple directories CMake - c++

I just would like to create my CMakeLists.txt like this, but the CMake guide is not that user friendly for beginners, I have already researched too much, do not downvote, please.
I have seen some solutions including in the add_executable() every source file manually, but I would like to make it more generic. Also, I would not like to use the file(GLOB SOURCES *.cpp *.h).
By the way, I am just attempting to create a Unix Makefile with the command
cmake -G 'Unix Makefiles'..
How can I do this?
CMakeLists.txt
build/
...
project/
CMakeLists.txt
Inc/
CMakeLists.txt
*.h
Src/
CMakeLists.txt
main.cpp
*.cpp
I have so far for the main directory/CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(my_project)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a")
add_subdirectory(project)
for the project/CMakeLists.txt
add_subdirectory(Inc)
add_subdirectory(Src)
add_executable(exec ${Sources})
target_link_libraries(exec ${Headers})
For the Inc/CMakeLists.txt
add_library(
Headers
H1.h
H2.h
...
Hn.h
)
and for the Src/CMakeLists.txt
set(Sources main.cpp
Src1.cpp
Src2.cpp
...
Srcn.cpp
)
As it is so far, it throws the following error
-- Version: 7.0.3
-- Build type:
-- CXX_STANDARD: 11
-- Required features: cxx_variadic_templates
-- Configuring done
CMake Error: Cannot determine link language for target "exec".
CMake Error: CMake can not determine linker language for target: exec
CMake Error: Cannot determine link language for target "Headers".
CMake Error: CMake can not determine linker language for target: Headers
-- Generating done
CMake Generate step failed. Build files cannot be regenerated correctly.

add_library(
Headers
H1.h
H2.h
does not add a include directory to search path. It only adds the headers to sources - and because headers are not compiled, it effectively does nothing. You can do that with target_include_directories. Because cmake doesn't know if these are C or C++ headers, it cannot determine the link language.
add_subdirectory(Src)
add_executable(exec ${Sources})
add_subdirectory introduces a new "scope". Variables set in add_subdirectory are not visible outside, unless you set them with PARENT_SCOPE like set(var "value" PARENT_SCOPE). ${Sources} is effectively empty, so it does add_executable(exec) with no sources, so cmake cannot determine the link language.
target_link_libraries(exec ${Headers})
A target is not a variable. ${Headers} is empty. To link with a target just use it's name.
I also subjectively advice do not use mixed case variables (and folder names).
You could:
# project/CMakeLists.txt
include(Inc/CMakeLists.txt)
include(Src/CMakeLists.txt)
add_executable(exec ${exec_sources} ${exec_headers})
target_include_directories(exec PUBLIC Inc)
# Inc/CMakeLists.txt
set(exec_headers
Inc/H1.h
Inc/H2.h
...
Inc/Hn.h
)
# Src/CMakeLists.txt
set(exec_sources
Src/main.cpp
Src/Src1.cpp
Src/Src2.cpp
...
Src/Srcn.cpp
)
# Instead of `Src/` in front you could write a `foreach()` loop.
but I do not see a point in having so many CMakeLists.txt. Just have one file:
# project/CMakeLists.txt
include(Inc/CMakeLists.txt)
include(Src/CMakeLists.txt)
add_executable(exec
Src/main.cpp
Src/Src1.cpp
Src/Src2.cpp
...
Src/Srcn.cpp
Inc/H1.h
Inc/H2.h
...
Inc/Hn.h
)
target_include_direcotories(exec PUBLIC Inc)
Och, there is also target_sources you could use, so you could also do it like this I think:
# project/CMakeLists.txt
add_executable(exec ${exec_sources} ${exec_headers})
add_subdirectory(Inc)
add_subdirectory(Src)
# Inc/CMakeLists.txt
target_include_directories(exec PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_sources(exec PRIVATE
H1.h
H2.h
...
Hn.h
)
# Src/CMakeLists.txt
target_sources(exec PRIVATE
main.cpp
Src1.cpp
Src2.cpp
...
Srcn.cpp
)

Related

pybind11 and another libs in one project [duplicate]

I want to be able to call my C++ code as a python package. To do this I am using pybind11 with CMakelists (following this example https://github.com/pybind/cmake_example). My problem is that I have to include GSL libraries in the compilation of the code, and these need an explicit linker -lgsl .
If I were just to compile and run the C++ without wrapping it with python, the following Cmakelists.txt file does the job
cmake_minimum_required(VERSION 3.0)
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
project(myProject)
add_executable(
myexecutable
main.cpp
function1.cpp
)
find_package(GSL REQUIRED)
target_link_libraries(myexecutable GSL::gsl GSL::gslcblas)
but when using pybind11 the template I found doesn't allow the add_executable therefore target_link_libraries doesn't work.
I have trie this
project(myProject)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED YES) # See below (1)
# Set source directory
set(SOURCE_DIR "project")
# Tell CMake that headers are also in SOURCE_DIR
include_directories(${SOURCE_DIR})
set(SOURCES "${SOURCE_DIR}/functions.cpp")
# Generate Python module
add_subdirectory(lib/pybind11)
pybind11_add_module(namr ${SOURCES} "${SOURCE_DIR}/bindings.cpp")
FIND_PACKAGE(GSL REQUIRED)
target_link_libraries(GSL::gsl GSL::gslcblas)
but this produces errors in the building.
Any idea ?
Function pybind11_add_module creates a library target, which can be used for link added module with other libraries:
pybind11_add_module(namr ${SOURCES} "${SOURCE_DIR}/bindings.cpp")
target_link_libraries(namr PUBLIC GSL::gsl GSL::gslcblas)
This is explicitely stated in documentation:
This function behaves very much like CMake’s builtin add_library (in fact, it’s a wrapper function around that command). It will add a library target called <name> to be built from the listed source files. In addition, it will take care of all the Python-specific compiler and linker flags as well as the OS- and Python-version-specific file extension. The produced target <name> can be further manipulated with regular CMake commands.

CMake: Cannot link to a static library in a subdirectory

I have the following folder structure in my c++ project
*--build
|---(building cmake here)
|
*--main.cpp
|
*--CMakeLists.txt (root)
|
*--modules
|---application
|------app.h
|------app.cpp
|------CMakeLists.txt
And the code below for both CMakeLists.txt files:
CMakeLists.txt (module)
cmake_minimum_required(VERSION 3.15.2)
file(GLOB APPLICATION_HEADERS *.h *.hpp)
file(GLOB APPLICATION_SRC *.c *.cpp)
add_library(app_lib STATIC
${APPLICATION_HEADERS}
${APPLICATION_SRC})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR})
CMakeLists.txt (root)
cmake_minimum_required(VERSION 3.15.2)
project(main)
enable_language(C CXX)
#set directories
set(CMAKE_BINARY_DIR build)
set(CMAKE_CONFIGURATION_TYPES UNIX)
set(CMAKE_MODULES_DIR ${SOURCE_DIR}/cmake)
add_executable(${PROJECT_NAME} main.cpp)
# Build sub-modules
include_directories(modules/application)
add_subdirectory(modules/application)
find_library(MY_APP_LIB app_lib REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC ${MY_APP_LIB})
However, when I do cmake .. in my build directory, it seems like my app library just doesn't build and it doesn't link to it. I end up with the following error:
CMake Error at CMakeLists.txt:80 (find_library):
Could not find MY_APP_LIB using the following names: app_lib
I tried looking at other stackoverflow questions but it seems like I'm missing something. Any help is appreciated!
Thanks!
You don't need to use find_* to locate the library. In fact you cannot locate the library this way, since find_library searches the file system for the library during configuration, i.e. before anything gets compiled.
There's good news though: If the targets are created in the same cmake project, you can simply use the name of the cmake target as parameter for target_link_libraries:
...
add_library(app_lib STATIC
${APPLICATION_HEADERS}
${APPLICATION_SRC})
# note: this should be a property of the library, not of the target created in the parent dir
target_include_directories(app_lib PUBLIC .)
...
add_subdirectory(modules/application)
target_link_libraries(${PROJECT_NAME} PUBLIC app_lib)
You don't need to do find_library for your own targets, just link directly to app_lib:
target_link_libraries(${PROJECT_NAME} PUBLIC app_lib)

why add_subdirectory() command did not work for my CMakeLists.txt?

I have a simple exercise on cmake with following file tree:
proj01/
include/
functions.h
src/
main.cpp
functions.cpp
CMakeLists.txt
CMakeLists.txt
README
My project CMakeLists.txt is like this:
cmake_minimum_required(VERSION 3.21)
project (test01)
add_subdirectory(src)
set(SOURCES
main.cpp
functions.cpp
)
add_executable(myProgram ${SOURCES})
and when I tried to build, I got error:
# Error!
CMake Error at CMakeLists.txt:18 (add_executable):
Cannot find source file:
main.cpp
CMake Error at CMakeLists.txt:18 (add_executable):
No SOURCES given to target: myProgram
If I change the project CMakeLists.txt by giving the absolute path(relative to the project), it worked!
#add_subdirectory(src)
set(SOURCES
src/main.cpp
src/functions.cpp
)
add_executable(myProgram ${SOURCES})
When there is multiple source files in multiple subdirectories, it would be better to explicitly list all source files including their paths as what is done with my working version of the CMakeLists.txt.
Spent hours to search for command add_subdirectories(), this, this, and this, but no luck.
The closest one would be this question, but there is no solution for that question so far.
What did I miss with my add_subdirectory(src) in this simple specific scenario? Any help is appreciated.
add_subdirectory(src) results in cmake parsing src/CMakeLists.txt creating a new directory src in the build tree for building the part of the project in this cmake file.
It doesn't result in you being able to use shorter paths in the CMakeLists.txt file containing the add_subdirectory command.
If you move the target to src/CMakeLists.txt you could use the shorter paths:
CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project (test01)
add_subdirectory(src) # add src/CMakeLists.txt to this project
src/CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
set(SOURCES
main.cpp
functions.cpp
)
add_executable(myProgram ${SOURCES})
Personally I'd avoid adding an additional CMakeLists.txt file just to shorten the paths. It's easy to remove the duplication of the src dir, if that's what you're worried about.
set(SOURCES
main.cpp
functions.cpp
)
list(TRANSFORM SOURCES PREPEND "src/")
or
function(subdir_files VAR DIR FILE1)
set(FILES)
foreach(SRC IN ITEMS ${FILE1} ${ARGN})
list(APPEND FILES ${DIR}/${SRC})
endforeach()
set(${VAR} ${FILES} PARENT_SCOPE)
endfunction()
subdir_files(SOURCES src
main.cpp
functions.cpp
)

How to include properly all files with CMake

I want to build my C++ project with CMake and I want to include automatically every new file on "cmake ." my project structure is:
Application/ Graphics/ CMakeLists.txt CMakeLists.txt.user main.cpp
./Application:
CMakeLists.txt Logger/ Recovery/ application.cpp application.hpp firstclass.cpp firstclass.hpp singleton.hpp
./Application/Logger:
CMakeLists.txt logger.cpp logger.hpp
./Application/Recovery:
CMakeLists.txt recovery.cpp recovery.hpp
./Graphics:
CMakeLists.txt drawableobject.cpp drawableobject.hpp graphics.cpp graphics.hpp
Each folder has own CMakeLists.txt
I did so far this in master CMake:
cmake_minimum_required(VERSION 3.10)
# set the project name and version
project(Asteri VERSION 1.0)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
message("Source dir: ${SOURCE_DIR}")
#file(GLOB_RECURSE SRC_FILES ${SOURCE_DIR}/*.cpp)
#file(GLOB_RECURSE HEADER_FILES ${HEADER_DIR}/*.hpp)
set(PROJECT_NAME "Asteri")
macro(SUBDIRLIST result curdir)
file(GLOB children RELATIVE ${curdir} ${curdir}/*)
set(dirlist "")
foreach(child ${children})
if(IS_DIRECTORY ${curdir}/${child})
list(APPEND dirlist ${child})
endif()
endforeach()
set(${result} ${dirlist})
endmacro()
SUBDIRLIST(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR})
foreach(subdir ${SUBDIRS})
message("Subdirectory: ${subdir}")
add_subdirectory(${subdir})
endforeach()
add_executable(${Asteri} main.cpp)
The question is how to connect all pieces together?
What I need in other CMakeLists.txt?
How to communicate children -> parent or I misunderstood the concept of CMake?
No need for other CMakeLists.
I guess you want something like this in top CMakeLists:
cmake_minimum_required(VERSION 3.12)
project(Asteri VERSION 1.0)
file(GLOB_RECURSE ASTERI_SRC_FILES CONFIGURE_DEPENDS
"${PROJECT_SOURCE_DIR}/Application/*.cpp"
"${PROJECT_SOURCE_DIR}/Graphics/*.cpp"
)
add_executable(Asteri main.cpp ${ASTERI_SRC_FILES})
It's worth noting that GLOB/GLOB_RECURSE -even with CONFIGURE_DEPENDS- is bad practice: it's slow, specially on Windows from my experience, and may not work as expected depending on generator used.
I found out the answer to my problems.
set(SOURCES "${PROJECT_DIR}/main.cpp" CACHE INTERNAL STRINGS)
add_subdirectory(application)
FOREACH(it ${SOURCES})
message("source file: ${it}")
ENDFOREACH()
add_executable(Asteri ${SOURCES})
In this way I store main.cpp path into variable SOURCES
You can see your variables after 'make' in CMakeCache.txt.
After this is done, my variable SOURCES looks like:
/STRINGS
SOURCES:INTERNAL=/home/default/cpp_testing_project/cmake_project/source/main.cpp;
After that in application subdirectory I have CMakeLists.txt:
cmake_minimum_required(VERSION 3.7)
# Get source files
file(GLOB CPP_LIST "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
set(SOURCES ${SOURCES} ${CPP_LIST} CACHE INTERNAL STRINGS)
And now SOURCES looks like:
SOURCES:INTERNAL=/home/default/cpp_testing_project/cmake_project/source/main.cpp;/home/default/cpp_testing_project/cmake_project/source/application/application.cpp;/home/default/cpp_testing_project/cmake_project/source/application/drawableobject.cpp;/home/default/cpp_testing_project/cmake_project/source/application/firstclass.cpp;/home/default/cpp_testing_project/cmake_project/source/application/graphics.cpp;/home/default/cpp_testing_project/cmake_project/source/application/application.hpp;/home/default/cpp_testing_project/cmake_project/source/application/drawableobject.hpp;/home/default/cpp_testing_project/cmake_project/source/application/firstclass.hpp;/home/default/cpp_testing_project/cmake_project/source/application/graphics.hpp;

include cmake headerfile boost.hpp with cmake

I like to add the boost/operators.hpp with cmake
From CMake's FindBoost Documentation:
find_package(Boost 1.36.0)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
add_executable(foo foo.cc)
endif()
So I added
find_package(Boost 1.60.0)
if (Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
add_library(core ${core_SRCS})
add_executable(app main.cpp)
target_link_libraries(app core)
endif ()
Output from message:
-- Boost version: 1.60.0
-- BOOST_ROOT=~/Projects/ClionProjects/.repo/boost_1_60_0
-- Boost_DIR=Boost_DIR-NOTFOUND
-- Boost_INCLUDE_DIR=/home/dornathal/Projects/ClionProjects/.repo/boost_1_60_0
However it builds (I can run the program and tests), but as soon as I try to include #include<boost/operators.hpp> it won't find it in the test project.
I actually extended one class by the boost::operators<T> and strangely my IDE (CLion) lets me jump to that sourcefile.
The include_directories CMake command adds include directories for the current directory and its subdirectories. Since you get the error in the test project and use include_directories in the main project, I guess the problem is that you have separate directories for these, for example:
src/
CMakeLists.txt - include_directories used here
test/
test.cc - no effect on this file
If this is the case you can either move include_directories up to their common parent directory or use target_include_directories that can propagate the public INCLUDE_DIRECTORIES property.
You can also see the commands passed to your compiler by adding VERBOSE=1 to your make command:
make VERBOSE=1
This shows what include directories are passed to the compiler via the -I... option among other things.