Unexpected execution of "all" target in my makefile

176 views Asked by At

I've a makefile that is suppose to repeat an execution of a c code (BootstrapCL.c) one time for each file.csv in the directory. For each execution it should give in input to the c code (as argv) 2 string: the name, with and without extention, of the input csv file used in the current execution. This is the makefile content:

SRCS := $(wildcard *.csv)
BINS := $(SRCS:%.csv=%)

all: ${BINS}

%: BootstrapCL.c
    gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
    ./BootstrapCL [email protected] $@

The problem is that, after the execution of all the group of csv file (iI'd like to execute only the target inside ${BINS} list) , it also run a last execution with "all" target. Of course I don't have any all.csv file in my folder; I think I'm using $@ in the wrong way but I don't understand why and how to fix the issue, any idea?

3

There are 3 answers

2
code_fodder On BEST ANSWER

I have a slightly different take on the solution then Beta's:

SRCS := $(wildcard *.csv)
BINS := $(SRCS:%.csv=%)

# All rule - requires binaries to be generated. This does not generate anything, therefore it is PHONY
.PHONY: all
all: ${BINS}

# Generates the binaries - requires BootstrapCL exe to be generated first
${BINS}: BootstrapCL
    ./BootstrapCL [email protected] $@

# Generates BootstrapCL
BootstrapCL:
    gcc -Wall BootstrapCL.c  -lm -o BootstrapCL

From what I can tell - you need to compile BootstrapCL.c once to generate BootstrapCL executable. Then using that you genetate multiple binaries - one for eacn .csv file.

So in reverse:

  • You have an all target that requires the BINS.
  • You have a BINS target that generates the BINs, but first requires BootstrapCL - this will run once for each .csv file.
  • You have a BootstrapCL target that generates the BootstrapCL executable - this will run just once.
1
Beta On

The problem is that you have no recipe for all, and a rule for % which matches anything. When Make has finished with the prerequisites (${BINS}), it tries to build all, goes looking for a recipe that fits, and finds %.

There are (at least) two ways to solve the problem. The quick and dirty way is to add a (null) recipe for all:

all: ${BINS}
    @:

Onother way, in my opinion better, is to tighten the second rule:

BINS := $(SRCS:%.csv=%.phony)

all: ${BINS}

%.phony: BootstrapCL.c
    gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
    ./BootstrapCL $*.csv $*

Just to be tidy, I suggest you also add the line:

.PHONY: $(BINS)

To let Make know that the .phony targets are not real files to be built.

Some other small improvements are possible. I would think about BootstrapCL and whether it produces a file that could be used as a real target.

0
raspy On

The % rule is too general and catches everything, even attempt to rebuild the Makefile itself. Moreover it compiles BootstrapCL every time, which seems unnecessary:

$ make
gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
./BootstrapCL Makefile.csv Makefile
gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
./BootstrapCL foo.csv foo
gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
./BootstrapCL bar.csv bar
gcc -Wall BootstrapCL.c  -lm -o BootstrapCL
./BootstrapCL all.csv all

I would make use of pattern rule for binary generation, as this also will rebuild the binary should the .csv file change. I would also separate BootstrapCL generation to a different rule to only compile it once, but keep it on the dependency list for the targets to regenerate them if BootstrapCL changes:

$ cat Makefile
SRCS := $(wildcard *.csv)
BINS := $(SRCS:%.csv=%)

all: ${BINS}

BootstrapCL: BootstrapCL.c
        gcc -Wall $< -lm -o $@

%: %.csv BootstrapCL
        ./BootstrapCL $< $@

Output:

$ make
gcc -Wall BootstrapCL.c -lm -o BootstrapCL
./BootstrapCL foo.csv foo
./BootstrapCL bar.csv bar