非递归Makefile中的变量

时间:2019-02-13 16:32:54

标签: makefile

我正在使用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

2 个答案:

答案 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来解决各种相关的陷阱。