1 # Copyright (C) 2012 The Android Open Source Project 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 # 15 # Definitions of various graph-related generic functions, used by 16 # ndk-build internally. 17 # 18 19 # Coding style note: 20 # 21 # All internal variables in this file begin with '_ndk_mod_' 22 # All internal functions in this file begin with '-ndk-mod-' 23 # 24 25 # Set this to true if you want to debug the functions here. 26 _ndk_mod_debug := $(if $(NDK_DEBUG_MODULES),true) 27 _ndk_topo_debug := $(if $(NDK_DEBUG_TOPO),true) 28 29 # Use $(call -ndk-mod-debug,<message>) to print a debug message only 30 # if _ndk_mod_debug is set to 'true'. Useful for debugging the functions 31 # available here. 32 # 33 ifeq (true,$(_ndk_mod_debug)) 34 -ndk-mod-debug = $(info $1) 35 else 36 -ndk-mod-debug := $(empty) 37 endif 38 39 ifeq (true,$(_ndk_topo_debug)) 40 -ndk-topo-debug = $(info $1) 41 else 42 -ndk-topo-debug = $(empty) 43 endif 44 45 ####################################################################### 46 # Filter a list of module with a predicate function 47 # $1: list of module names. 48 # $2: predicate function, will be called with $(call $2,<name>), if the 49 # result is not empty, <name> will be added to the result. 50 # Out: subset of input list, where each item passes the predicate. 51 ####################################################################### 52 -ndk-mod-filter = $(strip \ 53 $(foreach _ndk_mod_filter_n,$1,\ 54 $(if $(call $2,$(_ndk_mod_filter_n)),$(_ndk_mod_filter_n))\ 55 )) 56 57 -test-ndk-mod-filter = \ 58 $(eval -local-func = $$(call seq,foo,$$1))\ 59 $(call test-expect,,$(call -ndk-mod-filter,,-local-func))\ 60 $(call test-expect,foo,$(call -ndk-mod-filter,foo,-local-func))\ 61 $(call test-expect,foo,$(call -ndk-mod-filter,foo bar,-local-func))\ 62 $(call test-expect,foo foo,$(call -ndk-mod-filter,aaa foo bar foo,-local-func))\ 63 $(eval -local-func = $$(call sne,foo,$$1))\ 64 $(call test-expect,,$(call -ndk-mod-filter,,-local-func))\ 65 $(call test-expect,,$(call -ndk-mod-filter,foo,-local-func))\ 66 $(call test-expect,bar,$(call -ndk-mod-filter,foo bar,-local-func))\ 67 $(call test-expect,aaa bar,$(call -ndk-mod-filter,aaa foo bar,-local-func)) 68 69 70 ####################################################################### 71 # Filter out a list of modules with a predicate function 72 # $1: list of module names. 73 # $2: predicate function, will be called with $(call $2,<name>), if the 74 # result is not empty, <name> will be added to the result. 75 # Out: subset of input list, where each item doesn't pass the predicate. 76 ####################################################################### 77 -ndk-mod-filter-out = $(strip \ 78 $(foreach _ndk_mod_filter_n,$1,\ 79 $(if $(call $2,$(_ndk_mod_filter_n)),,$(_ndk_mod_filter_n))\ 80 )) 81 82 -test-ndk-mod-filter-out = \ 83 $(eval -local-func = $$(call seq,foo,$$1))\ 84 $(call test-expect,,$(call -ndk-mod-filter-out,,-local-func))\ 85 $(call test-expect,,$(call -ndk-mod-filter-out,foo,-local-func))\ 86 $(call test-expect,bar,$(call -ndk-mod-filter-out,foo bar,-local-func))\ 87 $(call test-expect,aaa bar,$(call -ndk-mod-filter-out,aaa foo bar foo,-local-func))\ 88 $(eval -local-func = $$(call sne,foo,$$1))\ 89 $(call test-expect,,$(call -ndk-mod-filter-out,,-local-func))\ 90 $(call test-expect,foo,$(call -ndk-mod-filter-out,foo,-local-func))\ 91 $(call test-expect,foo,$(call -ndk-mod-filter-out,foo bar,-local-func))\ 92 $(call test-expect,foo foo,$(call -ndk-mod-filter-out,aaa foo bar foo,-local-func)) 93 94 95 ####################################################################### 96 # Find the first item in a list that checks a valid predicate. 97 # $1: list of names. 98 # $2: predicate function, will be called with $(call $2,<name>), if the 99 # result is not empty, <name> will be added to the result. 100 # Out: subset of input list. 101 ####################################################################### 102 -ndk-mod-find-first = $(firstword $(call -ndk-mod-filter,$1,$2)) 103 104 -test-ndk-mod-find-first.empty = \ 105 $(eval -local-pred = $$(call seq,foo,$$1))\ 106 $(call test-expect,,$(call -ndk-mod-find-first,,-local-pred))\ 107 $(call test-expect,,$(call -ndk-mod-find-first,bar,-local-pred)) 108 109 -test-ndk-mod-find-first.simple = \ 110 $(eval -local-pred = $$(call seq,foo,$$1))\ 111 $(call test-expect,foo,$(call -ndk-mod-find-first,foo,-local-pred))\ 112 $(call test-expect,foo,$(call -ndk-mod-find-first,aaa foo bar,-local-pred))\ 113 $(call test-expect,foo,$(call -ndk-mod-find-first,aaa foo foo bar,-local-pred)) 114 115 ######################################################################## 116 # Many tree walking operations require setting a 'visited' flag on 117 # specific graph nodes. The following helper functions help implement 118 # this while hiding details to the callers. 119 # 120 # Technical note: 121 # _ndk_mod_tree_visited.<name> will be 'true' if the node was visited, 122 # or empty otherwise. 123 # 124 # _ndk_mod_tree_visitors lists all visited nodes, used to clean all 125 # _ndk_mod_tree_visited.<name> variables in -ndk-mod-tree-setup-visit. 126 # 127 ####################################################################### 128 129 # Call this before tree traversal. 130 -ndk-mod-tree-setup-visit = \ 131 $(foreach _ndk_mod_tree_visitor,$(_ndk_mod_tree_visitors),\ 132 $(eval _ndk_mod_tree_visited.$$(_ndk_mod_tree_visitor) :=))\ 133 $(eval _ndk_mod_tree_visitors :=) 134 135 # Returns non-empty if a node was visited. 136 -ndk-mod-tree-is-visited = \ 137 $(_ndk_mod_tree_visited.$1) 138 139 # Set the visited state of a node to 'true' 140 -ndk-mod-tree-set-visited = \ 141 $(eval _ndk_mod_tree_visited.$1 := true)\ 142 $(eval _ndk_mod_tree_visitors += $1) 143 144 ######################################################################## 145 # Many graph walking operations require a work queue and computing 146 # dependencies / children nodes. Here are a few helper functions that 147 # can be used to make their code clearer. This uses a few global 148 # variables that should be defined as follows during the operation: 149 # 150 # _ndk_mod_module current graph node name. 151 # _ndk_mod_wq current node work queue. 152 # _ndk_mod_list current result (list of nodes). 153 # _ndk_mod_depends current graph node's children. 154 # you must call -ndk-mod-get-depends to set this. 155 # 156 ####################################################################### 157 158 # Pop first item from work-queue into _ndk_mod_module. 159 -ndk-mod-pop-first = \ 160 $(eval _ndk_mod_module := $$(call first,$$(_ndk_mod_wq)))\ 161 $(eval _ndk_mod_wq := $$(call rest,$$(_ndk_mod_wq))) 162 163 -test-ndk-mod-pop-first = \ 164 $(eval _ndk_mod_wq := A B C)\ 165 $(call -ndk-mod-pop-first)\ 166 $(call test-expect,A,$(_ndk_mod_module))\ 167 $(call test-expect,B C,$(_ndk_mod_wq))\ 168 169 170 # Push list of items at the back of the work-queue. 171 -ndk-mod-push-back = \ 172 $(eval _ndk_mod_wq := $(strip $(_ndk_mod_wq) $1)) 173 174 -test-ndk-mod-push-back = \ 175 $(eval _ndk_mod_wq := A B C)\ 176 $(call -ndk-mod-push-back, D E)\ 177 $(call test-expect,A B C D E,$(_ndk_mod_wq)) 178 179 # Set _ndk_mod_depends to the direct dependencies of _ndk_mod_module 180 -ndk-mod-get-depends = \ 181 $(eval _ndk_mod_depends := $$(call $$(_ndk_mod_deps_func),$$(_ndk_mod_module))) 182 183 # Set _ndk_mod_depends to the direct dependencies of _ndk_mod_module that 184 # are not already in _ndk_mod_list. 185 -ndk-mod-get-new-depends = \ 186 $(call -ndk-mod-get-depends)\ 187 $(eval _ndk_mod_depends := $$(filter-out $$(_ndk_mod_list),$$(_ndk_mod_depends))) 188 189 ########################################################################## 190 # Compute the transitive closure 191 # $1: list of modules. 192 # $2: dependency function, $(call $2,<module>) should return all the 193 # module that <module> depends on. 194 # Out: transitive closure of all modules from those in $1. Always includes 195 # the modules in $1. Order is random. 196 # 197 # Implementation note: 198 # we use the -ndk-mod-tree-xxx functions to flag 'visited' nodes 199 # in the graph. A node is visited once it has been put into the work 200 # queue. For each item in the work queue, get the dependencies and 201 # append all those that were not visited yet. 202 ####################################################################### 203 -ndk-mod-get-closure = $(strip \ 204 $(eval _ndk_mod_wq :=)\ 205 $(eval _ndk_mod_list :=)\ 206 $(eval _ndk_mod_deps_func := $2)\ 207 $(call -ndk-mod-tree-setup-visit)\ 208 $(foreach _ndk_mod_module,$1,\ 209 $(call -ndk-mod-closure-visit,$(_ndk_mod_module))\ 210 )\ 211 $(call -ndk-mod-closure-recursive)\ 212 $(eval _ndk_mod_deps :=)\ 213 $(_ndk_mod_list)\ 214 ) 215 216 # Used internally to visit a new node during -ndk-mod-get-closure. 217 # This appends the node to the work queue, and set its 'visit' flag. 218 -ndk-mod-closure-visit = \ 219 $(call -ndk-mod-push-back,$1)\ 220 $(call -ndk-mod-tree-set-visited,$1) 221 222 -ndk-mod-closure-recursive = \ 223 $(call -ndk-mod-pop-first)\ 224 $(eval _ndk_mod_list += $$(_ndk_mod_module))\ 225 $(call -ndk-mod-get-depends)\ 226 $(foreach _ndk_mod_dep,$(_ndk_mod_depends),\ 227 $(if $(call -ndk-mod-tree-is-visited,$(_ndk_mod_dep)),,\ 228 $(call -ndk-mod-closure-visit,$(_ndk_mod_dep))\ 229 )\ 230 )\ 231 $(if $(_ndk_mod_wq),$(call -ndk-mod-closure-recursive)) 232 233 -test-ndk-mod-get-closure.empty = \ 234 $(eval -local-deps = $$($$1_depends))\ 235 $(call test-expect,,$(call -ndk-mod-get-closure,,-local-deps)) 236 237 -test-ndk-mod-get-closure.single = \ 238 $(eval -local-deps = $$($$1_depends))\ 239 $(eval A_depends :=)\ 240 $(call test-expect,A,$(call -ndk-mod-get-closure,A,-local-deps)) 241 242 -test-ndk-mod-get-closure.double = \ 243 $(eval -local-deps = $$($$1_depends))\ 244 $(eval A_depends := B)\ 245 $(eval B_depends :=)\ 246 $(call test-expect,A B,$(call -ndk-mod-get-closure,A,-local-deps)) 247 248 -test-ndk-mod-get-closure.circular-deps = \ 249 $(eval -local-deps = $$($$1_depends))\ 250 $(eval A_depends := B)\ 251 $(eval B_depends := C)\ 252 $(eval C_depends := A)\ 253 $(call test-expect,A B C,$(call -ndk-mod-get-closure,A,-local-deps)) 254 255 -test-ndk-mod-get-closure.ABCDE = \ 256 $(eval -local-deps = $$($$1_depends))\ 257 $(eval A_depends := B C)\ 258 $(eval B_depends := D)\ 259 $(eval C_depends := D E)\ 260 $(eval D_depends :=)\ 261 $(eval E_depends :=)\ 262 $(call test-expect,A B C D E,$(call -ndk-mod-get-closure,A,-local-deps)) 263 264 265 ######################################################################### 266 # For topological sort, we need to count the number of incoming edges 267 # in each graph node. The following helper functions implement this and 268 # hide implementation details. 269 # 270 # Count the number of incoming edges for each node during topological 271 # sort with a string of xxxxs. I.e.: 272 # 0 edge -> '' 273 # 1 edge -> 'x' 274 # 2 edges -> 'xx' 275 # 3 edges -> 'xxx' 276 # etc. 277 ######################################################################### 278 279 # zero the incoming edge counter for module $1 280 -ndk-mod-topo-zero-incoming = \ 281 $(eval _ndk_mod_topo_incoming.$1 :=) 282 283 # increment the incoming edge counter for module $1 284 -ndk-mod-topo-increment-incoming = \ 285 $(eval _ndk_mod_topo_incoming.$1 := $$(_ndk_mod_topo_incoming.$1)x) 286 287 # decrement the incoming edge counter for module $1 288 -ndk-mod-topo-decrement-incoming = \ 289 $(eval _ndk_mod_topo_incoming.$1 := $$(_ndk_mod_topo_incoming.$1:%x=%)) 290 291 # return non-empty if the module $1's incoming edge counter is > 0 292 -ndk-mod-topo-has-incoming = $(_ndk_mod_topo_incoming.$1) 293 294 # Find first node in a list that has zero incoming edges. 295 # $1: list of nodes 296 # Out: first node that has zero incoming edges, or empty. 297 -ndk-mod-topo-find-first-zero-incoming = $(firstword $(call -ndk-mod-filter-out,$1,-ndk-mod-topo-has-incoming)) 298 299 # Only use for debugging: 300 -ndk-mod-topo-dump-count = \ 301 $(foreach _ndk_mod_module,$1,\ 302 $(info .. $(_ndk_mod_module) incoming='$(_ndk_mod_topo_incoming.$(_ndk_mod_module))')) 303 304 305 306 ######################################################################### 307 # Return the topologically ordered closure of all nodes from a top-level 308 # one. This means that a node A, in the result, will always appear after 309 # node B if A depends on B. Assumes that the graph is a DAG (if there are 310 # circular dependencies, this property cannot be guaranteed, but at least 311 # the function should not loop infinitely). 312 # 313 # $1: top-level node name. 314 # $2: dependency function, i.e. $(call $2,<name>) returns the children 315 # nodes for <name>. 316 # Return: list of nodes, include $1, which will always be the first. 317 ######################################################################### 318 -ndk-mod-get-topo-list = $(strip \ 319 $(eval _ndk_mod_top_module := $1)\ 320 $(eval _ndk_mod_deps_func := $2)\ 321 $(eval _ndk_mod_nodes := $(call -ndk-mod-get-closure,$1,$2))\ 322 $(call -ndk-mod-topo-count,$(_ndk_mod_nodes))\ 323 $(eval _ndk_mod_list :=)\ 324 $(eval _ndk_mod_wq := $(call -ndk-mod-topo-find-first-zero-incoming,$(_ndk_mod_nodes)))\ 325 $(call -ndk-mod-topo-sort)\ 326 $(_ndk_mod_list) $(_ndk_mod_nodes)\ 327 ) 328 329 # Given a closure list of nodes, count their incoming edges. 330 # $1: list of nodes, must be a graph closure. 331 -ndk-mod-topo-count = \ 332 $(foreach _ndk_mod_module,$1,\ 333 $(call -ndk-mod-topo-zero-incoming,$(_ndk_mod_module)))\ 334 $(foreach _ndk_mod_module,$1,\ 335 $(call -ndk-mod-get-depends)\ 336 $(foreach _ndk_mod_dep,$(_ndk_mod_depends),\ 337 $(call -ndk-mod-topo-increment-incoming,$(_ndk_mod_dep))\ 338 )\ 339 ) 340 341 -ndk-mod-topo-sort = \ 342 $(call -ndk-topo-debug,-ndk-mod-topo-sort: wq='$(_ndk_mod_wq)' list='$(_ndk_mod_list)')\ 343 $(call -ndk-mod-pop-first)\ 344 $(if $(_ndk_mod_module),\ 345 $(eval _ndk_mod_list += $(_ndk_mod_module))\ 346 $(eval _ndk_mod_nodes := $(filter-out $(_ndk_mod_module),$(_ndk_mod_nodes)))\ 347 $(call -ndk-mod-topo-decrement-incoming,$(_ndk_mod_module))\ 348 $(call -ndk-mod-get-depends)\ 349 $(call -ndk-topo-debug,-ndk-mod-topo-sort: deps='$(_ndk_mod_depends)')\ 350 $(foreach _ndk_mod_dep,$(_ndk_mod_depends),\ 351 $(call -ndk-mod-topo-decrement-incoming,$(_ndk_mod_dep))\ 352 $(if $(call -ndk-mod-topo-has-incoming,$(_ndk_mod_dep)),,\ 353 $(call -ndk-mod-push-back,$(_ndk_mod_dep))\ 354 )\ 355 )\ 356 $(call -ndk-mod-topo-sort)\ 357 ) 358 359 360 -test-ndk-mod-get-topo-list.empty = \ 361 $(eval -local-deps = $$($$1_depends))\ 362 $(call test-expect,,$(call -ndk-mod-get-topo-list,,-local-deps)) 363 364 -test-ndk-mod-get-topo-list.single = \ 365 $(eval -local-deps = $$($$1_depends))\ 366 $(eval A_depends :=)\ 367 $(call test-expect,A,$(call -ndk-mod-get-topo-list,A,-local-deps)) 368 369 -test-ndk-mod-get-topo-list.no-infinite-loop = \ 370 $(eval -local-deps = $$($$1_depends))\ 371 $(eval A_depends := B)\ 372 $(eval B_depends := C)\ 373 $(eval C_depends := A)\ 374 $(call test-expect,A B C,$(call -ndk-mod-get-topo-list,A,-local-deps)) 375 376 -test-ndk-mod-get-topo-list.ABC = \ 377 $(eval -local-deps = $$($$1_depends))\ 378 $(eval A_depends := B C)\ 379 $(eval B_depends :=)\ 380 $(eval C_depends := B)\ 381 $(call test-expect,A C B,$(call -ndk-mod-get-topo-list,A,-local-deps)) 382 383 -test-ndk-mod-get-topo-list.ABCD = \ 384 $(eval -local-deps = $$($$1_depends))\ 385 $(eval A_depends := B C)\ 386 $(eval B_depends := D)\ 387 $(eval C_depends := B)\ 388 $(eval D_depends :=)\ 389 $(call test-expect,A C B D,$(call -ndk-mod-get-topo-list,A,-local-deps)) 390 391 -test-ndk-mod-get-topo-list.ABC.circular = \ 392 $(eval -local-deps = $$($$1_depends))\ 393 $(eval A_depends := B)\ 394 $(eval B_depends := C)\ 395 $(eval C_depends := B)\ 396 $(call test-expect,A B C,$(call -ndk-mod-get-topo-list,A,-local-deps)) 397 398 ######################################################################### 399 # Return the topologically ordered closure of all dependencies from a 400 # top-level node. 401 # 402 # $1: top-level node name. 403 # $2: dependency function, i.e. $(call $2,<name>) returns the children 404 # nodes for <name>. 405 # Return: list of nodes, include $1, which will never be included. 406 ######################################################################### 407 -ndk-mod-get-topological-depends = $(call rest,$(call -ndk-mod-get-topo-list,$1,$2)) 408 409 -test-ndk-mod-get-topological-depends.simple = \ 410 $(eval -local-get-deps = $$($$1_depends))\ 411 $(eval A_depends := B)\ 412 $(eval B_depends :=)\ 413 $(eval topo_deps := $$(call -ndk-mod-get-topological-depends,A,-local-get-deps))\ 414 $(call test-expect,B,$(topo_deps),topo dependencies) 415 416 -test-ndk-mod-get-topological-depends.ABC = \ 417 $(eval -local-get-deps = $$($$1_depends))\ 418 $(eval A_depends := B C)\ 419 $(eval B_depends :=)\ 420 $(eval C_depends := B)\ 421 $(eval bfs_deps := $$(call -ndk-mod-get-bfs-depends,A,-local-get-deps))\ 422 $(eval topo_deps := $$(call -ndk-mod-get-topological-depends,A,-local-get-deps))\ 423 $(call test-expect,B C,$(bfs_deps),dfs dependencies)\ 424 $(call test-expect,C B,$(topo_deps),topo dependencies) 425 426 -test-ndk-mod-get-topological-depends.circular = \ 427 $(eval -local-get-deps = $$($$1_depends))\ 428 $(eval A_depends := B)\ 429 $(eval B_depends := C)\ 430 $(eval C_depends := B)\ 431 $(eval bfs_deps := $$(call -ndk-mod-get-bfs-depends,A,-local-get-deps))\ 432 $(eval topo_deps := $$(call -ndk-mod-get-topological-depends,A,-local-get-deps))\ 433 $(call test-expect,B C,$(bfs_deps),dfs dependencies)\ 434 $(call test-expect,B C,$(topo_deps),topo dependencies) 435 436 ######################################################################### 437 # Return breadth-first walk of a graph, starting from an arbitrary 438 # node. 439 # 440 # This performs a breadth-first walk of the graph and will return a 441 # list of nodes. Note that $1 will always be the first in the list. 442 # 443 # $1: root node name. 444 # $2: dependency function, i.e. $(call $2,<name>) returns the nodes 445 # that <name> depends on. 446 # Result: list of dependent modules, $1 will be part of it. 447 ######################################################################### 448 -ndk-mod-get-bfs-list = $(strip \ 449 $(eval _ndk_mod_wq := $(call strip-lib-prefix,$1)) \ 450 $(eval _ndk_mod_deps_func := $2)\ 451 $(eval _ndk_mod_list :=)\ 452 $(call -ndk-mod-tree-setup-visit)\ 453 $(call -ndk-mod-tree-set-visited,$(_ndk_mod_wq))\ 454 $(call -ndk-mod-bfs-recursive) \ 455 $(_ndk_mod_list)) 456 457 # Recursive function used to perform a depth-first scan. 458 # Must initialize _ndk_mod_list, _ndk_mod_field, _ndk_mod_wq 459 # before calling this. 460 -ndk-mod-bfs-recursive = \ 461 $(call -ndk-mod-debug,-ndk-mod-bfs-recursive wq='$(_ndk_mod_wq)' list='$(_ndk_mod_list)' visited='$(_ndk_mod_tree_visitors)')\ 462 $(call -ndk-mod-pop-first)\ 463 $(eval _ndk_mod_list += $$(_ndk_mod_module))\ 464 $(call -ndk-mod-get-depends)\ 465 $(call -ndk-mod-debug,. node='$(_ndk_mod_module)' deps='$(_ndk_mod_depends)')\ 466 $(foreach _ndk_mod_child,$(_ndk_mod_depends),\ 467 $(if $(call -ndk-mod-tree-is-visited,$(_ndk_mod_child)),,\ 468 $(call -ndk-mod-tree-set-visited,$(_ndk_mod_child))\ 469 $(call -ndk-mod-push-back,$(_ndk_mod_child))\ 470 )\ 471 )\ 472 $(if $(_ndk_mod_wq),$(call -ndk-mod-bfs-recursive)) 473 474 -test-ndk-mod-get-bfs-list.empty = \ 475 $(eval -local-deps = $$($$1_depends))\ 476 $(call test-expect,,$(call -ndk-mod-get-bfs-list,,-local-deps)) 477 478 -test-ndk-mod-get-bfs-list.A = \ 479 $(eval -local-deps = $$($$1_depends))\ 480 $(eval A_depends :=)\ 481 $(call test-expect,A,$(call -ndk-mod-get-bfs-list,A,-local-deps)) 482 483 -test-ndk-mod-get-bfs-list.ABCDEF = \ 484 $(eval -local-deps = $$($$1_depends))\ 485 $(eval A_depends := B C)\ 486 $(eval B_depends := D E)\ 487 $(eval C_depends := F E)\ 488 $(eval D_depends :=)\ 489 $(eval E_depends :=)\ 490 $(eval F_depends :=)\ 491 $(call test-expect,A B C D E F,$(call -ndk-mod-get-bfs-list,A,-local-deps)) 492 493 ######################################################################### 494 # Return breadth-first walk of a graph, starting from an arbitrary 495 # node. 496 # 497 # This performs a breadth-first walk of the graph and will return a 498 # list of nodes. Note that $1 will _not_ be part of the list. 499 # 500 # $1: root node name. 501 # $2: dependency function, i.e. $(call $2,<name>) returns the nodes 502 # that <name> depends on. 503 # Result: list of dependent modules, $1 will not be part of it. 504 ######################################################################### 505 -ndk-mod-get-bfs-depends = $(call rest,$(call -ndk-mod-get-bfs-list,$1,$2)) 506 507 -test-ndk-mod-get-bfs-depends.simple = \ 508 $(eval -local-deps-func = $$($$1_depends))\ 509 $(eval A_depends := B)\ 510 $(eval B_depends :=)\ 511 $(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\ 512 $(call test-expect,B,$(deps)) 513 514 -test-ndk-mod-get-bfs-depends.ABC = \ 515 $(eval -local-deps-func = $$($$1_depends))\ 516 $(eval A_depends := B C)\ 517 $(eval B_depends :=)\ 518 $(eval C_depends := B)\ 519 $(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\ 520 $(call test-expect,B C,$(deps))\ 521 522 -test-ndk-mod-get-bfs-depends.ABCDE = \ 523 $(eval -local-deps-func = $$($$1_depends))\ 524 $(eval A_depends := B C)\ 525 $(eval B_depends := D)\ 526 $(eval C_depends := D E F)\ 527 $(eval D_depends :=)\ 528 $(eval E_depends :=)\ 529 $(eval F_depends :=)\ 530 $(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\ 531 $(call test-expect,B C D E F,$(deps))\ 532 533 -test-ndk-mod-get-bfs-depends.loop = \ 534 $(eval -local-deps-func = $$($$1_depends))\ 535 $(eval A_depends := B)\ 536 $(eval B_depends := A)\ 537 $(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\ 538 $(call test-expect,B,$(deps)) 539