Я использую GNU Make и пытаюсь проектировать Makefiles, используя нерекурсивный подход.У меня есть проблема - кажется, нет способа ограничить область видимости переменных в разных файлах Makefile.
Например, если у меня есть два файла Makefile для модулей libA и libB
libA Makefile.inc:
src_dir := libA/src
inc_dir := libA/inc
libB Makefile.inc:
src_dir := libB/src
inc_dir := libB/inc
Затем, когда я включаю вышеупомянутые Make-файлы в основной Make-файл
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/*
Если я запустил его, тоопция -L<object_path>
, переданная в gcc, содержит значение из последнего включенного Makefile, т.е. при сборке project1 он запускает gcc с -Lproject2/obj
, что не является правильным путем к объекту для этого проекта.Это проблема, которую я пытаюсь решить.
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