diff --git a/Modules/AddExternalProject.cmake b/Modules/AddExternalProject.cmake index 9e14bd24f..5fd6df046 100644 --- a/Modules/AddExternalProject.cmake +++ b/Modules/AddExternalProject.cmake @@ -36,12 +36,78 @@ function(get_configure_build_working_dir name working_dir_var) endfunction(get_configure_build_working_dir) +function(get_configure_command_id name cfg_cmd_id_var) + get_target_property(cmd ${name} AEP_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) + else() + if(cmd MATCHES "cmake") + set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE) + else() + if(cmd MATCHES "config") + set(${cfg_cmd_id_var} "configure" PARENT_SCOPE) + else() + set(${cfg_cmd_id_var} "unknown:${cmd}" PARENT_SCOPE) + endif() + endif() + endif() + endif() + endif() +endfunction(get_configure_command_id) + + function(add_external_project_download_command name) set(added 0) get_external_project_directories(base_dir build_dir downloads_dir install_dir sentinels_dir source_dir tmp_dir) + if(NOT added) + get_target_property(cmd ${name} AEP_DOWNLOAD_COMMAND) + if(cmd STREQUAL "") + # Explicit empty string means no download step for this project + add_custom_command( + OUTPUT ${sentinels_dir}/${name}-download + COMMAND ${CMAKE_COMMAND} -E touch ${sentinels_dir}/${name}-download + WORKING_DIRECTORY ${sentinels_dir} + COMMENT "No download step for '${name}'" + ) + set(added 1) + else() + if(cmd) + set(args "") + get_target_property(download_args ${name} AEP_DOWNLOAD_ARGS) + if(download_args) + set(args "${download_args}") + separate_arguments(args) + endif() + + add_custom_command( + OUTPUT ${sentinels_dir}/${name}-download + COMMAND ${cmd} ${args} + COMMAND ${CMAKE_COMMAND} -E touch ${sentinels_dir}/${name}-download + WORKING_DIRECTORY ${downloads_dir} + COMMENT "Performing download step for '${name}'" + ) + set(added 1) + else() + # No explicit DOWNLOAD_COMMAND property. Look for other properties + # indicating which download method to use in the logic below... + endif() + endif() + endif() + + if(NOT added) get_target_property(cvs_repository ${name} AEP_CVS_REPOSITORY) if(cvs_repository) @@ -275,13 +341,21 @@ function(add_external_project_build_command name) DEPENDS ${sentinels_dir}/${name}-configure ) else() + get_configure_command_id(${name} cfg_cmd_id) + if(NOT cmd) - set(cmd ${CMAKE_COMMAND}) + set(cmd make) + if(cfg_cmd_id STREQUAL "cmake") + set(cmd ${CMAKE_COMMAND}) + endif() endif() get_target_property(args ${name} AEP_BUILD_ARGS) if(NOT args) - set(args --build ${working_dir} --config ${CMAKE_CFG_INTDIR}) + set(args) + if(cfg_cmd_id STREQUAL "cmake") + set(args --build ${working_dir} --config ${CMAKE_CFG_INTDIR}) + endif() endif() add_custom_command( @@ -312,13 +386,24 @@ function(add_external_project_install_command name) DEPENDS ${sentinels_dir}/${name}-build ) else() + get_configure_command_id(${name} cfg_cmd_id) + if(NOT cmd) - set(cmd ${CMAKE_COMMAND}) + set(cmd make) + if(cfg_cmd_id STREQUAL "cmake") + set(cmd ${CMAKE_COMMAND}) + endif() endif() get_target_property(args ${name} AEP_INSTALL_ARGS) if(NOT args) - set(args --build ${working_dir} --config ${CMAKE_CFG_INTDIR} --target install) + set(args) + if(cfg_cmd_id STREQUAL "cmake") + set(args --build ${working_dir} --config ${CMAKE_CFG_INTDIR} --target install) + endif() + if(cfg_cmd_id STREQUAL "configure") + set(args "install") + endif() endif() add_custom_command( @@ -339,123 +424,101 @@ function(add_CMakeExternals_target) sentinels_dir source_dir tmp_dir) add_custom_command( - OUTPUT ${tmp_dir} + OUTPUT ${sentinels_dir}/CMakeExternals-directories COMMAND ${CMAKE_COMMAND} -E make_directory ${build_dir} COMMAND ${CMAKE_COMMAND} -E make_directory ${downloads_dir} COMMAND ${CMAKE_COMMAND} -E make_directory ${install_dir} COMMAND ${CMAKE_COMMAND} -E make_directory ${sentinels_dir} COMMAND ${CMAKE_COMMAND} -E make_directory ${source_dir} COMMAND ${CMAKE_COMMAND} -E make_directory ${tmp_dir} + COMMAND ${CMAKE_COMMAND} -E touch ${sentinels_dir}/CMakeExternals-directories + COMMENT "Creating CMakeExternals directories" ) add_custom_target(CMakeExternals ALL - DEPENDS ${tmp_dir} + DEPENDS ${sentinels_dir}/CMakeExternals-directories ) endif() endfunction(add_CMakeExternals_target) +function(is_known_aep_property_key key result_var) + set(${result_var} 0 PARENT_SCOPE) + + if(key MATCHES "^BUILD_ARGS|BUILD_COMMAND|CONFIGURE_ARGS|CONFIGURE_COMMAND|CONFIGURE_DIR|CVS_REPOSITORY|CVS_MODULE|CVS_TAG|DEPENDS|DOWNLOAD_ARGS|DOWNLOAD_COMMAND|DIR|INSTALL_ARGS|INSTALL_COMMAND|SVN_REPOSITORY|SVN_TAG|TAR|TAR_URL|TGZ|TGZ_URL$" + ) + #message(STATUS "info: recognized via MATCHES - key='${key}'") + set(${result_var} 1 PARENT_SCOPE) + else() + message(STATUS "warning: is_known_aep_property_key unknown key='${key}'") + endif() +endfunction(is_known_aep_property_key) + + function(add_external_project name) get_external_project_directories(base_dir build_dir downloads_dir install_dir sentinels_dir source_dir tmp_dir) + + # Ensure root CMakeExternals target and directories are created. + # All external projects will depend on this root CMakeExternals target. + # add_CMakeExternals_target() + + # Add a custom target for the external project and make its DEPENDS + # the output of the final build step: + # add_custom_target(${name} ALL DEPENDS ${sentinels_dir}/${name}-install ) set_target_properties(${name} PROPERTIES AEP_IS_EXTERNAL_PROJECT 1) + add_dependencies(${name} CMakeExternals) - # Loop over ARGN by 2's extracting key/value pairs from - # the non-explicit arguments to the function: + + # 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. + # + # Loop over ARGN by 2's extracting key/value pairs from the non-explicit + # arguments to this function: # list(LENGTH ARGN n) set(i 0) while(i LESS n) math(EXPR j ${i}+1) + list(GET ARGN ${i} key) list(GET ARGN ${j} value) - #message(STATUS " ${key}='${value}'") - if(key STREQUAL "BUILD_ARGS") - set_target_properties(${name} PROPERTIES AEP_BUILD_ARGS "${value}") - endif() + is_known_aep_property_key("${key}" is_known_key) - if(key STREQUAL "BUILD_COMMAND") - set_target_properties(${name} PROPERTIES AEP_BUILD_COMMAND "${value}") - endif() - - if(key STREQUAL "CONFIGURE_ARGS") - set_target_properties(${name} PROPERTIES AEP_CONFIGURE_ARGS "${value}") - endif() - - if(key STREQUAL "CONFIGURE_COMMAND") - set_target_properties(${name} PROPERTIES AEP_CONFIGURE_COMMAND "${value}") - endif() - - if(key STREQUAL "CONFIGURE_DIR") - set_target_properties(${name} PROPERTIES AEP_CONFIGURE_DIR "${value}") - endif() - - if(key STREQUAL "CVS_REPOSITORY") - set_target_properties(${name} PROPERTIES AEP_CVS_REPOSITORY "${value}") - endif() - - if(key STREQUAL "CVS_MODULE") - set_target_properties(${name} PROPERTIES AEP_CVS_MODULE "${value}") - endif() - - if(key STREQUAL "CVS_TAG") - set_target_properties(${name} PROPERTIES AEP_CVS_TAG "${value}") - endif() - - if(key STREQUAL "DEPENDS") - add_dependencies(${name} ${value}) - endif() - - if(key STREQUAL "DIR") - set_target_properties(${name} PROPERTIES AEP_DIR "${value}") - endif() - - if(key STREQUAL "INSTALL_ARGS") - set_target_properties(${name} PROPERTIES AEP_INSTALL_ARGS "${value}") - endif() - - if(key STREQUAL "INSTALL_COMMAND") - set_target_properties(${name} PROPERTIES AEP_INSTALL_COMMAND "${value}") - endif() - - if(key STREQUAL "SVN_REPOSITORY") - set_target_properties(${name} PROPERTIES AEP_SVN_REPOSITORY "${value}") - endif() - - if(key STREQUAL "SVN_TAG") - set_target_properties(${name} PROPERTIES AEP_SVN_TAG "${value}") - endif() - - if(key STREQUAL "TAR") - set_target_properties(${name} PROPERTIES AEP_TAR "${value}") - endif() - - if(key STREQUAL "TAR_URL") - set_target_properties(${name} PROPERTIES AEP_TAR_URL "${value}") - endif() - - if(key STREQUAL "TGZ") - set_target_properties(${name} PROPERTIES AEP_TGZ "${value}") - endif() - - if(key STREQUAL "TGZ_URL") - set_target_properties(${name} PROPERTIES AEP_TGZ_URL "${value}") + if(is_known_key) + if(key STREQUAL "DEPENDS") + if(NOT value STREQUAL "") + add_dependencies(${name} ${value}) + else() + message(STATUS "warning: empty DEPENDS value in add_external_project") + endif() + else() + set_target_properties(${name} PROPERTIES AEP_${key} "${value}") + endif() + else() + message(SEND_ERROR "error: unknown add_external_project key with name='${name}' key='${key}' value='${value}'") endif() math(EXPR i ${i}+2) endwhile() + + # 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.) + # add_external_project_download_command(${name}) add_external_project_configure_command(${name}) add_external_project_build_command(${name}) add_external_project_install_command(${name}) - - add_dependencies(${name} CMakeExternals) endfunction(add_external_project) diff --git a/Tests/ExternalProject/CMakeLists.txt b/Tests/ExternalProject/CMakeLists.txt index c894037d1..00fffc9b4 100644 --- a/Tests/ExternalProject/CMakeLists.txt +++ b/Tests/ExternalProject/CMakeLists.txt @@ -16,23 +16,64 @@ set(prefix "${install_dir}") # include("${CMAKE_CURRENT_SOURCE_DIR}/TryCheckout.cmake") -try_cvs_checkout( - ":pserver:anonymous:cmake@www.cmake.org:/cvsroot/CMake" - "CMake/Tests/Tutorial/Step1" - "${CMAKE_CURRENT_BINARY_DIR}/TryCheckout/TutorialStep1" - can_use_cvs - ) +if(NOT DEFINED can_use_cvs) + try_cvs_checkout( + ":pserver:anonymous:cmake@www.cmake.org:/cvsroot/CMake" + "CMake/Tests/Tutorial/Step1" + "${CMAKE_CURRENT_BINARY_DIR}/TryCheckout/TutorialStep1" + can_use_cvs + ) + set(can_use_cvs ${can_use_cvs} CACHE STRING "Was try_cvs_checkout successful?") +endif() -try_svn_checkout( - "http://gdcm.svn.sourceforge.net/svnroot/gdcm/trunk/Utilities/gdcmmd5" - "${CMAKE_CURRENT_BINARY_DIR}/TryCheckout/gdcmmd5" - can_use_svn - ) +if(NOT DEFINED can_use_svn) + try_svn_checkout( + "http://gdcm.svn.sourceforge.net/svnroot/gdcm/trunk/Utilities/gdcmmd5" + "${CMAKE_CURRENT_BINARY_DIR}/TryCheckout/gdcmmd5" + can_use_svn + ) + set(can_use_svn ${can_use_svn} CACHE STRING "Was try_svn_checkout successful?") +endif() message(STATUS "can_use_cvs='${can_use_cvs}'") message(STATUS "can_use_svn='${can_use_svn}'") +# Empty projects that test all the known add_external_project argument key words: +# +set(proj MinimalNoOpProject) +add_external_project(${proj} + BUILD_COMMAND "" + CONFIGURE_COMMAND "" + DOWNLOAD_COMMAND "" + INSTALL_COMMAND "" +) + +set(proj EmptyNoOpProject) +add_external_project(${proj} + BUILD_ARGS "" + BUILD_COMMAND "" + CONFIGURE_ARGS "" + CONFIGURE_COMMAND "" + CONFIGURE_DIR "" + CVS_REPOSITORY "" + CVS_MODULE "" + CVS_TAG "" + DEPENDS "MinimalNoOpProject" + DIR "" + DOWNLOAD_ARGS "" + DOWNLOAD_COMMAND "" + INSTALL_ARGS "" + INSTALL_COMMAND "" + SVN_REPOSITORY "" + SVN_TAG "" + TAR "" + TAR_URL "" + TGZ "" + TGZ_URL "" +) + + # Local DIR: # set(proj TutorialStep5-Local) @@ -70,7 +111,7 @@ add_external_project(${proj} set(proj TutorialStep1-LocalNoDirTGZ) add_external_project(${proj} - TGZ "${CMAKE_CURRENT_SOURCE_DIR}/Step1.tgz" + TGZ "${CMAKE_CURRENT_SOURCE_DIR}/Step1NoDir.tgz" CONFIGURE_ARGS "\"-DCMAKE_INSTALL_PREFIX:PATH=${prefix}\" -G \"${CMAKE_GENERATOR}\" \"${source_dir}/${proj}\"" INSTALL_COMMAND "" ) @@ -91,12 +132,13 @@ add_external_project(${proj} if(can_use_cvs) # CVS by date stamp: # - set(proj KWStyle-20081201) + set(proj TutorialStep1-20081201) add_external_project(${proj} - CVS_REPOSITORY ":pserver:anoncvs@public.kitware.com:/cvsroot/KWStyle" - CVS_MODULE "KWStyle" + CVS_REPOSITORY ":pserver:anonymous:cmake@www.cmake.org:/cvsroot/CMake" + CVS_MODULE "CMake/Tests/Tutorial/Step1" CVS_TAG "-D\;2008-12-01 01:00:00 UTC" CONFIGURE_ARGS "\"-DCMAKE_INSTALL_PREFIX:PATH=${prefix}\" -G \"${CMAKE_GENERATOR}\" \"${source_dir}/${proj}\"" + INSTALL_COMMAND "" ) # CVS by tag: @@ -112,12 +154,19 @@ if(can_use_cvs) # Live CVS / HEAD (no CVS_TAG): # - set(proj TutorialStep1-CVSHEAD) + set(proj KWStyle-CVSHEAD) add_external_project(${proj} - CVS_REPOSITORY ":pserver:anonymous:cmake@www.cmake.org:/cvsroot/CMake" - CVS_MODULE "CMake/Tests/Tutorial/Step1" + CVS_REPOSITORY ":pserver:anoncvs@public.kitware.com:/cvsroot/KWStyle" + CVS_MODULE "KWStyle" CONFIGURE_ARGS "\"-DCMAKE_INSTALL_PREFIX:PATH=${prefix}\" -G \"${CMAKE_GENERATOR}\" \"${source_dir}/${proj}\"" - INSTALL_COMMAND "" + DEPENDS "EmptyNoOpProject" + DEPENDS "TutorialStep5-Local" + DEPENDS "TutorialStep1-LocalTAR" + DEPENDS "TutorialStep1-LocalNoDirTAR" + DEPENDS "TutorialStep1-LocalTGZ" + DEPENDS "TutorialStep1-LocalNoDirTGZ" + DEPENDS "TutorialStep1-20081201" + DEPENDS "kwsys-from-CMake-2-6-2" ) endif() @@ -162,7 +211,7 @@ enable_testing() # Use these as input to the KWStyle tests: # -set(kwstyleXmlFile "${source_dir}/KWStyle-20081201/Testing/Data/0001-KWStyleConfiguration.kws.xml") +set(kwstyleXmlFile "${source_dir}/KWStyle-CVSHEAD/Testing/Data/0001-KWStyleConfiguration.kws.xml") set(header "${install_dir}/include/TutorialConfig.h") @@ -187,14 +236,14 @@ add_test(TutorialStep1-LocalNoDirTGZ-BuildTreeTest "${build_dir}/TutorialStep1-LocalNoDirTGZ/Tutorial" 9) if(can_use_cvs) - add_test(KWStyle-20081201-BuildTreeTest - "${build_dir}/KWStyle-20081201/KWStyle" -xml "${kwstyleXmlFile}" "${header}") + add_test(TutorialStep1-20081201-BuildTreeTest + "${build_dir}/TutorialStep1-20081201/Tutorial" 4) add_test(kwsys-from-CMake-2-6-2-BuildTreeTest "${build_dir}/kwsys-from-CMake-2-6-2/kwsysTestProcess" 1) - add_test(TutorialStep1-CVSHEAD-BuildTreeTest - "${build_dir}/TutorialStep1-LocalNoDirTGZ/Tutorial" 4) + add_test(KWStyle-CVSHEAD-BuildTreeTest + "${build_dir}/KWStyle-CVSHEAD/KWStyle" -xml "${kwstyleXmlFile}" "${header}") endif() if(can_use_svn)