Sample only once per call, while make is deleting intermediate files
I have the following rules in the Makefile to create an executable in 3 steps:
all: build/myexe
build/myexe: output/main_dats.o output/foo_dats.o | build/
gcc $^ -o $@
output/%.o: output/%.c
patscc -c $< -o $@
output/%_dats.c: src/%.dats | output/
patsopt -cc -o $@ -d $<
build/:
mkdir -p build/
output/:
mkdir -p output/
The an source file is src/%.dats
used to create a source file output/%_dats.c
that is compiled into an object file output/%.o
and finally linked to the executable build/myexe
.
Running make
the first time will only successfully generate the first of the two files .o
:
$ make
mkdir -p output/
patsopt -cc -o output/main_dats.c -d src/main.dats
patscc -c output/main_dats.c -o output/main_dats.o
make: *** No rule to make target `output/foo_dats.o', needed by `build/myexe'. Stop.
rm output/main_dats.c
But running it again will create a second file .o
and link the executable successfully:
$ make
patsopt -cc -o output/foo_dats.c -d src/foo.dats
patscc -c output/foo_dats.c -o output/foo_dats.o
mkdir -p build/
gcc output/main_dats.o output/foo_dats.o -o build/myexe
rm output/foo_dats.c
and note that at the end of each invocation, the command rm output/..._dats.c
deletes the generated source file .c
.
Here's a Makefile written without pattern matching:
all: build/myexe
build/myexe: output/main_dats.o output/foo_dats.o | build/
gcc $^ -o $@
output/foo_dats.o: output/foo_dats.c
patscc -c $< -o $@
output/main_dats.o: output/main_dats.c
patscc -c $< -o $@
output/foo_dats.c: src/foo.dats | output/
patsopt -cc -o $@ -d $<
output/main_dats.c: src/main.dats | output/
patsopt -cc -o $@ -d $<
build/:
mkdir -p build/
output/:
mkdir -p output/
which works more predictably:
$ make
mkdir -p output/
patsopt -cc -o output/main_dats.c -d src/main.dats
patscc -c output/main_dats.c -o output/main_dats.o
patsopt -cc -o output/foo_dats.c -d src/foo.dats
patscc -c output/foo_dats.c -o output/foo_dats.o
mkdir -p build/
gcc output/main_dats.o output/foo_dats.o -o build/myexe
and note that the generated files are .c
no longer deleted.
Apparently I am using the pattern matching mechanism incorrectly. I know there is some sort of wildcard feature, but I believe it is for file globbing.
source to share
To avoid deleting intermediate files, you just need to specify them as real targets somewhere. For example, you can write a separate rule:
make_srcs: output/main_dats.c output/foo_dats.c
You don't need to list this target make_srcs
as a prerequisite, or provide it with a recipe, etc. Just listing the files _dats.c
as real targets or preconditions in the makefile is enough to keep them from being deleted.
As for your "with only some output" behavior, I don't know: it works great for me:
$ make --version | head -n1
GNU Make 4.2.1
$ cat Makefile
all: build/myexe
build/myexe: output/main_dats.o output/foo_dats.o | build/
touch $@
output/%.o: output/%.c
touch $@
output/%_dats.c: src/%.dats | output/
touch $@
build/:
mkdir -p build/
output/:
mkdir -p output/
make_srcs: output/main_dats.c output/foo_dats.c
$ rm -rf output build && make
mkdir -p output/
touch output/main_dats.c
touch output/main_dats.o
touch output/foo_dats.c
touch output/foo_dats.o
mkdir -p build/
touch build/myexe
So, something about your setup that was not clearly stated in your question. As a comment, suggested that you need to run make -d
(I would omit the parameter -R
, I don't know why you added it) and figure out why make is throwing this error.
source to share
Ideally, template rules should be outdated. They are prone to over-matching (because, well, templates), they are hard to get to work, they bring with them the whole "intermediate target" problem (that deleting the files output/*.c
you observe), they need another dubious feature ("secondary expansion" ) to make them usable in some more complex scenarios, etc.
In short: the use of template rules is not recommended and the use of layered template rules is definitely not recommended. It's just more trouble than it's worth. IMHO, anyway.
(end rant)
So, I suggest you write a simple macro, so your makefile looks like this:
all: build/myexe
# $(call dats,basename)
define dats
output/$1_dats.o: output/$1_dats.c
patscc -c $$< -o $$@
output/$1_dats.c: src/$1.c | output
patcc -cc -o $$@ -d $$<
endif
build/myexe: output/main_dats.o output/foo_dats.o | build
gcc $^ -o $@
$(eval $(call dats,foo))
$(eval $(call dats,main))
build:
mkdir -p build
output:
mkdir -p output
source to share