Adding an extra dependency in new Rules to existing Rules

73 views Asked by At

I am writing a Shakefile with the aim of making it extensible with new Rules. Its interface is a function mainFor :: Rules () -> IO (), the idea being that client projects would only need to define main = mainFor myCustomRules to get the whole thing working. mainFor customRules is defined as a bunch of Shake Rules followed by a call to customRules.

This works as long as the custom rules passed to mainFor are for new targets.

However, some of my stock (non-custom) rules are basically of the form "run this big opaque proprietary external script with this input and hope for the best"; and there can be extra files used by the external script depending on its input. For example, imagine I have a rule of the following form:

"_build/output.bin" %> out -> do
    need ["_build/script.scr", "_build/src/generated.src"]
    runExternalScript

For a particular client project, maybe the generated source code contains references to another file _build/src/extrainput.src. So in the custom rules passed to mainFor, not only do I need extra rules for this file, but the existing rule should also be modified to mark that it needs this input:

main = mainFor $ do
    "_build/src/extrainput.src" %> \out -> do
       generateExtraSrc

    "_buld/output.bin" %> \out -> do
      need ["_build/src/extrainput.src"]

but this, unsurprisingly, fails because both the stock rule in mainFor and the second custom rule passed in the customRules argument are for the same target. Note that I do not want to fully override the stock rule, only extend it to add the extra dependency.

1

There are 1 answers

3
Neil Mitchell On

There is currently no way to do this using Shake. The possibilities are:

  • Add it to Shake. Whether that's the right thing depends on how common this requirement is - and my guess is relatively rare - but that needs validating. The fact you want the dependencies run before the rule is more concerning - it's somehow less compositional than just providing multiple actions that together produce a result.
  • Do it on the outside. My straw man would be to write the "extras" as some kind of FilePath -> Action () function, then define your own %> that also applied that function to the output. It would only work with pre-selected extension points, but if you redefine %> at the top of the file it can hit all your instances.
  • If you really want to hide it more, use shakeExtra to store the state in some way.