首页 > 解决方案 > 是否可以将延迟评估的变量导出到子 Makefile?

问题描述

希望这个问题是我从thisthis开始的最后一个问题。

我有以下目录结构:

.
├── Makefile
├── src
│   └── Makefile
└── test
    └── Makefile

我的顶级 Makefile 只$(MAKE)src/test/子目录上运行:

TOP_DIR := $(shell pwd)
export PRJ_LIBS = $(wildcard $(TOP_DIR)/build/*)

all: src test
        @echo $(PRJ_LIBS)

src:
        @$(MAKE) -C $@

test:
        @$(MAKE) -C $@

.PHONY: src test

我的src/Makefile 在 peer 子目录中创建一个文件build/

all:
        @mkdir -p ../build
        @touch ../build/libfoo.so

我希望我的test/Makefile 能够访问build/目录的更新内容:

all:
        @echo $(PRJ_LIBS)

上面的 Makefile 没有做到这一点:

$ rm -rf ./build/ && make
make[1]: Entering directory '/path/to/src'
make[1]: Leaving directory '/path/to/src'
make[1]: Entering directory '/path/to/test'

make[1]: Leaving directory '/path/to/test'

$ 

我发现一个问题是我在顶级 Makefile中导出。 $(PRJ_LIBS)将其设为非导出变量会稍微改善一些情况:子目录的更新内容build/在顶级 Makefile 的all配方中可见,但仍不在test/目录的 Makefile 中:

...
#export PRJ_LIBS = $(wildcard $(TOP_DIR)/build/*)
PRJ_LIBS = $(wildcard $(TOP_DIR)/build/*)
...
$ rm -rf ./build/ && make
make[1]: Entering directory '/path/to/src'
make[1]: Leaving directory '/path/to/src'
make[1]: Entering directory '/path/to/test'

make[1]: Leaving directory '/path/to/test'
/path/to/build/libfoo.so

根据我的业余估计,看起来我在这里有相互竞争的目标:我想“导出”我的惰性求值变量,以便顶级 Makefile 和子 Makefile 都“知道”它,但导出变量似乎有即时/预先评估的效果。


一个明显的解决方法是依赖对 shell 命令的显式调用:

#export PRJ_LIBS = $(wildcard $(TOP_DIR)/build/*)
#PRJ_LIBS = $(wildcard $(TOP_DIR)/build/*)
export PRJ_LIBS = $(shell find $(TOP_DIR)/build -type f)
$ rm -rf ./build/ && make
find: ‘/path/to/build’: No such file or directory
make[1]: Entering directory '/path/to/src'
make[1]: Leaving directory '/path/to/src'
make[1]: Entering directory '/path/to/test'
/path/to/build/libfoo.so
make[1]: Leaving directory '/path/to/test'
/path/to/build/libfoo.so
$ 

虽然这实现了我的目标,但导出变量具有预先评估的令人不快的副作用,导致findstderr 令人眼花缭乱的失败。导出变量与上面的第二次试验具有相同的效果:在顶级all配方中根据需要评估变量,但不在test/子目录的all配方中。


对于 Makefile 的更专业的人来说,对于我想要实现的目标,最好或“众所周知”的解决方案是什么:在顶级 Makefile 中定义一个可以在子级 Makefile 中延迟评估的变量?最好没有像前期 shell 命令失败这样的副作用。(实际上,在顶级 Makefile 中评估变量并不重要——这只是帮助我理解事物的调试工具)

标签: makefilegnu-makelazy-evaluation

解决方案


我想从无指导的实验结果中提供一种解决方案:

无法在顶级 Makefile 中导出我的惰性变量,然后将其作为参数传递给子 make,如下所示:

TOP_DIR := $(shell pwd)
PRJ_LIBS = $(wildcard $(TOP_DIR)/build/*)

all: src test
        @echo $(PRJ_LIBS)

src:
        @$(MAKE) -C $@

test:
        @$(MAKE) PRJ_LIBS=$(PRJ_LIBS) -C $@

.PHONY: src test
$ rm -rf ./build/ && make
make[1]: Entering directory '/home/amenon/code/fubar/src'
make[1]: Leaving directory '/home/amenon/code/fubar/src'
make[1]: Entering directory '/home/amenon/code/fubar/test'
/home/amenon/code/fubar/build/libfoo.so
make[1]: Leaving directory '/home/amenon/code/fubar/test'
/home/amenon/code/fubar/build/libfoo.so
$ 

我很好奇 Makefile 专家对这个解决方案的看法——这被认为是解决这个问题的好方法吗?


推荐阅读