• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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#
33ifeq (true,$(_ndk_mod_debug))
34-ndk-mod-debug = $(info $1)
35else
36-ndk-mod-debug := $(empty)
37endif
38
39ifeq (true,$(_ndk_topo_debug))
40-ndk-topo-debug = $(info $1)
41else
42-ndk-topo-debug = $(empty)
43endif
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    $(if $(_ndk_mod_wq),\
326        $(call -ndk-mod-topo-sort)\
327        $(_ndk_mod_list)\
328    ,\
329        $(_ndk_mod_nodes)\
330    ))
331
332# Given a closure list of nodes, count their incoming edges.
333# $1: list of nodes, must be a graph closure.
334-ndk-mod-topo-count = \
335    $(foreach _ndk_mod_module,$1,\
336        $(call -ndk-mod-topo-zero-incoming,$(_ndk_mod_module)))\
337    $(foreach _ndk_mod_module,$1,\
338        $(call -ndk-mod-get-depends)\
339        $(foreach _ndk_mod_dep,$(_ndk_mod_depends),\
340        $(call -ndk-mod-topo-increment-incoming,$(_ndk_mod_dep))\
341        )\
342    )
343
344-ndk-mod-topo-sort = \
345    $(call -ndk-topo-debug,-ndk-mod-topo-sort: wq='$(_ndk_mod_wq)' list='$(_ndk_mod_list)')\
346    $(call -ndk-mod-pop-first)\
347    $(if $(_ndk_mod_module),\
348        $(eval _ndk_mod_list += $(_ndk_mod_module))\
349        $(call -ndk-mod-topo-decrement-incoming,$(_ndk_mod_module))\
350        $(call -ndk-mod-get-depends)\
351        $(call -ndk-topo-debug,-ndk-mod-topo-sort:   deps='$(_ndk_mod_depends)')\
352        $(foreach _ndk_mod_dep,$(_ndk_mod_depends),\
353            $(call -ndk-mod-topo-decrement-incoming,$(_ndk_mod_dep))\
354            $(if $(call -ndk-mod-topo-has-incoming,$(_ndk_mod_dep)),,\
355                $(call -ndk-mod-push-back,$(_ndk_mod_dep))\
356            )\
357        )\
358        $(call -ndk-mod-topo-sort)\
359    )
360
361
362-test-ndk-mod-get-topo-list.empty = \
363    $(eval -local-deps = $$($$1_depends))\
364    $(call test-expect,,$(call -ndk-mod-get-topo-list,,-local-deps))
365
366-test-ndk-mod-get-topo-list.single = \
367    $(eval -local-deps = $$($$1_depends))\
368    $(eval A_depends :=)\
369    $(call test-expect,A,$(call -ndk-mod-get-topo-list,A,-local-deps))
370
371-test-ndk-mod-get-topo-list.no-infinite-loop = \
372    $(eval -local-deps = $$($$1_depends))\
373    $(eval A_depends := B)\
374    $(eval B_depends := C)\
375    $(eval C_depends := A)\
376    $(call test-expect,A B C,$(call -ndk-mod-get-topo-list,A,-local-deps))
377
378-test-ndk-mod-get-topo-list.ABC = \
379    $(eval -local-deps = $$($$1_depends))\
380    $(eval A_depends := B C)\
381    $(eval B_depends :=)\
382    $(eval C_depends := B)\
383    $(call test-expect,A C B,$(call -ndk-mod-get-topo-list,A,-local-deps))
384
385-test-ndk-mod-get-topo-list.ABCD = \
386    $(eval -local-deps = $$($$1_depends))\
387    $(eval A_depends := B C)\
388    $(eval B_depends := D)\
389    $(eval C_depends := B)\
390    $(eval D_depends :=)\
391    $(call test-expect,A C B D,$(call -ndk-mod-get-topo-list,A,-local-deps))
392
393#########################################################################
394# Return the topologically ordered closure of all dependencies from a
395# top-level node.
396#
397# $1: top-level node name.
398# $2: dependency function, i.e. $(call $2,<name>) returns the children
399#     nodes for <name>.
400# Return: list of nodes, include $1, which will never be included.
401#########################################################################
402-ndk-mod-get-topological-depends = $(call rest,$(call -ndk-mod-get-topo-list,$1,$2))
403
404-test-ndk-mod-get-topological-depends.simple = \
405    $(eval -local-get-deps = $$($$1_depends))\
406    $(eval A_depends := B)\
407    $(eval B_depends :=)\
408    $(eval topo_deps := $$(call -ndk-mod-get-topological-depends,A,-local-get-deps))\
409    $(call test-expect,B,$(topo_deps),topo dependencies)
410
411-test-ndk-mod-get-topological-depends.ABC = \
412    $(eval -local-get-deps = $$($$1_depends))\
413    $(eval A_depends := B C)\
414    $(eval B_depends :=)\
415    $(eval C_depends := B)\
416    $(eval bfs_deps := $$(call -ndk-mod-get-bfs-depends,A,-local-get-deps))\
417    $(eval topo_deps := $$(call -ndk-mod-get-topological-depends,A,-local-get-deps))\
418    $(call test-expect,B C,$(bfs_deps),dfs dependencies)\
419    $(call test-expect,C B,$(topo_deps),topo dependencies)
420
421#########################################################################
422# Return breadth-first walk of a graph, starting from an arbitrary
423# node.
424#
425# This performs a breadth-first walk of the graph and will return a
426# list of nodes. Note that $1 will always be the first in the list.
427#
428# $1: root node name.
429# $2: dependency function, i.e. $(call $2,<name>) returns the nodes
430#     that <name> depends on.
431# Result: list of dependent modules, $1 will be part of it.
432#########################################################################
433-ndk-mod-get-bfs-list = $(strip \
434    $(eval _ndk_mod_wq := $(call strip-lib-prefix,$1)) \
435    $(eval _ndk_mod_deps_func := $2)\
436    $(eval _ndk_mod_list :=)\
437    $(call -ndk-mod-tree-setup-visit)\
438    $(call -ndk-mod-tree-set-visited,$(_ndk_mod_wq))\
439    $(call -ndk-mod-bfs-recursive) \
440    $(_ndk_mod_list))
441
442# Recursive function used to perform a depth-first scan.
443# Must initialize _ndk_mod_list, _ndk_mod_field, _ndk_mod_wq
444# before calling this.
445-ndk-mod-bfs-recursive = \
446    $(call -ndk-mod-debug,-ndk-mod-bfs-recursive wq='$(_ndk_mod_wq)' list='$(_ndk_mod_list)' visited='$(_ndk_mod_tree_visitors)')\
447    $(call -ndk-mod-pop-first)\
448    $(eval _ndk_mod_list += $$(_ndk_mod_module))\
449    $(call -ndk-mod-get-depends)\
450    $(call -ndk-mod-debug,.  node='$(_ndk_mod_module)' deps='$(_ndk_mod_depends)')\
451    $(foreach _ndk_mod_child,$(_ndk_mod_depends),\
452        $(if $(call -ndk-mod-tree-is-visited,$(_ndk_mod_child)),,\
453            $(call -ndk-mod-tree-set-visited,$(_ndk_mod_child))\
454            $(call -ndk-mod-push-back,$(_ndk_mod_child))\
455        )\
456    )\
457    $(if $(_ndk_mod_wq),$(call -ndk-mod-bfs-recursive))
458
459-test-ndk-mod-get-bfs-list.empty = \
460    $(eval -local-deps = $$($$1_depends))\
461    $(call test-expect,,$(call -ndk-mod-get-bfs-list,,-local-deps))
462
463-test-ndk-mod-get-bfs-list.A = \
464    $(eval -local-deps = $$($$1_depends))\
465    $(eval A_depends :=)\
466    $(call test-expect,A,$(call -ndk-mod-get-bfs-list,A,-local-deps))
467
468-test-ndk-mod-get-bfs-list.ABCDEF = \
469    $(eval -local-deps = $$($$1_depends))\
470    $(eval A_depends := B C)\
471    $(eval B_depends := D E)\
472    $(eval C_depends := F E)\
473    $(eval D_depends :=)\
474    $(eval E_depends :=)\
475    $(eval F_depends :=)\
476    $(call test-expect,A B C D E F,$(call -ndk-mod-get-bfs-list,A,-local-deps))
477
478#########################################################################
479# Return breadth-first walk of a graph, starting from an arbitrary
480# node.
481#
482# This performs a breadth-first walk of the graph and will return a
483# list of nodes. Note that $1 will _not_ be part of the list.
484#
485# $1: root node name.
486# $2: dependency function, i.e. $(call $2,<name>) returns the nodes
487#     that <name> depends on.
488# Result: list of dependent modules, $1 will not be part of it.
489#########################################################################
490-ndk-mod-get-bfs-depends = $(call rest,$(call -ndk-mod-get-bfs-list,$1,$2))
491
492-test-ndk-mod-get-bfs-depends.simple = \
493    $(eval -local-deps-func = $$($$1_depends))\
494    $(eval A_depends := B)\
495    $(eval B_depends :=)\
496    $(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\
497    $(call test-expect,B,$(deps))
498
499-test-ndk-mod-get-bfs-depends.ABC = \
500    $(eval -local-deps-func = $$($$1_depends))\
501    $(eval A_depends := B C)\
502    $(eval B_depends :=)\
503    $(eval C_depends := B)\
504    $(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\
505    $(call test-expect,B C,$(deps))\
506
507-test-ndk-mod-get-bfs-depends.ABCDE = \
508    $(eval -local-deps-func = $$($$1_depends))\
509    $(eval A_depends := B C)\
510    $(eval B_depends := D)\
511    $(eval C_depends := D E F)\
512    $(eval D_depends :=)\
513    $(eval E_depends :=)\
514    $(eval F_depends :=)\
515    $(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\
516    $(call test-expect,B C D E F,$(deps))\
517
518-test-ndk-mod-get-bfs-depends.loop = \
519    $(eval -local-deps-func = $$($$1_depends))\
520    $(eval A_depends := B)\
521    $(eval B_depends := A)\
522    $(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\
523    $(call test-expect,B,$(deps))
524