ExternalProject: Add independent step targets

When adding step targets using ExternalProject_Add_StepTargets, the
STEP_TARGETS argument or the EP_STEP_TARGETS property, ExternalProject
sets all the dependencies for the main project to that target.  Due to
this, the update target cannot be used without downloading and building
all the dependencies.

In order to be able to add step targets that do not depend on other
external projects, this patch adds:

* An optional "NO_DEPENDS" argument to the
  ExternalProject_Add_StepTargets function. If this argument is set,
  then no dependencies are set for the target (file dependencies will
  still be set).

* A new argument INDEPENDENT_STEP_TARGETS to the ExternalProject_Add
  function and a new directory property EP_INDEPENDENT_STEP_TARGETS that
  behave like STEP_TARGETS and EP_STEP_TARGETS, but cause the
  ExternalProject_Add_StepTargets to be called with the NO_DEPENDS
  argument.
This commit is contained in:
Daniele E. Domenichelli 2014-11-03 16:14:35 +01:00
parent 40bab8d17b
commit 4ae133e09c
1 changed files with 57 additions and 14 deletions

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
@ -397,10 +412,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,8 +1307,14 @@ 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})
@ -1292,10 +1322,12 @@ function(ExternalProject_Add_StepTargets 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()
@ -1398,6 +1430,17 @@ 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()