Search code examples
shake-build-system

In Shake, does the definition order of Rules matter?


If I have a general build rule for *.o object files but a more specific build rule for a foo.o object file, does the definition order matter?


Solution

  • As described in the documentation for %> operator:

    Patterns with no wildcards have higher priority than those with wildcards, and no file required by the system may be matched by more than one pattern at the same priority (see priority and alternatives to modify this behaviour).

    So definition order doesn't matter, but files can't match multiple rules at the same priority.

    Therefore, in the case of *.o and foo.o, it'll be fine. Here's an example (using foo.txt and *.txt):

    import Development.Shake
    
    main = shakeArgs shakeOptions $ do
        want ["foo.txt", "bar.txt"]
        "foo.txt" %> \out -> writeFile' out "foo"
        "*.txt"   %> \out -> writeFile' out "anything"
    

    vs

    import Development.Shake
    
    main = shakeArgs shakeOptions $ do
        want ["foo.txt", "bar.txt"]
        "*.txt"   %> \out -> writeFile' out "anything"
        "foo.txt" %> \out -> writeFile' out "foo"
    

    In both cases foo.txt will contain "foo" and bar.txt will contain "anything" because the definition for "foo.txt" doesn't contain any wildcards.


    Alternatively, if you want to use definition order, you can use the alternatives function which uses "first-wins" matching semantics:

    alternatives $ do
        "hello.*" %> \out -> writeFile' out "hello.*"
        "*.txt" %> \out -> writeFile' out "*.txt"
    

    hello.txt will match the first rule, because it's defined before.

    Finally, you can directly assign the priority of a rule with the priority function:

    priority 4 $ "hello.*" %> \out -> writeFile' out "hello.*"
    priority 8 $ "*.txt" %> \out -> writeFile' out "*.txt"
    

    hello.txt will match the second rule, because it has a higher priority.