Merge topic 'ExternalProject_independent-step-targets'

468fb734 Help: Add notes for topic 'ExternalProject_independent-step-targets'
67cfbf8e ExternalProject: Add unit tests
f598f1aa ExternalProject: Add ExternalProject_Add_StepDependencies function
4ae133e0 ExternalProject: Add independent step targets
This commit is contained in:
Brad King 2014-11-04 15:09:51 -05:00 committed by CMake Topic Stage
commit db3cfc3376
8 changed files with 210 additions and 15 deletions

View File

@ -0,0 +1,6 @@
ExternalProject_independent-step-targets
----------------------------------------
* The :module:`ExternalProject` module learned options to create
independent external project step targets that do not depend
on the builtin steps.

View File

@ -166,6 +166,9 @@ Create custom targets to build projects in external trees
``STEP_TARGETS <step-target>...``
Generate custom targets for these steps
``INDEPENDENT_STEP_TARGETS <step-target>...``
Generate custom targets for these steps that do not depend on other
external projects even if a dependency is set
The ``*_DIR`` options specify directories for the project, with default
directories computed as follows. If the ``PREFIX`` option is given to
@ -260,18 +263,30 @@ not defined. Behavior of shell operators like ``&&`` is not defined.
The ``ExternalProject_Add_StepTargets`` function generates custom
targets for the steps listed::
ExternalProject_Add_StepTargets(<name> [step1 [step2 [...]]])
ExternalProject_Add_StepTargets(<name> [NO_DEPENDS] [step1 [step2 [...]]])
If ``STEP_TARGETS`` is set then ``ExternalProject_Add_StepTargets`` is
automatically called at the end of matching calls to
``ExternalProject_Add_Step``. Pass ``STEP_TARGETS`` explicitly to
If ``NO_DEPENDS`` is set, the target will not depend on the
dependencies of the complete project. This is usually safe to use for
the download, update, and patch steps that do not require that all the
dependencies are updated and built. Using ``NO_DEPENDS`` for other
of the default steps might break parallel builds, so you should avoid,
it. For custom steps, you should consider whether or not the custom
commands requires that the dependencies are configured, built and
installed.
If ``STEP_TARGETS`` or ``INDEPENDENT_STEP_TARGETS`` is set then
``ExternalProject_Add_StepTargets`` is automatically called at the end
of matching calls to ``ExternalProject_Add_Step``. Pass
``STEP_TARGETS`` or ``INDEPENDENT_STEP_TARGETS`` explicitly to
individual ``ExternalProject_Add`` calls, or implicitly to all
``ExternalProject_Add`` calls by setting the directory property
``EP_STEP_TARGETS``.
``ExternalProject_Add`` calls by setting the directory properties
``EP_STEP_TARGETS`` and ``EP_INDEPENDENT_STEP_TARGETS``. The
``INDEPENDENT`` version of the argument and of the property will call
``ExternalProject_Add_StepTargets`` with the ``NO_DEPENDS`` argument.
If ``STEP_TARGETS`` is not set, clients may still manually call
``ExternalProject_Add_StepTargets`` after calling
``ExternalProject_Add`` or ``ExternalProject_Add_Step``.
If ``STEP_TARGETS`` and ``INDEPENDENT_STEP_TARGETS`` are not set,
clients may still manually call ``ExternalProject_Add_StepTargets``
after calling ``ExternalProject_Add`` or ``ExternalProject_Add_Step``.
This functionality is provided to make it easy to drive the steps
independently of each other by specifying targets on build command
@ -288,6 +303,19 @@ line prior to any ``ExternalProject_Add`` calls in your ``CMakeLists.txt``
file::
set_property(DIRECTORY PROPERTY EP_STEP_TARGETS configure build test)
.. command:: ExternalProject_Add_StepDependencies
The ``ExternalProject_Add_StepDependencies`` function add some
dependencies for some external project step::
ExternalProject_Add_StepDependencies(<name> <step> [target1 [target2 [...]]])
This function takes care to set both target and file level
dependencies, and will ensure that parallel builds will not break.
It should be used instead of :command:`add_dependencies()` when adding
a dependency for some of the step targets generated by
``ExternalProject``.
#]=======================================================================]
#=============================================================================
@ -397,10 +425,19 @@ define_property(DIRECTORY PROPERTY "EP_STEP_TARGETS" INHERITED
BRIEF_DOCS
"List of ExternalProject steps that automatically get corresponding targets"
FULL_DOCS
"These targets will be dependent on the main target dependencies"
"See documentation of the ExternalProject_Add_StepTargets() function in the "
"ExternalProject module."
)
define_property(DIRECTORY PROPERTY "EP_INDEPENDENT_STEP_TARGETS" INHERITED
BRIEF_DOCS
"List of ExternalProject steps that automatically get corresponding targets"
FULL_DOCS
"These targets will not be dependent on the main target dependencies"
"See documentation of the ExternalProject_Add_StepTargets() function in the "
"ExternalProject module."
)
function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag git_submodules src_name work_dir gitclone_infofile gitclone_stampfile)
file(WRITE ${script_filename}
@ -1283,19 +1320,28 @@ endfunction()
function(ExternalProject_Add_StepTargets name)
set(steps ${ARGN})
if("${ARGV1}" STREQUAL "NO_DEPENDS")
set(no_deps 1)
list(REMOVE_AT steps 0)
endif()
foreach(step ${steps})
if(no_deps AND "${step}" MATCHES "^(configure|build|install|test)$")
message(AUTHOR_WARNING "Using NO_DEPENDS for \"${step}\" step might break parallel builds")
endif()
_ep_get_step_stampfile(${name} ${step} stamp_file)
add_custom_target(${name}-${step}
DEPENDS ${stamp_file})
set_property(TARGET ${name}-${step} PROPERTY _EP_IS_EXTERNAL_PROJECT_STEP 1)
set_property(TARGET ${name}-${step} PROPERTY LABELS ${name})
set_property(TARGET ${name}-${step} PROPERTY FOLDER "ExternalProjectTargets/${name}")
# Depend on other external projects (target-level).
get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
foreach(arg IN LISTS deps)
add_dependencies(${name}-${step} ${arg})
endforeach()
if(NOT no_deps)
get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
foreach(arg IN LISTS deps)
add_dependencies(${name}-${step} ${arg})
endforeach()
endif()
endforeach()
endfunction()
@ -1386,6 +1432,7 @@ function(ExternalProject_Add_Step name step)
WORKING_DIRECTORY ${work_dir}
VERBATIM
)
set_property(TARGET ${name} APPEND PROPERTY _EP_STEPS ${step})
# Add custom "step target"?
get_property(step_targets TARGET ${name} PROPERTY _EP_STEP_TARGETS)
@ -1398,6 +1445,60 @@ function(ExternalProject_Add_Step name step)
break()
endif()
endforeach()
get_property(independent_step_targets TARGET ${name} PROPERTY _EP_INDEPENDENT_STEP_TARGETS)
if(NOT independent_step_targets)
get_property(independent_step_targets DIRECTORY PROPERTY EP_INDEPENDENT_STEP_TARGETS)
endif()
foreach(st ${independent_step_targets})
if("${st}" STREQUAL "${step}")
ExternalProject_Add_StepTargets(${name} NO_DEPENDS ${step})
break()
endif()
endforeach()
endfunction()
function(ExternalProject_Add_StepDependencies name step)
set(dependencies ${ARGN})
# Sanity checks on "name" and "step".
if(NOT TARGET ${name})
message(FATAL_ERROR "Cannot find target \"${name}\". Perhaps it has not yet been created using ExternalProject_Add.")
endif()
get_property(is_ep TARGET ${name} PROPERTY _EP_IS_EXTERNAL_PROJECT)
if(NOT is_ep)
message(FATAL_ERROR "Target \"${name}\" was not generated by ExternalProject_Add.")
endif()
get_property(steps TARGET ${name} PROPERTY _EP_STEPS)
list(FIND steps ${step} is_step)
if(NOT is_step)
message(FATAL_ERROR "External project \"${name}\" does not have a step \"${step}\".")
endif()
if(TARGET ${name}-${step})
get_property(is_ep_step TARGET ${name}-${step} PROPERTY _EP_IS_EXTERNAL_PROJECT_STEP)
if(NOT is_ep_step)
message(FATAL_ERROR "Target \"${name}\" was not generated by ExternalProject_Add_StepTargets.")
endif()
endif()
# Always add file-level dependency, but add target-level dependency
# only if the target exists for that step.
_ep_get_step_stampfile(${name} ${step} stamp_file)
foreach(dep ${dependencies})
add_custom_command(APPEND
OUTPUT ${stamp_file}
DEPENDS ${dep})
if(TARGET ${name}-${step})
foreach(dep ${dependencies})
add_dependencies(${name}-${step} ${dep})
endforeach()
endif()
endforeach()
endfunction()

View File

@ -19,6 +19,7 @@ set(base "${CMAKE_BINARY_DIR}/CMakeExternals")
set(binary_base "${base}/Build")
set_property(DIRECTORY PROPERTY EP_BASE ${base})
set_property(DIRECTORY PROPERTY EP_STEP_TARGETS configure build test)
set_property(DIRECTORY PROPERTY EP_INDEPENDENT_STEP_TARGETS update)
set(do_git_tests 0)
@ -68,8 +69,8 @@ if(do_git_tests)
CMAKE_GENERATOR "${CMAKE_GENERATOR}"
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
INSTALL_COMMAND ""
DEPENDS "SetupLocalGITRepository"
)
ExternalProject_Add_StepDependencies(${proj} download SetupLocalGITRepository)
set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
endif()

View File

@ -0,0 +1,20 @@
cmake_minimum_required(VERSION ${CMAKE_VERSION})
include(ExternalProject)
ExternalProject_Add(BAR URL https://cmake.org/bar.tar.gz)
ExternalProject_Add(FOO URL https://cmake.org/foo.tar.gz STEP_TARGETS update)
ExternalProject_Add_Step(FOO do_something COMMAND ${CMAKE_COMMAND} -E echo "Doing something")
ExternalProject_Add_Step(FOO do_something_else COMMAND ${CMAKE_COMMAND} -E echo "Doing something else")
ExternalProject_Add_StepTargets(FOO do_something)
# download and do_something_else are not targets, but the file-level
# dependency are set.
ExternalProject_Add_StepDependencies(FOO download BAR)
ExternalProject_Add_StepDependencies(FOO do_something_else BAR)
# update and do_something are targets, therefore both file-level and
# target-level dependencies are set.
ExternalProject_Add_StepDependencies(FOO update BAR)
ExternalProject_Add_StepDependencies(FOO do_something BAR)

View File

@ -0,0 +1,10 @@
cmake_minimum_required(VERSION ${CMAKE_VERSION})
include(ExternalProject)
ExternalProject_Add(BAR URL https://cmake.org/bar.tar.gz)
ExternalProject_Add(FOO URL https://cmake.org/foo.tar.gz STEP_TARGETS update)
ExternalProject_Add_Step(FOO do_something COMMAND ${CMAKE_COMMAND} -E echo "Doing something")
ExternalProject_Add_Step(FOO do_something_else COMMAND ${CMAKE_COMMAND} -E echo "Doing something else")
ExternalProject_Add_StepTargets(FOO do_something)

View File

@ -0,0 +1,36 @@
CMake Warning \(dev\) at .*/Modules/ExternalProject.cmake:[0-9]+. \(message\):
Using NO_DEPENDS for "configure" step might break parallel builds
Call Stack \(most recent call first\):
.*/Modules/ExternalProject.cmake:[0-9]+ \(ExternalProject_Add_StepTargets\)
.*/Modules/ExternalProject.cmake:[0-9]+ \(ExternalProject_Add_Step\)
.*/Modules/ExternalProject.cmake:[0-9]+ \(_ep_add_configure_command\)
NO_DEPENDS.cmake:[0-9]+ \(ExternalProject_Add\)
CMakeLists.txt:[0-9]+ \(include\)
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Warning \(dev\) at .*/Modules/ExternalProject.cmake:[0-9]+. \(message\):
Using NO_DEPENDS for "build" step might break parallel builds
Call Stack \(most recent call first\):
.*/Modules/ExternalProject.cmake:[0-9]+ \(ExternalProject_Add_StepTargets\)
.*/Modules/ExternalProject.cmake:[0-9]+ \(ExternalProject_Add_Step\)
.*/Modules/ExternalProject.cmake:[0-9]+ \(_ep_add_build_command\)
NO_DEPENDS.cmake:[0-9]+ \(ExternalProject_Add\)
CMakeLists.txt:[0-9]+ \(include\)
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Warning \(dev\) at .*/Modules/ExternalProject.cmake:[0-9]+. \(message\):
Using NO_DEPENDS for "install" step might break parallel builds
Call Stack \(most recent call first\):
.*/Modules/ExternalProject.cmake:[0-9]+ \(ExternalProject_Add_StepTargets\)
.*/Modules/ExternalProject.cmake:[0-9]+ \(ExternalProject_Add_Step\)
.*/Modules/ExternalProject.cmake:[0-9]+ \(_ep_add_install_command\)
NO_DEPENDS.cmake:[0-9]+ \(ExternalProject_Add\)
CMakeLists.txt:[0-9]+ \(include\)
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Warning \(dev\) at .*/Modules/ExternalProject.cmake:[0-9]+. \(message\):
Using NO_DEPENDS for "test" step might break parallel builds
Call Stack \(most recent call first\):
NO_DEPENDS.cmake:[0-9]+ \(ExternalProject_Add_StepTargets\)
CMakeLists.txt:[0-9]+ \(include\)
This warning is for project developers. Use -Wno-dev to suppress it.

View File

@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 2.8.12)
include(ExternalProject RESULT_VARIABLE GOO)
set_property(DIRECTORY PROPERTY EP_INDEPENDENT_STEP_TARGETS download patch update configure build)
ExternalProject_Add(FOO
URL https://example.org/foo.tar.gz)
ExternalProject_Add(BAR
URL https://example.org/bar.tar.gz
TEST_COMMAND echo test
INDEPENDENT_STEP_TARGETS install)
# This one should not give a warning
ExternalProject_Add_Step(BAR bar
COMMAND echo bar)
ExternalProject_Add_StepTargets(BAR NO_DEPENDS test bar)

View File

@ -3,3 +3,6 @@ include(RunCMake)
run_cmake(CMAKE_CACHE_ARGS)
run_cmake(CMAKE_CACHE_DEFAULT_ARGS)
run_cmake(CMAKE_CACHE_mix)
run_cmake(NO_DEPENDS)
run_cmake(Add_StepDependencies)
run_cmake(Add_StepDependencies_no_target)