【问题标题】:makefile library dependencies - resolve circular dependencymakefile 库依赖 - 解决循环依赖
【发布时间】:2015-06-15 05:26:42
【问题描述】:

我正在尝试在我的 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))

makefile 将陷入无限循环。

如何让用户指定循环依赖,跳出死循环?

【问题讨论】:

  • 只是一种风格:最好不要在$(call …) 中的逗号后留下空格(或者实际上,在 make 函数中的任何逗号后)。这些空格不会消失——它们最终出现在参数的开头($1、$2 等)。这可能会让您感到困惑(例如,在连接标识符时)。改掉这个习惯吧!
  • 是的,图书馆可以有循环的部门,但它有点臭。如果可以避免,请不要这样做。在链接时,您需要让链接器重复链接,直到满足所有依赖项。 VisualC++ link 默认执行此操作。 ld 需要用--start-group 和--end-group 将库括起来(如果您从gcc 驱动链接,则使用gcc -Wl,--start-group libs... -Wl,--end-group 之类的东西)。跨度>
  • 问题是,这些库以什么方式相互依赖?它们是共享库还是静态库?如果是静态的,它们之间根本没有 build-time 依赖关系(也就是说,您不需要 liblog.a 来成功创建 libthread.a)。他们只有一个 link-time 依赖...所以 make 不关心这个依赖,只有链接器才关心。这意味着您不需要在库之间声明先决条件排序,您只需要在尝试链接它们之前确保它们都已构建。获得正确的链接线顺序是另一个问题。
  • @MadScientist 是的,我认为%_deps 变量仅用于指定可执行的链接时依赖项。
  • 在我的项目中,我只是按照我想要的顺序手动写出我的库列表。我还没有遇到过值得真正看中它的情况。现实情况是,正如 bobbogo 上面所说,如果您的库是循环引用的(并且您的链接器是单通道的,就像大多数 UNIX 链接器一样),那么根本没有线性的、非重复的库列表可以解决您的问题。您要么需要使用分组,要么必须在链接行上多次列出库。

标签: c++ makefile gnu-make


【解决方案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,将其替换为传递的参数。)

【讨论】:

    猜你喜欢
    • 2023-03-13
    • 1970-01-01
    • 2020-11-12
    • 1970-01-01
    • 2010-11-29
    相关资源
    最近更新 更多