Using multiple % in Makefile
I have to convert a set of file (let's say format fa) into another format (fb) by a command (fa2fb). Each target fb depends only on one fa file.
Data structure is in a format like this:
source:
./DATA/L1/fa/L1.fa
./DATA/L2/fa/L2.fa
...
./DATA/Ln/fa/Ln.fa
target:
./DATA/L1/fb/L1.fb
./DATA/L2/fb/L2.fb
...
./DATA/Ln/fb/Ln.fb
How can I implement it with make?
I have tried this but of course it did not work:
./DATA/%/fb/%.fb : ./DATA/%/fa/%.fb
@fa2fb $&l开发者_Go百科t; $@
Is there any simple solution without changing the data directories?
Many thanks!
Use secondary expansion and the subst
function to create a rule where the prerequisites are constructed as a more complex function of the target name:
.SECONDEXPANSION:
DATA/%.fb: $$(subst fb,fa,$$@)
@fa2fb $< $@
Note that this approach assumes that fb
will not occur anywhere else in the filename (which holds true if all of your filenames are of the form DATA/Ln/fb/Ln.fb
, for some integer n
).
This may be the sloppiest makefile I have ever written.
define template
$(2) : $(1)
echo hi
endef
sources=DATA/L1/fa/L1.fa DATA/L2/fa/L2.fa
$(foreach source,$(sources),$(eval $(call template,$(source),$(subst /fa/,/fb/,$(subst .fa,.fb,$(source))))))
The idea is to define a macro to generate your rules, then use foreach
and eval
+call
to invoke it once for each source. The source is the first argument to the call
, so it becomes $(1)
in the macro. The second argument is just the transformation from a source file name to a destination file name; it becomes $(2)
in the macro.
Replace echo hi
with your own rule and you should be good to go. And be sure to write a nice big clear comment or someday someone will surely show up at your door with a baseball bat.
This is basically the same as Nemo's answer. I just tried to make the foreach
call a bit more readable, by creating a list of modules, containing simply L1 L2 ... Ln
, instead of the list of full source names.
MODULES := $(notdir $(wildcard ./DATA/L*))
define rule
./DATA/$(1)/fb/$(1).fb: ./DATA/$(1)/fa/$(1).fa
@fa2fb $< $@
endef
$(foreach module, $(MODULES), $(eval $(call rule,$(module))))
精彩评论