214

I am considering switching a cross platform project from separate build management systems in Visual C++, XCode and makefiles to CMake.

One essential feature I need is to add automatically all files in a directory to a target. While this is easy to do with make, it is not easily doable with Visual C++ and XCode (correct me if I am wrong). Is it possible to do it in directly in CMake? How?

2
  • Btw. in In Visual Studio, at least in C# projects, there's a toolbar button in the project explorer, named show all files. It makes all sub-directories of a project visible, greyed out if they don't contain any files logically included in the project. You can include these directories via the context menu, which includes all source files inside them, recursively :) Commented Dec 13, 2016 at 12:34
  • 3
    Possible duplicate of How to use all *.c files in a directory with the Cmake build system? Commented Mar 16, 2019 at 10:32

5 Answers 5

313

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.

Sign up to request clarification or add additional context in comments.

14 Comments

An alternative to manually re-running cmake is to touch the CMakeLists.txt file before running make.
>"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." This is no longer recommeneded in CMAKE3.7 docs linked about by Hand1Cloud
whats the alternative to GLOB then?
And an absolute nightmare when trying to port an existing project with thousands of files.
A better way since v3.1 is suggested here: target_sources() crascit.com/2016/01/31/…
|
32

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.

7 Comments

Can't cmake simply be re-run, which should remove/modify the out-of-date Makefile?
This isn't an answer, it's a comment about @Kleist's answer.
@Neowizard not in Stackoverflow terminology.
This comment is nice, but it's "standard", right? The asker is using cmake already, so suggesting make can be "smarter" isn't that helpful.
So is there way to add new source files and then build without re-running cmake?
|
10

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.

2 Comments

"CMake documentation still does not recommend using file(GLOB) or file(GLOB_RECURSE) for collect the sources" What do they recommend then? Using something else to collect the sources or to manually list every single source file?
@Thomas: They recommend to manually list every source file. That answer gives a great explanation of the recommendation.
2

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})

Comments

-5

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")

6 Comments

Question is tagged cross-platform - powershell is not cross-platform.
@reichhart powershell works on linux and and mac too
I know. But there's no tag for powershell and "CMake" is already crossplatform. "Powershell" would be an additional dependency and is very seldom used on other OS than Windows. You might find even more C# developers on Linux than people with powershell. And the most important fact is the question: "Is it possible to do it in directly in CMake? How?"
I don't think I will ever install Powershell on my Linux box or on my Mac. Thanks but no thanks. Need another solution.
I'd sooner use Bash for Linux and Mac then use something like Cygwin to make it work on windows. But even before that I'd use just CMake.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.