Pregunta

I want to remove the duplication of recipe in a makefile like the following

SHELL := /bin/bash
a_% : a1_% a2_%       
          cat $^ > $@                                                                                                                             
b_% : b1_% b2_%   %_b3                                                                                                                         
          cat $^ > $@   

However the following does not work. I guess the trick in this SO question does not work with pattern rules.

SHELL := /bin/bash
a_% : a1_% a2_%       
b_% : b1_% b2_%   %_b3                                                                                                                         
a_% b_%:
          cat $^ > $@   

Any suggestions ? ( In my original makefile, recipe duplication is occurring in 4 targets, and each of those take 3 substitutions, so I can't unroll the targets)

--EDIT-- I realized that one way to solve this was the following.

CMD1 = cat $^ > $@
a_% : a1_% a2_%       
         $(CMD1)
b_% : b1_% b2_%   %_b3
        $(CMD1)
¿Fue útil?

Solución

I believe this does what you asked for:

SHELL := /bin/bash

define STUFF
$(1)_%: $(1)1_% $(1)2_% $(2)
    cat $$^ > $$@
endef

$(eval $(call STUFF,a))
$(eval $(call STUFF,b,%_b3))

How this works:

  1. The general form of the rule is defined as STUFF. (You'd obviously want a better name in your own Makefile.) Note the doubling of dollar signs in $$^ and $$@. This protects them from evaluation when $(call ...) is executed. $(1) and $(2) will be replaced by $(call ...) with positional arguments.

  2. $(call STUFF,a) "calls" STUFF with $(1) set to the string a and $(2) set to the empty string. The return value is:

    a_%: a1_% a2_% 
        cat $^ > $@
    

    Note how one $ was stripped from the remaining variables.

  3. $(eval ...) evaluates the return value obtained in the previous step as if that string had been put in the Makefile. So it creates the rule.

Steps 2 and 3 also happen for the b files. It is similar to what happens for the a files except that this time $(2) is set to the string %_b3.

This is essentially the method I've used in the past to avoid duplication of rules for cases where the rules were rather complex. For the specific case you show in your question, I'd use the shared command variable you mention in your question.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top