2015-06-15 96 views
1

我想建立一个功能到我的makefile,让我来指定库某个库取决于生成文件库的依赖 - 解决循环依赖

名单这将允许一个图书馆的家属被自动如果该库的依赖关系被重建,则重建,并且还将链接添加到链接行。

我问的SO here一个相关的问题,并通过给答案的工作,我想出了下面的测试

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)) 

运行上面的makefile产生以下结果:

$ 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. 

库可能具有循环依赖关系。

举个例子:日志库是多线程的,所以需要线程库。线程库可以发出日志语句,所以需要日志库。

如果我取消了具有循环依赖

$(eval $(call make-lib, thread, log utils)) 
$(eval $(call make-lib, log, thread)) 

生成文件将陷入无限循环线路。

我该如何让用户指定循环依赖关系并跳出无限循环?

+0

只是一个样式:最好不要在'$(call ...)'(或者在_make_函数中的任何逗号后面)逗号后留空格。这些空间不会消失 - 它们最终会在参数的开始处('$ 1','$ 2'等)出现。这会让你感到困惑(例如,连接标识符时)。只要戒除习惯! – bobbogo

+1

是的,图书馆可以有圆形图案,但有点臭。如果你能避免它,不要这样做。在链接时,您需要让链接器重复链接,直到满足所有依赖关系。 VisualC++ _link_默认执行此操作。 _ld_需要使用'--start-group'和'--end-group'来括号化库(如果你正在从_gcc_驱动链接,那么使用'gcc -Wl, - start-group libs .. 。-W1, - 结束组)。 – bobbogo

+0

问题是,这些库以何种方式相互依赖?他们是共享库还是静态库?如果是静态的,他们根本就没有相互依赖的_build-time_(也就是说,你不需要liblog.a来成功创建libthread.a)。它们只有一个_link-time_依赖项......所以make并不关心这个依赖项,只有链接器才会这样做。这意味着你不需要声明库之间的先决条件排序,你只需要确保它们都是在你尝试链接它们之前构建的。让链接线顺序正确是另一个问题。 – MadScientist

回答

1

所以,你的问题是,你递归地扩大lib_deps(说)。在这样做的时候,你再次开始扩展lib_deps。无限循环(呃,堆栈崩溃)。为了阻止自己,你需要保留一个你已经扩展的东西的列表。掉落的功能风格,保持了答案,在全球expansion(啊!),这样的:

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)) 

(作为练习,你可能会喜欢函数式改写这一点,即摆脱了全球$expansion的用一个传过来的参数替换它。)