1 # ============================================================================ 2 # Modified from Boost Utilities 4 # Copyright 2010 Kitware, Inc. 5 # ============================================================================ 6 # Copyright 2007 Douglas Gregor <doug.gregor@gmail.com> 7 # Copyright 2007 Troy Straszheim 9 # Distributed under the Boost Software License, Version 1.0. 10 # ============================================================================ 11 # Boost Software License - Version 1.0 - August 17th, 2003 13 # Permission is hereby granted, free of charge, to any person or organization 14 # obtaining a copy of the software and accompanying documentation covered by 15 # this license (the "Software") to use, reproduce, display, distribute, 16 # execute, and transmit the Software, and to prepare derivative works of the 17 # Software, and to permit third-parties to whom the Software is furnished to 18 # do so, all subject to the following: 20 # The copyright notices in the Software and this entire statement, including 21 # the above license grant, this restriction and the following disclaimer, 22 # must be included in all copies of the Software, in whole or in part, and 23 # all derivative works of the Software, unless such copies or derivative 24 # works are solely in the form of machine-executable object code generated by 25 # a source language processor. 27 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 # FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 30 # SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 31 # FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 32 # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 33 # DEALINGS IN THE SOFTWARE. 34 # ============================================================================ 36 ############################################################################## 37 # @file TopologicalSort.cmake 38 # @brief CMake implementation of topological sorting algorithm. 40 # Perform a reverse topological sort on the given LIST. 42 # topological_sort(my_list "MY_" "_EDGES") 44 # LIST is the name of a variable containing a list of elements to be 45 # sorted in reverse topological order. Each element in the list has a 46 # set of outgoing edges (for example, those other list elements that 47 # it depends on). In the resulting reverse topological ordering 48 # (written back into the variable named LIST), an element will come 49 # later in the list than any of the elements that can be reached by 50 # following its outgoing edges and the outgoing edges of any vertices 51 # they target, recursively. Thus, if the edges represent dependencies 52 # on build targets, for example, the reverse topological ordering is 53 # the order in which one would build those targets. 55 # For each element E in this list, the edges for E are contained in 56 # the variable named ${PREFIX}${E}${SUFFIX}. If no such variable 57 # exists, then it is assumed that there are no edges. For example, if 58 # my_list contains a, b, and c, one could provide a dependency graph 59 # using the following variables: 65 # With the involcation of topological_sort shown above and these 66 # variables, the resulting reverse topological ordering will be b, a, c. 68 # @ingroup CMakeUtilities 69 ############################################################################## 72 # Clear the stack and output variable
73 set(VERTICES
"${${LIST}}")
77 # Loop over all of the vertices, starting the topological sort from
79 foreach(VERTEX ${VERTICES})
81 # If we haven
't already processed this vertex, start a depth-first 83 if (NOT FOUND_${VERTEX}) 84 # Push this vertex onto the stack with all of its outgoing edges 85 string(REPLACE ";" " " NEW_ELEMENT 86 "${VERTEX};${${PREFIX}${VERTEX}${SUFFIX}}") 87 list(APPEND STACK ${NEW_ELEMENT}) 89 # We've now seen
this vertex
90 set(FOUND_${VERTEX} TRUE)
92 # While the depth-first search stack
is not empty
93 list(LENGTH STACK STACK_LENGTH)
94 while(STACK_LENGTH GREATER 0)
95 # Remove the vertex and its remaining out-edges from the top 97 list(GET STACK -1 OUT_EDGES)
98 list(REMOVE_AT STACK -1)
100 # Get the source vertex and the list of out-edges 101 separate_arguments(OUT_EDGES)
102 list(GET OUT_EDGES 0 SOURCE)
103 list(REMOVE_AT OUT_EDGES 0)
105 # While there are still out-edges remaining 106 list(LENGTH OUT_EDGES OUT_DEGREE)
107 while (OUT_DEGREE GREATER 0)
108 # Pull off the first outgoing edge 109 list(GET OUT_EDGES 0 TARGET)
110 list(REMOVE_AT OUT_EDGES 0)
112 if (NOT FOUND_${TARGET})
113 # We have not seen the target before, so we will traverse
114 # its outgoing edges before coming back to our
115 # source. This
is the key to the depth-first traversal.
117 # We
've now seen this vertex 118 set(FOUND_${TARGET} TRUE) 120 # Push the remaining edges for the current vertex onto the 122 string(REPLACE ";" " " NEW_ELEMENT 123 "${SOURCE};${OUT_EDGES}") 124 list(APPEND STACK ${NEW_ELEMENT}) 126 # Setup the new source and outgoing edges 127 set(SOURCE ${TARGET}) 129 ${${PREFIX}${SOURCE}${SUFFIX}}) 130 endif(NOT FOUND_${TARGET}) 132 list(LENGTH OUT_EDGES OUT_DEGREE) 133 endwhile (OUT_DEGREE GREATER 0) 135 # We have finished all of the outgoing edges for 136 # SOURCE; add it to the resulting list. 137 list(APPEND ${LIST} ${SOURCE}) 139 # Check the length of the stack 140 list(LENGTH STACK STACK_LENGTH) 141 endwhile(STACK_LENGTH GREATER 0) 142 endif (NOT FOUND_${VERTEX}) 145 set(${LIST} ${${LIST}} PARENT_SCOPE) 146 endfunction(topological_sort) function is(in result, in expected, in name)
Test whether a given result is equal to the expected result.
function topological_sort(in LIST, in PREFIX, in SUFFIX)