Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract the part of string matched by % in Makefile

I am doing my CS homework, which consists of a lot of single-file programs. My working directory looks like this:

133.c 134.c 220.c 281.c 337.c 338.c 339.c makefile

And I wrote a Makefile like this:

%: %.c
    ${CC} ${CFLAGS} -o $@ $^

So when I want to compile the program for Question 220, I type this:

ibug@wsl:~ $ make 220
gcc  -o 220 220.c
ibug@wsl:~ $

Question

I want to write a clean-% rule so that when I run this in shell, the result should look like below

ibug@wsl:~ $ make clean-133
rm -f 133
ibug@wsl:~ $ make clean-281
rm -f 281
ibug@wsl:~ $ make clean-337
rm -f 337

I've gone so far with this:

.PHONY: clean-%

SRC = $(wildcard %.c)
BIN = $(patsubst %.c,%,$(SRC))

clean-%:
    rm -f ??????

What should I put in place of the question marks?

I'm using GNU Make 4.1 (on Windows Subsystem for Linux).

like image 506
iBug Avatar asked Jan 28 '23 09:01

iBug


1 Answers

You are looking for the automatic variable $*, which contains the stem (i.e., the part matched against %):

clean-%:
    rm -f $*

However, keep reading.


Phony targets, patterns and implicit rules

Adding the prerequisite clean-% to the .PHONY target:

.PHONY: clean-%

does not turn the pattern rule clean-% into a phony target, but rather turns the explicit rule, whose actual target name is clean-% (not a pattern), into a phony target.

The reason is that only targets of explicit rules can be made phony targets, a pattern can't be a phony target. So, a phony target that looks like a pattern (i.e., contains %) is not really a pattern (i.e., the % is literally a %).

Adding all the possible values clean-% could be matched against to .PHONY won't help either, because phony targets do not match implicit pattern rules. So, if you do:

.PHONY: clean-foo

clean-foo will never match an implicit pattern rule (i.e., it will never match your clean-% pattern rule).


Defining clean-xxx as phony targets

I guess you actually want these clean-xxx targets to be phony targets, since these targets do not represent actual files on the file system.

Using a static pattern rule

Unlike implicit pattern rules, static pattern rules can match phony targets. The following approach consists of defining a single static pattern rule that can match those clean-xxx phony targets:

list := $(patsubst %.c,%,$(wildcard *.c))

# list of clean-xxx targets
clean-targets := $(addprefix clean-,$(list))

.PHONY: $(clean-targets)

$(clean-targets): clean-%:
    rm -f $*

The static pattern rule above will match any of the clean-xxx phony targets specified in its list of targets (i.e., the $(clean-targets).

Using explicit rules

The following approach consists of dynamically generating these clean-xxx rules as explicit rules instead of a single pattern rule:

list := $(patsubst %.c,%,$(wildcard *.c))

define create-clean-target
    $(eval .PHONY: clean-$1);
    $(eval clean-$1:; rm -f $1)
endef


# dynamically generate the clean-xxx targets
$(foreach t,$(list),$(call create-clean-target,$t))

The user-defined function create-target defines an explicit target clean-xxx, being xxx the argument passed to the function. Since this target to be defined is an explicit target, it can be made a phony target as well.

like image 144
ネロク・ゴ Avatar answered Jan 31 '23 19:01

ネロク・ゴ