
Better Makefile
improved syntax highlighting of makefiles in VS Code
Intended audience: anyone reading or writing makefiles in VS Code.
How to use
Just install the extension - no other action is needed; VS Code will automatically use the extension for all makefiles.
Improvements
Improvements vs. the default VS Code treatment of makefiles include:
Syntax support:
- correctly highlights commonly used syntax that the default VS Code grammar does not, e.g.
- assignment operators
::=, !=
- rulehead separators
&:, ::
- substitution references (
$(src:%.c=%.o))
- parenthesized automatic variables (
$(@D), $(@F), $(@))
- static-pattern rules (
a.o b.o: %.o: %.c)
- wildcard chars in ruleheads (
*.o: common.h)
- target-specific assignments (
main: CFLAGS = -g)
- single-line rules (
t: p; recipe)
- escape and escaped characters, depending on syntax context
- does not highlight invalid syntax as valid in some cases where the default VS Code grammar incorrectly does, making errors easier to spot
- e.g.
$(SHELL ), $((SHELL)) (GNU make does not expand those to the intended special variables, but the default VS Code grammar highlights as if they do)
- avoids a number of bugs in the default grammar — for example, this grammar:
- correctly scopes rules and variable assignments that start with an expansion (
$(objs): common.h)
- correctly scopes ruleheads with line continuation before the rulehead separator
:s and =s in substitution references are not mistaken for rulehead separators or assignment operators
- a
: in a comment does not mistake the line for a rulehead (not # a : rulehead)
Word highlighting and brackets:
- word highlighting for words like
my-target: .myPrereqs and my-var := value is done correctly
- defines
$(...) and ${...} as bracket pairs so VS Code can match and highlight them properly
Grammar robustness:
- unconditionally ends scopes on non-escaped newlines which avoids runaway highlighting for makefiles with incorrect syntax (and in case of bugs in the grammar itself)
- provides multiple scopes to syntax elements where appropriate, increasing the likelihood that themes provide appropriate highlighting
- thorough automatic tests, including verification against GNU
make's parsing of the test file to ensure the grammar and GNU make agree
General:
- is updated with the latest GNU
make 4.4.1 syntax (e.g. available special targets, special variables, built-in functions)
Where to get it
This extension is available through:
Choice of highlighting theme
This extension will improve the highlighting of makefiles regardless of the theme used.
Note however that the default VS Code themes are rather limited in what scopes they highlight. To benefit fully from the improved grammar, use a theme that highlights more ambitiously, e.g.
Design choices
- no shell syntax highlighting within recipes
- since we prefer to keep recipes visually distinct from the other parts of the file, improving readability of the file as a whole
- no support for custom
.RECIPEPREFIX, i.e. for makefiles that don't use <tab> (the default) as the recipe prefix
- since it's hard or impossible to detect and react to (given the limitations of the TextMate grammar format that VS Code uses)
- since unconditionally including
" " (whitespace character) as a recipe prefix for all files would make the scoping/highlighting less robust
- does not scope anything as syntax errors
- since it would cause e.g. makefiles for BSD-flavoured
makes to highlight valid syntax as invalid
Supported make flavours
The extension is targeted at and tested against GNU make 4.4.1 and supports most of its syntax and all of its built-in identifiers.
The extension highlights the makefile syntax of any earlier GNU make and any POSIX make almost as well. It does a reasonable job with BSD flavours (pmake, bmake, fmake) and Microsoft make (nmake).
Reporting issues
Grammar bugs can be reported in the GitHub issues.
For theme authors
The scopes this extension defines are listed in syntaxes/makefile.scopes.txt, also included with each release.
For downstream grammar users
The JSON TextMate grammar itself is available as:
The JSON grammar is generated from a YAML source. Git hooks (committed) make sure all commits have a freshly generated JSON grammar, and CI verifies the two match.
The JSON grammar:
- conforms to the public TextMate schema
- uses only regexes that:
- are valid Oniguruma regexes
- are valid PCRE2 regexes (allows use in tools interpreting TextMate grammar regexes with a PCRE regex engine)
- verified with an official pcre2 tool
- note: this is a design decision about the grammar, unrelated to the use of the grammar within this extension
The above is verified at build time and in CI.
Created by a human
This README.md is authored entirely by me (Carl), a human developer; AI tools were not allowed to author text or suggest phrasing in it.
The grammar itself was hand-rolled by me; so were the extensive tests and the testing set-up[1]. The majority of the work was done early 2025; experiments with the latest agentic tooling and models at that time still could not speed up the work compared with me hand-coding everything myself.
Post the 1.0 release (spring 2026) agentic tooling might be used for improvements and edits. This README.md file, however, remains fully human-authored.
[1]: The test runner used in this project could be characterized as maybe "a small custom-made test runner implemented in GNU make". It is quite unconventional but it does, I must say, serve its purpose reasonably well. Writing it as a Makefile allowed me to express it concisely and declaratively.