Reputation: 4958
I'd like to have one specific target be dependent on all the other added targets in my project. To say it in a different way - I'd like this target (say lint
) to run after all the libraries and applications were built.
Is there a way in the top CMakeLists.txt
file, where the project
is specified, to get the list of all targets added by other CMakeLists.txt
files in the directories added using add_subdirectory
? Then I can use the add_dependencies
to specify the order. There is a BUILDSYSTEM_TARGETS
property, but it only works on a directory level.
If there is some other way to achieve this, please let me know. I use CMake 3.14.
Upvotes: 8
Views: 7999
Reputation: 4958
For the future reference, I've ended up writing my own function instead of a macro. But the concept is the same as the accepted answer by @thomas_f.
Here is the code:
# Collect all currently added targets in all subdirectories
#
# Parameters:
# - _result the list containing all found targets
# - _dir root directory to start looking from
function(get_all_targets _result _dir)
get_property(_subdirs DIRECTORY "${_dir}" PROPERTY SUBDIRECTORIES)
foreach(_subdir IN LISTS _subdirs)
get_all_targets(${_result} "${_subdir}")
endforeach()
get_directory_property(_sub_targets DIRECTORY "${_dir}" BUILDSYSTEM_TARGETS)
set(${_result} ${${_result}} ${_sub_targets} PARENT_SCOPE)
endfunction()
Upvotes: 11
Reputation: 1993
You did not mention your CMake version, so I will assume 3.8
or better, for which this solution has been tested.
One possible solution is to iterate through all sub-directories in your project, and then apply BUILDSYSTEM_TARGETS
to each of them. For the sake of simplicity and readability, I have split this up into three different macros.
First, we need a way of recursively obtaining all sub-directories in the project. For this, we can use file(GLOB_RECURSE ...)
with LIST_DIRECTORIES
set to ON
:
#
# Get all directories below the specified root directory.
# _result : The variable in which to store the resulting directory list
# _root : The root directory, from which to start.
#
macro(get_directories _result _root)
file(GLOB_RECURSE dirs RELATIVE ${_root} LIST_DIRECTORIES ON ${_root}/*)
foreach(dir ${dirs})
if(IS_DIRECTORY ${dir})
list(APPEND ${_result} ${dir})
endif()
endforeach()
endmacro()
Secondly, we need a way to obtain all targets at a particular directory level. DIRECTORY
takes an optional parameter, namely the directory you wish to query, which is key for this to work:
#
# Get all targets defined at the specified directory (level).
# _result : The variable in which to store the resulting list of targets.
# _dir : The directory to query for targets.
#
macro(get_targets_by_directory _result _dir)
get_property(_target DIRECTORY ${_dir} PROPERTY BUILDSYSTEM_TARGETS)
set(_result ${_target})
endmacro()
Thirdly, we need another macro to tie all this together:
#
# Get all targets defined below the specified root directory.
# _result : The variable in which to store the resulting list of targets.
# _root_dir : The root project root directory
#
macro(get_all_targets _result _root_dir)
get_directories(_all_directories ${_root_dir})
foreach(_dir ${_all_directories})
get_targets_by_directory(_target ${_dir})
if(_target)
list(APPEND ${_result} ${_target})
endif()
endforeach()
endmacro()
Finally, here is how you can use it:
get_all_targets(ALL_TARGETS ${CMAKE_CURRENT_LIST_DIR})
ALL_TARGETS
should now be a list holding the names of every target created below the caller's directory level. Note that it does not include any targets created in the current CMakeLists.txt
. For that, you can make an extra call to get_targets_by_directory(ALL_TARGETS ${CMAKE_CURRENT_LIST_DIR})
.
Upvotes: 11