我正在使用GNU Make,并尝试使用非递归方法设计Makefile。我遇到的问题-似乎没有一种方法可以限制不同Makefile中变量的范围。
例如,如果我有两个用于模块libA和libB的Makefile,
SELECT TO_CHAR('04.0','0D9') FROM dual;
4.0
然后当我将上述Makefile包含到主Makefile中
libA Makefile.inc:
src_dir := libA/src
inc_dir := libA/inc
libB Makefile.inc:
src_dir := libB/src
inc_dir := libB/inc
变量include libA/Makefile.inc
include libB/Makefile.inc
和src_dir
中的值被包含的最后一个Makefile覆盖。好的,这很可能是预料之中的,因为变量在这里是全局范围的,这会弄乱使用这些变量的构建命令,即libA的build命令找到libB的变量值。
一种解决方法是为每个Makefile创建唯一的变量
inc_dir
这可以解决问题,但是使用起来有点尴尬,因为每个变量都必须重命名。有谁知道是否有更好的方法来解决这个问题,例如GNU Make是否具有范围或命名空间的概念?我看过文档,但是似乎找不到任何东西。有特定于目标的变量,但它们似乎有讨厌的副作用。
好的,很具体,下面是一个示例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
如果我运行它,则传递给gcc的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/*
选项包含最后一个包含的Makefile中的值,即,在构建project1时,它使用-L<object_path>
运行gcc,这不是正确的对象路径项目。这是我要解决的问题。
-Lproject2/obj
答案 0 :(得分:0)
解决方案是使用特定的前缀命名特定文件本地的所有变量。
例如,我使用this_
前缀。
然后,在每个子makefile文件的开头,可以清除具有this_
前缀的那些变量,如下所示:
$(foreach var,$(filter this_%,$(.VARIABLES)),$(eval $(var) := ))
PS。我在非递归makefile
的实现中使用了这种方法,清除了此处描述的变量:https://github.com/igagis/prorab/blob/master/wiki/TutorialBasicConcepts.md#defining-several-builds-in-one-makefile
答案 1 :(得分:0)
我想我已经找到了解决方案。我在读《 The GNU Make Book》,它指出了目标特定变量的副作用
特定于目标的变量不仅适用于目标,还适用于所有目标 目标的先决条件及其所有先决条件,以及 以此类推。目标特定变量的范围是 目标,从为其定义变量的目标开始。
这不是我想要的行为,但是从GNU Make 3.82开始,支持专用于私有目标的变量
通常为目标和所有目标定义目标特定的变量 它的先决条件。但是如果特定于目标的变量带有前缀 如果使用关键字private,则仅针对该目标定义该关键字, 先决条件。
因此以下Makefile对于这些私有变量似乎正常工作
dep_all :=
all:
# Begin Makefile.inc for project1
# ------------------------------------------------------------------------------
inc_dir := project1/inc
src_dir := project1/src
obj_dir := project1/obj
src := $(src_dir)/fileA.c $(src_dir)/fileB.c
obj := $(patsubst $(src_dir)/%.c,$(obj_dir)/%.o,$(src))
# These flags will be overwritten by another Makefile
CFLAGS := -I$(inc_dir)
# These flags will be private and not be overwritten by another Makefile
CFLAGS_priv := -I$(inc_dir) -L$(obj_dir)
dep_all += $(src)
dep_all += $(obj)
# Private target specific variables
$(obj): private CFLAGS_priv:=$(CFLAGS_priv)
$(obj): $(obj_dir)/%.o: $(src_dir)/%.c
gcc $(CFLAGS) $(CFLAGS_priv) -c -o $@ $<
# ------------------------------------------------------------------------------
# End Makefile.inc for project1
# Begin Makefile.inc for project2
# ------------------------------------------------------------------------------
inc_dir := project2/inc
src_dir := project2/src
obj_dir := project2/obj
src := $(src_dir)/fileX.c $(src_dir)/fileY.c
obj := $(patsubst $(src_dir)/%.c,$(obj_dir)/%.o,$(src))
# These flags will be overwritten by another Makefile
CFLAGS := -I$(inc_dir)
# These flags will be private and not be overwritten by another Makefile
CFLAGS_priv := -I$(inc_dir) -L$(obj_dir)
dep_all += $(src)
dep_all += $(obj)
# Private target specific variables
$(obj): private CFLAGS_priv:=$(CFLAGS_priv)
$(obj): $(obj_dir)/%.o: $(src_dir)/%.c
gcc $(CFLAGS) $(CFLAGS_priv) -c -o $@ $<
# ------------------------------------------------------------------------------
# End Makefile.inc for project2
.PHONY: all
all: $(dep_all)
.PHONY: clean
clean:
rm -f project1/obj/* project2/obj/*
输出是我想要的,因为现在我可以为每个项目定义私有CFLAGS_priv变量,该变量设置-I<dir>
,-L<dir>
路径,并且不会被其他Makefile覆盖。
$ make
gcc -Iproject2/inc -Iproject1/inc -Lproject1/obj -c -o project1/obj/fileA.o project1/src/fileA.c
gcc -Iproject2/inc -Iproject1/inc -Lproject1/obj -c -o project1/obj/fileB.o project1/src/fileB.c
gcc -Iproject2/inc -Iproject2/inc -Lproject2/obj -c -o project2/obj/fileX.o project2/src/fileX.c
gcc -Iproject2/inc -Iproject2/inc -Lproject2/obj -c -o project2/obj/fileY.o project2/src/fileY.c
我希望这可以解决我遇到的所有问题,并且我不必使用递归make来解决各种相关的陷阱。