Reputation: 28699
I am trying to build a feature into my makefile which allows me to specify a list of libraries a particular library depends on
This will allow dependants of a library to automatically be rebuilt if that library's dependencies are rebuilt, and also have the dependencies added to the link line.
I asked a related question on SO here, and working through a given answer, I came up with the following test
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
expand-deps = $1 $(foreach _,$1, $(call expand-deps,$($__deps)))
make-dep-list = $(call uniq,$(call expand-deps,$1))
define make-lib
$(warning $1_deps: $2)
# capture the list of libraries this library depends on
$1_deps = $2
endef
define make-bin
# show the fully expanded list of libraries this binary depends on
$(warning $1 dep-list: [$(call make-dep-list,$2)])
endef
#$(eval $(call make-lib, thread, log utils)) circular-dependency log->thread; thread->log
$(eval $(call make-lib, thread, utils))
$(eval $(call make-lib, log, thread))
$(eval $(call make-lib, order, log))
$(eval $(call make-lib, price, log))
$(eval $(call make-bin, test, order price))
running the above makefile yields the following results:
$ make
makefile:15: thread_deps: utils
makefile:16: log_deps: thread
makefile:17: order_deps: log
makefile:18: price_deps: log
makefile:19: test dep-list: [order price log thread utils ]
make: *** No targets. Stop.
It is possible for libraries to have circular dependencies.
As an example: The logging library is multi-threaded, so requires the thread library. The thread library can issue log statements, so requires the log library.
If I uncomment out the line which has a circular dependency
$(eval $(call make-lib, thread, log utils))
$(eval $(call make-lib, log, thread))
The makefile will get stuck in an infinite loop.
How can I allow users to specify circular dependencies, and break out of the infinite loop?
Upvotes: 1
Views: 1255
Reputation: 15503
So, your problem is that you are recursively expanding lib_deps
(say). While doing that you start expanding lib_deps
again. Infinite loop (er, stack crash). To stop yourself you need to keep a list of things that you have already expanded. Falling out of functional style and keeping the answer in the global expansion
(ugh!), something like:
expand-deps = \
$(foreach _,$1, \
$(if $(filter $_,${expansion}),, \
$(eval expansion += $_)$(call expand-deps,${$__deps})))
make-dep-list = $(eval expansion :=)$(call expand-deps,$1)${expansion}
define make-lib
$(warning $1_deps: $2)
# capture the list of libraries this library depends on
$1_deps := $2
endef
define make-bin
# show the fully expanded list of libraries this binary depends on
$(warning $1 dep-list: [$(call make-dep-list,$2)])
endef
$(eval $(call make-lib,thread,log utils))#circular-dependency log->thread; thread->log
#$(eval $(call make-lib,thread,utils))
$(eval $(call make-lib,log,thread))
$(eval $(call make-lib,order,log))
$(eval $(call make-lib,price,log))
$(eval $(call make-bin,test,order price))
(As an exercise you might like to rewrite this in functional style, i.e., get rid of the global $expansion
replacing it with a parameter that gets passed around.)
Upvotes: 1