unmake: a makefile linter
_
_ _ ___ _____ ___| |_ ___
| | | | | .'| '_| -_|
|___|_|_|_|_|_|__,|_,_|___|
WARNING
Work in progress
EXAMPLES
$ cd examples
$ unmake -n Makefile; echo "$?"
0
$ unmake -n bsd/makefile; echo "$?"
error at 1:16: expected one of " ", "$(", "${", ":", "\t", [^ (' ' | '\t' | ':' | ';' | '#' | '\r' | '\n')]
1
See unmake -h for more options.
INSTALL FROM SOURCE
$ cargo install --force --path .
MOTIVATION
The unmake linter serves several purposes.
unmake provides a strict replacement for make -n, in case the local make implementation has BSD, GNU, etc. extensions. unmake encourages validating makefiles for syntactic wholeness as part of their projects' linter suites, before any tasks are actually run.
unmake encourages long or subtle shell snippets to be moved to dedicated shell script files, where they are more amenable to scanning with shell script linters. Most linters for common shell snippet wrapping languages (e.g., Ansible, Dockerfile, makefile, Vagrantfile, various CI/CD pipelines) perform very limited scanning for potential flaws in the embedded snippets, compared with linters that specifically scan shell script files.
unmake discourages vendor locking in makefile scripts. Numerous makefiles online assume a highly specific development environment. For example, assuming that (GNU) findutils, (GNU) sed, (GNU) awk, (non-PowerShell) curl are installed, with a GNU bash or zsh user interpreter, on a GNU/Linux operating system. So the typical makefile is likely to fail for (non-WSL) Windows users, or macOS users, or FreeBSD users, and so on. Ideally, our makefiles strive for portability, so that our projects can be enjoyed on a wider variety of computers.
make is a natural candidate for working around limitations in provisioning scripts. For example, go mod / cargo do not track linters or other dev dependencies, and sh defaults to ignoring errors during provisioning. make's default semantics prepare it well for provisioning and other activities. make can do many things! unmake helps it do them better.
CAVEATS
We do our best to catch POSIX make violations, but some may slip by. For example:
- POSIX violations hiding inside macro expansions
- POSIX violations hiding inside command output
- Violations hiding inside chains of
includedirectives - Misuse of reserved target names
- Behavior during live
makescript execution - An ever-growing list of GNU/BSD/etc. extensions to POSIX make
RUNTIME REQUIREMENTS
(None)
CONTRIBUTING
For more details on developing crit itself, see DEVELOPMENT.md.
LICENSE
FreeBSD
SEE ALSO
- BSD make, a popular make implementation with BSD extensions
- checkmake, an experimental makefile linter
- cmake, a build system for C/C++ projects
- dale, a task runner for D projects
- GNU autotools, a build system for Linux C/C++ projects
- GNU make, a popular make implementation with GNU extensions
- Gradle, a build system for JVM projects
- invoke, a task runner for Python projects
- lake, a task runner for Lua projects
- Mage, a task runner for Go projects
- npm, Grunt, Node.js task runners
- the POSIX make standard
- Rake, a task runner for Ruby projects
- rez, a task runner for C/C++ projects
- Shake, a task runner for Haskell projects
- tinyrick, a task runner for Rust projects
- vast, a task runner for sh projects