# - Create custom targets to build projects in external trees
# The 'ExternalProject_Add' function creates a custom target to drive
# download, update/patch, configure, build, install and test steps of an
# external project:
# ExternalProject_Add(<name> # Name for custom target
# [DEPENDS projects...] # Targets on which the project depends
# [PREFIX dir] # Root dir for entire project
# [LIST_SEPARATOR sep] # Sep to be replaced by ; in cmd lines
# [TMP_DIR dir] # Directory to store temporary files
# [STAMP_DIR dir] # Directory to store step timestamps
# #--Download step--------------
# [DOWNLOAD_DIR dir] # Directory to store downloaded files
# [DOWNLOAD_COMMAND cmd...] # Command to download source tree
# [CVS_REPOSITORY cvsroot] # CVSROOT of CVS repository
# [CVS_MODULE mod] # Module to checkout from CVS repo
# [CVS_TAG tag] # Tag to checkout from CVS repo
# [SVN_REPOSITORY url] # URL of Subversion repo
# [SVN_REVISION rev] # Revision to checkout from Subversion repo
# [SVN_USERNAME john ] # Username for Subversion checkout and update
# [SVN_PASSWORD doe ] # Password for Subversion checkout and update
# [GIT_REPOSITORY url] # URL of git repo
# [GIT_TAG tag] # Git branch name, commit id or tag
# [URL /.../src.tgz] # Full path or URL of source
# [URL_MD5 md5] # MD5 checksum of file at URL
# [TIMEOUT seconds] # Time allowed for file download operations
# #--Update/Patch step----------
# [UPDATE_COMMAND cmd...] # Source work-tree update command
# [PATCH_COMMAND cmd...] # Command to patch downloaded source
# #--Configure step-------------
# [SOURCE_DIR dir] # Source dir to be used for build
# [CONFIGURE_COMMAND cmd...] # Build tree configuration command
# [CMAKE_COMMAND /.../cmake] # Specify alternative cmake executable
# [CMAKE_GENERATOR gen] # Specify generator for native build
# [CMAKE_ARGS args...] # Arguments to CMake command line
# #--Build step-----------------
# [BINARY_DIR dir] # Specify build dir location
# [BUILD_COMMAND cmd...] # Command to drive the native build
# [BUILD_IN_SOURCE 1] # Use source dir for build dir
# #--Install step---------------
# [INSTALL_DIR dir] # Installation prefix
# [INSTALL_COMMAND cmd...] # Command to drive install after build
# #--Test step------------------
# [TEST_BEFORE_INSTALL 1] # Add test step executed before install step
# [TEST_AFTER_INSTALL 1] # Add test step executed after install step
# [TEST_COMMAND cmd...] # Command to drive test
# #--Output logging-------------
# [LOG_DOWNLOAD 1] # Wrap download in script to log output
# [LOG_UPDATE 1] # Wrap update in script to log output
# [LOG_CONFIGURE 1] # Wrap configure in script to log output
# [LOG_BUILD 1] # Wrap build in script to log output
# [LOG_TEST 1] # Wrap test in script to log output
# [LOG_INSTALL 1] # Wrap install in script to log output
# #--Custom targets-------------
# [STEP_TARGETS st1 st2 ...] # Generate custom targets for these steps
# )
# The *_DIR options specify directories for the project, with default
# directories computed as follows.
# If the PREFIX option is given to ExternalProject_Add() or the EP_PREFIX
# directory property is set, then an external project is built and installed
# under the specified prefix:
# TMP_DIR = <prefix>/tmp
# STAMP_DIR = <prefix>/src/<name>-stamp
# DOWNLOAD_DIR = <prefix>/src
# SOURCE_DIR = <prefix>/src/<name>
# BINARY_DIR = <prefix>/src/<name>-build
# INSTALL_DIR = <prefix>
# Otherwise, if the EP_BASE directory property is set then components
# of an external project are stored under the specified base:
# TMP_DIR = <base>/tmp/<name>
# STAMP_DIR = <base>/Stamp/<name>
# DOWNLOAD_DIR = <base>/Download/<name>
# SOURCE_DIR = <base>/Source/<name>
# BINARY_DIR = <base>/Build/<name>
# INSTALL_DIR = <base>/Install/<name>
# If no PREFIX, EP_PREFIX, or EP_BASE is specified then the default
# is to set PREFIX to "<name>-prefix".
# Relative paths are interpreted with respect to the build directory
# corresponding to the source directory in which ExternalProject_Add is
# invoked.
#
# If SOURCE_DIR is explicitly set to an existing directory the project
# will be built from it.
# Otherwise a download step must be specified using one of the
# DOWNLOAD_COMMAND, CVS_*, SVN_*, or URL options.
# The URL option may refer locally to a directory or source tarball,
# or refer to a remote tarball (e.g. http://.../src.tgz).
#
# The 'ExternalProject_Add_Step' function adds a custom step to an external
# project:
# ExternalProject_Add_Step(<name> <step> # Names of project and custom step
# [COMMAND cmd...] # Command line invoked by this step
# [COMMENT "text..."] # Text printed when step executes
# [DEPENDEES steps...] # Steps on which this step depends
# [DEPENDERS steps...] # Steps that depend on this step
# [DEPENDS files...] # Files on which this step depends
# [ALWAYS 1] # No stamp file, step always runs
# [WORKING_DIRECTORY dir] # Working directory for command
# [LOG 1] # Wrap step in script to log output
# )
# The command line, comment, and working directory of every standard
# and custom step is processed to replace tokens
# <SOURCE_DIR>,
# <BINARY_DIR>,
# <INSTALL_DIR>,
# and <TMP_DIR>
# with corresponding property values.
#
# The 'ExternalProject_Get_Property' function retrieves external project
# target properties:
# ExternalProject_Get_Property(<name> [prop1 [prop2 [...]]])
# It stores property values in variables of the same name.
# Property names correspond to the keyword argument names of
# 'ExternalProject_Add'.
#
# The 'ExternalProject_Add_StepTargets' function generates custom targets for
# the steps listed:
# ExternalProject_Add_StepTargets(<name> [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 individual ExternalProject_Add calls, or
# implicitly to all ExternalProject_Add calls by setting the directory property
# EP_STEP_TARGETS.
#
# If STEP_TARGETS is 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 lines.
# For example, you may be submitting to a sub-project based dashboard, where
# you want to drive the configure portion of the build, then submit to the
# dashboard, followed by the build portion, followed by tests. If you invoke
# a custom target that depends on a step halfway through the step dependency
# chain, then all the previous steps will also run to ensure everything is
# up to date.
#
# For example, to drive configure, build and test steps independently for each
# ExternalProject_Add call in your project, write the following line prior to
# any ExternalProject_Add calls in your CMakeLists file:
#
# set_property(DIRECTORY PROPERTY EP_STEP_TARGETS configure build test)
#=============================================================================
# Copyright 2008-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# Pre-compute a regex to match documented keywords for each command.
math ( EXPR _ep_documentation_line_count "${CMAKE_CURRENT_LIST_LINE} - 16" )
file ( STRINGS "${CMAKE_CURRENT_LIST_FILE}" lines
L I M I T _ C O U N T $ { _ e p _ d o c u m e n t a t i o n _ l i n e _ c o u n t }
R E G E X " ^ # ( \\[[A-Z0-9_]+ [^]]*\\] +#.*$|[A-Za-z0-9_]+\\()")
foreach ( line IN LISTS lines )
if ( "${line}" MATCHES "^# [A-Za-z0-9_]+\\(" )
if ( _ep_func )
set ( _ep_keywords_ ${ _ep_func } "${_ep_keywords_${_ep_func}})$" )
endif ( )
string ( REGEX REPLACE "^# ([A-Za-z0-9_]+)\\(.*" "\\1" _ep_func "${line}" )
#message("function [${_ep_func}]")
set ( _ep_keywords_ ${ _ep_func } "^(" )
set ( _ep_keyword_sep )
else ( )
string ( REGEX REPLACE "^# \\[([A-Z0-9_]+) .*" "\\1" _ep_key "${line}" )
#message(" keyword [${_ep_key}]")
set ( _ep_keywords_ ${ _ep_func }
" $ { _ e p _ k e y w o r d s _ $ { _ e p _ f u n c } } $ { _ e p _ k e y w o r d _ s e p } $ { _ e p _ k e y } " )
set ( _ep_keyword_sep "|" )
endif ( )
endforeach ( )
if ( _ep_func )
set ( _ep_keywords_ ${ _ep_func } "${_ep_keywords_${_ep_func}})$" )
endif ( )
function ( _ep_parse_arguments f name ns args )
# Transfer the arguments to this function into target properties for the
# new custom target we just added so that we can set up all the build steps
# correctly based on target properties.
#
# We loop through ARGN and consider the namespace starting with an
# upper-case letter followed by at least two more upper-case letters,
# numbers or underscores to be keywords.
set ( key )
foreach ( arg IN LISTS args )
set ( is_value 1 )
if ( arg MATCHES "^[A-Z][A-Z0-9_][A-Z0-9_]+$" AND
NOT ( ( arg STREQUAL "${key}" ) AND ( key STREQUAL "COMMAND" ) ) A N D
N O T a r g M A T C H E S " ^ ( T R U E | F A L S E ) $ " )
if ( _ep_keywords_ ${ f } AND arg MATCHES "${_ep_keywords_${f}}" )
set ( is_value 0 )
endif ( )
endif ( )
if ( is_value )
if ( key )
# Value
if ( NOT arg STREQUAL "" )
set_property ( TARGET ${ name } APPEND PROPERTY ${ ns } ${ key } "${arg}" )
else ( )
get_property ( have_key TARGET ${ name } PROPERTY ${ ns } ${ key } SET )
if ( have_key )
get_property ( value TARGET ${ name } PROPERTY ${ ns } ${ key } )
set_property ( TARGET ${ name } PROPERTY ${ ns } ${ key } "${value};${arg}" )
else ( )
set_property ( TARGET ${ name } PROPERTY ${ ns } ${ key } "${arg}" )
endif ( )
endif ( )
else ( )
# Missing Keyword
message ( AUTHOR_WARNING "value '${arg}' with no previous keyword in ${f}" )
endif ( )
else ( )
set ( key "${arg}" )
endif ( )
endforeach ( )
endfunction ( _ep_parse_arguments )
define_property ( DIRECTORY PROPERTY "EP_BASE" INHERITED
B R I E F _ D O C S " B a s e d i r e c t o r y f o r E x t e r n a l P r o j e c t s t o r a g e . "
F U L L _ D O C S
" S e e d o c u m e n t a t i o n o f t h e ExternalProject_Add ( ) f u n c t i o n i n t h e "
" E x t e r n a l P r o j e c t m o d u l e . "
)
define_property ( DIRECTORY PROPERTY "EP_PREFIX" INHERITED
B R I E F _ D O C S " T o p p r e f i x f o r E x t e r n a l P r o j e c t s t o r a g e . "
F U L L _ D O C S
" S e e d o c u m e n t a t i o n o f t h e ExternalProject_Add ( ) f u n c t i o n i n t h e "
" E x t e r n a l P r o j e c t m o d u l e . "
)
define_property ( DIRECTORY PROPERTY "EP_STEP_TARGETS" INHERITED
B R I E F _ D O C S
" L i s t o f E x t e r n a l P r o j e c t s t e p s t h a t a u t o m a t i c a l l y g e t c o r r e s p o n d i n g t a r g e t s "
F U L L _ D O C S
" S e e d o c u m e n t a t i o n o f t h e ExternalProject_Add_StepTargets ( ) f u n c t i o n i n t h e "
" E x t e r n a l P r o j e c t m o d u l e . "
)
function ( _ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag src_name work_dir )
file ( WRITE ${ script_filename }
" if ( \"${git_tag}\" STREQUAL \"\")
message ( FATAL_ERROR \"Tag for git checkout should not be empty.\ " )
endif ( )
execute_process (
C O M M A N D \ $ { C M A K E _ C O M M A N D } - E r e m o v e _ d i r e c t o r y \ " $ { s o u r c e _ d i r } \ "
R E S U L T _ V A R I A B L E e r r o r _ c o d e
)
if ( error_code )
message ( FATAL_ERROR \"Failed to remove directory: ' ${ source_dir } '\ " )
endif ( )
execute_process (
C O M M A N D \ " $ { g i t _ E X E C U T A B L E } \ " c l o n e \ " $ { g i t _ r e p o s i t o r y } \ " \ " $ { s r c _ n a m e } \ "
W O R K I N G _ D I R E C T O R Y \ " $ { w o r k _ d i r } \ "
R E S U L T _ V A R I A B L E e r r o r _ c o d e
)
if ( error_code )
message ( FATAL_ERROR \"Failed to clone repository: ' ${ git_repository } '\ " )
endif ( )
execute_process (
C O M M A N D \ " $ { g i t _ E X E C U T A B L E } \ " c h e c k o u t $ { g i t _ t a g }
W O R K I N G _ D I R E C T O R Y \ " $ { w o r k _ d i r } / $ { s r c _ n a m e } \ "
R E S U L T _ V A R I A B L E e r r o r _ c o d e
)
if ( error_code )
message ( FATAL_ERROR \"Failed to checkout tag: ' ${ git_tag } '\ " )
endif ( )
execute_process (
C O M M A N D \ " $ { g i t _ E X E C U T A B L E } \ " s u b m o d u l e i n i t
W O R K I N G _ D I R E C T O R Y \ " $ { w o r k _ d i r } / $ { s r c _ n a m e } \ "
R E S U L T _ V A R I A B L E e r r o r _ c o d e
)
if ( error_code )
message ( FATAL_ERROR \"Failed to init submodules in: ' ${ work_dir } / ${ src_name } '\ " )
endif ( )
execute_process (
C O M M A N D \ " $ { g i t _ E X E C U T A B L E } \ " s u b m o d u l e u p d a t e - - r e c u r s i v e
W O R K I N G _ D I R E C T O R Y \ " $ { w o r k _ d i r } / $ { s r c _ n a m e } \ "
R E S U L T _ V A R I A B L E e r r o r _ c o d e
)
if ( error_code )
message ( FATAL_ERROR \"Failed to update submodules in: ' ${ work_dir } / ${ src_name } '\ " )
endif ( )
"
)
endfunction ( _ep_write_gitclone_script )
function ( _ep_write_downloadfile_script script_filename remote local timeout md5 )
if ( timeout )
set ( timeout_args TIMEOUT ${ timeout } )
set ( timeout_msg "${timeout} seconds" )
else ( )
set ( timeout_args "# no TIMEOUT" )
set ( timeout_msg "none" )
endif ( )
if ( md5 )
set ( md5_args EXPECTED_MD5 ${ md5 } )
else ( )
set ( md5_args "# no EXPECTED_MD5" )
endif ( )
file ( WRITE ${ script_filename }
" message ( STATUS \"downloading...
s r c = ' $ { r e m o t e } '
d s t = ' $ { l o c a l } '
t i m e o u t = ' $ { t i m e o u t _ m s g } ' \ " )
file ( DOWNLOAD
\ " $ { r e m o t e } \ "
\ " $ { l o c a l } \ "
S H O W _ P R O G R E S S
$ { m d 5 _ a r g s }
$ { t i m e o u t _ a r g s }
S T A T U S s t a t u s
L O G l o g )
list ( GET status 0 status_code )
list ( GET status 1 status_string )
if ( NOT status_code EQUAL 0 )
message ( FATAL_ERROR \"error: downloading ' ${ remote } ' failed
s t a t u s _ c o d e : \ $ { s t a t u s _ c o d e }
s t a t u s _ s t r i n g : \ $ { s t a t u s _ s t r i n g }
l o g : \ $ { l o g }
\ " )
endif ( )
message ( STATUS \"downloading... done\ " )
"
)
endfunction ( _ep_write_downloadfile_script )
function ( _ep_write_verifyfile_script script_filename local md5 )
file ( WRITE ${ script_filename }
" message ( STATUS \"verifying file...
f i l e = ' $ { l o c a l } ' \ " )
set ( verified 0 )
# If an expected md5 checksum exists, compare against it:
#
if ( NOT \"${md5}\" STREQUAL \"\")
execute_process ( COMMAND \${CMAKE_COMMAND} -E md5sum \"${local}\"
O U T P U T _ V A R I A B L E o v
O U T P U T _ S T R I P _ T R A I L I N G _ W H I T E S P A C E
R E S U L T _ V A R I A B L E r v )
if ( NOT rv EQUAL 0 )
message ( FATAL_ERROR \"error: computing md5sum of ' ${ local } ' failed\ " )
endif ( )
string ( REGEX MATCH \"^([0-9A-Fa-f]+)\" md5_actual \"\${ov}\")
string ( TOLOWER \"\${md5_actual}\" md5_actual )
string ( TOLOWER \"${md5}\" md5 )
if ( NOT \"\${md5}\" STREQUAL \"\${md5_actual}\")
message ( FATAL_ERROR \"error: md5sum of ' ${ local } ' does not match expected value
m d 5 _ e x p e c t e d : \ $ { m d 5 }
m d 5 _ a c t u a l : \ $ { m d 5 _ a c t u a l }
\ " )
endif ( )
set ( verified 1 )
endif ( )
if ( verified )
message ( STATUS \"verifying file... done\ " )
else ( )
message ( STATUS \"verifying file... warning: did not verify file - no URL_MD5 checksum argument? corrupt file?\ " )
endif ( )
"
)
endfunction ( _ep_write_verifyfile_script )
function ( _ep_write_extractfile_script script_filename name filename directory )
set ( args "" )
if ( filename MATCHES "(\\.bz2|\\.tar\\.gz|\\.tgz|\\.zip)$" )
set ( args xfz )
endif ( )
if ( filename MATCHES "\\.tar$" )
set ( args xf )
endif ( )
if ( args STREQUAL "" )
message ( SEND_ERROR "error: do not know how to extract '${filename}' -- known types are .bz2, .tar, .tar.gz, .tgz and .zip" )
return ( )
endif ( )
file ( WRITE ${ script_filename }
" # Make file names absolute:
#
get_filename_component ( filename \"${filename}\" ABSOLUTE )
get_filename_component ( directory \"${directory}\" ABSOLUTE )
message ( STATUS \"extracting...
s r c = ' \ $ { f i l e n a m e } '
d s t = ' \ $ { d i r e c t o r y } ' \ " )
if ( NOT EXISTS \"\${filename}\")
message ( FATAL_ERROR \"error: file to extract does not exist: '\ ${ filename } '\ " )
endif ( )
# Prepare a space for extracting:
#
set ( i 1234 )
while ( EXISTS \"\${directory}/../ex-${name}\${i}\")
math ( EXPR i \"\${i} + 1\ " )
endwhile ( )
set ( ut_dir \"\${directory}/../ex-${name}\${i}\")
file ( MAKE_DIRECTORY \"\${ut_dir}\")
# Extract it:
#
message ( STATUS \"extracting... [tar ${ args } ]\ " )
execute_process ( COMMAND \${CMAKE_COMMAND} -E tar ${ args } \${filename}
W O R K I N G _ D I R E C T O R Y \ $ { u t _ d i r }
R E S U L T _ V A R I A B L E r v )
if ( NOT rv EQUAL 0 )
message ( STATUS \"extracting... [error clean up]\ " )
file ( REMOVE_RECURSE \"\${ut_dir}\")
message ( FATAL_ERROR \"error: extract of '\ ${ filename } ' failed\ " )
endif ( )
# Analyze what came out of the tar file:
#
message ( STATUS \"extracting... [analysis]\ " )
file ( GLOB contents \"\${ut_dir}/*\")
list ( LENGTH contents n )
if ( NOT n EQUAL 1 OR NOT IS_DIRECTORY \"\${contents}\")
set ( contents \"\${ut_dir}\")
endif ( )
# Move \"the one\" directory to the final directory:
#
message ( STATUS \"extracting... [rename]\ " )
file ( REMOVE_RECURSE \${directory})
get_filename_component ( contents \${contents} ABSOLUTE )
file ( RENAME \${contents} \${directory})
# Clean up:
#
message ( STATUS \"extracting... [clean up]\ " )
file ( REMOVE_RECURSE \"\${ut_dir}\")
message ( STATUS \"extracting... done\ " )
"
)
endfunction ( _ep_write_extractfile_script )
function ( _ep_set_directories name )
get_property ( prefix TARGET ${ name } PROPERTY _EP_PREFIX )
if ( NOT prefix )
get_property ( prefix DIRECTORY PROPERTY EP_PREFIX )
if ( NOT prefix )
get_property ( base DIRECTORY PROPERTY EP_BASE )
if ( NOT base )
set ( prefix "${name}-prefix" )
endif ( )
endif ( )
endif ( )
if ( prefix )
set ( tmp_default "${prefix}/tmp" )
set ( download_default "${prefix}/src" )
set ( source_default "${prefix}/src/${name}" )
set ( binary_default "${prefix}/src/${name}-build" )
set ( stamp_default "${prefix}/src/${name}-stamp" )
set ( install_default "${prefix}" )
else ( ) # assert(base)
set ( tmp_default "${base}/tmp/${name}" )
set ( download_default "${base}/Download/${name}" )
set ( source_default "${base}/Source/${name}" )
set ( binary_default "${base}/Build/${name}" )
set ( stamp_default "${base}/Stamp/${name}" )
set ( install_default "${base}/Install/${name}" )
endif ( )
get_property ( build_in_source TARGET ${ name } PROPERTY _EP_BUILD_IN_SOURCE )
if ( build_in_source )
get_property ( have_binary_dir TARGET ${ name } PROPERTY _EP_BINARY_DIR SET )
if ( have_binary_dir )
message ( FATAL_ERROR
" E x t e r n a l p r o j e c t $ { n a m e } h a s b o t h B I N A R Y _ D I R a n d B U I L D _ I N _ S O U R C E ! " )
endif ( )
endif ( )
set ( top "${CMAKE_CURRENT_BINARY_DIR}" )
set ( places stamp download source binary install tmp )
foreach ( var ${ places } )
string ( TOUPPER "${var}" VAR )
get_property ( ${ var } _dir TARGET ${ name } PROPERTY _EP_ ${ VAR } _DIR )
if ( NOT ${ var } _dir )
set ( ${ var } _dir "${${var}_default}" )
endif ( )
if ( NOT IS_ABSOLUTE "${${var}_dir}" )
get_filename_component ( ${ var } _dir "${top}/${${var}_dir}" ABSOLUTE )
endif ( )
set_property ( TARGET ${ name } PROPERTY _EP_ ${ VAR } _DIR "${${var}_dir}" )
endforeach ( )
if ( build_in_source )
get_property ( source_dir TARGET ${ name } PROPERTY _EP_SOURCE_DIR )
set_property ( TARGET ${ name } PROPERTY _EP_BINARY_DIR "${source_dir}" )
endif ( )
# Make the directories at CMake configure time *and* add a custom command
# to make them at build time. They need to exist at makefile generation
# time for Borland make and wmake so that CMake may generate makefiles
# with "cd C:\short\paths\with\no\spaces" commands in them.
#
# Additionally, the add_custom_command is still used in case somebody
# removes one of the necessary directories and tries to rebuild without
# re-running cmake.
foreach ( var ${ places } )
string ( TOUPPER "${var}" VAR )
get_property ( dir TARGET ${ name } PROPERTY _EP_ ${ VAR } _DIR )
file ( MAKE_DIRECTORY "${dir}" )
if ( NOT EXISTS "${dir}" )
message ( FATAL_ERROR "dir '${dir}' does not exist after file(MAKE_DIRECTORY)" )
endif ( )
endforeach ( )
endfunction ( _ep_set_directories )
function ( ExternalProject_Get_Property name )
foreach ( var ${ ARGN } )
string ( TOUPPER "${var}" VAR )
get_property ( ${ var } TARGET ${ name } PROPERTY _EP_ ${ VAR } )
if ( NOT ${ var } )
message ( FATAL_ERROR "External project \" ${ name } \" has no ${ var } " )
endif ( )
set ( ${ var } "${${var}}" PARENT_SCOPE )
endforeach ( )
endfunction ( ExternalProject_Get_Property )
function ( _ep_get_configure_command_id name cfg_cmd_id_var )
get_target_property ( cmd ${ name } _EP_CONFIGURE_COMMAND )
if ( cmd STREQUAL "" )
# Explicit empty string means no configure step for this project
set ( ${ cfg_cmd_id_var } "none" PARENT_SCOPE )
else ( )
if ( NOT cmd )
# Default is "use cmake":
set ( ${ cfg_cmd_id_var } "cmake" PARENT_SCOPE )
else ( )
# Otherwise we have to analyze the value:
if ( cmd MATCHES "^[^;]*/configure" )
set ( ${ cfg_cmd_id_var } "configure" PARENT_SCOPE )
elseif ( cmd MATCHES "^[^;]*/cmake" AND NOT cmd MATCHES ";-[PE];" )
set ( ${ cfg_cmd_id_var } "cmake" PARENT_SCOPE )
elseif ( cmd MATCHES "config" )
set ( ${ cfg_cmd_id_var } "configure" PARENT_SCOPE )
else ( )
set ( ${ cfg_cmd_id_var } "unknown:${cmd}" PARENT_SCOPE )
endif ( )
endif ( )
endif ( )
endfunction ( _ep_get_configure_command_id )
function ( _ep_get_build_command name step cmd_var )
set ( cmd "${${cmd_var}}" )
if ( NOT cmd )
set ( args )
_ep_get_configure_command_id ( ${ name } cfg_cmd_id )
if ( cfg_cmd_id STREQUAL "cmake" )
# CMake project. Select build command based on generator.
get_target_property ( cmake_generator ${ name } _EP_CMAKE_GENERATOR )
if ( "${CMAKE_GENERATOR}" MATCHES "Make" AND
( " $ { c m a k e _ g e n e r a t o r } " M A T C H E S " M a k e " O R N O T c m a k e _ g e n e r a t o r ) )
# The project uses the same Makefile generator. Use recursive make.
set ( cmd "$(MAKE)" )
if ( step STREQUAL "INSTALL" )
set ( args install )
endif ( )
if ( step STREQUAL "TEST" )
set ( args test )
endif ( )
else ( )
# Drive the project with "cmake --build".
get_target_property ( cmake_command ${ name } _EP_CMAKE_COMMAND )
if ( cmake_command )
set ( cmd "${cmake_command}" )
else ( )
set ( cmd "${CMAKE_COMMAND}" )
endif ( )
set ( args --build ${ binary_dir } --config ${ CMAKE_CFG_INTDIR } )
if ( step STREQUAL "INSTALL" )
list ( APPEND args --target install )
endif ( )
# But for "TEST" drive the project with corresponding "ctest".
if ( step STREQUAL "TEST" )
string ( REGEX REPLACE "^(.*/)cmake([^/]*)$" "\\1ctest\\2" cmd "${cmd}" )
set ( args "" )
endif ( )
endif ( )
else ( ) # if(cfg_cmd_id STREQUAL "configure")
# Non-CMake project. Guess "make" and "make install" and "make test".
# But use "$(MAKE)" to get recursive parallel make.
set ( cmd "$(MAKE)" )
if ( step STREQUAL "INSTALL" )
set ( args install )
endif ( )
if ( step STREQUAL "TEST" )
set ( args test )
endif ( )
endif ( )
# Use user-specified arguments instead of default arguments, if any.
get_property ( have_args TARGET ${ name } PROPERTY _EP_ ${ step } _ARGS SET )
if ( have_args )
get_target_property ( args ${ name } _EP_ ${ step } _ARGS )
endif ( )
list ( APPEND cmd ${ args } )
endif ( )
set ( ${ cmd_var } "${cmd}" PARENT_SCOPE )
endfunction ( _ep_get_build_command )
function ( _ep_write_log_script name step cmd_var )
ExternalProject_Get_Property ( ${ name } stamp_dir )
set ( command "${${cmd_var}}" )
set ( make "" )
set ( code_cygpath_make "" )
if ( "${command}" MATCHES "^\\$\\(MAKE\\)" )
# GNU make recognizes the string "$(MAKE)" as recursive make, so
# ensure that it appears directly in the makefile.
string ( REGEX REPLACE "^\\$\\(MAKE\\)" "\${make}" command "${command}" )
set ( make "-Dmake=$(MAKE)" )
if ( WIN32 AND NOT CYGWIN )
set ( code_cygpath_make "
if ( \${make} MATCHES \"^/\")
execute_process (
C O M M A N D c y g p a t h - w \ $ { m a k e }
O U T P U T _ V A R I A B L E c y g p a t h _ m a k e
E R R O R _ V A R I A B L E c y g p a t h _ m a k e
R E S U L T _ V A R I A B L E c y g p a t h _ e r r o r
O U T P U T _ S T R I P _ T R A I L I N G _ W H I T E S P A C E
)
if ( NOT cygpath_error )
set ( make \${cygpath_make})
endif ( )
endif ( )
" )
endif ( )
endif ( )
set ( config "" )
if ( "${CMAKE_CFG_INTDIR}" MATCHES "^\\$" )
string ( REPLACE "${CMAKE_CFG_INTDIR}" "\${config}" command "${command}" )
set ( config "-Dconfig=${CMAKE_CFG_INTDIR}" )
endif ( )
# Wrap multiple 'COMMAND' lines up into a second-level wrapper
# script so all output can be sent to one log file.
if ( "${command}" MATCHES ";COMMAND;" )
set ( code_execute_process "
$ { c o d e _ c y g p a t h _ m a k e }
execute_process ( COMMAND \${command} RESULT_VARIABLE result )
if ( result )
set ( msg \"Command failed ( \${result}):\\n\")
foreach ( arg IN LISTS command )
set ( msg \"\${msg} '\ ${ arg } '\ " )
endforeach ( arg )
message ( FATAL_ERROR \"\${msg}\")
endif ( )
" )
set ( code "" )
set ( cmd "" )
set ( sep "" )
foreach ( arg IN LISTS command )
if ( "x${arg}" STREQUAL "xCOMMAND" )
set ( code "${code}set(command \" ${ cmd } \")${code_execute_process}")
set ( cmd "" )
set ( sep "" )
else ( )
set ( cmd "${cmd}${sep}${arg}" )
set ( sep ";" )
endif ( )
endforeach ( )
set ( code "${code}set(command \" ${ cmd } \")${code_execute_process}")
file ( WRITE ${ stamp_dir } / ${ name } - ${ step } -impl.cmake "${code}" )
set ( command ${ CMAKE_COMMAND } "-Dmake=\${make}" "-Dconfig=\${config}" -P ${ stamp_dir } / ${ name } - ${ step } -impl.cmake )
endif ( )
# Wrap the command in a script to log output to files.
set ( script ${ stamp_dir } / ${ name } - ${ step } .cmake )
set ( logbase ${ stamp_dir } / ${ name } - ${ step } )
file ( WRITE ${ script } "
$ { c o d e _ c y g p a t h _ m a k e }
set ( command \"${command}\")
execute_process (
C O M M A N D \ $ { c o m m a n d }
R E S U L T _ V A R I A B L E r e s u l t
O U T P U T _ F I L E \ " $ { l o g b a s e } - o u t . l o g \ "
E R R O R _ F I L E \ " $ { l o g b a s e } - e r r . l o g \ "
)
if ( result )
set ( msg \"Command failed: \${result}\\n\")
foreach ( arg IN LISTS command )
set ( msg \"\${msg} '\ ${ arg } '\ " )
endforeach ( arg )
set ( msg \"\${msg}\\nSee also\\n ${ logbase } -*.log\\n\ " )
message ( FATAL_ERROR \"\${msg}\")
else ( )
set ( msg \"${name} ${ step } command succeeded. See also ${ logbase } -*.log\\n\ " )
message ( STATUS \"\${msg}\")
endif ( )
" )
set ( command ${ CMAKE_COMMAND } ${ make } ${ config } -P ${ script } )
set ( ${ cmd_var } "${command}" PARENT_SCOPE )
endfunction ( _ep_write_log_script )
# This module used to use "/${CMAKE_CFG_INTDIR}" directly and produced
# makefiles with "/./" in paths for custom command dependencies. Which
# resulted in problems with parallel make -j invocations.
#
# This function was added so that the suffix (search below for ${cfgdir}) is
# only set to "/${CMAKE_CFG_INTDIR}" when ${CMAKE_CFG_INTDIR} is not going to
# be "." (multi-configuration build systems like Visual Studio and Xcode...)
#
function ( _ep_get_configuration_subdir_suffix suffix_var )
set ( suffix "" )
if ( CMAKE_CONFIGURATION_TYPES )
set ( suffix "/${CMAKE_CFG_INTDIR}" )
endif ( )
set ( ${ suffix_var } "${suffix}" PARENT_SCOPE )
endfunction ( _ep_get_configuration_subdir_suffix )
function ( ExternalProject_Add_StepTargets name )
set ( steps ${ ARGN } )
_ep_get_configuration_subdir_suffix ( cfgdir )
ExternalProject_Get_Property ( ${ name } stamp_dir )
foreach ( step ${ steps } )
add_custom_target ( ${ name } - ${ step }
D E P E N D S $ { s t a m p _ d i r } $ { c f g d i r } / $ { n a m e } - $ { s t e p } )
endforeach ( )
endfunction ( ExternalProject_Add_StepTargets )
function ( ExternalProject_Add_Step name step )
set ( cmf_dir ${ CMAKE_CURRENT_BINARY_DIR } /CMakeFiles )
ExternalProject_Get_Property ( ${ name } stamp_dir )
_ep_get_configuration_subdir_suffix ( cfgdir )
add_custom_command ( APPEND
O U T P U T $ { c m f _ d i r } $ { c f g d i r } / $ { n a m e } - c o m p l e t e
D E P E N D S $ { s t a m p _ d i r } $ { c f g d i r } / $ { n a m e } - $ { s t e p }
)
_ep_parse_arguments ( ExternalProject_Add_Step
$ { n a m e } _ E P _ $ { s t e p } _ " $ { A R G N } " )
# Steps depending on this step.
get_property ( dependers TARGET ${ name } PROPERTY _EP_ ${ step } _DEPENDERS )
foreach ( depender IN LISTS dependers )
add_custom_command ( APPEND
O U T P U T $ { s t a m p _ d i r } $ { c f g d i r } / $ { n a m e } - $ { d e p e n d e r }
D E P E N D S $ { s t a m p _ d i r } $ { c f g d i r } / $ { n a m e } - $ { s t e p }
)
endforeach ( )
# Dependencies on files.
get_property ( depends TARGET ${ name } PROPERTY _EP_ ${ step } _DEPENDS )
# Dependencies on steps.
get_property ( dependees TARGET ${ name } PROPERTY _EP_ ${ step } _DEPENDEES )
foreach ( dependee IN LISTS dependees )
list ( APPEND depends ${ stamp_dir } ${ cfgdir } / ${ name } - ${ dependee } )
endforeach ( )
# The command to run.
get_property ( command TARGET ${ name } PROPERTY _EP_ ${ step } _COMMAND )
if ( command )
set ( comment "Performing ${step} step for '${name}'" )
else ( )
set ( comment "No ${step} step for '${name}'" )
endif ( )
get_property ( work_dir TARGET ${ name } PROPERTY _EP_ ${ step } _WORKING_DIRECTORY )
# Replace list separators.
get_property ( sep TARGET ${ name } PROPERTY _EP_LIST_SEPARATOR )
if ( sep AND command )
string ( REPLACE "${sep}" "\\;" command "${command}" )
endif ( )
# Replace location tags.
foreach ( var comment command work_dir )
if ( ${ var } )
foreach ( dir SOURCE_DIR BINARY_DIR INSTALL_DIR TMP_DIR )
get_property ( val TARGET ${ name } PROPERTY _EP_ ${ dir } )
string ( REPLACE "<${dir}>" "${val}" ${ var } "${${var}}" )
endforeach ( )
endif ( )
endforeach ( )
# Custom comment?
get_property ( comment_set TARGET ${ name } PROPERTY _EP_ ${ step } _COMMENT SET )
if ( comment_set )
get_property ( comment TARGET ${ name } PROPERTY _EP_ ${ step } _COMMENT )
endif ( )
# Run every time?
get_property ( always TARGET ${ name } PROPERTY _EP_ ${ step } _ALWAYS )
if ( always )
set_property ( SOURCE ${ stamp_dir } ${ cfgdir } / ${ name } - ${ step } PROPERTY SYMBOLIC 1 )
set ( touch )
else ( )
set ( touch ${ CMAKE_COMMAND } -E touch ${ stamp_dir } ${ cfgdir } / ${ name } - ${ step } )
endif ( )
# Wrap with log script?
get_property ( log TARGET ${ name } PROPERTY _EP_ ${ step } _LOG )
if ( command AND log )
_ep_write_log_script ( ${ name } ${ step } command )
endif ( )
add_custom_command (
O U T P U T $ { s t a m p _ d i r } $ { c f g d i r } / $ { n a m e } - $ { s t e p }
C O M M E N T $ { c o m m e n t }
C O M M A N D $ { c o m m a n d }
C O M M A N D $ { t o u c h }
D E P E N D S $ { d e p e n d s }
W O R K I N G _ D I R E C T O R Y $ { w o r k _ d i r }
V E R B A T I M
)
# Add custom "step target"?
get_property ( step_targets TARGET ${ name } PROPERTY _EP_STEP_TARGETS )
if ( NOT step_targets )
get_property ( step_targets DIRECTORY PROPERTY EP_STEP_TARGETS )
endif ( )
foreach ( st ${ step_targets } )
if ( "${st}" STREQUAL "${step}" )
ExternalProject_Add_StepTargets ( ${ name } ${ step } )
break ( )
endif ( )
endforeach ( )
endfunction ( ExternalProject_Add_Step )
function ( _ep_add_mkdir_command name )
ExternalProject_Get_Property ( ${ name }
s o u r c e _ d i r b i n a r y _ d i r i n s t a l l _ d i r s t a m p _ d i r d o w n l o a d _ d i r t m p _ d i r )
_ep_get_configuration_subdir_suffix ( cfgdir )
ExternalProject_Add_Step ( ${ name } mkdir
C O M M E N T " C r e a t i n g d i r e c t o r i e s f o r ' $ { n a m e } ' "
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y $ { s o u r c e _ d i r }
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y $ { b i n a r y _ d i r }
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y $ { i n s t a l l _ d i r }
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y $ { t m p _ d i r }
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y $ { s t a m p _ d i r } $ { c f g d i r }
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y $ { d o w n l o a d _ d i r }
)
endfunction ( _ep_add_mkdir_command )
function ( _ep_get_git_version git_EXECUTABLE git_version_var )
if ( git_EXECUTABLE )
execute_process (
C O M M A N D " $ { g i t _ E X E C U T A B L E } " - - v e r s i o n
O U T P U T _ V A R I A B L E o v
O U T P U T _ S T R I P _ T R A I L I N G _ W H I T E S P A C E
)
string ( REGEX REPLACE "^git version (.+)$" "\\1" version "${ov}" )
set ( ${ git_version_var } "${version}" PARENT_SCOPE )
endif ( )
endfunction ( )
function ( _ep_is_dir_empty dir empty_var )
file ( GLOB gr "${dir}/*" )
if ( "${gr}" STREQUAL "" )
set ( ${ empty_var } 1 PARENT_SCOPE )
else ( )
set ( ${ empty_var } 0 PARENT_SCOPE )
endif ( )
endfunction ( )
function ( _ep_add_download_command name )
ExternalProject_Get_Property ( ${ name } source_dir stamp_dir download_dir tmp_dir )
get_property ( cmd_set TARGET ${ name } PROPERTY _EP_DOWNLOAD_COMMAND SET )
get_property ( cmd TARGET ${ name } PROPERTY _EP_DOWNLOAD_COMMAND )
get_property ( cvs_repository TARGET ${ name } PROPERTY _EP_CVS_REPOSITORY )
get_property ( svn_repository TARGET ${ name } PROPERTY _EP_SVN_REPOSITORY )
get_property ( git_repository TARGET ${ name } PROPERTY _EP_GIT_REPOSITORY )
get_property ( url TARGET ${ name } PROPERTY _EP_URL )
# TODO: Perhaps file:// should be copied to download dir before extraction.
string ( REGEX REPLACE "^file://" "" url "${url}" )
set ( depends )
set ( comment )
set ( work_dir )
if ( cmd_set )
set ( work_dir ${ download_dir } )
elseif ( cvs_repository )
find_package ( CVS )
if ( NOT CVS_EXECUTABLE )
message ( FATAL_ERROR "error: could not find cvs for checkout of ${name}" )
endif ( )
get_target_property ( cvs_module ${ name } _EP_CVS_MODULE )
if ( NOT cvs_module )
message ( FATAL_ERROR "error: no CVS_MODULE" )
endif ( )
get_property ( cvs_tag TARGET ${ name } PROPERTY _EP_CVS_TAG )
set ( repository ${ cvs_repository } )
set ( module ${ cvs_module } )
set ( tag ${ cvs_tag } )
configure_file (
" $ { C M A K E _ R O O T } / M o d u l e s / R e p o s i t o r y I n f o . t x t . i n "
" $ { s t a m p _ d i r } / $ { n a m e } - c v s i n f o . t x t "
@ O N L Y
)
get_filename_component ( src_name "${source_dir}" NAME )
get_filename_component ( work_dir "${source_dir}" PATH )
set ( comment "Performing download step (CVS checkout) for '${name}'" )
set ( cmd ${ CVS_EXECUTABLE } -d ${ cvs_repository } -q co ${ cvs_tag } -d ${ src_name } ${ cvs_module } )
list ( APPEND depends ${ stamp_dir } / ${ name } -cvsinfo.txt )
elseif ( svn_repository )
find_package ( Subversion )
if ( NOT Subversion_SVN_EXECUTABLE )
message ( FATAL_ERROR "error: could not find svn for checkout of ${name}" )
endif ( )
get_property ( svn_revision TARGET ${ name } PROPERTY _EP_SVN_REVISION )
get_property ( svn_username TARGET ${ name } PROPERTY _EP_SVN_USERNAME )
get_property ( svn_password TARGET ${ name } PROPERTY _EP_SVN_PASSWORD )
set ( repository "${svn_repository} user=${svn_username} password=${svn_password}" )
set ( module )
set ( tag ${ svn_revision } )
configure_file (
" $ { C M A K E _ R O O T } / M o d u l e s / R e p o s i t o r y I n f o . t x t . i n "
" $ { s t a m p _ d i r } / $ { n a m e } - s v n i n f o . t x t "
@ O N L Y
)
get_filename_component ( src_name "${source_dir}" NAME )
get_filename_component ( work_dir "${source_dir}" PATH )
set ( comment "Performing download step (SVN checkout) for '${name}'" )
set ( svn_user_pw_args "" )
if ( svn_username )
set ( svn_user_pw_args ${ svn_user_pw_args } "--username=${svn_username}" )
endif ( )
if ( svn_password )
set ( svn_user_pw_args ${ svn_user_pw_args } "--password=${svn_password}" )
endif ( )
set ( cmd ${ Subversion_SVN_EXECUTABLE } co ${ svn_repository } ${ svn_revision }
$ { s v n _ u s e r _ p w _ a r g s } $ { s r c _ n a m e } )
list ( APPEND depends ${ stamp_dir } / ${ name } -svninfo.txt )
elseif ( git_repository )
find_package ( Git )
if ( NOT GIT_EXECUTABLE )
message ( FATAL_ERROR "error: could not find git for clone of ${name}" )
endif ( )
# The git submodule update '--recursive' flag requires git >= v1.6.5
#
_ep_get_git_version ( "${GIT_EXECUTABLE}" git_version )
if ( git_version VERSION_LESS 1.6.5 )
message ( FATAL_ERROR "error: git version 1.6.5 or later required for 'git submodule update --recursive': git_version='${git_version}'" )
endif ( )
get_property ( git_tag TARGET ${ name } PROPERTY _EP_GIT_TAG )
if ( NOT git_tag )
set ( git_tag "master" )
endif ( )
set ( repository ${ git_repository } )
set ( module )
set ( tag ${ git_tag } )
configure_file (
" $ { C M A K E _ R O O T } / M o d u l e s / R e p o s i t o r y I n f o . t x t . i n "
" $ { s t a m p _ d i r } / $ { n a m e } - g i t i n f o . t x t "
@ O N L Y
)
get_filename_component ( src_name "${source_dir}" NAME )
get_filename_component ( work_dir "${source_dir}" PATH )
# Since git clone doesn't succeed if the non-empty source_dir exists,
# create a cmake script to invoke as download command.
# The script will delete the source directory and then call git clone.
#
_ep_write_gitclone_script ( ${ tmp_dir } / ${ name } -gitclone.cmake ${ source_dir }
$ { G I T _ E X E C U T A B L E } $ { g i t _ r e p o s i t o r y } $ { g i t _ t a g } $ { s r c _ n a m e } $ { w o r k _ d i r }
)
set ( comment "Performing download step (git clone) for '${name}'" )
set ( cmd ${ CMAKE_COMMAND } -P ${ tmp_dir } / ${ name } -gitclone.cmake )
list ( APPEND depends ${ stamp_dir } / ${ name } -gitinfo.txt )
elseif ( url )
get_filename_component ( work_dir "${source_dir}" PATH )
get_property ( md5 TARGET ${ name } PROPERTY _EP_URL_MD5 )
set ( repository "external project URL" )
set ( module "${url}" )
set ( tag "${md5}" )
configure_file (
" $ { C M A K E _ R O O T } / M o d u l e s / R e p o s i t o r y I n f o . t x t . i n "
" $ { s t a m p _ d i r } / $ { n a m e } - u r l i n f o . t x t "
@ O N L Y
)
list ( APPEND depends ${ stamp_dir } / ${ name } -urlinfo.txt )
if ( IS_DIRECTORY "${url}" )
get_filename_component ( abs_dir "${url}" ABSOLUTE )
set ( comment "Performing download step (DIR copy) for '${name}'" )
set ( cmd ${ CMAKE_COMMAND } -E remove_directory ${ source_dir }
C O M M A N D $ { C M A K E _ C O M M A N D } - E c o p y _ d i r e c t o r y $ { a b s _ d i r } $ { s o u r c e _ d i r } )
else ( )
if ( "${url}" MATCHES "^[a-z]+://" )
# TODO: Should download and extraction be different steps?
string ( REGEX MATCH "[^/]*$" fname "${url}" )
if ( NOT "${fname}" MATCHES "\\.(bz2|tar|tgz|tar\\.gz|zip)$" )
message ( FATAL_ERROR "Could not extract tarball filename from url:\n ${url}" )
endif ( )
set ( file ${ download_dir } / ${ fname } )
get_property ( timeout TARGET ${ name } PROPERTY _EP_TIMEOUT )
_ep_write_downloadfile_script ( "${stamp_dir}/download-${name}.cmake" "${url}" "${file}" "${timeout}" "${md5}" )
set ( cmd ${ CMAKE_COMMAND } -P ${ stamp_dir } /download- ${ name } .cmake
C O M M A N D )
set ( comment "Performing download step (download, verify and extract) for '${name}'" )
else ( )
set ( file "${url}" )
set ( comment "Performing download step (verify and extract) for '${name}'" )
endif ( )
_ep_write_verifyfile_script ( "${stamp_dir}/verify-${name}.cmake" "${file}" "${md5}" )
list ( APPEND cmd ${ CMAKE_COMMAND } -P ${ stamp_dir } /verify- ${ name } .cmake )
_ep_write_extractfile_script ( "${stamp_dir}/extract-${name}.cmake" "${name}" "${file}" "${source_dir}" )
list ( APPEND cmd ${ CMAKE_COMMAND } -P ${ stamp_dir } /extract- ${ name } .cmake )
endif ( )
else ( )
_ep_is_dir_empty ( "${source_dir}" empty )
if ( ${ empty } )
message ( SEND_ERROR "error: no download info for '${name}' -- please specify existing/non-empty SOURCE_DIR or one of URL, CVS_REPOSITORY and CVS_MODULE, SVN_REPOSITORY, GIT_REPOSITORY or DOWNLOAD_COMMAND" )
endif ( )
endif ( )
get_property ( log TARGET ${ name } PROPERTY _EP_LOG_DOWNLOAD )
if ( log )
set ( log LOG 1 )
else ( )
set ( log "" )
endif ( )
ExternalProject_Add_Step ( ${ name } download
C O M M E N T $ { c o m m e n t }
C O M M A N D $ { c m d }
W O R K I N G _ D I R E C T O R Y $ { w o r k _ d i r }
D E P E N D S $ { d e p e n d s }
D E P E N D E E S m k d i r
$ { l o g }
)
endfunction ( _ep_add_download_command )
function ( _ep_add_update_command name )
ExternalProject_Get_Property ( ${ name } source_dir )
get_property ( cmd_set TARGET ${ name } PROPERTY _EP_UPDATE_COMMAND SET )
get_property ( cmd TARGET ${ name } PROPERTY _EP_UPDATE_COMMAND )
get_property ( cvs_repository TARGET ${ name } PROPERTY _EP_CVS_REPOSITORY )
get_property ( svn_repository TARGET ${ name } PROPERTY _EP_SVN_REPOSITORY )
get_property ( git_repository TARGET ${ name } PROPERTY _EP_GIT_REPOSITORY )
set ( work_dir )
set ( comment )
set ( always )
if ( cmd_set )
set ( work_dir ${ source_dir } )
elseif ( cvs_repository )
if ( NOT CVS_EXECUTABLE )
message ( FATAL_ERROR "error: could not find cvs for update of ${name}" )
endif ( )
set ( work_dir ${ source_dir } )
set ( comment "Performing update step (CVS update) for '${name}'" )
get_property ( cvs_tag TARGET ${ name } PROPERTY _EP_CVS_TAG )
set ( cmd ${ CVS_EXECUTABLE } -d ${ cvs_repository } -q up -dP ${ cvs_tag } )
set ( always 1 )
elseif ( svn_repository )
if ( NOT Subversion_SVN_EXECUTABLE )
message ( FATAL_ERROR "error: could not find svn for update of ${name}" )
endif ( )
set ( work_dir ${ source_dir } )
set ( comment "Performing update step (SVN update) for '${name}'" )
get_property ( svn_revision TARGET ${ name } PROPERTY _EP_SVN_REVISION )
get_property ( svn_username TARGET ${ name } PROPERTY _EP_SVN_USERNAME )
get_property ( svn_password TARGET ${ name } PROPERTY _EP_SVN_PASSWORD )
set ( svn_user_pw_args "" )
if ( svn_username )
set ( svn_user_pw_args ${ svn_user_pw_args } "--username=${svn_username}" )
endif ( )
if ( svn_password )
set ( svn_user_pw_args ${ svn_user_pw_args } "--password=${svn_password}" )
endif ( )
set ( cmd ${ Subversion_SVN_EXECUTABLE } up ${ svn_revision }
$ { s v n _ u s e r _ p w _ a r g s } )
set ( always 1 )
elseif ( git_repository )
if ( NOT GIT_EXECUTABLE )
message ( FATAL_ERROR "error: could not find git for fetch of ${name}" )
endif ( )
set ( work_dir ${ source_dir } )
set ( comment "Performing update step (git fetch) for '${name}'" )
get_property ( git_tag TARGET ${ name } PROPERTY _EP_GIT_TAG )
if ( NOT git_tag )
set ( git_tag "master" )
endif ( )
set ( cmd ${ GIT_EXECUTABLE } fetch
C O M M A N D $ { G I T _ E X E C U T A B L E } c h e c k o u t $ { g i t _ t a g }
C O M M A N D $ { G I T _ E X E C U T A B L E } s u b m o d u l e u p d a t e - - r e c u r s i v e
)
set ( always 1 )
endif ( )
get_property ( log TARGET ${ name } PROPERTY _EP_LOG_UPDATE )
if ( log )
set ( log LOG 1 )
else ( )
set ( log "" )
endif ( )
ExternalProject_Add_Step ( ${ name } update
C O M M E N T $ { c o m m e n t }
C O M M A N D $ { c m d }
A L W A Y S $ { a l w a y s }
W O R K I N G _ D I R E C T O R Y $ { w o r k _ d i r }
D E P E N D E E S d o w n l o a d
$ { l o g }
)
endfunction ( _ep_add_update_command )
function ( _ep_add_patch_command name )
ExternalProject_Get_Property ( ${ name } source_dir )
get_property ( cmd_set TARGET ${ name } PROPERTY _EP_PATCH_COMMAND SET )
get_property ( cmd TARGET ${ name } PROPERTY _EP_PATCH_COMMAND )
set ( work_dir )
if ( cmd_set )
set ( work_dir ${ source_dir } )
endif ( )
ExternalProject_Add_Step ( ${ name } patch
C O M M A N D $ { c m d }
W O R K I N G _ D I R E C T O R Y $ { w o r k _ d i r }
D E P E N D E E S d o w n l o a d
)
endfunction ( _ep_add_patch_command )
# TODO: Make sure external projects use the proper compiler
function ( _ep_add_configure_command name )
ExternalProject_Get_Property ( ${ name } source_dir binary_dir tmp_dir )
_ep_get_configuration_subdir_suffix ( cfgdir )
# Depend on other external projects (file-level).
set ( file_deps )
get_property ( deps TARGET ${ name } PROPERTY _EP_DEPENDS )
foreach ( dep IN LISTS deps )
get_property ( dep_stamp_dir TARGET ${ dep } PROPERTY _EP_STAMP_DIR )
list ( APPEND file_deps ${ dep_stamp_dir } ${ cfgdir } / ${ dep } -done )
endforeach ( )
get_property ( cmd_set TARGET ${ name } PROPERTY _EP_CONFIGURE_COMMAND SET )
if ( cmd_set )
get_property ( cmd TARGET ${ name } PROPERTY _EP_CONFIGURE_COMMAND )
else ( )
get_target_property ( cmake_command ${ name } _EP_CMAKE_COMMAND )
if ( cmake_command )
set ( cmd "${cmake_command}" )
else ( )
set ( cmd "${CMAKE_COMMAND}" )
endif ( )
get_property ( cmake_args TARGET ${ name } PROPERTY _EP_CMAKE_ARGS )
list ( APPEND cmd ${ cmake_args } )
get_target_property ( cmake_generator ${ name } _EP_CMAKE_GENERATOR )
if ( cmake_generator )
list ( APPEND cmd "-G${cmake_generator}" "${source_dir}" )
else ( )
list ( APPEND cmd "-G${CMAKE_GENERATOR}" "${source_dir}" )
endif ( )
endif ( )
# If anything about the configure command changes, (command itself, cmake
# used, cmake args or cmake generator) then re-run the configure step.
# Fixes issue http://public.kitware.com/Bug/view.php?id=10258
#
if ( NOT EXISTS ${ tmp_dir } / ${ name } -cfgcmd.txt.in )
file ( WRITE ${ tmp_dir } / ${ name } -cfgcmd.txt.in "cmd='@cmd@'\n" )
endif ( )
configure_file ( ${ tmp_dir } / ${ name } -cfgcmd.txt.in ${ tmp_dir } / ${ name } -cfgcmd.txt )
list ( APPEND file_deps ${ tmp_dir } / ${ name } -cfgcmd.txt )
get_property ( log TARGET ${ name } PROPERTY _EP_LOG_CONFIGURE )
if ( log )
set ( log LOG 1 )
else ( )
set ( log "" )
endif ( )
ExternalProject_Add_Step ( ${ name } configure
C O M M A N D $ { c m d }
W O R K I N G _ D I R E C T O R Y $ { b i n a r y _ d i r }
D E P E N D E E S u p d a t e p a t c h
D E P E N D S $ { f i l e _ d e p s }
$ { l o g }
)
endfunction ( _ep_add_configure_command )
function ( _ep_add_build_command name )
ExternalProject_Get_Property ( ${ name } binary_dir )
get_property ( cmd_set TARGET ${ name } PROPERTY _EP_BUILD_COMMAND SET )
if ( cmd_set )
get_property ( cmd TARGET ${ name } PROPERTY _EP_BUILD_COMMAND )
else ( )
_ep_get_build_command ( ${ name } BUILD cmd )
endif ( )
get_property ( log TARGET ${ name } PROPERTY _EP_LOG_BUILD )
if ( log )
set ( log LOG 1 )
else ( )
set ( log "" )
endif ( )
ExternalProject_Add_Step ( ${ name } build
C O M M A N D $ { c m d }
W O R K I N G _ D I R E C T O R Y $ { b i n a r y _ d i r }
D E P E N D E E S c o n f i g u r e
$ { l o g }
)
endfunction ( _ep_add_build_command )
function ( _ep_add_install_command name )
ExternalProject_Get_Property ( ${ name } binary_dir )
get_property ( cmd_set TARGET ${ name } PROPERTY _EP_INSTALL_COMMAND SET )
if ( cmd_set )
get_property ( cmd TARGET ${ name } PROPERTY _EP_INSTALL_COMMAND )
else ( )
_ep_get_build_command ( ${ name } INSTALL cmd )
endif ( )
get_property ( log TARGET ${ name } PROPERTY _EP_LOG_INSTALL )
if ( log )
set ( log LOG 1 )
else ( )
set ( log "" )
endif ( )
ExternalProject_Add_Step ( ${ name } install
C O M M A N D $ { c m d }
W O R K I N G _ D I R E C T O R Y $ { b i n a r y _ d i r }
D E P E N D E E S b u i l d
$ { l o g }
)
endfunction ( _ep_add_install_command )
function ( _ep_add_test_command name )
ExternalProject_Get_Property ( ${ name } binary_dir )
get_property ( before TARGET ${ name } PROPERTY _EP_TEST_BEFORE_INSTALL )
get_property ( after TARGET ${ name } PROPERTY _EP_TEST_AFTER_INSTALL )
get_property ( cmd_set TARGET ${ name } PROPERTY _EP_TEST_COMMAND SET )
# Only actually add the test step if one of the test related properties is
# explicitly set. (i.e. the test step is omitted unless requested...)
#
if ( cmd_set OR before OR after )
if ( cmd_set )
get_property ( cmd TARGET ${ name } PROPERTY _EP_TEST_COMMAND )
else ( )
_ep_get_build_command ( ${ name } TEST cmd )
endif ( )
if ( before )
set ( dep_args DEPENDEES build DEPENDERS install )
else ( )
set ( dep_args DEPENDEES install )
endif ( )
get_property ( log TARGET ${ name } PROPERTY _EP_LOG_TEST )
if ( log )
set ( log LOG 1 )
else ( )
set ( log "" )
endif ( )
ExternalProject_Add_Step ( ${ name } test
C O M M A N D $ { c m d }
W O R K I N G _ D I R E C T O R Y $ { b i n a r y _ d i r }
$ { d e p _ a r g s }
$ { l o g }
)
endif ( )
endfunction ( _ep_add_test_command )
function ( ExternalProject_Add name )
_ep_get_configuration_subdir_suffix ( cfgdir )
# Add a custom target for the external project.
set ( cmf_dir ${ CMAKE_CURRENT_BINARY_DIR } /CMakeFiles )
add_custom_target ( ${ name } ALL DEPENDS ${ cmf_dir } ${ cfgdir } / ${ name } -complete )
set_property ( TARGET ${ name } PROPERTY _EP_IS_EXTERNAL_PROJECT 1 )
_ep_parse_arguments ( ExternalProject_Add ${ name } _EP_ "${ARGN}" )
_ep_set_directories ( ${ name } )
ExternalProject_Get_Property ( ${ name } stamp_dir )
# The 'complete' step depends on all other steps and creates a
# 'done' mark. A dependent external project's 'configure' step
# depends on the 'done' mark so that it rebuilds when this project
# rebuilds. It is important that 'done' is not the output of any
# custom command so that CMake does not propagate build rules to
# other external project targets.
add_custom_command (
O U T P U T $ { c m f _ d i r } $ { c f g d i r } / $ { n a m e } - c o m p l e t e
C O M M E N T " C o m p l e t e d ' $ { n a m e } ' "
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y $ { c m f _ d i r } $ { c f g d i r }
C O M M A N D $ { C M A K E _ C O M M A N D } - E t o u c h $ { c m f _ d i r } $ { c f g d i r } / $ { n a m e } - c o m p l e t e
C O M M A N D $ { C M A K E _ C O M M A N D } - E t o u c h $ { s t a m p _ d i r } $ { c f g d i r } / $ { n a m e } - d o n e
D E P E N D S $ { s t a m p _ d i r } $ { c f g d i r } / $ { n a m e } - i n s t a l l
V E R B A T I M
)
# Depend on other external projects (target-level).
get_property ( deps TARGET ${ name } PROPERTY _EP_DEPENDS )
foreach ( arg IN LISTS deps )
add_dependencies ( ${ name } ${ arg } )
endforeach ( )
# Set up custom build steps based on the target properties.
# Each step depends on the previous one.
#
# The target depends on the output of the final step.
# (Already set up above in the DEPENDS of the add_custom_target command.)
#
_ep_add_mkdir_command ( ${ name } )
_ep_add_download_command ( ${ name } )
_ep_add_update_command ( ${ name } )
_ep_add_patch_command ( ${ name } )
_ep_add_configure_command ( ${ name } )
_ep_add_build_command ( ${ name } )
_ep_add_install_command ( ${ name } )
# Test is special in that it might depend on build, or it might depend
# on install.
#
_ep_add_test_command ( ${ name } )
endfunction ( ExternalProject_Add )