Automatically Add All Files in a Folder to a Target Using Cmake

Automatically add all files in a folder to a target using CMake?

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.

Add all files under a folder to a CMake glob?

Turning my comment into an answer

If you want to add recursive searching for files use file(GLOB_RECURSE ...)

file(GLOB_RECURSE source_list "*.cpp" "*.hpp")

Your second example would translate into

file(GLOB_RECURSE BAR "src/baz/*.cpp")

References

  • file(...)
  • Specify source files globally with GLOB?

How to use all *.c files in a directory with the Cmake build system?

Try this:

AUX_SOURCE_DIRECTORY

Find all source files in a directory.

AUX_SOURCE_DIRECTORY(dir VARIABLE) 

Collects the names of all the source files in the specified directory
and stores the list in the variable provided. This command is intended
to be used by projects that use explicit template instantiation.
Template instantiation files can be stored in a "Templates"
subdirectory and collected automatically using this command to avoid
manually listing all instantiations.

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.

Add files in sub folders to target

It's a little unclear what you are trying to achieve, but just from looking at it I would say it should be:

set(dest_dir ${PROJECT_SOURCE_DIR}/sub)
add_custom_target(
subtask ALL
COMMAND ${CMAKE_COMMAND} -E make_directory ${dest_dir}
COMMAND ${PROJECT_SOURCE_DIR}/process.sh
)

Only if the output.txt is an input for something else, you need a custom command:

set(dest_dir ${PROJECT_SOURCE_DIR}/sub)
add_custom_command(
OUTPUT ${dest_dir}/output.txt
COMMAND ${CMAKE_COMMAND} -E make_directory ${dest_dir}
COMMAND ${PROJECT_SOURCE_DIR}/process.sh
MAIN_DEPENDENCY ${PROJECT_SOURCE_DIR}/process.sh
)
add_custom_target(
subtask ALL
DEPENDS ${dest_dir}/output.txt
)

Note that the default working directory for those commands is CMAKE_CURRENT_BINARY_DIR.

Edit: I think the problem in your code is the use of add_dependencies() for file level dependencies. But add_dependencies() can only be used to declare target dependencies.

Edit: With a foreach() you can either collect the dependencies or APPEND them with to a dummy output. The first looks something like this:

file(GLOB srcfiles "src/*.txt")
set(dest_dir "${PROJECT_SOURCE_DIR}/sub")
file(MAKE_DIRECTORY "${dest_dir}")
foreach(srcfile ${srcfiles})
get_filename_component(filename "${srcfile}" NAME_WE)
add_custom_command(
OUTPUT "${dest_dir}/${filename}.txt"
COMMAND ${PROJECT_SOURCE_DIR}/process.sh ${srcfile}
MAIN_DEPENDENCY "${srcfile}"
DEPENDS "${PROJECT_SOURCE_DIR}/process.sh"
WORKING_DIRECTORY "${dest_dir}"
)
list(APPEND subtask_deps "${dest_dir}/${filename}.txt")
endforeach(srcfile)
add_custom_target(
subtask ALL
DEPENDS ${subtask_deps}
)

CMake, how to add files to executable target that hasn't been created yet

CMake can handle outputs of custom commands residing in the same CMakeLists.txt directly.

A target created in the same directory (CMakeLists.txt file) that specifies any output of the custom command as a source file is given a rule to generate the file using the command at build time.

So your code should look like this:

include(FindUnixCommands)

add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/a.h"
COMMAND ${BASH} "${CMAKE_CURRENT_SOURCE_DIR}/create_a_header.sh"
)

set(
SOURCE_FILES
"a.c"
"${CMAKE_CURRENT_BINARY_DIR}/a.h"
)

add_executable(${PROJECT_NAME} ${SOURCE_FILES})
target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")


Related Topics



Leave a reply



Submit