TopologicalSort.cmake
Go to the documentation of this file.
1 # ============================================================================
2 # Modified from Boost Utilities
3 #
4 # Copyright 2010 Kitware, Inc.
5 # ============================================================================
6 # Copyright 2007 Douglas Gregor <doug.gregor@gmail.com>
7 # Copyright 2007 Troy Straszheim
8 #
9 # Distributed under the Boost Software License, Version 1.0.
10 # ============================================================================
11 # Boost Software License - Version 1.0 - August 17th, 2003
12 #
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:
19 #
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.
26 #
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 # ============================================================================
35 
36 ##############################################################################
37 # @file TopologicalSort.cmake
38 # @brief CMake implementation of topological sorting algorithm.
39 #
40 # Perform a reverse topological sort on the given LIST.
41 #
42 # topological_sort(my_list "MY_" "_EDGES")
43 #
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.
54 #
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:
60 #
61 # MY_A_EDGES b
62 # MY_B_EDGES
63 # MY_C_EDGES a b
64 #
65 # With the involcation of topological_sort shown above and these
66 # variables, the resulting reverse topological ordering will be b, a, c.
67 #
68 # @ingroup CMakeUtilities
69 ##############################################################################
70 
71 function(topological_sort LIST PREFIX SUFFIX)
72  # Clear the stack and output variable
73  set(VERTICES "${${LIST}}")
74  set(STACK)
75  set(${LIST})
76 
77  # Loop over all of the vertices, starting the topological sort from
78  # each one.
79  foreach(VERTEX ${VERTICES})
80 
81  # If we haven't already processed this vertex, start a depth-first
82  # search from where.
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})
88 
89  # We've now seen this vertex
90  set(FOUND_${VERTEX} TRUE)
91 
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
96  # of the stack
97  list(GET STACK -1 OUT_EDGES)
98  list(REMOVE_AT STACK -1)
99 
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)
104 
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)
111 
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.
116 
117  # We've now seen this vertex
118  set(FOUND_${TARGET} TRUE)
119 
120  # Push the remaining edges for the current vertex onto the
121  # stack
122  string(REPLACE ";" " " NEW_ELEMENT
123  "${SOURCE};${OUT_EDGES}")
124  list(APPEND STACK ${NEW_ELEMENT})
125 
126  # Setup the new source and outgoing edges
127  set(SOURCE ${TARGET})
128  set(OUT_EDGES
129  ${${PREFIX}${SOURCE}${SUFFIX}})
130  endif(NOT FOUND_${TARGET})
131 
132  list(LENGTH OUT_EDGES OUT_DEGREE)
133  endwhile (OUT_DEGREE GREATER 0)
134 
135  # We have finished all of the outgoing edges for
136  # SOURCE; add it to the resulting list.
137  list(APPEND ${LIST} ${SOURCE})
138 
139  # Check the length of the stack
140  list(LENGTH STACK STACK_LENGTH)
141  endwhile(STACK_LENGTH GREATER 0)
142  endif (NOT FOUND_${VERTEX})
143  endforeach(VERTEX)
144 
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)