Summary: Shake can interpret some Makefiles, just like Make.
Since version 0.10 the Shake build system also installs a
shake executable that can interpret a
Makefile, just like you would use with
make. To try it out, just type
shake where you would normally type
make (i.e. a directory containing a
Makefile) and Shake will attempt to perform the build. I say attempt, as there are plenty of caveats, and it is unlikely that randomly chosen
Makefile will work.
The current state
shakecan interpret some
Makefileexamples. For example, the first four examples from this Makefile tutorial can be executed by
shake. There are plenty of missing features, too many to list. It is likely that some tutorials or simple projects will work, but most "real" projects will not.
shakeis sufficiently compatible with
make(for the subset of features it supports) that I actually run the GNU Make testsuite using
test-make.sh). I currently pass 16 tests from 8 categories, out of 83 tests in 39 categories. One of the tests I pass is even failed by the MinGW version of
- The command like arguments to
shakeare mostly a superset of those to
make. In fact, all Shake programs that use
shakeWithArgssupport most of these options - including things like
The original plan
My original plan had 3 steps (spoiler alert: I never even finished step 1):
Step 1: I wanted to interpret many common
Makefile patterns, so some simpler projects could use either
shake interchangeably. I never expected it to work for complex projects like GHC or the Linux Kernel, but did hope to work for the average one-author open source project.
Step 2: I wanted to add
need as a command that pulled in additional dependencies. One of the weaknesses of
make (fixed by Shake) is that you have to specify all dependencies up front, before you have generated other dependencies. I wanted to extend the
Makefile syntax to support:
foo.tar : foo.txt cat foo.txt | need tar -cf foo.tar `cat foo.txt`
cat foo.txt | need would add dependencies on all the files listed by
foo.txt and build them if necessary, before continuing.
Step 3: I wanted to write a converter that took an extended
Makefile and produced a
Shakefile.hs Haskell program that used the standard Shake library, giving users a seamless migration path.
This feature has no active users, and I don't immediately see who would chose to use it. There are advantages of using
make, primarily profiling and progress prediction, but they aren't killer advantages. Make is a large and complex program, and while you could replicate it in Haskell on top of Shake, you probably don't want to. As an example, if a rule for a file does not update the file, Shake will not rerun that rule in subsequent builds but Make will. Arguably the Make behaviour is a bug, but like so many misfeatures, someone will have relied on it somewhere. Replicating Make bug-for-bug would be a lot of effort, end up very ugly, and if you don't have complete compatibility, big projects are unlikely to be able to switch.
Despite my pessimism around this feature, I don't intend to remove it. If it gains users I would be pleasantly surprised. If there is some small feature someone thinks it should support (ideally to gain additional users!) I'm happy to implement it. If people want to send pull requests, or even take over development of this part, I'd be very happy. Shake has gained a number of useful features while implementing Make compatibility, so even if the code is never used in anger, it was still of benefit.
A quick tour of the code
The code for the Make compatibility is all in the repo under
Development/Make. It's relatively short and might serve as a nice example for intermediate level Haskell programmers. There are 5 files:
Typedefines the type
Makefile, which is the parsed representation of a
Parsetakes a file and parses it, producing a
Makefilevalue (71 lines).
Envprovides a representation of the Make environment, describes which variables are assigned to which values, and evaluates expressions in the environment (40 lines).
Rulesdefines a new Shake rule type, mostly like the normal Shake file rule, but having slightly different semantics - if a rule fails to generate a file, that isn't an error (59 lines).
Allputs all the pieces together - parsing a
Makefile, evaluating the expressions within it while building up an environment, and then translating to Shake rules (135 lines).
The code is fairly well segregated and serves as a reasonable template for interpreting alternative input build specifications under Shake. The
Development/Ninja source code follows much the same pattern.