CMake project with independent subprojects - c++

I am trying to create a cmake project which has the following directory structure:
root_folder
lib
common_library_for_all_submodules
submodule_1
src
main.cpp
tests
main_test.cpp
submodule_2
src
main.cpp
tests
main_test.cpp
Being new to C++ and also to CMake I have the following confusions and would be really glad if someone can guide me in the right direction here.
Coming from a Java world I know that this is possible to create in a maven project using the modules tag in pom.xml. Is there an equivalent to this in CMake? If yes what to do we call it and can someone give me an example?
I want to then import this project into CLion and when I run the root project, all the submodules should be compiled and relevant tests be run.
Note: submodule_1 and submodule_2 are not using each other's code. They are entirely independent. But they will need to share some common libraries from the root_folder/lib
Thanks a lot in advance

You can use several CMakeLists.txt files, use add_subdirectory statement. To declare library (which will be used in another subproject) use add_library. To declare app - add_executable. To link library to app - target_link_libraries(app1 PRIVATE utils common). This is short and very common description-example. There are more options and parameters.
I'm attaching examples here:
CMakeLists.txt
project(Example)
add_subdirectory(3rd-party)
add_subdirectory(apps)
add_subdirectory(libs)
libs/CMakeLists.txt
add_subdirectory(common)
add_subdirectory(utils)
libs/utils/CMakeLists.txt
FILE(GLOB SOURCES *.cpp *.h)
add_library(utils STATIC ${SOURCES})
target_include_directories(utils PUBLIC .)
apps/CMakeLists.txt
add_subdirectory(app1)
add_subdirectory(app2)
apps/app1/CMakeLists.txt
FILE(GLOB_RECURSE SOURCES src/*.cpp src/*.h)
add_executable(app1 ${SOURCES})
target_link_libraries(app1 PRIVATE utils common)
In this example libraries utils and common are independent and could be built without each other and without apps

Related

CMakelist include subfolders

I can't figure out how to import my source files, which are in a different directory. The structure of my project looks like this:
root
- src
- core
App.h
App.cpp
CMakelist.txt
CMakelist.txt
main.cpp
CMakelist.txt
My main CMakelist under root looks like this:
cmake_minimum_required(VERSION 3.17)
project(edu)
set(CMAKE_CXX_STANDARD 17)
## add subdirectory with source files
add_subdirectory(src)
add_executable(edu main.cpp)
My CMakelist under src looks like this:
add_subdirectory(core)
And finaly my CMakelist under core looks like this:
set(all_src
App.h
App.cpp
)
target_sources(core ${all_src})
But it doesn't work, I get an error:
Cannot specify sources for target "core" which is not built by this project
How do I fix it? My project is getting quite large and it would be convenient to put all the files in different directories instead of stacking them in add_executable
Thx!
The main issue here is that you never created a target called core. You need to either use either add_executable or add_library to create a target to add files to. You never created a target named core, so you're trying to add these files to something that doesn't exist.
What might help here is implementing Modern CMake, which is an approach to CMake looking at it more akin to a language than a tool. Here's a good beginners guide to structuring your project that should make it far easier to use CMake. If you want to separate your project into modules, I'd recommend making this it's own confined library within your project that will then be included into your main executable as a library. IF you just want to organize your source code, then try the method keeping separate src and include directories. It makes it far easier to organize and sort your code~
Here's some references for Modern CMake:
https://cliutils.gitlab.io/modern-cmake/
https://hsf-training.github.io/hsf-training-cmake-webpage/aio/index.html
https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
If you do not want to use a separate library for core, you can use the following structure in src/CMakeLists.txt:
# core sources
set(core_srcs core/App.cpp core/App.h)
# aux sources
set(aux_srcs aux/stuff.cpp aux/stuff.h)
add_executable(edu main.cpp ${core_srcs} ${aux_srcs})
This lets you organize your CMakeLists.txt by module and keep your sources in different directories, without exploding the number of CMakeLists and sublibraries.

Is there a way to add library changes as a dependency in cmake?

I have an application and a library that I build with CMake and I would like to make the build process easier if possible. As it stands, if there is a change to the library and I rebuild the application, CMake doesn't rebuild the modified library files. Similarly, if I rebuild the library and then run make on the application, it will say there is nothing to do. My current workaround is to use bash scripts to rebuild everything, but that unnecessarily re-compiles a lot of files and I would like to handle it all within the build directory for the application if possible.
Update with simple example:
There are 3 folders: app, lib, and include. include contains test_program.h, lib contains test_program.cpp, and app contains test.cpp which includes test_program.h.
Here is the CMakeLists.txt for lib:
include_directories(.)
add_library (test_lib STATIC
test_program.cpp
)
Here is the CMakeLists.txt for app:
include_directories(
.
../include
)
link_directories(
../../lib/build
)
add_executable(test_exe
test.cpp
)
target_link_libraries(
test_exe
test_lib
)
I would like to make it so that if I make a change to test_program.cpp, I can simply run cmake ../ and then make in app/build and it will use the updated version of test_program.cpp.
Update:
I have added a top level CMakeLists.txt and a build to the top level of the project. The file is very simple and seems to do what I was wanting from the beginning:
add_subdirectory(app)
add_subdirectory(lib)
I would be happy to take suggestions if there are any improvements to be made here.

CMake for Proto libraires

I have two Proto files across two different folders and am trying to use CMake for building the overall project.
protofile1 has protofile2 as it's dependency.
Library1 has protofile1 as it's dependency which I can generate using protobuf_generate_cpp.
But for generating protofile1, I have protofile2 as it's dependency. How do I do this using CMake?
How do I compile proto file and make it available as a library using CMake (in folder2)?
Folder Structure:
|
|-folder1
---|-protofile1.proto
---|-library1.cc
|-folder2
---|-protofile2.proto
---|-library2.cc
CMakeLists.txt for folder1
cmake_minimum_required(VERSION 3.3)
find_package(Protobuf REQUIRED)
protobuf_generate_cpp(protofile1_cc protofile1_header protofile1.proto)
target_link_libraries(protofile1_cc INTERFACE protofile2_lib) # is this correct?
add_library(library1 INTERFACE)
target_sources(library1 INTERFACE library1.cc)
target_link_libraries(library1 INTERFACE protofile1_cc)
CMakeLists.txt for folder2
cmake_minimum_required(VERSION 3.3)
find_package(Protobuf REQUIRED)
# don't know how to do this
add_library(protofile2_lib INTERFACE) # is this correct?
target_sources(protofile2_lib INTERFACE protofile2.proto) # is this correct?
The protobuf_generate_cpp command does not define targets, but it defines CMake variables referring to the auto-generated source files (.cc, .h). These variables should be used to define your targets via add_library(). You are on the right track, but your CMakeLists.txt file in folder2 should also call protobuf_generate_cpp to process protofile2.proto as well.
Also, if you're using CMake to build both, the top-level CMake (in the parent folder to folder1 and folder2) can find Protobuf so you don't have to find it twice. Something like this should get you closer to the desired solution:
CMakeLists.txt (top-level):
cmake_minimum_required(VERSION 3.3)
find_package(Protobuf REQUIRED)
add_subdirectory(folder2)
add_subdirectory(folder1)
folder2/CMakeLists.txt
# Auto-generate the source files for protofile2.
protobuf_generate_cpp(protofile2_cc protofile2_header protofile2.proto)
# Use the CMake variables to add the generated source to the new library.
add_library(protofile2_lib SHARED ${protofile2_cc} ${protofile2_header})
# Link the protobuf libraries to this new library.
target_link_libraries(protofile2_lib PUBLIC ${Protobuf_LIBRARIES})
folder1/CMakeLists.txt
# Auto-generate the source files for protofile1.
protobuf_generate_cpp(protofile1_cc protofile1_header protofile1.proto)
# Use the CMake variables to add the generated source to the new library.
add_library(library1 SHARED ${protofile1_cc} ${protofile1_header})
# Link proto2 library to library1.
target_link_libraries(library1 INTERFACE protofile2_lib)

CMake - objects being built twice unnecessarily?

I have a list of files that need to be compiled for my main executable. My tests also need these files. When the test executable(s) are built, the object files are built again, even though earlier in the build they were built when the main executable was built.
Am I wrong in thinking this is not needed? If so is there a way to disable this?
Example:
set(SOURCES
${SOURCE_DIR}/file.c
${SOURCE_DIR}/another_file.c)
set(MAIN ${SOURCE_DIR}/main.c)
add_executable(main_executable ${SOURCES} ${MAIN})
add_executable(test1_ex ${PROJECT_SOURCE_DIR}/test/test1.cc ${SOURCES})
Put the common code in a library and link the library to both your application and tests.
# The application's sources - except main
set(SOURCES
${SOURCE_DIR}/file.c
${SOURCE_DIR}/another_file.c)
# build an application library
add_library(app_lib ${SOURCES})
# build an executable in terms of the application library
set(MAIN ${SOURCE_DIR}/main.c)
add_executable(main_executable ${MAIN})
target_link_libraries(main_executable PRIVATE app_lib)
# build a test executable in terms of the application library
add_executable(test1_ex ${PROJECT_SOURCE_DIR}/test/test1.cc)
target_link_libraries(test1_ex PRIVATE app_lib)
This could be due to the following scenario:
add_library(mylib1 file1.cpp common.cpp)
add_library(mylib2 file2.cpp common.cpp)
That created the same problem you're having for me, where common.cpp was being rebuilt for every library. My solution was this:
add_library(common_lib common.cpp)
add_library(mylib1 file1.cpp)
add_library(mylib2 file2.cpp)
target_link_libraries(mylib1 common_lib)
target_link_libraries(mylib2 common_lib)
That resolved the problem for me as the building (object creation) was done once, but it was linked to every other library.

CMake add library with subdirectories

TL;DR
Using CMake, how can I include subdirectories into a library such that they can be included without referencing the directories they reside?
End TL;DR
In attempt to be brief and speak in higher level ideas of what and how, I have removed everything that I consider to be unnecessary details. I will make edits if need be. As such, this is a brief synopsis of my project structure.
ParentDir
--src
----source.cpp
----source.h
----entities_dir
------entity.cpp
------entity.h
------CMakeLists.txt
----CMakeLists.txt
--CMakeLists.txt
--main.cpp
as it currently stands, I have a library defined by the CMakeLists in the src directory. As such, I can include src files in main by #include as apposed to #include "src/file.h" I would like to be able to do the same for my headers that exist within the subdirectories of src.
CMakeLists.txt
cmake_minimum_required(VERSION 3.6)
project(Project)
add_executable(Project ${SOURCE_FILES} main.cpp)
include_directories(src)
add_subdirectory(src)
target_link_libraries(Project Library) # Engine Libraries
src/CMakeLists.txt
file(GLOB SOURCE_FILES *.cpp)
file(GLOB HEADER_FILES *.h)
add_library(Library STATIC ${SOURCE_FILES} ${HEADER_FILES})
main.cpp
#include <source.h> // this works
#include <entity.h> // this does not work but I want it to
#include <entities/entity.h> // this works but I don't want this
int main() {}
I am not sure how to do this exactly. I have tried to GLOB_RECURSE, add_subdirectory(entities), etc. I have also tried creating a library called Entities inside the src/entities/CMakeLists.txt and linking that with link_libraries. None of these have been successful. What is the proper way to accomplish this, because I think I am probably approaching this completely wrong.
You need that path in your compilers header search path, which is achieved with include_directories() call. You can amend your existing include_directories(src) call to be:
include_directories(src src/entities)
Also, this SO post is related and worth reading: Recursive CMake search for header and source files. There is an excerpt there from the CMake website itself recommending against the usage of file(GLOB ...), which lends to recommending against recursive solutions in general. As a heavy user of CMake, I agree with the arguments made against it.
You just need to add:
include_directories(${CMAKE_CURRENT_LIST_DIR})
In each CMakeLists.txt in your your hierarchy.
CMake in itself doesn't compile your project, it only calls your toolchain and passes parameters to it, and your toolchain doesn't 'know' that it is being called by CMake, or the structure of your project. As such, you need to tell the toolchain where to locate include files.
While it is commonplace to have a CMakeLists.txt in every subdirectory, this is by no means a requirement. The CMakeLists.txt in your src directory could contain all instructions necessary to generate a build. Generally, CMakeLists.txt are put at each level to make the structure easier to manage, eg. each directory only needs to know what it needs to do (presumably, with the files in that directory).