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.

0


source to share


2 answers


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.

+2


source


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

      

0


source







All Articles