Wednesday, September 20, 2017

Shake 0.16 - revised rule definitions

Summary: I've just released shake v0.16. A lot has changed, but it's probably only visible if you have defined your own rules or oracles.

Shake-0.16 is now out, 8 months since the last release, and with a lot of improvements. For full details read the changelog, but in this post I'm going to go through a few of the things that might have the biggest impact on users.

Rule types redefined

Since the first version of Shake there has been a Rule key value type class defining all rule types - for instance the file rule type has key of filename and value of modification time. With version 0.16 the type class is gone, rules are harder to write, but offer higher performance and more customisation. For people using the builtin rule types, you'll see those advantages, and in the future see additional features that weren't previously possible. For people defining custom rule types, those will require rewriting - read the docs and if things get tough, ask on StackOverflow.

The one place many users might encounter the changes are that oracle rules now require a type instance defining between the key and value types. For example, if defining an oracle for the CompilerVersion given the CompilerName, you would have to add:

type instance RuleResult CompilerName = CompilerVersion

As a result of this type instance the previously problematic askOracle can now infer the result type, removing possible sources of error and simplifying callers.

The redefining of rule types represents most of the work in this release.

Add cmd_

The cmd_ function is not much code, but I suspect will turn out to be remarkably useful. The cmd function in Shake is variadic (can take multiple arguments) and polymorphic in the return type (you can run it in multiple monads with multiple results). However, because of the overloading, if you didn't use the result of cmd it couldn't be resolved, leading to ugly code such as () <- cmd args. With cmd_ the result is constrained to be m (), so cmd_ args can be used.

Rework Skip/Rebuild

Since the beginning Shake has tried to mirror the make command line flags. In terms of flags to selectively control rebuilding, make is based entirely on ordered comparison of timestamps, and flags such as --assume-new don't make a lot of sense for Shake. In this release Shake stops trying to pretend to be make, removing the old flags (that never worked properly) and adding --skip (don't build something even if it is otherwise required) and --build (build something regardless). Both these flags can take file patterns, e.g, --build=**/*.o to rebuild all object files. I don't think these flags are finished with, but it's certainly less of a mess than before.

2 comments:

Sven Heyll said...

Hi Neil,

thanks for Shake!

Since the upgrade to 0.16 I am struggling with the generated documentation while finding out
howto migrate the < 0.16 'Rule' instances I had written.

I really don't understand what what builtin- and user rules are.

What should I pass to 'addUserRule', what is the 'a' supposed to be?

What is the idea behind UserRule?

And what are 'builtin rules'?

When do I need to add them, and why are they called 'built-in', if users can/have to add them ;) ?

Neil Mitchell said...

@Sven: I'll reply here, but if you need more clarification or discussion, can I suggest a GitHub ticket - https://github.com/ndmitchell/shake/issues - they tend to be easier to capture/follow.

You're right that the terminology is confusing - I raised https://github.com/ndmitchell/shake/issues/574 to fix that. Simple version, you almost certainly want to use BuiltinRule. If the docs from that don't make sense do shout and I'll clarify them. I probably should give a worked example of BuiltinRule...