How could I match all subdirectories automatically with cmake - c++

Provided my project is like this:
|--main.cpp
|-A--a1.cpp
| |-a2.cpp
|
|-B--b1.cpp
|-b2.cpp
|--CMakeLists.txt
How could I add all the *.cpp (e.g main.cpp, A/a1.cpp, A/a2.cpp, B/b1.cpp, B/b2.cpp) to a cmake variable SRC ? I hope I could only need one CMakeLists.txt. By the way, what if I need to exclude certain .cpps ?

As mentioned by Alexander, you can use file(GLOB_RECURSE myVar myRegex) to get all the files matching the myRegex into a myVar as a list. In order to exclude some you could play around with the myRegex, or you could filter the list with list(FILTER myVar <INCLUDE|EXCLUDE> REGEX <regular_expression>)
But note that adding another .cpp file to your project will not automatically be added to your target on rebuild. You will need to explicitly reconfigure your project for the changes to be made. Since CMake 3.12 there is also an option CONFIGURE_DEPENDS for file GLOBE and GLOBE_RECURSE, that will do the update on rebuild for you.
Here is the NOTE from CMake documentation:
Note We do not recommend using GLOB to collect a list of source files
from your source tree. If no CMakeLists.txt file changes when a source
is added or removed then the generated build system cannot know when
to ask CMake to regenerate. The CONFIGURE_DEPENDS flag may not work
reliably on all generators, or if a new generator is added in the
future that cannot support it, projects using it will be stuck. Even
if CONFIGURE_DEPENDS works reliably, there is still a cost to perform
the check on every rebuild.

It's what you want:
file(GLOB_RECURSE SRC *.cpp)
For more info: https://cmake.org/cmake/help/v3.0/command/file.html
For excluding you can write function.
Note: But I don't recommend to use 'glob'.
Better use 'set' with list of files.

Related

CMake and VisualStudio: Group files in solution explorer

To finish a long coding session on a project, I wanted to test if my CPP project is compilable on an arrangement of OS'es.
I've been working in Win10 all the time. Compiles fine.
I've tried a Raspberry Pi. Compiles fine.
I re-download a seperate copy of my project to a Win10 client, run cmake-gui, and open the project: My folder structure in the solution explorer all gone.
So I started digging around, and apparently this structure is kept in CMakeLists.txt with the command source_group. So I start adding more source_groupings to my cmake lists, and for some reason my groupings won't take.
Example:
source_group("game\\entitysystem" FILES ${entitysystem_SRC}) // Existing grouping
source_group("game\\entitysystem\\components" FILES ${components_SRC}) // My new grouping
My glob would be this:
file(GLOB components_SRC
"game/components/*.h"
"game/components/*.cpp"
)
file(GLOB entitysystem_SRC
"game/entitysystem/*.h"
"game/entitysystem/*.cpp"
)
I do believe my GLOB's are correct since the new project-clone compiles fine. It's just that every part of the new structure in Visual Studio's Solution Explorer seems lost. Yes, I have cleared Cmake's cache and regenerated the project. Doesn't change it.
Original structure:
Cloned project structure:
Edit:
I did make a mistake in my source_group as in that it should not put components beneath entitysystem, but still, why aren't there any filters created in Visual Studio?
First, make sure you are setting set_property(GLOBAL PROPERTY USE_FOLDERS ON).
Second, it is not recommended to use GLOB to collect a list of source files. From the file(GLOB documentation:
We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate.
The recommended way to list project files is to add them by hand to CMakeLists.txt.
If you still want to GLOB, it looks like you want to mirror the directory structure in your source tree. You can use a macro such as this every place you define a library or executable to automatically sort them for you:
foreach(FILE ${SRCS})
# Get the directory of the source file
get_filename_component(PARENT_DIR "${FILE}" DIRECTORY)
# Remove common directory prefix to make the group
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" GROUP "${PARENT_DIR}")
# Make sure we are using windows slashes
string(REPLACE "/" "\\" GROUP "${GROUP}")
# Group into "Source Files" and "Header Files"
if ("${FILE}" MATCHES ".*\\.cpp")
set(GROUP "Source Files${GROUP}")
elseif("${FILE}" MATCHES ".*\\.h")
set(GROUP "Header Files${GROUP}")
endif()
source_group("${GROUP}" FILES "${FILE}")
endforeach()

Files exclusion (custom and transient) from build

I have many C++ (Google Test) source files in my Visual Studiosolution and I want to have the possibility to keep only a few for the build (to focus on the problem), but also to come back quick enough (two times by day) to the initial configuration.
We are using, more or less, about three solutions: Visual Studio, CMake and QT (but I could add yet another one). I never used QT, so the other two solutions I see are:
Visual Studio: folders are useless, but I can select files and exclude them from build. But these changes are saved in vcproj so I have to pay attention not to save them on the version control, which is annoying.
CMake: easy change the CMakeLists.txt (comment lines with the sources folders), but I always have the version control problem ... maybe I can configure the excluded files in a custom (user) file. Advantage: I can generate only what I want, more flexible and not so boring like the previous one.
By example, if I do not want the sources in src_2:
file(GLOB_RECURSE SRC_FILES_1
${SOURCE_BASE_DIR}/src_1/*.cpp
${SOURCE_BASE_DIR}/src_1/*.h
)
file(GLOB_RECURSE SRC_FILES_2
${SOURCE_BASE_DIR}/src_2/*.cpp
${SOURCE_BASE_DIR}/src_2/*.h
)
file(GLOB_RECURSE SRC_FILES_3
${SOURCE_BASE_DIR}/src_3/*.cpp
${SOURCE_BASE_DIR}/src_3/*.h
)
add_executable(${PROJECT_TEST_NAME}
${SRC_FILES_1}
# next line is commented
# ${SRC_FILES_2}
${SRC_FILES_3}
)
Is there another solution or a way to improve one of these proposed here?
You can control this with a cmake variable.
option(BUILD_TESTS "builds test cpp files" ON)
This adds an option for your cmake file. It defaults in this case to ON you can change that though. Now lets get on:
if(BUILD_TESTS)
set(TEST_CPP_FILES test1.cpp test2.cpp)
endif(BUILD_TESTS)
add_executabe(foo bar.cpp bar1.cpp $(TEST_CPP_FILES))
Here you define a variable with the source file of your tests (or whatever source files you want to build when the BUILD_TESTS is ON. These then get added to the target. If BUILD_TESTS is off this variable will be empty.
now to change the Value you can run
cmake <...> -DBUILD_TESTS=OFF
Or with ON if you want to turn them back on again. You also can keep the change in version control because it will default to ON and you need to explicitly disable it.
You can also exclude whole subdirectories or targets with this in the if statement if you not just only want to exclude source files.
EDIT:
For your example it could look like this:
if(BUILD_TESTS)
file(GLOB_RECURSE SRC_FILES_2
${SOURCE_BASE_DIR}/src_2/*.cpp
${SOURCE_BASE_DIR}/src_2/*.h
)
endif(BUILD_TESTS)
SRC_FILES_2 should be empty afterwards.

How to remove tokens from a list in cmake?

I want to exclude some source files from building when not in Windows.
What is wrong in the following CMakeLists.txt cmake file?
aux_source_directory(. SRC_LIST)
# Remove Microsoft specific files
message(${SRC_LIST})
list(REMOVE_ITEM SRC_LIST stdafx.h stdafx.cpp)
message("------------------")
message(${SRC_LIST})
The contents of the messages before and after trying to remove the two files are exactly the same.
What is wrong?
You have to specify the exact name of the element you want to remove.
In your case, aux_source_directory prepends each entry with a ./, so the correct command has to be
list(REMOVE_ITEM SRC_LIST ./stdafx.h ./stdafx.cpp)
Also, please make sure you understand the implications of using manual calls to aux_source_directory for maintaining lists of source files:
It is tempting to use this command to avoid writing the list of source
files for a library or executable target. While this seems to work,
there is no way for CMake to generate a build system that knows when a
new source file has been added. Normally the generated build system
knows when it needs to rerun CMake because the CMakeLists.txt file is
modified to add a new source. When the source is just added to the
directory without modifying this file, one would have to manually
rerun CMake to generate a build system incorporating the new file.
Quoting the documentation for aux_source_directory.

Map include path to different directory

I am looking for a way to tell CMake to make an include directory appear under another name to the compiler.
Let's say I have a project that needs code from a foreign library. This code resides in a directory foreignLib-1.5.0_build123456 in my project's root directory. From time to time I will want to update this library and in this process change the library directory name.
I want to reference this directory as foreignLib in my C++ source files. I want to be able to write
#include "foreignLib/include/lib.h"
and CMake should tell my compiler to translate this to
#include "foreignLib-1.5.0_build123456/include/lib.h"
Now I am wondering:
Does a feature like this exist in CMake?
If yes, how do I use it?
If yes, which compilers are supported?
I'd probably just copy the entire include directory into my build tree and make that available.
A decent way of doing that is to use file(GLOB_RECURSE ...) to gather a list of files in the includes folder, then use configure_file(<input> <output> COPYONLY) to copy them to the build tree.
By using configure_file, the files in the build tree are only replaced as required. This means that re-running CMake won't automatically make these files appear out-of-date to the build tool, hence avoiding an unnecessary recompilation.
set(ForeignLibName foreignLib-1.5.0_build123456)
set(ForeignLibRoot ${CMAKE_SOURCE_DIR}/${ForeignLibName})
file(GLOB_RECURSE IncludeFiles RELATIVE ${ForeignLibRoot} ${ForeignLibRoot}/*)
foreach(IncludeFile ${IncludeFiles})
configure_file(${ForeignLibRoot}/${IncludeFile}
${CMAKE_BINARY_DIR}/${ForeignLibName}/foreignLib/${IncludeFile}
COPYONLY)
endforeach()
include_directories(${CMAKE_BINARY_DIR}/${ForeignLibName})
This should allow you to do:
#include "foreignLib/include/lib.h"
When you update the foreign library, you'd have to ensure that you also updated the CMakeLists.txt so that CMake re-runs the next time you go to build. Updating the CMakeLists.txt should only involve changing the single line set(ForeignLibName ...).
You could have a look at Cmake's configure_file: Rename your source file into yourfile.cpp.in and do
#include ${DIR_TO_LIB}/include/xy.h
In your CMakeLists, you set the variable DIR_TO_LIB somehow (by parsing command line or something) and issue
configure_file(yourfile.cpp.in, yourfile.cpp)
This will yield yourfile.cpp with the correct path set.
This is probably not exactly what you intended, but I think it would work.
As part of the build process generate an include file at a well known location (later on called "boilerplate/foreignLib_lib.h") with the real include path.
your code file:
#include "boilerplate/foreignLib_lib.h"
boilerplate/foreignLib_lib.h:
#include "foreignLib-1.5.0_build123456/include/lib.h"
Use CMake's include_directories statement or add an -I switch to the *_CXX_FLAGS to add the current foreignLib path to your include path.

Should I separate CMakeList.txt from source folder?

I'm new to build tool, when I come across Autotool, I have an option to write only one Makefile.am in the top build folder and leave the source folder containing all cpp files clean. I could use VPATH to tell automake to look for the source code inside that folder instead of write /src/ every where. (refer to my old question here: Automake Variables to tidy up Makefile.am)
However It appears to me that CMake have no VPATH to set and some fox around said that It's impossible to do so. So there are two choices:
Create CMakeList.txt in the source folder
Create CMakeList.txt in top build folder and leave the source alone, with a cost that I need to extend "/src" to every source code files.
Which one is more commonly use? I prefer the second because It leave my source code clean from any build-relating-source. In that case is there anyway to get rid of "/src"?
In our company we're using the first option, having a CMakeLists.txt in every subdirectory and building the tree from a root-CMakeLists.txt by using the add_subdirectory command.
This is a modular approach where each subcomponent (think about the project has different parts like boost is split up into system, thread, date_time etc) has its own build-file. If a user wants he is able to just build the subcomponent or to build the whole project.
We're additionally using this as an easy way to include optional subcomponents to the project. The user then can set a Bool value like BUILD_SUBFOO and the add_subdirectory will just be executed, if this Bool is TRUE.
Well-known projects are using this approach too. Here is a link to the root CMakeLists.txt from KDevelop (look at lines 52-62).
I'm quite sure you can do:
FILE(GLOB Source_files src/*.cpp)
which would do exactly what you want.