Makefile Pattern recipe for filename copying and renaming as temporary file

62 Views Asked by At

How can I make a pattern recipe for renaming files?

I have a recipe that takes a variable with a list of input files. But those files (Which always have .irx extension) must be stripped of the extension and renamed (copied to preserve the original) to uppercase before calling the program that will process them.

An example:

If the variable value is foo.irx bla.irx the files should be copied to another place as FOO and BLA before the actual recipe executes

Haven't tried anything concrete yet, just have been reading makefile docs in search for something that helps me out.

3

There are 3 best solutions below

0
MadScientist On

There's no simple way in GNU Make to "uppercase" a value. But the shell can do this with the tr program.

You can do something like:

FILES = foo.irx bla.irx

doit: $(FILES)
        for f in $(^:%.irx=%); do \
            cp $$f.irx $$(echo $$f | tr a-z A-Z); \
        done
0
Renaud Pacalet On

With GNU make you could try:

.PHONY: rename
define rename_rule
$1-up := $$(shell echo "$1" | tr '[a-z]' '[A-Z]')
rename: $$($1-up)
$$($1-up): $1.irx
    cp $$< $$@
endef
$(foreach i,$(basename $(wildcard *.irx)),$(eval $(call rename_rule,$i)))

Demo:

$ touch foo.irx bla.irx
$ make rename
cp bla.irx BLA
cp foo.irx FOO

Note that the GNU Make Standard Library by John Graham-Cumming has tr, uc, lc macros and many amazing others. If you can use it (just download two Makefiles and you're done) a GMSL-based solution could look like:

include gmsl
UPS := $(call uc,$(basename $(wildcard *.irx))) # compute uppercase target names
.PHONY: rename
rename: $(UPS)
.SECONDEXPANSION:              # secondary expansion
$(UPS): %: $$(call lc,$$*).irx # static pattern rule
    cp $< $@
7
HolyBlackCat On

Alright... Here's the function to convert a string to uppercase:

override alphabet := \
    A-a B-b C-c D-d E-e \
    F-f G-g H-h I-i J-j \
    K-k L-l M-m N-n O-o \
    P-p Q-q R-r S-s T-t \
    U-u V-v W-w X-x Y-y \
    Z-z

override var = $(eval override $(subst #,$$(strip #),$(subst $,$$$$,$1)))

override uppercase = $(call,$(call var,_ret := $1)$(foreach x,$(alphabet),$(call var,_ret := $(subst $(lastword $(subst -, ,$x)),$(firstword $(subst -, ,$x)),$(_ret)))))$(_ret)

This is way faster than using $(shell ) as @RenaudPacalet does in his answer (made a little benchmark processing 10 strings; this code takes ~6ms, while their takes ~56ms).

Here, var is a helper function that safely assigns to a variable, without tripping on special characters. $(call, ...) is a hack to evaluate the argument and destroy the string it expands to.

And here's how you use it to copy files: (this isn't too different from @RenaudPacalet's answer)

.PHONY: all

override define rename_rule =
all: $(call uppercase,$(basename $1))
$(call uppercase,$(basename $1)): $1
    cp $$< $$@
endef
$(foreach f,$(wildcard *.irx),$(eval $(call rename_rule,$f)))