The linter is not specific to unextended POSIX make, or GNU make, or BSD make. It is meant as a practical, universal make linter.
Allow rules to be disabled and customized with a canary.yaml file.
Search for canary.yaml in the current directory.
Trampoline up to the root directory for canary.yaml files.
Merge files together, with the closest one taking the highest priority at an individual config field level.
Recurse over common makefile file patterns.
Offer a flag to bypass linting and simply emit makefile matches (preferably null delimited), for piping to xargs -0 <other make linters that may lack directory recursion>.
Consider validating syntax against the active make implementation like make -n.
Encourage an all default task declaration.
Treat missing .PHONY, or missing all in (uncommented) .PHONY:, as a symptom of improper PHONY configuration. Link to documentation on proper PHONY configuration.
When all or test or clean are present, encourage them to be marked PHONY.
Provide a customizable, default max 80 character column rule.
Encourage UTF-8 / ASCII encoding, no BOM.
Encourage more commands to be silenced with at (@).
Encourage commands in clean* tasks to have their exit codes softened and ignored with hyphen-minus (-).
Warn on commands of simple cd, pushd, popd, which will not behave as intended in make.
Warn on double colons / rem (case insensitive) for DOS comment semantics.
Warn on curly braces and hard brackets as nonportable shell code.
Warn on backticks as nonportable shell code.
Encourage backslash multiline commands when pipes are involved.
Warn on single and double ampersand as nonportable.
Treat globs, especially recursive globs, as nonportable.
Treat coreutils / base commands as nonportable.
Treat find and xargs as nonportable.
Treat OS package manager commands as nonportable.
Treat FreeBSD and macOS commands as nonportable.
We could treat echo flags as nonportable.
We could treat printf as nonportable.
We could treat sed and awk as nonportable.
We could warn on common UNIXisms (uname, which, command -v, type, etc.) and common Windowsisms (cmd[.exe], regedit, slmgr, ver, where, etc.) as nonportable.
We could warn on some common command substrings like mkdir -p, rm, del, touch, curl, wget, etc., which may break in cmd.exe and/or PowerShell.
We could warn on single quotes and some other POSIX sh syntax which are likely to break in certain Windows contexts.
We could treat 101 commands in a task as high cyclonatic complexity. Simplify the technical stack (for too many installed components), or delegate to multiple tasks / makefiles / artifacts (for complex build workflows), or move logic to dedicated shell scripts (for more fragile, elaborate tasks).
We could warn on ./ as nonportable.
For each linter rule, provide a standard rule identifier and link to a wiki page with details about the rule.
Check whether make and/or make -n considers referencing missing task definitions as a syntax error. If both silently ignore that until the task is explicitly invoked, then create a rule.
We could offer an optional rule to prohibit hyphen-minus for non-clean* task commands.
We could encourage a declarative style, in terms of warning when tasks are referenced earlier than they are defined.
We could ignore common node_modules and vendor directories.
Backlog VCS ignore pattern matching such as .gitignore integration.
We could ignore makefiles generated by cmake, in terms of their location relative to CMakeLists.txt.
We could recommend replacement with ninja, for makefiles lacking conditional logic.
We could treat OS specific build tools, such as golink, gcc, g++, gas/as, masm as nonportable.
We could treat most hex dumpers as nonportable.
We could treat certain absolute UNIX paths, and drive-based Windows paths, and NUL, as monportable. Without creating too many false positives.
Check whether make uses PowerShell or cmd.exe interpreter when run from a PowerShell environment.
copy is nonportable.
Check whether PoweShell supports cp -r.
wscript, vbscript, sh, bash, zsh, erc. commands are nonportable.
open, explorer[.exe], and xdg-open result in bizarre workflows and are nonportable.
Treat .exe commands as nonportable.
Treat blah.sh, blah.bash, blah.zsh, etc. commands as nonportable.
Treat manual make interpreter assignment as nonportable.
Ignore Makefiles generated by Makefile.PL.
Ignore Makefiles generated by configure scripts.
Relative paths using ../ or ..\ may be nonportable.
putty is nonportable.
osascriot nonportable.
xorg nonportable.
expect is nonportable.
telnet is insecure.
We could support inline and/or above line rule suppression comments.
tar is nonportable.
We could treat grep as nonportable.
bat files and psh commands are non portable.
The UNIX file command may not be portable.
.msc commands, and mac settings commands are not portable.
The Microsoft net command tool is not portable.
Redirection to numbered file handles for stdout/stdere/etc. may not be portable. That MS-DOS console redirection is not portable.
cl[.exe] and clang-cl[.exe] are not portable.
cat is not portable.
sort, uniq may not be portable.
readlink, ln, chmod, groups, groupadd, chown are not portable.
Calling npm run-script, bundle, or cabal bin run commands may be a symptom that the Makefile tasks would be better defined as Grunt, Rake, or tinyrick tasks instead. Possibly with dub and dale. Possibly with sh and vast. Possibly with go run hacks and Mage.
ps, kill, halt, reboot, shutdown are likely nonportable.
python* -m is likely a symptom that the tasks would be better defined in an invoke script than a makefile.
tasm is likely nonportable.
Inline comments after backlash multiline continuations are likely going to break things.
Store wiki articles as Markdown files rather than GitHub wiki pages.
Write a basic makefile linter.
The linter is not specific to unextended POSIX make, or GNU make, or BSD make. It is meant as a practical, universal make linter.
xargs -0 <other make linters that may lack directory recursion>
.make -n
.@
).clean*
tasks to have their exit codes softened and ignored with hyphen-minus (-
).We could treat echo flags as nonportable.
We could treat printf as nonportable.
We could treat sed and awk as nonportable.
We could warn on common UNIXisms (uname, which, command -v, type, etc.) and common Windowsisms (cmd[.exe], regedit, slmgr, ver, where, etc.) as nonportable.
We could warn on some common command substrings like mkdir -p, rm, del, touch, curl, wget, etc., which may break in cmd.exe and/or PowerShell.
We could warn on single quotes and some other POSIX sh syntax which are likely to break in certain Windows contexts.
We could treat 101 commands in a task as high cyclonatic complexity. Simplify the technical stack (for too many installed components), or delegate to multiple tasks / makefiles / artifacts (for complex build workflows), or move logic to dedicated shell scripts (for more fragile, elaborate tasks).
We could warn on ./ as nonportable.
For each linter rule, provide a standard rule identifier and link to a wiki page with details about the rule.
Check whether make and/or make -n considers referencing missing task definitions as a syntax error. If both silently ignore that until the task is explicitly invoked, then create a rule.
We could offer an optional rule to prohibit hyphen-minus for non-
clean*
task commands.We could encourage a declarative style, in terms of warning when tasks are referenced earlier than they are defined.
We could ignore common node_modules and vendor directories.
Backlog VCS ignore pattern matching such as .gitignore integration.
We could ignore makefiles generated by cmake, in terms of their location relative to CMakeLists.txt.
We could recommend replacement with ninja, for makefiles lacking conditional logic.
We could treat OS specific build tools, such as golink, gcc, g++, gas/as, masm as nonportable.
We could treat most hex dumpers as nonportable.
We could treat certain absolute UNIX paths, and drive-based Windows paths, and NUL, as monportable. Without creating too many false positives.
Check whether PowerShell supports appending redirection.
Check whether make uses PowerShell or cmd.exe interpreter when run from a PowerShell environment.
copy is nonportable.
Check whether PoweShell supports cp -r.
wscript, vbscript, sh, bash, zsh, erc. commands are nonportable.
open, explorer[.exe], and xdg-open result in bizarre workflows and are nonportable.
Treat .exe commands as nonportable.
Treat blah.sh, blah.bash, blah.zsh, etc. commands as nonportable.
Treat manual make interpreter assignment as nonportable.
Ignore Makefiles generated by Makefile.PL.
Ignore Makefiles generated by configure scripts.
Relative paths using ../ or ..\ may be nonportable.
putty is nonportable.
osascriot nonportable.
xorg nonportable.
expect is nonportable.
telnet is insecure.
We could support inline and/or above line rule suppression comments.
tar is nonportable.
We could treat grep as nonportable.
bat files and psh commands are non portable.
The UNIX file command may not be portable.
.msc commands, and mac settings commands are not portable.
The Microsoft net command tool is not portable.
Redirection to numbered file handles for stdout/stdere/etc. may not be portable. That MS-DOS console redirection is not portable.
cl[.exe] and clang-cl[.exe] are not portable.
cat is not portable.
sort, uniq may not be portable.
readlink, ln, chmod, groups, groupadd, chown are not portable.
Calling npm run-script, bundle, or cabal bin run commands may be a symptom that the Makefile tasks would be better defined as Grunt, Rake, or tinyrick tasks instead. Possibly with dub and dale. Possibly with sh and vast. Possibly with go run hacks and Mage.
ps, kill, halt, reboot, shutdown are likely nonportable.
python* -m
is likely a symptom that the tasks would be better defined in an invoke script than a makefile.tasm is likely nonportable.
Inline comments after backlash multiline continuations are likely going to break things.
Store wiki articles as Markdown files rather than GitHub wiki pages.