Reputation: 6285
This question is hopefully the last one I've been building up to from this and this.
I have the following directory structure:
.
├── Makefile
├── src
│ └── Makefile
└── test
└── Makefile
My top-level Makefile just runs $(MAKE)
on the src/
and test/
subdirs:
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
My src/
Makefile creates a file in peer subdirectory build/
:
all:
@mkdir -p ../build
@touch ../build/libfoo.so
I would like my test/
Makefile to be able to access the updated content of the build/
directory:
all:
@echo $(PRJ_LIBS)
The above Makefiles don't achieve this:
$ 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'
$
I figured out that one problem is that I was exporting $(PRJ_LIBS)
in the top-level Makefile. Making this a non-exported variable improves things slightly: the updated content of the build/
subdir is visible in the top-level Makefile's all
recipe, but still not in the test/
directory's 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
By my amateur estimation, it looks like I have competing goals here: I want to "export" my lazily-evaluated variable so that it's "known" by both the top-level Makefile and a child Makefile, but exporting the variable seems to have the effect of immediate/up-front evaluation.
An apparent workaround is to rely on an explicit call to a shell command:
#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
$
Though this achieves my goal, exporting the variable has that unpleasant side-effect of the up-front evaluation resulting in the eyesore find
failure to stderr. Not exporting the variable has the same effect as the second trial, above: the variable being evaluated as desired in the top-level all
recipe, but not in the test/
subdirectory's all
recipe.
To someone more expert with Makefiles, what is the best or "well-known" solution to what I'm trying to achieve: define a variable in a top-level Makefile that can be lazily-evaluated in a child-level Makefile? Preferably with no side-effects like up-front shell command failures. (It's actually not important that the variable be evaluated in the top-level Makefile -- that was just more a debugging aid for me to understand things)
Upvotes: 1
Views: 248
Reputation: 6285
I'd like to offer one solution from the results of unguided experimentation:
I can not export my lazy variable in the top-level Makefile, and then pass it as an argument to the child make, like so:
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
$
I'm curious what Makefile experts make of this solution -- is this considered a good way to solve this?
Upvotes: 1