Brian McFarland
Brian McFarland

Reputation: 9412

gnumake and pattern rules

I'm using GNUmake to generate a deployment version of some web content from a source directory. I want to be rules that will run some files through compression tools (e.g. YUI compressor), and then for anything that doesn't have a rule, just copy it.

So for example:

# Rule with all the $(WWW_OUT_DIR)/*.* files as a prerequisite
all: $(WWW_OUT_FILES)

# Generic rule to perform compression on Javascript files.
$(WWW_OUT_DIR)/%.js:     $(WWW_SRC_DIR)/%.js
    $(YUI_COMP) $(YUI_COMP_OPTS) $< > $@

# Generic rule to perform compression on CSS files.
$(WWW_OUT_DIR)/%.css:    $(WWW_SRC_DIR)/%.css
    $(YUI_COMP) $(YUI_COMP_OPTS) $< > $@

# TDB Rule to magically handle everything else? (This doesn't work)
$(WWW_OUT_DIR)/%.%:   $(WWW_SRC_DIR)/%.%
    cp $< $@

How do I accomplish what that last rule is trying to do? I.e. For everything in $(WWW_OUT_FILES) that's not a .js or .css, just copy it? If possible, I want to retain the dependency on the corresponding input file.

Upvotes: 4

Views: 1566

Answers (1)

Eldar Abusalimov
Eldar Abusalimov

Reputation: 25483

You are almost right, the only thing to fix is the last pattern rule, just remove redundant percent symbol:

$(WWW_OUT_DIR)/%:   $(WWW_SRC_DIR)/%
    cp $< $@

Also keep in mind that as of GNU Make 3.82 pattern search algorithm has been modified a bit (from Changelog):

The pattern-specific variables and pattern rules are now applied in the shortest stem first order instead of the definition order (variables and rules with the same stem length are still applied in the definition order). This produces the usually-desired behavior where more specific patterns are preferred.

It is exactly what you want in case if you use the most recent version of Make. In order to get your Makefile compatible with other versions of GNU Make (including versions earlier than 3.82), the rule must be defined after other ones (as in the original question).

UPD.

A good example from here:

Prior to version 3.82, when gmake finds multiple matches during a pattern search, it prefers patterns declared earlier in the makefile over patterns declared later. As of 3.82, gmake instead prefers the pattern that results in the shortest stem. That sounds a bit confusing thanks to the jargon, but I think this will actually cause gmake to better adhere to the principle of least astonishment. Here’s an example:

all: sub/foo.x

%.x:
    @echo "Prefer first match (stem is $*)."

sub/%.x:
    @echo "Prefer most specific match (stem is $*)."

Compare the output from gmake 3.81 and 3.82:

  • gmake 3.81

    Prefer first match (stem is sub/foo).
    
  • gmake 3.82

    Prefer most specific match (stem is foo).
    

gmake 3.82 prefers the second pattern because it is a more specific match than the first. Note that this is a significant backwards-incompatibility compared with previous versions of gmake!

Upvotes: 7

Related Questions