Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keeping file hierarchy across subdirectories in CMake

Tags:

c++

cmake

Till date I still do not really understand what the 'best practice' is for doing this for a CMake project with many subdirectories.

Say I have a project hierarchy as such and each subdirectory has source files in it...

--CMake Project Source dir
 |-- SubD1
   |-- SubSubD1
 |-- SubD2

What I would usually do is to do add_subdirectory(SubD1) and respectively for D2 in the CMakeLists.txt of the root directory and recursively for the subdirectory in the CMakeLists.txt of the SubD1 directory, while declaring variables in each subdirectory and making them visible in the root directory with PARENT_SCOPE.

That means if a file Source2.cpp exists in `SubSubD1', I'd simply do

set(SUBSUBD1_SOURCES Source2.cpp PARENT_SCOPE)

and expect to be able to use SUBSUBD1_SOURCE in my SubD1 directory. Subsequently, say Source.cpp exists in SubD1, I would do

set(SUBD1_SOURCES ${SUBSUBD1_SOURCES} Source.cpp PARENT_SCOPE)

so that all sources would be visible in root dir.

The problem is of course that the file paths aren't kept when the variables arrive at the root directory. What I'm currently doing is for all source files that I set, I include a ${CMAKE_CURRENT_LIST_DIR}, making it

set(SUBSUBD1_SOURCES ${CMAKE_CURRENT_LIST_DIR}/Source2.cpp PARENT_SCOPE)

and

set(SUBD1_SOURCES ${SUBSUBD1_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/Source.cpp PARENT_SCOPE)

In this case, I could then say, do add_executable(myProg SUBSUBD1_SOURCES) in the root directory of my CMake project.

Are there any better ways of doing this then having to always include a CMake variable in front of all source files?

like image 792
Jon Gan Avatar asked Jul 21 '15 12:07

Jon Gan


People also ask

What does Add_subdirectory do in CMake?

Add a subdirectory to the build. Adds a subdirectory to the build. The source_dir specifies the directory in which the source CMakeLists.

How do I compile multiple files in CMake?

Multiple directories, multiple source files. In this case, you need to write cmakelists in the project root directory demo3 and math directory respectively Txt file. For convenience, we can compile the files in the math directory into a static library, and then call the main function.

What is ${} CMake?

Local VariablesYou access a variable by using ${} , such as ${MY_VARIABLE} . 1. CMake has the concept of scope; you can access the value of the variable after you set it as long as you are in the same scope. If you leave a function or a file in a sub directory, the variable will no longer be defined.

Where do I put CMakeLists txt?

CMakeLists. txt is placed at the root of the source tree of any application, library it will work for. If there are multiple modules, and each module can be compiled and built separately, CMakeLists. txt can be inserted into the sub folder.


1 Answers

There is a fourth way if you're using newer versions of CMake.

Take a look at target_sources() command of CMake.

It seems like you are declaring your target in your CMakeLists.txt

add_executable(my_target "subd1/CMakeLists.txt" "subd2/CMakeLists.txt")
add_subdirectory(subd1)
add_subdirectory(subd2)

Instead of propagating your Source files up to the root you can depend on the target you have defined in the root CMakeLists.txt. That means subd1/CMakeLists.txt may look like:

target_sources(my_target PRIVATE "subd1/Source.cpp" "subd1/Source2.cpp")

[EDIT]

As stated in the comments you must give the relative path of the source-files to target_sources(). I use target_sources() because I do not want the explicit source file listing to pollute the targets CMakeLists.txt. Another use case is that target_sources() can be invoked with the PUBLIC or INTERFACE keyword to propagate source files to depending targets. Well I never used target_sources() that way.

[/EDIT]

If you're using IDEs like Visual Studio that support folders you make want to also declare a source_group() in the CMakeLists.txt that contains your target. So the root CMakeLists.txt may look like:

add_executable(my_target "subd1/CMakeLists.txt" "subd2/CMakeLists.txt")
add_subdirectory(subd1)
add_subdirectory(subd2)
...
source_group(subd1 REGULAR_EXPRESSION "subd1/*")
source_group(subd2 REGULAR_EXPRESSION "subd2/*")

I'm using this approach because it leads to much cleaner CMakeLists.txt files, its lesser work and I think the introduction of not needed variables only raises the complexity of your CMakeLists.txt files.

CMakeLists.txt as target sources

I currently use the CMakeLists.txt of the sub folders as source files of the target because otherwise CMake will complain that the add_executable command has no source files given.

like image 186
DarthB Avatar answered Oct 05 '22 14:10

DarthB