Cloned SEACAS for EXODUS library with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1678 lines
56 KiB

# @HEADER
# ************************************************************************
#
# TriBITS: Tribal Build, Integrate, and Test System
# Copyright 2013 Sandia Corporation
#
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
# the U.S. Government retains certain rights in this software.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the Corporation nor the names of the
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# ************************************************************************
# @HEADER
include(TribitsGetCDashUrlsInsideCTestS)
# Wrapper used for unit testing purposes
#
macro(extrarepo_execute_process_wrapper)
if (NOT CTEST_DEPENDENCY_HANDLING_UNIT_TESTING)
execute_process(${ARGN}
RESULT_VARIABLE EXTRAREPO_EXECUTE_PROCESS_WRAPPER_RTN_VAL)
if (NOT EXTRAREPO_EXECUTE_PROCESS_WRAPPER_RTN_VAL STREQUAL "0")
message(SEND_ERROR
"Error: execute_process(${ARGN}) returned"
" '${EXTRAREPO_EXECUTE_PROCESS_WRAPPER_RTN_VAL}'")
endif()
else()
message("execute_process(${ARGN})")
endif()
endmacro()
# Update an existing git repo
#
function(tribits_update_git_extrarepo GIT_EXE EXTRAREPO_SRC_DIR)
set(EXTRAREPO_FETCH_OUT_FILE
"${CTEST_BINARY_DIRECTORY}/${EXTRAREPO_NAME_IN}.fetch.out")
set(EXTRAREPO_CLEAN_OUT_FILE
"${CTEST_BINARY_DIRECTORY}/${EXTRAREPO_NAME_IN}.clean.out")
set(EXTRAREPO_RESET_OUT_FILE
"${CTEST_BINARY_DIRECTORY}/${EXTRAREPO_NAME_IN}.reset.out")
set(EXTRAREPO_SET_BRANCH_OUT_FILE
"${CTEST_BINARY_DIRECTORY}/${EXTRAREPO_NAME_IN}.set_branch.out")
set(FETCH_CMND_ARGS
COMMAND "${GIT_EXE}" fetch ${${PROJECT_NAME}_GIT_REPOSITORY_REMOTE}
TIMEOUT 600 # seconds
WORKING_DIRECTORY "${EXTRAREPO_SRC_DIR}"
OUTPUT_FILE "${EXTRAREPO_FETCH_OUT_FILE}" )
set(CLEAN_CMND_ARGS
COMMAND "${GIT_EXE}" clean -fdx
WORKING_DIRECTORY "${EXTRAREPO_SRC_DIR}"
OUTPUT_FILE "${EXTRAREPO_CLEAN_OUT_FILE}" )
set(RESET_CMND_ARGS
COMMAND "${GIT_EXE}" reset --hard HEAD
WORKING_DIRECTORY "${EXTRAREPO_SRC_DIR}"
OUTPUT_FILE "${EXTRAREPO_RESET_OUT_FILE}" )
if (${PROJECT_NAME}_EXTRAREPOS_BRANCH)
set(SET_BRANCH_CMND_ARGS
COMMAND "${GIT_EXE}" checkout -B ${${PROJECT_NAME}_EXTRAREPOS_BRANCH}
--track ${${PROJECT_NAME}_GIT_REPOSITORY_REMOTE}/${${PROJECT_NAME}_EXTRAREPOS_BRANCH}
WORKING_DIRECTORY "${EXTRAREPO_SRC_DIR}"
OUTPUT_FILE "${EXTRAREPO_SET_BRANCH_OUT_FILE}" )
ELSE ()
set(SET_BRANCH_CMND_ARGS
COMMAND "${GIT_EXE}" reset --hard "@{u}"
WORKING_DIRECTORY "${EXTRAREPO_SRC_DIR}"
OUTPUT_FILE "${EXTRAREPO_SET_BRANCH_OUT_FILE}" )
endif()
extrarepo_execute_process_wrapper(${FETCH_CMND_ARGS})
extrarepo_execute_process_wrapper(${CLEAN_CMND_ARGS})
extrarepo_execute_process_wrapper(${RESET_CMND_ARGS})
extrarepo_execute_process_wrapper(${SET_BRANCH_CMND_ARGS})
endfunction()
# Update or clone a single extra repo
#
function(tribits_clone_or_update_extrarepo EXTRAREPO_NAME_IN EXTRAREPO_DIR_IN
EXTRAREPO_REPOTYPE_IN EXTRAREPO_REPOURL_IN
)
#message("TRIBITS_CLONE_OR_UPDATE_EXTRAREPO: ${EXTRAREPO_NAME_IN} ${EXTRAREPO_REPOURL_IN}")
set(EXTRAREPO_SRC_DIR "${${PROJECT_NAME}_SOURCE_DIRECTORY}/${EXTRAREPO_DIR_IN}")
#print_var(EXTRAREPO_SRC_DIR)
set(EXTRAREPO_CLONE_OUT_FILE
"${CTEST_BINARY_DIRECTORY}/${EXTRAREPO_NAME_IN}.clone.out")
set(EXTRAREPO_CHECKOUT_OUT_FILE
"${CTEST_BINARY_DIRECTORY}/${EXTRAREPO_NAME_IN}.checkout.out")
if (NOT EXISTS "${EXTRAREPO_SRC_DIR}")
message("\n${EXTRAREPO_NAME_IN}: Doing initial ${EXTRAREPO_REPOTYPE_IN}"
" clone/checkout from URL '${EXTRAREPO_REPOURL_IN}' to dir '${EXTRAREPO_DIR_IN}' ...")
# Set the command to clone
if (${EXTRAREPO_REPOTYPE_IN} STREQUAL GIT)
if (${PROJECT_NAME}_EXTRAREPOS_BRANCH)
set(CHECKOUT_BRANCH_ARG -b ${${PROJECT_NAME}_EXTRAREPOS_BRANCH})
else()
set(CHECKOUT_BRANCH_ARG)
endif()
set(CLONE_CMND_ARGS
COMMAND "${GIT_EXECUTABLE}" clone
${CHECKOUT_BRANCH_ARG} -o ${${PROJECT_NAME}_GIT_REPOSITORY_REMOTE}
"${EXTRAREPO_REPOURL}" ${EXTRAREPO_DIR_IN}
WORKING_DIRECTORY "${${PROJECT_NAME}_SOURCE_DIRECTORY}"
OUTPUT_FILE "${EXTRAREPO_CLONE_OUT_FILE}" )
else()
message(SEND_ERROR
"Error, Invalid EXTRAREPO_REPOTYPE_IN='${EXTRAREPO_REPOTYPE_IN}'!")
endif()
# Do the clone
extrarepo_execute_process_wrapper(${CLONE_CMND_ARGS})
else()
message("\n${EXTRAREPO_NAME_IN}: Doing ${EXTRAREPO_REPOTYPE_IN} update"
" from URL '${EXTRAREPO_REPOURL_IN}' to dir '${EXTRAREPO_SRC_DIR}' ...")
endif()
if (${EXTRAREPO_REPOTYPE_IN} STREQUAL GIT)
# Always update the git repo, even after a clone. See
# tribits_ctest_driver() documentation.
tribits_update_git_extrarepo("${GIT_EXECUTABLE}" "${EXTRAREPO_SRC_DIR}")
else()
message(SEND_ERROR
"Error, Invalid EXTRAREPO_REPOTYPE_IN='${EXTRAREPO_REPOTYPE_IN}'!")
endif()
endfunction()
# Clone or update all of the extra repos and put them on the right branch.
#
# NOTE: The base repo is cloned by ctest_start() and updated by ctest_update()
# before calling this function. This function only operates on the extra
# repos.
#
function(tribits_clone_or_update_extra_repos CTEST_UPDATE_RETURN_VAL
UPDATE_FAILED_VAR_OUT
)
set(UPDATE_FAILED FALSE)
if (${PROJECT_NAME}_EXTRAREPOS_BRANCH)
message("For extra repos, doing switch to branch ${${PROJECT_NAME}_EXTRAREPOS_BRANCH}")
endif()
set(EXTRAREPO_IDX 0)
foreach(EXTRAREPO_NAME ${${PROJECT_NAME}_ALL_EXTRA_REPOSITORIES})
list(GET ${PROJECT_NAME}_ALL_EXTRA_REPOSITORIES_DIRS ${EXTRAREPO_IDX}
EXTRAREPO_DIR )
list(GET ${PROJECT_NAME}_ALL_EXTRA_REPOSITORIES_VCTYPES ${EXTRAREPO_IDX}
EXTRAREPO_REPOTYPE )
list(GET ${PROJECT_NAME}_ALL_EXTRA_REPOSITORIES_REPOURLS ${EXTRAREPO_IDX}
EXTRAREPO_REPOURL )
tribits_clone_or_update_extrarepo( ${EXTRAREPO_NAME} ${EXTRAREPO_DIR}
${EXTRAREPO_REPOTYPE} ${EXTRAREPO_REPOURL} )
# ToDo: Detect and return failure in cloning or updating extra repos!
math(EXPR EXTRAREPO_IDX "${EXTRAREPO_IDX}+1")
endforeach()
set(${UPDATE_FAILED_VAR_OUT} ${UPDATE_FAILED} PARENT_SCOPE)
endfunction()
# Create the Updates.txt file
#
function(tribits_create_repo_updates_file)
extrarepo_execute_process_wrapper(
COMMAND ${PYTHON_EXECUTABLE}
${GITDIST_EXE} --dist-no-color
log "--pretty=format:%h: %s%nAuthor: %an <%ae>%nDate: %ad%n"
--name-status -C ORIG_HEAD..HEAD
WORKING_DIRECTORY ${CTEST_SOURCE_DIRECTORY}
OUTPUT_FILE "${CTEST_BINARY_DIRECTORY}/Updates.txt"
)
endfunction()
# Select the set of extra repositories
#
macro(tribits_setup_extrarepos)
if (EXISTS "${${PROJECT_NAME}_EXTRAREPOS_FILE}" )
# Repos many not already exist because we have not cloned them yet!
set(${PROJECT_NAME}_CHECK_EXTRAREPOS_EXIST FALSE)
tribits_get_and_process_extra_repositories_lists()
else()
message("${${PROJECT_NAME}_EXTRAREPOS_FILE} does not exist,"
" skipping extra repositories.")
endif()
endmacro()
# Select the list of packages
#
# OUTPUT: Sets ${PROJECT_NAME}_DEFAULT_PACKAGES
#
# NOTE: This macro is used to clean up the main tribits_ctest_driver()
# macro.
#
macro(tribits_setup_packages)
include(TribitsPrintDependencyInfo)
include(TribitsWriteXmlDependenciesFiles)
# Here, we must point into the source tree just cloned (or updated)
# and not the "driver" source dir tree for two reasons. First, the
# list of core packages may be more recent in what was checked out.
# Second, the extra repos do not even exist in the "driver" source
# tree.
set(${PROJECT_NAME}_ASSERT_DEFINED_DEPENDENCIES OFF)
set(${PROJECT_NAME}_OUTPUT_DEPENDENCY_FILES FALSE)
if (CTEST_GENERATE_OUTER_DEPS_XML_OUTPUT_FILE)
set(${PROJECT_NAME}_DEPS_XML_OUTPUT_FILE
"${PROJECT_BINARY_DIR}/${${PROJECT_NAME}_PACKAGE_DEPS_XML_FILE_NAME}")
else()
set(${PROJECT_NAME}_DEPS_XML_OUTPUT_FILE)
endif()
if (CTEST_SUBMIT_CDASH_SUBPROJECTS_DEPS_FILE)
set(${PROJECT_NAME}_CDASH_DEPS_XML_OUTPUT_FILE
"${PROJECT_BINARY_DIR}/${${PROJECT_NAME}_CDASH_SUBPROJECT_DEPS_XML_FILE_NAME}" )
else()
set(${PROJECT_NAME}_CDASH_DEPS_XML_OUTPUT_FILE)
endif()
set(${PROJECT_NAME}_DEPS_HTML_OUTPUT_FILE)
# Don't ignore missing repos by default. This will allow processing to
# continue but this outer CTest script will fail (thereby sending a CDash
# email from the TDD system). However, when we configure actual packages,
# we do set this to TRUE so that the package configures will not fail due to
# missing extra repositories.
set_default_and_from_env(${PROJECT_NAME}_IGNORE_MISSING_EXTRA_REPOSITORIES FALSE)
set_default_and_from_env(${PROJECT_NAME}_PRE_REPOSITORIES "")
set_default_and_from_env(${PROJECT_NAME}_EXTRA_REPOSITORIES "")
split("${${PROJECT_NAME}_PRE_REPOSITORIES}" "," ${PROJECT_NAME}_PRE_REPOSITORIES)
split("${${PROJECT_NAME}_EXTRA_REPOSITORIES}" "," ${PROJECT_NAME}_EXTRA_REPOSITORIES)
tribits_read_in_native_repositories()
tribits_combine_native_and_extra_repos()
tribits_read_all_project_deps_files_create_deps_graph()
tribits_print_initial_dependency_info()
tribits_write_xml_dependency_files()
# When we get here, we will have the basic dependency structure set up
# with only defaults set
# Set this to "" so that it can be defined in enable_modified_packages_only()
set(${PROJECT_NAME}_ENABLE_ALL_PACKAGES "")
endmacro()
macro(enable_package_if_not_explicitly_excluded TRIBITS_PACKAGE)
if ("${${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE}}" STREQUAL "")
message("Enabling explicitly set package ${TRIBITS_PACKAGE} ...")
set(${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE} ON)
elseif(NOT ${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE})
if (${TRIBITS_PACKAGE}_EXPLICITY_EXCLUDED)
message("NOT enabling explicitly set package ${TRIBITS_PACKAGE} since it was explicitly excluded!")
else()
message("Enabling explicitly set package ${TRIBITS_PACKAGE} which was default or otherwise disabed!")
set(${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE} ON)
endif()
else()
message("Explicitly set package ${TRIBITS_PACKAGE} is already enabled?")
endif()
endmacro()
# Select packages set by the input
#
macro(enable_user_selected_packages)
# 1) Set the enables for packages
if (${PROJECT_NAME}_PACKAGE_ENABLES_FILE)
message("Setting package enables specified in file"
" '${${PROJECT_NAME}_PACKAGE_ENABLES_FILE}'")
include(${${PROJECT_NAME}_PACKAGE_ENABLES_FILE})
elseif (NOT "${${PROJECT_NAME}_PACKAGES_USER_SELECTED}" STREQUAL "")
foreach(TRIBITS_PACKAGE ${${PROJECT_NAME}_PACKAGES_USER_SELECTED})
enable_package_if_not_explicitly_excluded(${TRIBITS_PACKAGE})
endforeach()
else()
message("Setting ${PROJECT_NAME}_ENABLE_ALL_PACKAGES=ON since"
" ${PROJECT_NAME}_PACKAGES_USER_SELECTED='${${PROJECT_NAME}_PACKAGES_USER_SELECTED}'")
set(${PROJECT_NAME}_ENABLE_ALL_PACKAGES ON)
endif()
# 2) Set extra package enables from ${PROJECT_NAME}_ADDITIONAL_PACKAGES
foreach(TRIBITS_PACKAGE ${${PROJECT_NAME}_ADDITIONAL_PACKAGES})
enable_package_if_not_explicitly_excluded(${TRIBITS_PACKAGE})
endforeach()
endmacro()
# Extract the list of changed files for the main repo on put into an
# modified files file.
#
macro(tribits_get_modified_files WORKING_DIR_IN MODIFIED_FILES_FILE_NAME_IN)
set(CMND_ARGS
COMMAND "${GIT_EXECUTABLE}" diff --name-only ORIG_HEAD..HEAD
WORKING_DIRECTORY "${WORKING_DIR_IN}"
OUTPUT_FILE ${MODIFIED_FILES_FILE_NAME_IN}
#OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (NOT CTEST_DEPENDENCY_HANDLING_UNIT_TESTING)
execute_process(${CMND_ARGS})
else()
message("execute_process(${CMND_ARGS})")
endif()
endmacro()
# Select only packages that are modified or failed in the last CI iteration
#
macro(enable_only_modified_packages)
#
# A) Get the list of changed packages
#
set(MODIFIED_FILES_FILE_NAME "${CTEST_BINARY_DIRECTORY}/modifiedFiles.txt")
# A.1) Get changes from main ${PROJECT_NAME} repo
tribits_get_modified_files("${CTEST_SOURCE_DIRECTORY}" "${MODIFIED_FILES_FILE_NAME}")
# A.2) Get changes from extra repos
set(EXTRAREPO_IDX 0)
foreach(EXTRAREPO_NAME ${${PROJECT_NAME}_ALL_EXTRA_REPOSITORIES})
list(GET ${PROJECT_NAME}_ALL_EXTRA_REPOSITORIES_DIRS
${EXTRAREPO_IDX} EXTRAREPO_DIR )
list(GET ${PROJECT_NAME}_ALL_EXTRA_REPOSITORIES_HASPKGS
${EXTRAREPO_IDX} EXTRAREPO_PACKSTAT )
# For now, only look for changes if it has packages. Later, we may need
# to generalize this for the general extra repo case with deeper directory
# and other VC systems than GIT.
if (EXTRAREPO_PACKSTAT STREQUAL HASPACKAGES)
set(EXTRAREPO_SRC_DIR "${CTEST_SOURCE_DIRECTORY}/${EXTRAREPO_DIR}")
set(EXTRAREPO_MODIFIED_FILES_FILE_NAME
"${CTEST_BINARY_DIRECTORY}/modifiedFiles.${EXTRAREPO_NAME}.txt")
tribits_get_modified_files("${EXTRAREPO_SRC_DIR}"
"${EXTRAREPO_MODIFIED_FILES_FILE_NAME}")
file(STRINGS ${EXTRAREPO_MODIFIED_FILES_FILE_NAME} EXTRAREPO_MODIFIED_FILES_STR)
set(EXTRAREPO_FILES_STR "")
foreach(STR_LINE ${EXTRAREPO_MODIFIED_FILES_STR})
string(APPEND EXTRAREPO_FILES_STR "${EXTRAREPO_DIR}/${STR_LINE}\n")
endforeach()
file(APPEND "${MODIFIED_FILES_FILE_NAME}" ${EXTRAREPO_FILES_STR})
endif()
math(EXPR EXTRAREPO_IDX "${EXTRAREPO_IDX}+1")
endforeach()
# A.3) Get the names of the modified packages
if (NOT PYTHON_EXECUTABLE)
message(FATAL_ERROR "Error, Python must be enabled to map from modified"
" files to packages!")
endif()
if (EXISTS "${MODIFIED_FILES_FILE_NAME}")
execute_process(
COMMAND ${PYTHON_EXECUTABLE}
${${PROJECT_NAME}_TRIBITS_DIR}/ci_support/get-tribits-packages-from-files-list.py
--files-list-file=${MODIFIED_FILES_FILE_NAME}
--project-dir=${TRIBITS_PROJECT_ROOT}
--deps-xml-file=${CTEST_BINARY_DIRECTORY}/${${PROJECT_NAME}_PACKAGE_DEPS_XML_FILE_NAME}
OUTPUT_VARIABLE MODIFIED_PACKAGES_LIST
OUTPUT_STRIP_TRAILING_WHITESPACE
)
else()
set(MODIFIED_PACKAGES_LIST)
endif()
split("${MODIFIED_PACKAGES_LIST}" "," MODIFIED_PACKAGES_LIST)
print_var(MODIFIED_PACKAGES_LIST)
#
# B) Get the list of packages that failed last CI iteration
#
# NOTE: It is critical to enable and test packages until they pass. If you
# don't do this, then the package will not show as updated in the above
# logic. In this case only downstream packages will get enabled. If the
# failing packages break the downstream packages, this will be bad (for lots
# of reasons). Therefore, we must enable failing packages from the last CI
# iteration and keep enabling and testing them until they do pass!
if (EXISTS "${FAILED_PACKAGES_FILE_NAME}")
file(READ "${FAILED_PACKAGES_FILE_NAME}" FAILING_PACKAGES_LIST)
string(STRIP "${FAILING_PACKAGES_LIST}" FAILING_PACKAGES_LIST)
print_var(FAILING_PACKAGES_LIST)
endif()
#
# C) Enable the changed and previously failing packages
#
foreach(TRIBITS_PACKAGE ${MODIFIED_PACKAGES_LIST})
#print_var(${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE})
assert_defined(${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE})
if ("${${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE}}" STREQUAL "")
if (
${TRIBITS_PACKAGE} STREQUAL "ALL_PACKAGES"
OR
${TRIBITS_PACKAGE}_TESTGROUP STREQUAL "PT"
OR
(
${TRIBITS_PACKAGE}_TESTGROUP STREQUAL "ST"
AND
${PROJECT_NAME}_ENABLE_SECONDARY_TESTED_CODE
)
)
message("Enabling modified package: ${TRIBITS_PACKAGE}")
set(${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE} ON)
else()
message("NOT enabling modified ST package: ${TRIBITS_PACKAGE}")
endif()
else()
message("Not enabling explicitly disabled modified package: ${TRIBITS_PACKAGE}")
endif()
endforeach()
if (FAILING_PACKAGES_LIST STREQUAL "ALL_PACKAGES")
message("Enabling previously failing ALL_PACKAGES")
set(${PROJECT_NAME}_ENABLE_ALL_PACKAGES ON)
else()
foreach(TRIBITS_PACKAGE ${FAILING_PACKAGES_LIST})
if ("${${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE}}" STREQUAL "")
if (
${TRIBITS_PACKAGE}_TESTGROUP STREQUAL "PT"
OR
(
${TRIBITS_PACKAGE}_TESTGROUP STREQUAL "ST"
AND
${PROJECT_NAME}_ENABLE_SECONDARY_TESTED_CODE
)
)
message("Enabling previously failing package: ${TRIBITS_PACKAGE}")
set(${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE} ON)
else()
message("NOT enabling previously failing ST package: ${TRIBITS_PACKAGE}")
endif()
else()
message("Not enabling explicitly disabled previously"
" failing package: ${TRIBITS_PACKAGE}")
endif()
endforeach()
endif()
#
# D) Print the final status
#
if (${PROJECT_NAME}_ENABLE_ALL_PACKAGES)
if (NOT ${PROJECT_NAME}_CTEST_DO_ALL_AT_ONCE)
message(FATAL_ERROR
"Error, failing 'ALL_PACKAGES' only allowed with all-at-once mode!")
endif()
message("\nDirectly modified or failing non-disabled packages that need"
" to be tested: ALL_PACKAGES")
else()
tribits_print_package_list_enable_status(
"\nDirectly modified or failing non-disabled packages that need to be tested"
INTERNAL ON NONEMPTY )
endif()
endmacro()
# Exclude disabled packages from ${PROJECT_NAME}_EXCLUDE_PACKAGES
#
# NOTE: These disables need to dominate over the above enables so this code is
# after all the enable code has run
#
macro(disable_excluded_packages)
foreach(TRIBITS_PACKAGE ${${PROJECT_NAME}_EXCLUDE_PACKAGES})
message("Disabling excluded package ${TRIBITS_PACKAGE} ...")
set(${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE} OFF)
set(${TRIBITS_PACKAGE}_EXPLICITY_EXCLUDED TRUE)
endforeach()
endmacro()
# Remove packages that are only implicitly enabled but don't have tests
# enabled.
#
macro(select_final_set_of_packages_to_directly_test)
set(${PROJECT_NAME}_PACKAGES_TO_DIRECTLY_TEST)
foreach(TRIBITS_PACKAGE ${${PROJECT_NAME}_DEFINED_INTERNAL_TOPLEVEL_PACKAGES})
set(PROCESS_THE_PACKAGE FALSE)
if (${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE}
AND ${TRIBITS_PACKAGE}_ENABLE_TESTS
)
set(PROCESS_THE_PACKAGE TRUE)
elseif (${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE}
AND CTEST_EXPLICITLY_ENABLE_IMPLICITLY_ENABLED_PACKAGES
)
set(PROCESS_THE_PACKAGE TRUE)
endif()
if(PROCESS_THE_PACKAGE)
append_set(${PROJECT_NAME}_PACKAGES_TO_DIRECTLY_TEST ${TRIBITS_PACKAGE})
endif()
endforeach()
endmacro()
# Set mapping of labels to subprojects (i.e. TriBITS packages) for CDash.
#
# NOTE: Unlike for the inner CMake configure, only subprojects that are
# explicitly tested will be marked as a CDash subproject. This limits the
# rows in CDash. This does not seem to be a problem for when running ctest
# locally. When run locally, ctest will just report aggregated times for
# subprojects that have 1 or more tests. Not true for CDash.
#
macro(tribits_ctest_driver_set_labels_to_subprojects_mapping)
set(CTEST_LABELS_FOR_SUBPROJECTS)
foreach(TRIBITS_PACKAGE ${${PROJECT_NAME}_PACKAGES_TO_DIRECTLY_TEST})
list(APPEND CTEST_LABELS_FOR_SUBPROJECTS ${TRIBITS_PACKAGE})
endforeach()
endmacro()
# Select the default generator.
#
macro(select_default_generator)
# When the build tree is known and exists, use
# its generator.
set(DEFAULT_GENERATOR "DID NOT SET!")
if(EXISTS "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt")
file(STRINGS "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt"
line REGEX "^CMAKE_GENERATOR:" LIMIT_COUNT 1)
if("${line}" MATCHES "=(.+)$")
set(DEFAULT_GENERATOR "${CMAKE_MATCH_1}")
endif()
else()
set(DEFAULT_GENERATOR "Unix Makefiles")
endif()
endmacro()
# Call INITIALIZE_ERROR_QUEUE once at the top of TRIBITS_CTEST_DRIVER
#
macro(initialize_error_queue)
set(TRIBITS_CTEST_DRIVER_ERROR_QUEUE "")
endmacro()
# QUEUE_ERROR should be called only for errors that are not already reported to
# the dashboard in some other way. For example, if calling ctest_submit fails,
# then that failure does NOT show up on the dashboard, so it is appropriate to
# call QUEUE_ERROR for that case. For a build error or test failure, it is NOT
# appropriate to call QUEUE_ERROR because those already show up on the
# dashboard (assuming a good ctest_submit...)
#
# When adding more callers of QUEUE_ERROR, just make sure that it does not
# duplicate an existing/reported dashboard failure.
#
macro(queue_error err_msg)
set(TRIBITS_CTEST_DRIVER_ERROR_QUEUE
${TRIBITS_CTEST_DRIVER_ERROR_QUEUE} "${err_msg}")
endmacro()
# Call report_queued_errors() once at the bottom of tribits_ctest_driver()
#
macro(report_queued_errors)
if ("${TRIBITS_CTEST_DRIVER_ERROR_QUEUE}" STREQUAL "")
message("TRIBITS_CTEST_DRIVER_ERROR_QUEUE is empty. All is well.")
else()
message("ERROR: TRIBITS_CTEST_DRIVER_ERROR_QUEUE reports the following error message queue:")
foreach(err_msg ${TRIBITS_CTEST_DRIVER_ERROR_QUEUE})
message("${err_msg}")
endforeach()
endif()
endmacro()
# Setup for tracking if a configure is being attempted to keep memory if it
# will pass or not.
#
# This will wrilte files in the directory ${CTEST_BINARY_DIRECTORY} to keep
# track of this across multiple ctest -S script invocations.
#
macro(tribits_remember_if_configure_attempted)
# Must always define these files names as they they are used in functions
# called later in the same ctest -S invocation!
set(CONFIGURE_ATTEMPTED_FILE
"${CTEST_BINARY_DIRECTORY}/ConfigureAttempted.txt")
set(CONFIGURE_PASSED_FILE
"${CTEST_BINARY_DIRECTORY}/ConfigurePasssed.txt")
if (CTEST_DO_CONFIGURE)
file(WRITE "${CONFIGURE_ATTEMPTED_FILE}" "Attempting configure")
if (EXISTS "${CONFIGURE_PASSED_FILE}")
file(REMOVE "${CONFIGURE_PASSED_FILE}")
endif()
elseif(CTEST_DO_NEW_START)
if (EXISTS "${CONFIGURE_ATTEMPTED_FILE}")
file(REMOVE "${CONFIGURE_ATTEMPTED_FILE}")
endif()
if (EXISTS "${CONFIGURE_PASSED_FILE}")
file(REMOVE "${CONFIGURE_PASSED_FILE}")
endif()
endif()
endmacro()
# NOTE: Above, this is made a macro because it defines the vars
# CONFIGURE_ATTEMPTED_FILE and CONFIGURE_PASSED_FILE at the top function
# scope. This is needed so the below functions will see them set.
# Determine if a past configure was attempted but did not pass
#
function(tribits_previous_configure_attempted_but_not_passsed
PREVIOUS_CONFIGURE_ATTEMPTED_BUT_NOT_PASSSED_VAR_OUT
)
#print_var(CONFIGURE_ATTEMPTED_FILE)
#print_var(CONFIGURE_PASSED_FILE)
if(
(EXISTS "${CONFIGURE_ATTEMPTED_FILE}")
AND
(NOT EXISTS "${CONFIGURE_PASSED_FILE}")
)
set(PREVIOUS_CONFIGURE_ATTEMPTED_BUT_NOT_PASSSED TRUE)
else()
set(PREVIOUS_CONFIGURE_ATTEMPTED_BUT_NOT_PASSSED FALSE)
endif()
set(${PREVIOUS_CONFIGURE_ATTEMPTED_BUT_NOT_PASSSED_VAR_OUT}
${PREVIOUS_CONFIGURE_ATTEMPTED_BUT_NOT_PASSSED} PARENT_SCOPE)
endfunction()
# Remember that the configure passed for later ctest -S invocations
#
function(tribits_remember_configure_passed)
file(WRITE "${CONFIGURE_PASSED_FILE}" "Configure Passed!")
endfunction()
# Override CTEST_SUBMIT to drive multiple submits and to detect failed
# submissions and track them as queued errors.
#
macro(tribits_ctest_submit)
# Cache the original CTEST_DROP_SITE and CTEST_DROP_LOCATION
if ("${TRIBITS_CTEST_DROP_SITE_ORIG}" STREQUAL "")
set(TRIBITS_CTEST_DROP_SITE_ORIG ${CTEST_DROP_SITE})
if (TRIBITS_CTEST_SUBMIT_DEBUG_DUMP)
print_var(TRIBITS_CTEST_DROP_SITE_ORIG)
endif()
endif()
if ("${TRIBITS_CTEST_DROP_LOCATION_ORIG}" STREQUAL "")
set(TRIBITS_CTEST_DROP_LOCATION_ORIG ${CTEST_DROP_LOCATION})
if (TRIBITS_CTEST_SUBMIT_DEBUG_DUMP)
print_var(TRIBITS_CTEST_DROP_LOCATION_ORIG)
endif()
endif()
# Do the first submit
set(CTEST_DROP_SITE ${TRIBITS_CTEST_DROP_SITE_ORIG})
set(CTEST_DROP_LOCATION ${TRIBITS_CTEST_DROP_LOCATION_ORIG})
if (TRIBITS_CTEST_SUBMIT_DEBUG_DUMP)
print_var(CTEST_DROP_SITE)
print_var(CTEST_DROP_LOCATION)
endif()
tribits_ctest_submit_driver(${ARGN})
# Do the second submit if requested!
if (TRIBITS_2ND_CTEST_DROP_SITE OR TRIBITS_2ND_CTEST_DROP_LOCATION)
message("\nDoing submit to second CDash site ...\n")
if (NOT "${TRIBITS_2ND_CTEST_DROP_SITE}" STREQUAL "")
if (TRIBITS_CTEST_SUBMIT_DEBUG_DUMP)
print_var(TRIBITS_2ND_CTEST_DROP_SITE)
endif()
set(CTEST_DROP_SITE ${TRIBITS_2ND_CTEST_DROP_SITE})
endif()
if (NOT "${TRIBITS_2ND_CTEST_DROP_LOCATION}" STREQUAL "")
if (TRIBITS_CTEST_SUBMIT_DEBUG_DUMP)
print_var(TRIBITS_2ND_CTEST_DROP_LOCATION)
endif()
set(CTEST_DROP_LOCATION ${TRIBITS_2ND_CTEST_DROP_LOCATION})
endif()
tribits_ctest_submit_driver(${ARGN})
endif()
endmacro()
macro(tribits_ctest_submit_driver)
# If using a recent enough ctest with RETRY_COUNT, use it to overcome
# failed submits:
set(retry_args "")
set(retry_args
RETRY_COUNT ${CTEST_SUBMIT_RETRY_COUNT}
RETRY_DELAY ${CTEST_SUBMIT_RETRY_DELAY})
message("info: using retry_args='${retry_args}' for _ctest_submit call")
# Call the original CTEST_SUBMIT and pay attention to its RETURN_VALUE:
ctest_submit(${ARGN} ${retry_args} RETURN_VALUE rv)
if(NOT "${rv}" STREQUAL "0")
queue_error("error: ctest_submit failed: rv='${rv}' ARGN='${ARGN}' retry_args='${retry_args}'")
endif()
endmacro()
# Wrapper for ctest_update(...) for unit testing
#
macro(ctest_update_wrapper)
if (NOT CTEST_UPDATE_UNIT_TESTING_MODE)
ctest_update(${ARGN})
else()
message("ctest_update(${ARGN})")
set(UPDATE_RETURN_VAL ${CTEST_UPDATE_RETURN_VAL})
endif()
endmacro()
# Helper macros to pass through common CMake configure arguments used by both
# package-by-package approach and all-at-once approach
#
macro(tribits_fwd_cmake_config_args_0)
set( CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR}"
"-DCTEST_USE_LAUNCHERS:BOOL=${CTEST_USE_LAUNCHERS}"
"-D${PROJECT_NAME}_ENABLE_ALL_OPTIONAL_PACKAGES:BOOL=ON"
"-D${PROJECT_NAME}_WARNINGS_AS_ERRORS_FLAGS:STRING=${${PROJECT_NAME}_WARNINGS_AS_ERRORS_FLAGS}"
"-D${PROJECT_NAME}_ALLOW_NO_PACKAGES:BOOL=ON"
"-D${PROJECT_NAME}_DISABLE_ENABLED_FORWARD_DEP_PACKAGES=${${PROJECT_NAME}_DISABLE_ENABLED_FORWARD_DEP_PACKAGES}"
)
if (NOT CTEST_GENERATE_DEPS_XML_OUTPUT_FILE)
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_DEPS_XML_OUTPUT_FILE:FILEPATH=")
endif()
if (NOT "${${PROJECT_NAME}_GENERATE_VERSION_DATE_FILES}" STREQUAL "")
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_GENERATE_VERSION_DATE_FILES:BOOL=${${PROJECT_NAME}_GENERATE_VERSION_DATE_FILES}")
endif()
if (NOT "${${PROJECT_NAME}_ENABLE_SECONDARY_TESTED_CODE}" STREQUAL "")
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_ENABLE_SECONDARY_TESTED_CODE:BOOL=${${PROJECT_NAME}_ENABLE_SECONDARY_TESTED_CODE}")
endif()
if (NOT MPI_EXEC_MAX_NUMPROCS STREQUAL 0)
list(APPEND CONFIGURE_OPTIONS
"-DMPI_EXEC_MAX_NUMPROCS:STRING=${MPI_EXEC_MAX_NUMPROCS}")
endif()
if (${PROJECT_NAME}_SKIP_CTEST_ADD_TEST)
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_SKIP_CTEST_ADD_TEST:BOOL=${${PROJECT_NAME}_SKIP_CTEST_ADD_TEST}")
endif()
if (CTEST_DO_COVERAGE_TESTING)
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_ENABLE_COVERAGE_TESTING:BOOL=ON")
endif()
if (${PROJECT_NAME}_EXTRAREPOS_FILE STREQUAL "NONE")
set(EXTRAREOS_FILE_PASSED "")
else()
set(EXTRAREOS_FILE_PASSED "${${PROJECT_NAME}_EXTRAREPOS_FILE}")
endif()
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_EXTRAREPOS_FILE:STRING=${EXTRAREOS_FILE_PASSED}")
list(APPEND CONFIGURE_OPTIONS # See TRIBITS_SETUP_PACKAGES
"-D${PROJECT_NAME}_IGNORE_MISSING_EXTRA_REPOSITORIES:BOOL=ON")
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_ENABLE_KNOWN_EXTERNAL_REPOS_TYPE:STRING=${${PROJECT_NAME}_ENABLE_KNOWN_EXTERNAL_REPOS_TYPE}")
if (CTEST_DO_INSTALL)
list(APPEND CONFIGURE_OPTIONS
"-DCMAKE_SKIP_INSTALL_ALL_DEPENDENCY=ON")
endif()
endmacro()
macro(tribits_fwd_cmake_config_args_1)
set(CONFIGURE_OPTIONS ${CONFIGURE_OPTIONS}
${EXTRA_SYSTEM_CONFIGURE_OPTIONS} ${EXTRA_CONFIGURE_OPTIONS}
${${PROJECT_NAME}_EXTRA_CONFIGURE_OPTIONS} )
endmacro()
# Remove the all of the LastTestsFailed*.log files so we can determine if any
# tests have failed.
#
macro(tribits_remove_last_test_failed_log_file)
# Remove the LastTestsFailed log so we can detect if there are any
# failed tests.
set(TEST_TMP_DIR "${CTEST_BINARY_DIRECTORY}/Testing/Temporary")
set(LAST_TESTS_FILED_LOG_FILE_GLOB "${TEST_TMP_DIR}/LastTestsFailed*.log")
file(GLOB logfiles "${LAST_TESTS_FILED_LOG_FILE_GLOB}")
foreach(logfile ${logfiles})
file(REMOVE "${logfile}")
endforeach()
endmacro()
# Sets the var FAILED_TEST_LOG_FILE if the file is found
macro(tribits_find_last_test_failed_log_file)
file(GLOB FAILED_TEST_LOG_FILE "${LAST_TESTS_FILED_LOG_FILE_GLOB}")
endmacro()
# Get names of failed packages from failed tests
function(tribits_get_failed_packages_from_failed_tests
LAST_TESTS_FAILED_FILE FAILED_PACKAGES_OUT
)
execute_process(
COMMAND ${PYTHON_EXECUTABLE}
"${${PROJECT_NAME}_TRIBITS_DIR}/ci_support/get-tribits-packages-from-last-tests-failed.py"
"--deps-xml-file=${CTEST_BINARY_DIRECTORY}/${${PROJECT_NAME}_PACKAGE_DEPS_XML_FILE_NAME}"
"--last-tests-failed-file=${LAST_TESTS_FAILED_FILE}"
OUTPUT_VARIABLE FAILED_PACKAGES
OUTPUT_STRIP_TRAILING_WHITESPACE
)
split("${FAILED_PACKAGES}" "," FAILED_PACKAGES)
set(${FAILED_PACKAGES_OUT} "${FAILED_PACKAGES}" PARENT_SCOPE)
endfunction()
# Drive the configure, build, test, and submit package-by-package
#
# Sets ${PROJECT_NAME}_FAILED_PACKAGES as an indication if there are any
# failures.
#
macro(tribits_ctest_package_by_package)
message(
"\n***"
"\n*** Loop through ${PROJECT_NAME} packages to configure, build, and test ..."
"\n***")
set(${PROJECT_NAME}_LAST_CONFIGURED_PACKAGE)
set(${PROJECT_NAME}_FAILED_LIB_BUILD_PACKAGES)
set(PACKAGE_IDX 0)
foreach(TRIBITS_PACKAGE ${${PROJECT_NAME}_PACKAGES_TO_DIRECTLY_TEST})
message("")
message("${PACKAGE_IDX}) Processing current package ${TRIBITS_PACKAGE}:"
" libs='${${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE}}',"
" tests='${${TRIBITS_PACKAGE}_ENABLE_TESTS}'")
message("")
set_property(GLOBAL PROPERTY SubProject ${TRIBITS_PACKAGE})
set_property(GLOBAL PROPERTY Label ${TRIBITS_PACKAGE})
#
# A) Configure the package and its dependent packages
#
message("Configuring TRIBITS_PACKAGE='${TRIBITS_PACKAGE}'")
# Create CONFIGURE_OPTIONS for this TRIBITS_PACKAGE
tribits_fwd_cmake_config_args_0()
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_ENABLE_TESTS:BOOL=${${TRIBITS_PACKAGE}_ENABLE_TESTS}")
if (DEFINED ${PROJECT_NAME}_LAST_CONFIGURED_PACKAGE)
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_ENABLE_${${PROJECT_NAME}_LAST_CONFIGURED_PACKAGE}:BOOL=")
set(${PROJECT_NAME}_LAST_CONFIGURED_PACKAGE)
endif()
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_DEFINE_MISSING_PACKAGE_LIBS_TARGETS=ON")
foreach(FAILED_PACKAGE ${${PROJECT_NAME}_FAILED_LIB_BUILD_PACKAGES})
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_ENABLE_${FAILED_PACKAGE}:BOOL=OFF")
endforeach()
tribits_fwd_cmake_config_args_1()
list(APPEND CONFIGURE_OPTIONS # Package enable must be at the very end to override other stuff!
"-D${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE}:BOOL=ON" )
message("\nCONFIGURE_OPTIONS = '${CONFIGURE_OPTIONS}'")
# Remember this package so we can set its enable to "" next time
set(${PROJECT_NAME}_LAST_CONFIGURED_PACKAGE "${TRIBITS_PACKAGE}")
#
# B) Configure the package and its dependent packages
#
set(PBP_CONFIGURE_PASSED TRUE)
if (CTEST_DEPENDENCY_HANDLING_UNIT_TESTING)
message("${TRIBITS_PACKAGE}: Skipping configure due"
" to running in unit testing mode!")
else()
#
# We always have to configure if we are going to do anything for the
# package. We just want submit configure results to CDash if we are not
# asked to configure!
#
set(PBP_CONFIGURE_PASSED FALSE)
ctest_configure(
BUILD "${CTEST_BINARY_DIRECTORY}"
OPTIONS "${CONFIGURE_OPTIONS}" # New option!
RETURN_VALUE CONFIGURE_RETURN_VAL
)
message("Generating the file '${CMAKE_CACHE_CLEAN_FILE}' ...")
tribits_strip_comments_from_cmake_cache_file(
"${CTEST_BINARY_DIRECTORY}/CMakeCache.txt"
"${CMAKE_CACHE_CLEAN_FILE}"
)
# If the configure failed, add the package to the list
# of failed packages
if ("${CONFIGURE_RETURN_VAL}" EQUAL "0")
message("\n${TRIBITS_PACKAGE}: Configure passed!\n")
set(PBP_CONFIGURE_PASSED TRUE)
# load target properties and test keywords
ctest_read_custom_files(BUILD "${CTEST_BINARY_DIRECTORY}")
# Overridde from this file!
include("${TRIBITS_PROJECT_ROOT}/CTestConfig.cmake")
else()
message("\n${TRIBITS_PACKAGE} FAILED to configure!\n")
endif()
if (EXISTS ${CMAKE_CACHE_CLEAN_FILE})
set(CTEST_NOTES_FILES "${CTEST_NOTES_FILES_WO_CACHE};${CMAKE_CACHE_CLEAN_FILE}")
else()
set(CTEST_NOTES_FILES "${CTEST_NOTES_FILES_WO_CACHE}")
endif()
print_var(CTEST_NOTES_FILES)
if (NOT CTEST_DO_CONFIGURE AND CTEST_DO_SUBMIT)
message("${TRIBITS_PACKAGE}: Skipping submitting configure"
" and notes due to CTEST_DO_CONFIGURE='${CTEST_DO_CONFIGURE}'!")
elseif (CTEST_DO_SUBMIT)
message("\nSubmitting configure and notes ...")
tribits_ctest_submit( PARTS configure notes )
endif()
endif()
# Print out values read from project CTestCustom.cmake file!
print_var(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE)
print_var(CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE)
#
# C) Build the library and then ALL
#
set(PBP_BUILD_PASSED TRUE)
set(PBP_BUILD_LIBS_PASSED TRUE)
print_var(PBP_CONFIGURE_PASSED)
if ( NOT PBP_CONFIGURE_PASSED AND CTEST_DO_BUILD )
message("\n${TRIBITS_PACKAGE}: Skipping build due"
" to configure failing!")
set(PBP_BUILD_PASSED FALSE)
set(PBP_BUILD_LIBS_PASSED FALSE)
elseif (NOT CTEST_DO_BUILD)
message("\n${TRIBITS_PACKAGE}: Skipping build due"
" to CTEST_DO_BUILD='${CTEST_DO_BUILD}'!")
elseif (CTEST_DEPENDENCY_HANDLING_UNIT_TESTING OR
CTEST_CONFIGURATION_UNIT_TESTING
)
message("\n${TRIBITS_PACKAGE}: Skipping build due"
" to running in unit testing mode!")
else()
# Start by trying to build just the libraries for the current package
set( CTEST_BUILD_TARGET ${TRIBITS_PACKAGE}_libs )
message("\nBuilding target: '${CTEST_BUILD_TARGET}' ...\n")
set(PBP_BUILD_LIBS_PASSED FALSE)
ctest_build(
BUILD "${CTEST_BINARY_DIRECTORY}"
RETURN_VALUE BUILD_LIBS_RETURN_VAL
NUMBER_ERRORS BUILD_LIBS_NUM_ERRORS
APPEND
)
message("Build return: RETURN_VALUE=${BUILD_LIBS_RETURN_VAL},"
" NUMBER_ERRORS=${BUILD_LIBS_NUM_ERRORS}")
# Determine if the build failed or not.
if ("${BUILD_LIBS_NUM_ERRORS}" EQUAL "0")
message("\n${TRIBITS_PACKAGE}: Libs build passed!")
set(PBP_BUILD_LIBS_PASSED TRUE)
else()
message("\nFAILED library build for package '${TRIBITS_PACKAGE}'!")
set(PBP_BUILD_PASSED FALSE)
endif()
# Above: Since make -i is used BUILD_LIBS_RETURN_VAL might be 0, but
# if there are errors the build should fail, so both
# BUILD_LIBS_RETURN_VAL and BUILD_LIBS_NUM_ERRORS should be 0 for a
# good build and for the all target to be built.
# Submit the library build results to the dashboard
if (CTEST_DO_SUBMIT)
tribits_ctest_submit( PARTS build )
endif()
# If the build of the libraries passed, then go on the build
# the tests/examples and run them.
if (PBP_BUILD_LIBS_PASSED)
# Build the ALL target, but append the results to the last build.xml
set(CTEST_BUILD_TARGET)
message("\nBuild ALL target for '${TRIBITS_PACKAGE}' ...\n")
ctest_build(
BUILD "${CTEST_BINARY_DIRECTORY}"
RETURN_VALUE BUILD_ALL_RETURN_VAL
NUMBER_ERRORS BUILD_ALL_NUM_ERRORS
APPEND
)
message("Build all: BUILD_ALL_NUM_ERRORS='${BUILD_ALL_NUM_ERRORS}',"
"BUILD_ALL_RETURN_VAL='${BUILD_ALL_RETURN_VAL}'" )
if (NOT "${BUILD_ALL_NUM_ERRORS}" EQUAL "0")
message("${TRIBITS_PACKAGE}: All build FAILED!")
set(PBP_BUILD_PASSED FALSE)
else()
message("${TRIBITS_PACKAGE}: All build passed!")
endif()
# Submit the build for all target
if (CTEST_DO_SUBMIT)
tribits_ctest_submit( PARTS build )
endif()
endif()
endif()
#
# D) Run the tests
#
set(PBP_TESTS_PASSED TRUE)
if (NOT PBP_BUILD_LIBS_PASSED AND CTEST_DO_TEST)
message("\n${TRIBITS_PACKAGE}: Skipping tests since library build failed!\n")
set(PBP_TESTS_PASSED FALSE)
elseif (NOT CTEST_DO_TEST)
message("\n${TRIBITS_PACKAGE}: Skipping running tests due"
" to CTEST_DO_TEST='${CTEST_DO_TEST}'!")
else()
#
# D.1) Run the regular tests
#
set(PBP_TESTS_PASSED FALSE)
# Run the tests that match the ${TRIBITS_PACKAGE} name
message("\nRunning test for package '${TRIBITS_PACKAGE}'"
" (parallel level ${CTEST_PARALLEL_LEVEL}) ...\n")
tribits_remove_last_test_failed_log_file()
ctest_test(
BUILD "${CTEST_BINARY_DIRECTORY}"
PARALLEL_LEVEL "${CTEST_PARALLEL_LEVEL}"
INCLUDE_LABEL "^${TRIBITS_PACKAGE}$"
)
# See if a 'LastTestsFailed*.log' file exists to determine if there are
# failed tests
tribits_find_last_test_failed_log_file()
if (FAILED_TEST_LOG_FILE)
message("\n${TRIBITS_PACKAGE}: File '${FAILED_TEST_LOG_FILE}'"
" exists so there were failed tests!")
else()
message("\n${TRIBITS_PACKAGE}: File '${FAILED_TEST_LOG_FILE}'"
" does NOT exist so all tests passed!")
set(PBP_TESTS_PASSED TRUE)
endif()
# 2009/12/05: ToDo: We need to add an argument to ctest_test(...)
# called something like 'NUMBER_FAILED numFailedTests' to allow us to
# detect when the tests have filed.
if (CTEST_DO_SUBMIT)
tribits_ctest_submit( PARTS Test )
endif()
#
# D.2) Collect coverage results
#
if (CTEST_DO_COVERAGE_TESTING)
message("\nRunning coverage for package '${TRIBITS_PACKAGE}' ...\n")
ctest_coverage(
BUILD "${CTEST_BINARY_DIRECTORY}"
LABELS ${TRIBITS_PACKAGE} ${TRIBITS_PACKAGE}Libs ${TRIBITS_PACKAGE}Exes
)
if (CTEST_DO_SUBMIT)
tribits_ctest_submit( PARTS Coverage )
endif()
endif()
endif()
#
# E) Run memory testing
#
if (NOT PBP_BUILD_LIBS_PASSED AND CTEST_DO_MEMORY_TESTING)
message("\n${TRIBITS_PACKAGE}: Skipping running memory checking"
"tests since library build failed!\n")
elseif (NOT CTEST_DO_MEMORY_TESTING)
message("\n${TRIBITS_PACKAGE}: Skipping running memory checking tests due"
" to CTEST_DO_MEMORY_TESTING='${CTEST_DO_MEMORY_TESTING}'!")
else()
message("\nRunning memory testing for package '${TRIBITS_PACKAGE}' ...\n")
print_var(CTEST_MEMORYCHECK_COMMAND)
print_var(CTEST_MEMORYCHECK_COMMAND_OPTIONS)
print_var(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE)
ctest_memcheck(
BUILD "${CTEST_BINARY_DIRECTORY}"
PARALLEL_LEVEL "${CTEST_PARALLEL_LEVEL}"
INCLUDE_LABEL "^${TRIBITS_PACKAGE}$"
)
# ToDo: Determine if memory testing passed or not and affect overall
# pass/fail!
if (CTEST_DO_SUBMIT)
tribits_ctest_submit( PARTS MemCheck )
endif()
endif()
#
# F) Record if this package failed the build or any tests
#
if (NOT PBP_CONFIGURE_PASSED OR NOT PBP_BUILD_LIBS_PASSED)
list(APPEND ${PROJECT_NAME}_FAILED_LIB_BUILD_PACKAGES ${TRIBITS_PACKAGE})
endif()
if (NOT PBP_BUILD_PASSED OR NOT PBP_TESTS_PASSED)
list(APPEND ${PROJECT_NAME}_FAILED_PACKAGES ${TRIBITS_PACKAGE})
endif()
#
# G) Do submit of update
#
if (CTEST_DO_SUBMIT)
message("\nSubmit the update file that will trigger the notification email ...\n")
tribits_ctest_submit( PARTS update )
endif()
math(EXPR PACKAGE_IDX "${PACKAGE_IDX}+1")
endforeach(TRIBITS_PACKAGE)
if (${PROJECT_NAME}_FAILED_LIB_BUILD_PACKAGES)
message(
"\nFinal set packages that failed to configure or have the libraries build:"
" '${${PROJECT_NAME}_FAILED_LIB_BUILD_PACKAGES}'")
endif()
message("\nDone with the incremental building and testing of"
" ${PROJECT_NAME} packages!\n")
endmacro()
# NOTE: Above, the option
# ${PROJECT_NAME}_DEFINE_MISSING_PACKAGE_LIBS_TARGETS=ON is passed down
# through to the inner CMake TriBITS configure to trigger the creation of
# dummy targets <PackageName>_libs for all the packages for the case where a
# package is disabled due to a disabled upstream package and
# ${PROJECT_NAME}_DISABLE_ENABLED_FORWARD_DEP_PACKAGES=ON but the target
# <thePackage>_libs is attempted to be built anyway and we expect it to build
# nothing and result in no error. (The outer ctest -S driver is not smart
# enough to know all the lgoic for if a package will actually be enabled or
# not. That is the job of the inner TriBITS dependency logic and
# ${PROJECT_NAME}_DISABLE_ENABLED_FORWARD_DEP_PACKAGES=ON.) Otherwise, with
# CMake 3.19+, cmake_build() catches errors in undefined global build targets
# like this and reports them correctly. This workaround allows the
# package-by-package mode to gracefully disable downstream packages that can't
# be enabled due to the disable of a broken upstream packages. See the test
# TriBITS_CTestDriver_PBP_ST_BreakConfigureRequiredPkg that exercises this use
# case.
# Drive the configure, build, test, and submit all at once for all of the
# enabled packages.
#
# Sets ${PROJECT_NAME}_FAILED_PACKAGES as an indication if there are any
# failures.
#
macro(tribits_ctest_all_at_once)
message(
"\n***"
"\n*** Configure, build, test and submit results all-at-once for all enabled packages ..."
"\n***")
set(AAO_CONFIGURE_FAILED FALSE)
set(AAO_BUILD_FAILED FALSE)
set(AAO_INSTALL_FAILED FALSE)
#
# A) Define mapping from labels to subprojects and gather configure arguments
#
tribits_ctest_driver_set_labels_to_subprojects_mapping()
print_var(CTEST_LABELS_FOR_SUBPROJECTS)
message("")
message("Configuring ...")
message("")
# Create CONFIGURE_OPTIONS
tribits_fwd_cmake_config_args_0()
if (NOT "${${PROJECT_NAME}_PACKAGE_ENABLES_FILE}" STREQUAL "")
# NOTE: For now, the user is expected to pass through this file in the
# inner CMake cache var ${PROJECT_NAME}_CONFIGURE_OPTIONS_FILE! We should
# fix this in the future but that is what it is for now.
elseif (${PROJECT_NAME}_ENABLE_ALL_PACKAGES)
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_ENABLE_ALL_PACKAGES=ON" )
foreach(TRIBITS_PACKAGE ${${PROJECT_NAME}_EXCLUDE_PACKAGES})
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE}=OFF" )
endforeach()
# NOTE: Above we have to explicitly set disables for the excluded packages
# since we are pssing in ${PROJECT_NAME}_ENABLE_ALL_PACKAGES=ON. This is
# effectively the "black-listing" approach.
else()
foreach(TRIBITS_PACKAGE ${${PROJECT_NAME}_PACKAGES_TO_DIRECTLY_TEST})
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_ENABLE_${TRIBITS_PACKAGE}=ON" )
endforeach()
# NOTE: Above we don't have to consider the packages excluded in
# ${PROJECT_NAME}_EXCLUDE_PACKAGES because they are not enabled ad this
# point and therefore no in ${PROJECT_NAME}_PACKAGES_TO_DIRECTLY_TEST.
# This is effectively the "white-listing" approach.
endif()
list(APPEND CONFIGURE_OPTIONS
"-D${PROJECT_NAME}_ENABLE_TESTS:BOOL=${${PROJECT_NAME}_INNER_ENABLE_TESTS}")
tribits_fwd_cmake_config_args_1()
message("\nCONFIGURE_OPTIONS = '${CONFIGURE_OPTIONS}'")
#
# B) Configure the package and its dependent packages
#
tribits_previous_configure_attempted_but_not_passsed(
PREVIOUS_CONFIGURE_ATTEMPTED_BUT_NOT_PASSSED)
#print_var(PREVIOUS_CONFIGURE_ATTEMPTED_BUT_NOT_PASSSED)
if ((NOT CTEST_DO_CONFIGURE) AND PREVIOUS_CONFIGURE_ATTEMPTED_BUT_NOT_PASSSED)
message(
"\nSkipping configure due to CTEST_DO_CONFIGURE='${CTEST_DO_CONFIGURE}'!\n"
"\nHOWEVER: A configure was previously attempted but did not pass so consider configure FAILED!")
set(AAO_CONFIGURE_PASSED FALSE)
set(AAO_CONFIGURE_FAILED TRUE)
elseif (NOT CTEST_DO_CONFIGURE)
message("\nSkipping configure due to CTEST_DO_CONFIGURE='${CTEST_DO_CONFIGURE}'!\n")
set(AAO_CONFIGURE_PASSED TRUE)
# Just assume configure passeed for the purpose of running the build.
elseif (CTEST_DEPENDENCY_HANDLING_UNIT_TESTING)
message("Skipping actual ctest_configure() because"
" CTEST_DEPENDENCY_HANDLING_UNIT_TESTING='${CTEST_DEPENDENCY_HANDLING_UNIT_TESTING}'!"
)
set(AAO_CONFIGURE_PASSED TRUE)
else()
ctest_configure(
BUILD "${CTEST_BINARY_DIRECTORY}"
OPTIONS "${CONFIGURE_OPTIONS}" # New option!
RETURN_VALUE CONFIGURE_RETURN_VAL
)
message("Generating the file '${CMAKE_CACHE_CLEAN_FILE}' ...")
tribits_strip_comments_from_cmake_cache_file(
"${CTEST_BINARY_DIRECTORY}/CMakeCache.txt"
"${CMAKE_CACHE_CLEAN_FILE}"
)
if (NOT "${CONFIGURE_RETURN_VAL}" EQUAL "0")
message("Configure FAILED!")
set(AAO_CONFIGURE_PASSED FALSE)
set(AAO_CONFIGURE_FAILED TRUE)
else()
message("Configure PASSED!")
set(AAO_CONFIGURE_PASSED TRUE)
endif()
if (AAO_CONFIGURE_PASSED)
tribits_remember_configure_passed()
endif()
set(CTEST_NOTES_FILES "${CTEST_NOTES_FILES_WO_CACHE}")
if (EXISTS ${CMAKE_CACHE_CLEAN_FILE})
list(APPEND CTEST_NOTES_FILES "${CMAKE_CACHE_CLEAN_FILE}")
endif()
if (EXISTS "${REPO_VERSION_FILE}")
set(CTEST_NOTES_FILES "${REPO_VERSION_FILE};${CTEST_NOTES_FILES}")
endif()
print_var(CTEST_NOTES_FILES)
# Submit configure results and the notes to the dashboard
if (CTEST_DO_SUBMIT)
message("\nSubmitting update, configure and notes ...")
tribits_ctest_submit( PARTS update configure notes )
endif()
endif()
# Read in configured CTestCustom.cmake
ctest_read_custom_files(BUILD "${CTEST_BINARY_DIRECTORY}")
# NOTE: Above, it is safe to call ctest_read_custom_files() even if the
# configure failed and the file CTestCustom.cmake does exist. In this case,
# CTest will just do nothing.
# Overridde any values by loading <projectDir>/CTestConfig.cmake
include("${TRIBITS_PROJECT_ROOT}/CTestConfig.cmake")
# Print out values read from project CTestCustom.cmake file
print_var(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE)
print_var(CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE)
#
# C) Do the build
#
if (NOT CTEST_DO_BUILD)
message("\nSkipping build due to CTEST_DO_BUILD='${CTEST_DO_BUILD}'!\n")
elseif (CTEST_DEPENDENCY_HANDLING_UNIT_TESTING AND AAO_CONFIGURE_PASSED)
message("Skipping build because"
" CTEST_DEPENDENCY_HANDLING_UNIT_TESTING='${CTEST_DEPENDENCY_HANDLING_UNIT_TESTING}'!"
)
elseif (AAO_CONFIGURE_PASSED)
message("")
message("Building all targets ...")
message("")
ctest_build(
BUILD "${CTEST_BINARY_DIRECTORY}"
RETURN_VALUE BUILD_ALL_RETURN_VAL
NUMBER_ERRORS BUILD_ALL_NUM_ERRORS
)
message("Build output: BUILD_ALL_NUM_ERRORS='${BUILD_ALL_NUM_ERRORS}',"
"BUILD_ALL_RETURN_VAL='${BUILD_ALL_RETURN_VAL}'" )
if (NOT "${BUILD_ALL_NUM_ERRORS}" EQUAL "0")
message("Build FAILED!")
set(AAO_BUILD_FAILED TRUE)
else()
message("Build PASSED!")
endif()
# Submit the build for all target
if (CTEST_DO_SUBMIT)
tribits_ctest_submit( PARTS build )
endif()
if (CTEST_DO_INSTALL)
message("")
message("Installing (i.e. building target 'install_package_by_package') ...")
message("")
ctest_build(
BUILD "${CTEST_BINARY_DIRECTORY}"
TARGET install_package_by_package
RETURN_VALUE BUILD_INSTALL_RETURN_VAL
NUMBER_ERRORS BUILD_INSTALL_NUM_ERRORS
)
message("Build install output:"
" BUILD_INSTALL_NUM_ERRORS='${BUILD_INSTALL_NUM_ERRORS}',"
"BUILD_INSTALL_RETURN_VAL='${BUILD_INSTALL_RETURN_VAL}'" )
if (NOT "${BUILD_INSTALL_NUM_ERRORS}" EQUAL "0")
message("Install FAILED!")
set(AAO_INSTALL_FAILED TRUE)
else()
message("Install PASSED!")
endif()
# Submit the build for all target
if (CTEST_DO_SUBMIT)
tribits_ctest_submit( PARTS build )
endif()
endif()
else()
message("")
message("Skipping build because configure failed!")
message("")
endif()
#
# D) Run tests
#
if (NOT CTEST_DO_TEST)
message("")
message("Skipping tests because CTEST_DO_TEST='${CTEST_DO_TEST}'!")
message("")
elseif (NOT AAO_CONFIGURE_PASSED)
message("")
message("Skipping tests because configure failed!")
message("")
elseif (CTEST_DEPENDENCY_HANDLING_UNIT_TESTING AND AAO_CONFIGURE_PASSED)
message("Skipping testing because"
" CTEST_DEPENDENCY_HANDLING_UNIT_TESTING='${CTEST_DEPENDENCY_HANDLING_UNIT_TESTING}'!"
)
else()
# NOTE: We always run the tests if the configure passed no matter if there
# are build failures because the only way that we can detect what packages
# have build failures is to see what packages have test failures.
tribits_remove_last_test_failed_log_file()
# Run the tests
message("")
message("\nRunning tests (parallel level ${CTEST_PARALLEL_LEVEL}) ...\n")
message("")
ctest_test(
BUILD "${CTEST_BINARY_DIRECTORY}"
PARALLEL_LEVEL "${CTEST_PARALLEL_LEVEL}"
)
# See if a 'LastTestsFailed*.log' file exists to determine if there are
# failed tests.
tribits_find_last_test_failed_log_file()
if (FAILED_TEST_LOG_FILE)
message("File '${FAILED_TEST_LOG_FILE}' exists so there were non-passing tests!")
else()
message("File '${FAILED_TEST_LOG_FILE}' does NOT exist so all tests passed!")
endif()
if (CTEST_DO_SUBMIT)
tribits_ctest_submit( PARTS Test )
endif()
endif()
#
# E) Gather coverage results
#
if (NOT CTEST_DO_COVERAGE_TESTING)
message("")
message("Skipping converage tests because CTEST_DO_COVERAGE_TESTING='${CTEST_DO_COVERAGE_TESTING}'!")
message("")
elseif (NOT AAO_CONFIGURE_PASSED)
message("")
message("Skipping coverage tests because configure failed!")
message("")
elseif (CTEST_DEPENDENCY_HANDLING_UNIT_TESTING AND AAO_CONFIGURE_PASSED)
message("Skipping coverage testing because"
" CTEST_DEPENDENCY_HANDLING_UNIT_TESTING='${CTEST_DEPENDENCY_HANDLING_UNIT_TESTING}'!"
)
else()
# NOTE: We always gather the coverage results if the configure passed
# independent if there was any build or test failures. The coverage stats
# may not be very valid if there are build or test failures but there is
# no harm and showing the coverage based on tests that actually run (even
# if they fail).
message("\nGathering coverage results ...\n")
ctest_coverage(
BUILD "${CTEST_BINARY_DIRECTORY}"
)
if (CTEST_DO_SUBMIT)
tribits_ctest_submit( PARTS Coverage )
endif()
endif()
#
# F) Do memory testing
#
if (NOT CTEST_DO_MEMORY_TESTING)
message("")
message("Skipping memory testing because CTEST_DO_MEMORY_TESTING='${CTEST_DO_MEMORY_TESTING}'!")
message("")
elseif (NOT AAO_CONFIGURE_PASSED)
message("")
message("Skipping memory tests because configure failed!")
message("")
elseif (CTEST_DEPENDENCY_HANDLING_UNIT_TESTING AND AAO_CONFIGURE_PASSED)
message("Skipping memory testing because"
" CTEST_DEPENDENCY_HANDLING_UNIT_TESTING='${CTEST_DEPENDENCY_HANDLING_UNIT_TESTING}'!"
)
else()
# NOTE: We always gather the memory results if the configure passed
# independent if there was any build or test failures. The memory stats
# may not be very valid if there are build or test failures but there is
# no harm and showing the memory based on tests that actually run (even
# if they fail).
message("\nRunning memory tests ...\n")
print_var(CTEST_MEMORYCHECK_COMMAND)
print_var(CTEST_MEMORYCHECK_COMMAND_OPTIONS)
print_var(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE)
ctest_memcheck(
BUILD "${CTEST_BINARY_DIRECTORY}"
)
if (CTEST_DO_SUBMIT)
tribits_ctest_submit( PARTS MemCheck )
endif()
endif()
#
# G) Determine final pass/fail by gathering list of failing packages
#
if (AAO_CONFIGURE_FAILED OR AAO_BUILD_FAILED OR AAO_INSTALL_FAILED)
if (${PROJECT_NAME}_ENABLE_ALL_PACKAGES)
# Special value "ALL_PACKAGES" so that it will trigger enabling all
# packages on the next CI iteration!
set(${PROJECT_NAME}_FAILED_PACKAGES ALL_PACKAGES)
else()
# Specific packages were selected to be tested so fail all of them!
set(${PROJECT_NAME}_FAILED_PACKAGES ${${PROJECT_NAME}_PACKAGES_TO_DIRECTLY_TEST})
endif()
# NOTE: With the all-at-once approach, there is no way to determine which
# packages have build or install failures given the current ctest_build()
# command. And since some build targets don't get used in tests, we can't
# look at what packages have test failures in order to know that a build
# failure will cause a test failure. And in the case of install failures,
# those will never cause test failures. Therefore, if there are any build
# or install failures, we just have to assume that any tested package
# could have failed. Hence, we set the above just like for a (global)
# configure failures. Perhaps we could read the generated *.xml files to
# figure that out but that is not worth the work right now. The only bad
# consequence of this is that a CI build would end up building and testing
# every package even if only one downstream package had a build failure,
# for example. That is just one of the downsides of the all-at-once
# approach vs. the package-by-package approach.
elseif (FAILED_TEST_LOG_FILE)
tribits_get_failed_packages_from_failed_tests("${FAILED_TEST_LOG_FILE}"
${PROJECT_NAME}_FAILED_PACKAGES )
else()
# If no tests failed, then there are no failed packages!
set(${PROJECT_NAME}_FAILED_PACKAGES)
endif()
# ToDo: Optionally determine pass/fail based
message("\nDone with the all-at-once configure, build, test, and submit of ${PROJECT_NAME} packages!\n")
endmacro()