-1

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.

Cactus
  • 27,075
  • 9
  • 69
  • 149
  • You could introduce an intermediate target `Key` for "extra_input.txt" that could generate a file list in a file called "extra_input.txt". For your standard build, the contents of that file might be empty but for your special targets, it will add the necessary dependencies. We would need more context from your shake file to suggest where to put the intermediate `Key`. – Bob Dalgleish Sep 24 '18 at 22:40
  • @BobDalgleish but that sounds like it would only work with pre-selected explicit extension points. I'm more looking for a solution where `mainFor` doesn't have to anticipate which rules would be possibly extended this way in various clients. – Cactus Sep 25 '18 at 01:19

1 Answers1

1

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.
Neil Mitchell
  • 9,090
  • 1
  • 27
  • 85