Commit 7defc104 authored by Ben Boeckel's avatar Ben Boeckel Committed by Kitware Robot

Merge topic 'use-common-superbuild'

538f7511 pythongirderclient: add project and dependencies
5565a587 windows: implement packaging
0503b0b3 apple: implement packaging
ba4c68b0 unix: implement packaging
f4484d14 ctest: extend PATH on Windows for testing
11b7ad7d cmb: inform about the developer root path
e8ca3088 vxl: apply patch to support GCC6
83a5969e vxl: convert into a tarball
...
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !115
parents 4d34153e 538f7511
*.patch whitespace=-blank-at-eol -text
[submodule "superbuild"]
path = superbuild
url = https://gitlab.kitware.com/ben.boeckel/common-superbuild.git
* VTK does not build correctly when VTK_USE_SYSTEM_HDF5 is ON and HDF5 was built
with HL enabled (which is needed for NetCDF). To solution currently is to
manually edit the CMake variable HDF5_C_LIBRARY to be
<INSTALL_DIR>/lib/libhdf5.so;<INSTALL_DIR>/lib/libhdf5_hl.so
It cannot be set in paraview.cmake file, unfortunately.
* MPICH2 does not build correctly when make -j<N> is used. Simply run a
non-parallel make.
* Need libXrender to ensure that Icons and fonts render smoothly.
* If Manta fails to build with SSE, set USE_SSE flag to OFF.
include (ParaViewModules)
#------------------------------------------------------------------------------
#Macro to hide all non optional CMB modules
macro (SetupCMBSuperBuild)
#force the variables to be advanced so user don't play with them
#we want to show the user python as a option
mark_as_advanced(FORCE
ENABLE_boost
ENABLE_cgns
ENABLE_cmb
ENABLE_ffmpeg
ENABLE_freetype
ENABLE_hdf5
ENABLE_libxml2
ENABLE_manta
ENABLE_moab
ENABLE_mpi
ENABLE_png
ENABLE_remus
ENABLE_shiboken
ENABLE_silo
ENABLE_smtk
ENABLE_szip
ENABLE_triangle
ENABLE_visitbridge
ENABLE_vxl
ENABLE_zeroMQ
ENABLE_zlib
ENABLE_ftgl
ENABLE_netcdf
ENABLE_oce
ENABLE_paraviewsdk
)
if (UNIX AND NOT APPLE)
mark_as_advanced(FORCE
ENABLE_fontconfig
ENABLE_mesa
ENABLE_osmesa
)
endif()
set(ENABLE_cmb ON CACHE BOOL "")
set(ENABLE_smtk ON CACHE BOOL "")
set(ENABLE_visitbridge ON CACHE BOOL "")
endmacro()
#------------------------------------------------------------------------------
# similar to add_external_project, except provides the user with an option to
# specify to that we just build the dependencies and don't build the primary
# program
macro(add_external_project_or_just_build_dependencies _name)
if (build-projects)
add_external_project(${_name} ${ARGN})
else()
add_external_project(${_name} ${ARGN})
set(default_mode "SuperBuild")
if("${_name}" STREQUAL "cmb")
set(default_mode "Developer")
endif()
set(ENABLE_${_name}_BUILD_MODE "${default_mode}" CACHE STRING
"Super Build Type. Developer builds minimial cmb dependencies by default. Release builds all dependencies.")
set_property(CACHE ENABLE_${_name}_BUILD_MODE PROPERTY STRINGS Developer SuperBuild)
endif()
endmacro()
#------------------------------------------------------------------------------
macro(cmb_process_dependencies)
set (CM_PROJECTS_ENABLED "")
foreach(cm-project IN LISTS CM_PROJECTS_ALL)
set(${cm-project}_ENABLED FALSE)
if (ENABLE_${cm-project})
list(APPEND CM_PROJECTS_ENABLED ${cm-project})
endif()
endforeach()
list(SORT CM_PROJECTS_ENABLED) # Deterministic order.
# Order list to satisfy dependencies. We don't include the use-system
# libraries in the depedency walk.
include(TopologicalSort)
topological_sort(CM_PROJECTS_ENABLED "" _DEPENDS)
# Now generate a project order using both, optional and non-optional
# dependencies.
set (CM_PROJECTS_ORDER ${CM_PROJECTS_ENABLED})
topological_sort(CM_PROJECTS_ORDER "" _DEPENDS_ANY)
# Update CM_PROJECTS_ENABLED to be in the correct order taking into
# consideration optional dependencies.
set (new_order)
foreach (cm-project IN LISTS CM_PROJECTS_ORDER)
list(FIND CM_PROJECTS_ENABLED "${cm-project}" found)
if (found GREATER -1)
list(APPEND new_order "${cm-project}")
endif()
endforeach()
set (CM_PROJECTS_ENABLED ${new_order})
# build information about what project needs what.
foreach (cm-project IN LISTS CM_PROJECTS_ENABLED)
enable_project(${cm-project} "")
foreach (dependency IN LISTS ${cm-project}_DEPENDS)
enable_project(${dependency} "${cm-project}")
endforeach()
endforeach()
foreach (cm-project IN LISTS CM_PROJECTS_ENABLED)
if (ENABLE_${cm-project})
message(STATUS "Enabling ${cm-project} as requested.")
set_property(CACHE ENABLE_${cm-project} PROPERTY TYPE BOOL)
else()
list(SORT ${cm-project}_NEEDED_BY)
list(REMOVE_DUPLICATES ${cm-project}_NEEDED_BY)
message(STATUS "Enabling ${cm-project} since needed by: ${${cm-project}_NEEDED_BY}")
set_property(CACHE ENABLE_${cm-project} PROPERTY TYPE INTERNAL)
endif()
endforeach()
message(STATUS "PROJECTS_ENABLED ${CM_PROJECTS_ENABLED}")
set (build-projects 1)
foreach (cm-project IN LISTS CM_PROJECTS_ENABLED)
#if we are in developer mode for this project it is the same
#as being a dummy project
if(ENABLE_${cm-project}_BUILD_MODE STREQUAL "Developer")
set(${cm-project}_DEVELOPER_PROJECT TRUE)
else()
#set it to false so that everything works when a user toggles
#the setting
set(${cm-project}_DEVELOPER_PROJECT FALSE)
endif()
if (${cm-project}_CAN_USE_SYSTEM)
# for every enabled project that can use system, expose the option to the
# user.
set_property(CACHE USE_SYSTEM_${cm-project} PROPERTY TYPE BOOL)
if (USE_SYSTEM_${cm-project})
message(STATUS "using system ${cm-project}")
add_external_dummy_project_internal(${cm-project})
include(${cm-project}.use.system OPTIONAL RESULT_VARIABLE rv)
if (rv STREQUAL "NOTFOUND")
message(AUTHOR_WARNING "${cm-project}.use.system not found!!!")
endif()
else()
include(${cm-project})
add_external_project_internal(${cm-project} "${${cm-project}_ARGUMENTS}")
endif()
elseif(${cm-project}_IS_DUMMY_PROJECT)
#this project isn't built, just used as a graph node to
#represent a group of dependencies
add_external_dummy_project_internal(${cm-project})
elseif(${cm-project}_DEVELOPER_PROJECT)
#this project isn't built, just used as a graph node to
#represent a group of dependencies. We write out the search
#path and cmake args we generally pass to the build to a file
#so a dev can use that info to build the project outside the superbuild
include(${cm-project}) #include the project to get the cmake_args
add_external_developer_project_internal(${cm-project} "${${cm-project}_ARGUMENTS}")
else()
include(${cm-project})
add_external_project_internal(${cm-project} "${${cm-project}_ARGUMENTS}")
endif()
endforeach()
unset (build-projects)
endmacro()
#------------------------------------------------------------------------------
function(add_external_developer_project_internal name)
#start the parameters to write out to the file with
#the prefix path that we build everything with. Most well formed
#FindPackages will only need this set to work.
set(cmake_cache_args "-DCMAKE_PREFIX_PATH:PATH=${prefix_path}")
if (CMAKE_BUILD_TYPE)
list (APPEND cmake_cache_args -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE})
endif()
if (APPLE)
list (APPEND cmake_cache_args
-DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES}
-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET}
-DCMAKE_OSX_SYSROOT:PATH=${CMAKE_OSX_SYSROOT})
endif()
#get extra-cmake args from every dependent project, if any.
set(arg_DEPENDS)
get_project_depends(${name} arg)
foreach(dependency IN LISTS arg_DEPENDS)
get_property(dependency_args GLOBAL PROPERTY ${dependency}_CMAKE_ARGS)
list(APPEND cmake_cache_args ${dependency_args})
endforeach()
#parse ARGN for all cmake args
set(insert FALSE)
set(insert_following_args FALSE)
foreach(arg IN LISTS ARGN)
if ("${arg}" MATCHES "CMAKE_ARGS")
#set insert_following_args true which on the next iteration
#will set insert to true which makes sure we don't insert CMAKE_ARGS
#into the list of arguments.
set(insert_following_args TRUE)
elseif("${arg}" MATCHES "_ep_keywords_PVExternalProject_Add")
set(insert FALSE)
elseif(insert_following_args)
set(insert TRUE)
set(insert_following_args FALSE)
endif()
if(insert)
list(APPEND cmake_cache_args "${arg}")
endif()
endforeach()
#add a dummy project that is needed by the _ep_write_initial_cache
add_external_dummy_project_internal(${name})
#write out all the cmake vars to a file that can be used to prime a build
set(cache_file "${SuperBuild_BINARY_DIR}/${name}-Developer-Config.cmake")
if (COMMAND _ep_command_line_to_initial_cache)
# Upstream ExternalProject changed its argument parsing. Since these are
# internal functions, go with the flow.
_ep_command_line_to_initial_cache(cmake_cache_args "${cmake_cache_args}" 0)
endif ()
_ep_write_initial_cache(${name} "${cache_file}" "${cmake_cache_args}")
endfunction()
function (cmb_superbuild_add_bundle name generator)
set(cpack_working_dir "${CMAKE_BINARY_DIR}/cpack/${name}/${generator}")
configure_file(
"${SuperBuild_CMAKE_DIR}/package_cmakelists.cmake.in"
"${cpack_working_dir}/CMakeLists.txt"
@ONLY)
add_test(
NAME "cpack-${name}-${generator}"
COMMAND "${CMAKE_COMMAND}"
-Dname=${name}
-Dcmake_generator=${CMAKE_GENERATOR}
-Dcpack_generator=${generator}
-Doutput_directory=${CMAKE_BINARY_DIR}
-Dworking_directory=${cpack_working_dir}
-P "${SuperBuild_CMAKE_DIR}/package_test.cmake"
WORKING_DIRECTORY "${cpack_working_dir}")
set_tests_properties("cpack-${name}-${generator}"
PROPERTIES
RESOURCE_LOCK cpack
${ARGN})
endfunction ()
#=============================================================================
# Ask user what the target machine is, so that we can choose the right
# right build hints and patches later on.
#
macro(query_target_machine)
set(cross_target "generic" CACHE STRING
"Platform to cross compile for, either generic|bgp_xlc|xk7_gnu")
set_property(CACHE cross_target PROPERTY STRINGS
"generic" "bgp_xlc" "xk7_gnu")
set(CROSS_BUILD_SITE "" CACHE STRING
"Specify Site to load appropriate configuration defaults, if available.")
endmacro()
#=============================================================================
# Configures the cmake files that describe how to cross compile paraview
# From the ${cross_target} directory into the build tree.
#
macro(do_cross_platform_settings)
#copy toolchains
configure_file(
${CMAKE_SOURCE_DIR}/CMake/crosscompile/${cross_target}/ToolChain.cmake
${CMAKE_BINARY_DIR}/crosscompile/ParaViewToolChain.cmake
@ONLY
)
set(PARAVIEW_TOOLCHAIN_FILE
"${CMAKE_BINARY_DIR}/crosscompile/ParaViewToolChain.cmake")
#configure tryrunresults
#see CMake/crosscompile/trycompiler.py for sample of how to generate new ones
configure_file(
${CMAKE_SOURCE_DIR}/CMake/crosscompile/${cross_target}/ParaViewTryRunResults.cmake
${CMAKE_BINARY_DIR}/crosscompile/ParaViewTryRunResults.cmake
@ONLY
)
set(PARAVIEW_TRYRUN_FILE
"${CMAKE_BINARY_DIR}/crosscompile/ParaViewTryRunResults.cmake")
#configure additional platform specific options
string(TOLOWER "${CROSS_BUILD_SITE}" lsite)
set (site-specific-defaults
${CMAKE_SOURCE_DIR}/CMake/crosscompile/${cross_target}/ParaViewDefaults.${lsite}.cmake)
if (EXISTS "${site-specific-defaults}")
configure_file(
"${site-specific-defaults}"
${CMAKE_BINARY_DIR}/crosscompile/ParaViewDefaults.cmake
@ONLY)
else()
configure_file(
${CMAKE_SOURCE_DIR}/CMake/crosscompile/${cross_target}/ParaViewDefaults.cmake
${CMAKE_BINARY_DIR}/crosscompile/ParaViewDefaults.cmake
@ONLY)
endif()
set(CROSS_OPTIONS_FILE
"${CMAKE_BINARY_DIR}/crosscompile/ParaViewDefaults.cmake")
include(${CROSS_OPTIONS_FILE})
endmacro()
#=============================================================================
#Asks user where the results of the hosttools pass are so that it can
#use them in the cross compile pass.
#
macro(find_hosttools)
set(PARAVIEW_HOSTTOOLS_DIR ${CMAKE_BINARY_DIR}/../tools/toolsparaview/src/toolsparaview-build/ CACHE PATH
"Location of host built paraview compile tools directory")
set(PYTHON_HOST_EXE ${CMAKE_BINARY_DIR}/../tools/install/bin/python CACHE PATH
"Location of host built python executable")
set(PYTHON_HOST_LIBDIR ${CMAKE_BINARY_DIR}/../tools/install/lib CACHE PATH
"Location of host built python libraries")
set(BOOST_HOST_INCLUDEDIR ${CMAKE_BINARY_DIR}/../tools/install/include CACHE PATH
"Location of host built boost headers")
endmacro()
#=============================================================================
# looks for a patch file for the current ${cross_target} and ${_project}
# patch is given arguments from the ${project}_patch.cmake file if
# one exists, otherwise it uses defaults
#
macro(conditionally_patch_for_crosscompilation _project)
#get options for how to apply this specific patch
set(_subdir)
set(_patchlevel 1)
set(_step 1)
if (EXISTS
"${SuperBuild_CMAKE_DIR}/crosscompile/${cross_target}/${_project}_patch.cmake"
)
include("${SuperBuild_CMAKE_DIR}/crosscompile/${cross_target}/${_project}_patch.cmake")
endif()
#apply the patch if one exists for this project and target platform
if (EXISTS "${SuperBuild_CMAKE_DIR}/crosscompile/${cross_target}/${_project}.patch")
add_external_project_step(patch${_step}
COMMENT "Applying ${cross_target} specific patches for ${_project}"
COMMAND sh "${SuperBuild_CMAKE_DIR}/crosscompile/patcher.sh" "<SOURCE_DIR>/${_subdir}" -p${_patchlevel} "${SuperBuild_CMAKE_DIR}/crosscompile/${cross_target}/${_project}.patch"
DEPENDEES update
DEPENDERS patch)
else()
message("No ${_project} patch step for ${cross_target}")
endif()
endmacro()
# Extends ExternalProject_Add(...) by adding a new option.
# PROCESS_ENVIRONMENT <environment variables>
# When present the BUILD_COMMAND and CONFIGURE_COMMAND are executed as a
# sub-process (using execute_process()) so that the sepecified environment
# is passed on to the executed command (which does not happen by default).
# This will be deprecated once CMake starts supporting it.
include(ExternalProject)
string(REPLACE ")" "|PROCESS_ENVIRONMENT)"
_ep_keywords_PVExternalProject_Add "${_ep_keywords_ExternalProject_Add}")
#------------------------------------------------------------------------------
# win32 version of the macro that simply strips the PROCESS_ENVIRONMENT and call
# ExternalProject_Add().
function(_PVExternalProject_Add_Win32 name)
set (arguments)
set (optional_depends)
set (accumulate TRUE)
foreach(arg IN LISTS ARGN)
if ("${arg}" MATCHES "^PROCESS_ENVIRONMENT$")
set (accumulate FALSE)
elseif ("${arg}" MATCHES "${_ep_keywords_ExternalProject_Add}")
set (accumulate TRUE)
endif()
if (accumulate)
list(APPEND arguments "${arg}")
endif()
endforeach()
ExternalProject_Add(${name} "${arguments}")
unset(arguments)
unset(optional_depends)
unset(accumulate)
endfunction()
function (PVExternalProject_Add name)
if (WIN32)
_PVExternalProject_Add_Win32(${name} "${ARGN}")
return()
endif()
# process arguments are detect USE_ENVIRONMENT, BUILD_COMMAND and
# CONFIGURE_COMMAND.
# just create a temporary target so we can set target properties.
add_custom_target(pv-${name})
set( source "${ARGN}" )
_ep_parse_arguments(PVExternalProject_Add pv-${name} _EP_ "${source}")
get_property(loc_TEMP TARGET pv-${name}
PROPERTY _EP_BUILD_IN_SOURCE)
get_property(has_process_environment TARGET pv-${name}
PROPERTY _EP_PROCESS_ENVIRONMENT SET)
if (NOT has_process_environment)
ExternalProject_Add(${name} "${source}")
return()
endif()
set (new_argn)
#check for configure command
get_property(has_configure_command TARGET pv-${name}
PROPERTY _EP_CONFIGURE_COMMAND SET)
#override the configure command
if (has_configure_command)
get_property(configure_cmd TARGET pv-${name}
PROPERTY _EP_CONFIGURE_COMMAND)
if(configure_cmd STREQUAL "")
list(APPEND new_argn CONFIGURE_COMMAND "${configure_cmd}")
set(has_configure_command 0) #we don't want to call execute process
else()
list(APPEND new_argn
CONFIGURE_COMMAND
${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/pv-${name}-configure.cmake)
endif()
endif()
# check if we have a BUILD_COMMAND
get_property(has_build_command TARGET pv-${name}
PROPERTY _EP_BUILD_COMMAND SET)
if(has_build_command)
get_property(build_cmd TARGET pv-${name}
PROPERTY _EP_BUILD_COMMAND)
#if the build command is an empty string it means we don't have a build
#command and we need to explicitly not create the external process
#build step, but instead pass down an empty build step
if(build_cmd STREQUAL "")
list(APPEND new_argn BUILD_COMMAND "${build_cmd}")
set(has_build_command 0) #we don't want to call execute process
endif()
else()
# if no BUILD_COMMAND was specified, then the default build cmd is going to
# be used, but then too we want to environment to be setup correctly. So we
# obtain the default build command.
_ep_get_build_command(pv-${name} BUILD build_cmd)
if("${build_cmd}" MATCHES "^\\$\\(MAKE\\)")
# GNU make recognizes the string "$(MAKE)" as recursive make, so
# ensure that it appears directly in the makefile.
if (CROSS_BUILD_STAGE STREQUAL "HOST")
string(REGEX REPLACE "^\\$\\(MAKE\\)" "${CMAKE_MAKE_PROGRAM} -j5" build_cmd "${build_cmd}")
else()
# Don't do parallel 'make' when cross compiling or building tools for
# cross compiling.
string(REGEX REPLACE "^\\$\\(MAKE\\)" "${CMAKE_MAKE_PROGRAM} -j1" build_cmd "${build_cmd}")
endif()
set_property(TARGET pv-${name} PROPERTY _EP_BUILD_COMMAND "${build_cmd}")
endif()
set(has_build_command 1)
endif()
#setup the new build command
if(has_build_command)
list(APPEND new_argn
BUILD_COMMAND
${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/pv-${name}-build.cmake)
endif()
#check for install command, we always enforce an install command
get_property(has_install_command TARGET pv-${name}
PROPERTY _EP_INSTALL_COMMAND SET)
if (has_install_command)
get_property(install_cmd TARGET pv-${name}
PROPERTY _EP_INSTALL_COMMAND)
else()
_ep_get_build_command(pv-${name} INSTALL install_cmd)
endif()
#write out the new install command
list(APPEND new_argn INSTALL_COMMAND "${install_cmd}")
# now strip PROCESS_ENVIRONMENT from argments.
set (skip TRUE)
foreach(arg IN LISTS source)
if (arg MATCHES "${_ep_keywords_PVExternalProject_Add}")
if (arg MATCHES "^(PROCESS_ENVIRONMENT|BUILD_COMMAND|INSTALL_COMMAND|CONFIGURE_COMMAND)$")
set (skip FALSE)
else()
set (skip TRUE)
endif ()
endif()
if (skip)
list(APPEND new_argn ${arg})
endif()
endforeach()
#new_argn has to be quoted to keep empty list elements around
#so that we properly parse empty install, configure, build, etc
ExternalProject_Add(${name} "${new_argn}")
# configure the scripts after the call ExternalProject_Add() since that sets
# up the directories correctly.
get_target_property(process_environment pv-${name}
_EP_PROCESS_ENVIRONMENT)
_ep_replace_location_tags(${name} process_environment)
if (has_configure_command)
get_target_property(step_command pv-${name} _EP_CONFIGURE_COMMAND)
_ep_replace_location_tags(${name} step_command)
configure_file(${SuperBuild_CMAKE_DIR}/pep_configure.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/pv-${name}-configure.cmake
@ONLY
)
endif()
if (has_build_command)
get_target_property(step_command pv-${name} _EP_BUILD_COMMAND)
_ep_replace_location_tags(${name} step_command)
configure_file(${SuperBuild_CMAKE_DIR}/pep_configure.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/pv-${name}-build.cmake
@ONLY)
endif()
endfunction()
This diff is collapsed.
# Perform a reverse topological sort on the given LIST.
#
# topological_sort(my_list "MY_" "_EDGES")
#
# LIST is the name of a variable containing a list of elements to be
# sorted in reverse topological order. Each element in the list has a
# set of outgoing edges (for example, those other list elements that
# it depends on). In the resulting reverse topological ordering
# (written back into the variable named LIST), an element will come
# later in the list than any of the elements that can be reached by
# following its outgoing edges and the outgoing edges of any vertices
# they target, recursively. Thus, if the edges represent dependencies
# on build targets, for example, the reverse topological ordering is
# the order in which one would build those targets.
#
# For each element E in this list, the edges for E are contained in
# the variable named ${PREFIX}${E}${SUFFIX}. If no such variable
# exists, then it is assumed that there are no edges. For example, if
# my_list contains a, b, and c, one could provide a dependency graph
# using the following variables:
#
# MY_A_EDGES b
# MY_B_EDGES
# MY_C_EDGES a b
#
# With the involcation of topological_sort shown above and these
# variables, the resulting reverse topological ordering will be b, a,
# c.
##############################################################################
# Modified from Boost Utilities
#
# Copyright 2010 Kitware, Inc.
##############################################################################
# Copyright 2007 Douglas Gregor <doug.gregor@gmail.com>
# Copyright 2007 Troy Straszheim
#
# Distributed under the Boost Software License, Version 1.0.
##############################################################################
# Boost Software License - Version 1.0 - August 17th, 2003
#
# Permission is hereby granted, free of charge, to any person or organization
# obtaining a copy of the software and accompanying documentation covered by
# this license (the "Software") to use, reproduce, display, distribute,
# execute, and transmit the Software, and to prepare derivative works of the
# Software, and to permit third-parties to whom the Software is furnished to
# do so, all subject to the following:
#
# The copyright notices in the Software and this entire statement, including
# the above license grant, this restriction and the following disclaimer,
# must be included in all copies of the Software, in whole or in part, and
# all derivative works of the Software, unless such copies or derivative
# works are solely in the form of machine-executable object code generated by
# a source language processor.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
# SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
# FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
##############################################################################
function(topological_sort LIST PREFIX SUFFIX)
# Clear the stack and output variable
set(VERTICES "${${LIST}}")
set(STACK)
set(${LIST})
# Loop over all of the vertices, starting the topological sort from
# each one.
foreach(VERTEX ${VERTICES})
# If we haven't already processed this vertex, start a depth-first
# search from where.
if (NOT FOUND_${VERTEX})
# Push this vertex onto the stack with all of its outgoing edges
string(REPLACE ";" " " NEW_ELEMENT
"${VERTEX};${${PREFIX}${VERTEX}${SUFFIX}}")
list(APPEND STACK ${NEW_ELEMENT})
# We've now seen this vertex