Search code examples
haskellshake-build-system

Haskell shake: special rule for building directories


Sometimes it is the case that to create a directory mkdir is not the right tool. It may be git clone or rsync or mount. So when we have a rule like this:

needDir dirs = filterM ((fmap not) . doesDirectoryExist) dirs >>= need

rules = do {
  "project" </> "tool" %> \out -> do {
    needDir [takeDirectory out];
    cmd "make -C" [takeDirectory out];
    }

  "project" %> \out -> cmd "git clone a.url.to/repo.git" [out]
  }

As one might expect the "project" </> "tool" creates the directory project before anything else and git clone isn't even run. Is there a way to go around this?

I suspect a new Rule is due here but I the docs were minimal and the code too confusing for me to come up with a working solution.


Solution

  • Think of directories as containers for files. They exist or don't pretty randomly, but if they have files, they must exist. In particular, you can't depend on a directory with need or write a rule to create a directory. Directories are created as needed - the rule for project/tool.txt will create the project directory if necessary.

    If you want to depend on a git clone having being performed, depend on a particular checked-out file instead (e.g. README.md), with the rule to create it being git clone. If you want to ensure a make was run, depend on a file that make produces.

    It is possible to define directory-aware rules, see this discussion, but there are lots of caveats so it's not the recommended approach or supported by default.