Building a cmake project with multiple directories - c++

I have been given some C++ which I want to use in my project. This code comes with its own CMakeLists.txt file. To keep things neat, I want to make a new directory foo in my main project directory, and put this code and the CMakeLists.txt file in that directory. What I now want to know, is how do I edit the CMakeLists.txt file of my own project, to include all the source files from this other project?
Normally, I use file(glob SOURCES *.cpp) to create a list of all source files. Then, I would create the executable by using add_executable(${PROJECT_NAME} ${SOURCES}). However, how do I tell SOURCES to also include all the source files in the foo directory?
Now, if I use add_subdirectory(foo) in my main CMakeLists.txt file, then I believe this will search directory foo for a CMakeLists.txt file, and effectively add this to the main CMakeLists.txt file in my project. Is this correct? How can I extend this to including all the source files in this directory?
Thanks!

Related

Project Linking and Compiling files

I want to start building a project and I have the following folder structure:
lib
|---class1.cpp
|---class1.hpp
src
|---main.cpp
I have the MinGW compiler and I don't know how to compile all .cpp files. I know the command g++ *.cpp -o main for compiling all the files, but works only for files in the same folder.
Should I move all my files to the src folder? Should I change the project structure?
Also, I'm really doubtful if I should use CMake or not.
FINAL:
I decided to go with CMake which made my life easier.
For a barebones project, your structure is fine. Just add the following CMakeLists.txt file to the root of your directory:
cmake_minimum_required(VERSION 3.5)
# Given your project a descriptive name
project(cool_project)
# CHoose whatever standard you want here... 11, 14, 17, ...
set(CMAKE_CXX_STANDARD 14)
# The first entry is the name of the target (a.k.a. the executable that will be built)
# every entry after that should be the path to the cpp files that need to be built
add_executable(cool_exe src/main.cpp lib/class1.cpp)
# Tell the compiler where the header files are
target_link_libraries(cool_exe PRIVATE lib)
Your directory should now look like
CMakeLists.txt
lib
|---class1.cpp
|---class1.hpp
src
|---main.cpp
Then to build the project, you will typically
Make a folder where you build everything (often called build, but it's up to you). Now the directory looks like
CMakeLists.txt
lib
|---class1.cpp
|---class1.hpp
src
|---main.cpp
build
Go into the build folder and on the command like, configure your project with the command cmake .. (just to reiterate... this needs to be done from inside the build folder).
Build your project with the make command (again from inside the build folder).
After that, you should have an executable called cool_exe in the build folder.

using cmake to make header files descendants of the project's source directory

As in Google C++ Style Guide is mentioned all of a project's header files should be listed as descendants of the project's source directory without use of UNIX directory shortcuts . (the current directory) or .. (the parent directory). How can I do that in my project that is shortly described below.
My project directory hierarchy is like this:
GraphicsEngine
header_files.h
source_files.cc
CMakeLists.txt (1)
Light
CMakeLists.txt (2)
header_files.h
source_files.cc
Camera
CMakeLists.txt (3)
header_files.h
source_files.cc
Core
CMakeLists.txt (4)
header_files.h
source_files.cc
These are contents of CMakeLists.txt files:
CMakeLists.txt (1)
add_library(GraphicsEngineLib source_files.cc)
target_link_libraries(GraphicsEngineLib LightLib CameraLib CoreLib)
add_subdirectory(Light)
add_subdirectory(Camera)
add_subdirectory(Core)
CMakeLists.txt (2)
add_library(LightLib source_files.cc)
CMakeLists.txt (3)
add_library(CameraLib source_files.cc)
CMakeLists.txt (4)
add_library(CoreLib source_files.cc)
Now when for example I want to include header files from Camera folder in to files in Core folder, I have to use ../Camera/header_file.h but I want to use GraphicsEngine/Camera/header_file.h. How can I do this?
What I have done in the past is to set this in the top level CMakeLists.txt (which should be in your GraphicsEngine directory):
SET(PROJECT_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/..")
INCLUDE_DIRECTORIES(
${PROJECT_ROOT}
)
where according to this, CMAKE_CURRENT_SOURCE_DIR is
this is the directory where the currently processed CMakeLists.txt is located in
Note that by defining Project_Root in this way, your GraphicsEngine project can also #include headers from sister projects to GraphicsEngine.
Hope this helps.

CMake doesn't include header directory of submodule A within submodule B

I have a CMake project that looks like this:
project/
CMakeLists.txt
subprojectA/
CMakeLists.txt
include/
headerA.hpp
src/
libraryA.cpp
subprojectB/
CMakeLists.txt
src/
mainB.cpp
The "library" subproject, A, is compiled as a static library, becoming libsubprojectA.a. The "main" project, B, is compiled as a binary and depends on the library. mainB.cpp includes a reference to headerA.hpp.
Here is subprojectA/CMakeLists.txt:
project(SubProjectA)
include_directories(include)
add_library(subprojectA STATIC src/libraryA.cpp)
set(${PROJECT_NAME}_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/include
CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
And here is subprojectB/CMakeLists.txt:
project(SubProjectB)
include_directories(${SubProjectA_INCLUDE_DIRS})
add_executable(mainBinary src/mainB.cpp)
target_link_libraries(mainBinary subprojectA)
The main Project CMakeLists.txt looks like:
project(Project)
add_subdirectory(subprojectB)
add_subdirectory(subprojectA)
Note that subprojectB, the main project, is listed before subprojectA.
Here's the problem. When I first run "cmake" on this project, ${SubProjectA_INCLUDE_DIRS} is not set within SubProjectB.
What I think is happening is that the CMakeLists for SubProjectB loads first, when ${SubProjectA_INCLUDE_DIRS} has not yet been set. It sets its own include path to an empty string as a result. However, even though libsubprojectA.a gets built successfully before mainBinary, the include path was already set empty beforehand. As a result, I get this error when trying to make mainBinary:
subprojectB/src/mainB.cpp:1:23: fatal error: headerA.hpp: No such file or directory
#include "headerA.hpp"
^
It's a workaround to put subprojectA before subprojectB in the main Project CMakeLists in the declarative world of CMake. What I really want is to know the proper way to indicate to CMake that the include_directories(${SubProjectA_INCLUDE_DIRS}) line depends on the definitions that exist inside SubProjectA's CMakeLists. Is there a better way to do this?
If you want to express that include directory subprojectA/include is an interface of the library subprojectA, attach this property to the target with target_include_directories command:
subprojectA/CMakeLists.txt:
project(SubProjectA)
add_library(subprojectA STATIC src/libraryA.cpp)
# PUBLIC adds both:
# 1) include directories for compile library and
# 2) include directories for library's interface
target_include_directories(subprojectA PUBLIC include)
So any executable(or other library) which linked with subprojectA will have this include directory automatically:
subprojectB/CMakeLists.txt:
project(SubProjectB)
add_executable(mainBinary src/mainB.cpp)
target_link_libraries(mainBinary subprojectA)
Of course, for use last command properly you need to process directory with library before one with executable:
CMakeLists.txt:
project(Project)
add_subdirectory(subprojectA)
add_subdirectory(subprojectB)

CMake link files from subdirectories and parent directories

I have a folder net like:
main
headers
cls1.hpp cls2.hpp ...
sources
cls1.cpp cls2.cpp ...
resources
r1.hpp r2.hpp ...
I have tried more cmake methods to link the files, like
set(SRC ${SRC})
in parent dir and
set(SRC ${SRC} ${CMAKE_CURRENT_SOURCE_DIR}/cls1.cpp PARENT_SCOPE)
in subdir
OR
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE HDR_FILES ${PROJECT_SOURCE_DIR}/*.hpp)
to get the .cpp and .hpp files, but when I do
#include "resources/r1.hpp"
I get error like "resources/r1.hpp" No such a file or directory
Can anyone help me pleas? How can I do linking between files in folders in my case?
To solve this specific problem, in your main CMakeLists.txt add this line before adding subfolders:
include_directories(".")
This will allow the compiler to see the file located in resources/r1.hpp starting from the root path.
However, I suggest you take a look to some CMake projects examples, because it doesn't seem you are doing things in the standard way (e.g. usually a good way is to add a sub directory that creates its own library, that then you link to your main executable)

How can I build a C++ project with multiple interdependent subdirectories?

I have a C++ project where I've used directories as more of an organizational element -- the way one might use packages in Java or directories in PHP. Directories are not intended to be self-sufficient elements, but rather just a way of organizing the whole of the project and keeping me from being overwhelmed by sources. How can I construct my CMakeLists.txt files to deal with this? Making the directories libraries doesn't seem to fit here, since they are all interdependent and not intended to be used that way.
As a related issue, most of the examples I've seen of multiple subdirectories in CMake (and there aren't very many of those) have ignored or glossed over the issue of setting include_directories, which is something I've been having trouble with. Short of combing my source files to determine which file depends on which and in what directory, is there anyway to just set all directories under /src/ as potential include directories and let CMake work out which ones are actually dependent?
Here's an example structure:
--src
--top1
--mid1
--bot1
--src1.cpp
--hdr1.h
--bot2
--src2.cpp
--hdr2.h
--mid2
--bot3
--src3.cpp
--src4.cpp
--hdr3.h
--top2
--mid3
--src5.cpp
--hdr4.h
So on and so forth. How can I structure my CMakeLists.txt files to handle this sort of structure?
Since the directory structure in your project is just there to keep your files organized, one approach is to have a CMakeLists.txt that automatically finds all sources files in the src directory and also adds all directories as include directories that have a header file in them. The following CMake file may serve as a starting point:
cmake_minimum_required(VERSION 3.12)
project (Foo)
file (GLOB_RECURSE Foo_SOURCES CONFIGURE_DEPENDS "src/*.cpp")
file (GLOB_RECURSE Foo_HEADERS CONFIGURE_DEPENDS "src/*.h")
set (Foo_INCLUDE_DIRS "")
foreach (_headerFile ${Foo_HEADERS})
get_filename_component(_dir ${_headerFile} PATH)
list (APPEND Foo_INCLUDE_DIRS ${_dir})
endforeach()
list (REMOVE_DUPLICATES Foo_INCLUDE_DIRS)
add_executable(FooExe ${Foo_SOURCES})
target_include_directories(FooExe PRIVATE ${Foo_INCLUDE_DIRS})
The two file(GLOB_RECURSE ... commands determine the set of source and header files. The foreach loop computes the set of include directories from the list of all header files. The CONFIGURE_DEPENDS flags tells CMake to re-run the glob command at build time.
One drawback with computing the set of source files is that CMake will not automatically detect when new files are added to your source tree. You manually have to re-create your build files then.
Though #sakra gave a good answer to this question, I believe it is more proper to approach it more in depth.
We want to separate our code into modules and libraries for many reasons. Like code encapsulation, re usability, easier debugging etc. This idea would propagate in compiling process too.
In other word, we want to divide the compilation process into little compilation steps, each belong to one module. So every module must have its own compilation procedure. This is why we use one CMakeLists.txt file per directory. Hence every directory would have its own compilation commands and there would be one master CMakeLists.txt file in the root directory of your project.
Here is an example. Consider the following structure of a project:
src/
|
- main.cpp
|
_sum/
|
- sum.h
|
- sum.cpp
We would have one CmakeLists.txt Per directory. First directory is the root directory of the project which src/ folder is in it. here is content for that file:
cmake_minimum_required(VERSION 3.4)
project(multi_file)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "-Wall")
add_subdirectory(src)
Next CMakeLists.txt would located in src/ directory:
add_subdirectory("sum")
add_executable(out main.cpp)
target_link_libraries(out sum)
And the last one will be in the sum/ directory:
add_library(sum SHARED sum.cpp)
I hope this helps. I created a github repository in case you feel you need to see the code or you need further explanation.
I'm not an expert on CMake but since there are no other answers I'll take a look at the documentaton and give it a go. Organizing source and include files in different directories is pretty much the norm.
It looks like CMake allows you to give a list of include directories:
http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories
So something like:
include_directories("src/top1/mid1/bot1" "src/top1/mid1/bot2/" ... )
These are passed to the compiler so it can find the header files and will be passed for each of the source files. So any of your source files should be able to include any of the header files (which I think is what you're asking for).
Similar to that you should be able to list all your source files in the add_executable command:
add_executable(name "src/top1/mid1/bot1/src1.cpp" "src/top1/id1/bot2/src2.cpp" ...)
So this would be a naive way of getting everything to build. Each source file will be compiled and will look for headers in all those directories and then the object files will get linked together. Consider if there is any way of simplifying this such that you don't need so many include folders, maybe there are only a few common header files that need to be referenced by all source files. If things get more complex you can buiild sub-hierarchies into libraries etc. Also consider seperating source files and headers (e.g. in src and include).