visual c++ - Automatically add all files in a folder to a target using CMake?

ID : 20300

viewed : 44

Tags : visual-c++cmakecross-platformvisual-c++

Top 5 Answer for visual c++ - Automatically add all files in a folder to a target using CMake?

vote vote


As of CMake 3.1+ the developers strongly discourage users from using file(GLOB or file(GLOB_RECURSE to collect lists of source files.

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.

See the documentation here.

There are two goods answers ([1], [2]) here on SO detailing the reasons to manually list source files.

It is possible. E.g. with file(GLOB:

cmake_minimum_required(VERSION 2.8)  file(GLOB helloworld_SRC      "*.h"      "*.cpp" )  add_executable(helloworld ${helloworld_SRC}) 

Note that this requires manual re-running of cmake if a source file is added or removed, since the generated build system does not know when to ask CMake to regenerate, and doing it at every build would increase the build time.

As of CMake 3.12, you can pass the CONFIGURE_DEPENDS flag to file(GLOB to automatically check and reset the file lists any time the build is invoked. You would write:

cmake_minimum_required(VERSION 3.12)  file(GLOB helloworld_SRC CONFIGURE_DEPENDS "*.h" "*.cpp") 

This at least lets you avoid manually re-running CMake every time a file is added.

vote vote


The answer by Kleist certainly works, but there is an important caveat:

When you write a Makefile manually, you might generate a SRCS variable using a function to select all .cpp and .h files. If a source file is later added, re-running make will include it.

However, CMake (with a command like file(GLOB ...)) will explicitly generate a file list and place it in the auto-generated Makefile. If you have a new source file, you will need to re-generate the Makefile by re-running cmake.

edit: No need to remove the Makefile.

vote vote


Extension for @Kleist answer:

Since CMake 3.12 additional option CONFIGURE_DEPENDS is supported by commands file(GLOB) and file(GLOB_RECURSE). With this option there is no needs to manually re-run CMake after addition/deletion of a source file in the directory - CMake will be re-run automatically on next building the project.

However, the option CONFIGURE_DEPENDS implies that corresponding directory will be re-checked every time building is requested, so build process would consume more time than without CONFIGURE_DEPENDS.

Even with CONFIGURE_DEPENDS option available CMake documentation still does not recommend using file(GLOB) or file(GLOB_RECURSE) for collect the sources.

vote vote


To use Visual Studio project hierarchy inside Clion with cmake:

cmake_minimum_required(VERSION 3.17) project(MyProject)  set(CMAKE_CXX_STANDARD 17)  file(GLOB APP_SOURCES */*.cpp) foreach (testsourcefile ${APP_SOURCES})     get_filename_component(testname ${testsourcefile} NAME_WLE)     get_filename_component(dirname ${testsourcefile} DIRECTORY)     file(GLOB dir_src CONFIGURE_DEPENDS             "${dirname}/*.h"             "${dirname}/*.cpp"             )     message("${testname}.cpp | ${dir_src}")     add_executable("${testname}.cpp" ${dir_src}) endforeach (testsourcefile ${APP_SOURCES})  
vote vote


So Why not use powershell to create the list of source files for you. Take a look at this script

param (     [Parameter(Mandatory=$True)]     [string]$root  )  if (-not (Test-Path  -Path $root)) {     throw "Error directory does not exist" }  #get the full path of the root $rootDir = get-item -Path $root $fp=$rootDir.FullName;   $files = Get-ChildItem -Path $root -Recurse -File |           Where-Object { ".cpp",".cxx",".cc",".h" -contains $_.Extension} |           Foreach {$_.FullName.replace("${fp}\","").replace("\","/")}  $CMakeExpr = "set(SOURCES "  foreach($file in $files){      $CMakeExpr+= """$file"" " ; } $CMakeExpr+=")" return $CMakeExpr; 

Suppose you have a folder with this structure

C:\Workspace\A --a.cpp C:\Workspace\B  --b.cpp 

Now save this file as "generateSourceList.ps1" for example, and run the script as

~>./generateSourceList.ps1 -root "C:\Workspace" > out.txt 

out.txt file will contain

set(SOURCE "A/a.cpp" "B/b.cpp") 

Top 3 video Explaining visual c++ - Automatically add all files in a folder to a target using CMake?