【发布时间】:2019-02-13 16:32:53
【问题描述】:
我正在使用 GNU Make 并尝试使用非递归方法设计 Makefile。我遇到的问题 - 似乎没有办法限制不同 Makefile 中变量的范围。
例如,如果我有两个模块 libA 和 libB 的 Makefile
libA Makefile.inc:
src_dir := libA/src
inc_dir := libA/inc
libB Makefile.inc:
src_dir := libB/src
inc_dir := libB/inc
然后当我将上述 Makefile 包含到主 Makefile 中时
include libA/Makefile.inc
include libB/Makefile.inc
变量src_dir 和inc_dir 中的值被包含的最后一个Makefile 覆盖。好的,这可能是预期的,因为变量在此处是全局范围的,这会弄乱使用这些变量的构建命令,即 libA 的构建命令会找到 libB 的变量值。
一种解决方法是为每个 Makefile 创建唯一的变量
libA Makefile.inc:
src_dir_libA := libA/src
inc_dir_libA := libA/inc
libB Makefile.inc:
src_dir_libB := libB/src
inc_dir_libB := libB/inc
这解决了问题,但使用起来有点尴尬,因为每个变量都必须重命名。有谁知道是否有更好的方法来解决这个问题,例如如果 GNU Make 有一些范围或命名空间的概念?我查看了文档,但似乎找不到任何类似的东西。有特定于目标的变量,但它们似乎有令人讨厌的副作用。
好的,具体一点,下面是一个Makefile示例
dep_all :=
all:
# Begin Makefile.inc for project1
# ------------------------------------------------------------------------------
$(foreach var,$(filter local_%,$(.VARIABLES)),$(eval $(var) := ))
local_src_dir := project1/src
local_obj_dir := project1/obj
local_src := $(local_src_dir)/fileA.c $(local_src_dir)/fileB.c
local_obj := $(patsubst $(local_src_dir)/%.c,$(local_obj_dir)/%.o,$(local_src))
dep_all += $(local_src)
dep_all += $(local_obj)
$(info local_obj="$(local_obj)")
$(local_obj): $(local_obj_dir)/%.o: $(local_src_dir)/%.c
gcc -L$(local_obj_dir) -c -o $@ $<
# ------------------------------------------------------------------------------
# End Makefile.inc for project1
# Begin Makefile.inc for project2
# ------------------------------------------------------------------------------
$(foreach var,$(filter local_%,$(.VARIABLES)),$(eval $(var) := ))
local_src_dir := project2/src
local_obj_dir := project2/obj
local_src := $(local_src_dir)/fileX.c $(local_src_dir)/fileY.c
local_obj := $(patsubst $(local_src_dir)/%.c,$(local_obj_dir)/%.o,$(local_src))
dep_all += $(local_src)
dep_all += $(local_obj)
$(info local_obj="$(local_obj)")
$(local_obj): $(local_obj_dir)/%.o: $(local_src_dir)/%.c
gcc -L$(local_obj_dir) -c -o $@ $<
# ------------------------------------------------------------------------------
# End Makefile.inc for project2
$(info dep_all="$(dep_all)")
.PHONY: all
all: $(dep_all)
.PHONY: clean
clean:
rm -f project1/obj/* project2/obj/*
如果我运行它,那么传递给 gcc 的 -L<object_path> 选项包含来自最后包含的 Makefile 的值,即在构建 project1 时,它使用 -Lproject2/obj 运行 gcc,这不是该项目的正确对象路径。这就是我要解决的问题。
mkdir -p project1/{src,obj} project2/{src,obj}
touch project1/src/{fileA.c,fileB.c} project2/src/{fileX.c,fileY.c}
$ make
local_obj="project1/obj/fileA.o project1/obj/fileB.o"
local_obj="project2/obj/fileX.o project2/obj/fileY.o"
dep_all=" project1/src/fileA.c project1/src/fileB.c project1/obj/fileA.o project1/obj/fileB.o project2/src/fileX.c project2/src/fileY.c project2/obj/fileX.o project2/obj/fileY.o"
gcc -Lproject2/obj -c -o project1/obj/fileA.o project1/src/fileA.c
gcc -Lproject2/obj -c -o project1/obj/fileB.o project1/src/fileB.c
gcc -Lproject2/obj -c -o project2/obj/fileX.o project2/src/fileX.c
gcc -Lproject2/obj -c -o project2/obj/fileY.o project2/src/fileY.c
【问题讨论】:
-
显而易见且合理的标准解决方案是递归
make。 -
看看我的非递归 makefile 实现:github.com/igagis/prorab 方法是所有这些“本地”变量都以
this_前缀命名,并在每个makefile的开头全部带有this_前缀的变量被清除,看这里:github.com/igagis/prorab/blob/master/wiki/… -
我见过的另一种方法是在每个局部变量前面加上
$(DIR),其中$(DIR)派生自目录名称。 (顺便说一句,现在已经使用非递归 makefile 了一段时间,我不得不说我支持@tripleee 对此的建议......) -
recursive
make遇到各种问题,为什么要使用它?
标签: makefile