mbake: a Makefile formatter that guesses which targets are phony
mbake is a Makefile formatter and linter. It only took 50 years!
At a glance
- What is it?
- mbake is a Python formatter and linter for Makefiles that ships on PyPI, normalises recipe indentation, cleans up line continuations, can detect phony targets by reading the recipe commands, and offers a check mode for CI. It also comes with a VSCode extension, Emacs modes and pre-commit hooks.
- Who is it for?
- Adopt mbake if your team edits Makefiles by hand and wants one agreed style enforced by mbake format --check in CI, since the rules are simple, the config is a small toml file and the exit codes make the check usable as a gate. Do not adopt it if your build files rely on formatting that only a human can judge, because the tool rewrites recipe lines and the phony detection is a guess based on the commands inside the recipe.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 94 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Makefiles have no formatting culture, so the first job is picking one
A Makefile is one of the few build files where nobody agrees on what a line should look like. Assign operators can be written with or without spaces, recipes can be indented with tabs or with four spaces, and a long list of source files gets split across backslash continuations in whatever shape the author was typing that day. The result is diff noise, because reformatting a Makefile buries the real change in a wall of whitespace edits.
mbake is a Python formatter and linter for exactly this file. The project's own description is a joke about the age of the problem, saying the tool only took 50 years, and the practical effect is that it settles the small decisions once. The formatter uses tabs for recipes, applies consistent spacing around assignments, and cleans up line continuations. The linter side validates that the Makefile is still valid, before and after formatting, so a bad edit is caught rather than shipped.
The audience is a team that has already decided to be consistent and needs a machine to enforce it, plus anyone who has inherited a Makefile and wants to see what a canonical version looks like without arguing about it.
The configuration lives in a small toml file that mbake init writes for you
Every behaviour is a flag in a config file, and the file is created by the tool rather than by hand. The commands are grouped under a formatter section, and the defaults are conservative: spacing rules are on, alignment is off, and phony insertion is off.
[formatter]
# Spacing and formatting
space_around_assignment = true # CC=gcc to CC = gcc
space_after_colon = true # myapp.o:myapp.c to myapp.o: myapp.c
normalize_line_continuations = true # Clean up backslash continuations
remove_trailing_whitespace = true # Remove trailing spaces
fix_missing_recipe_tabs = true # Convert spaces to tabs in recipes
# Variable alignment
align_variable_assignments = false # Align consecutive assignments
align_across_comments = false # Continue alignment across comments
# .PHONY management
auto_insert_phony_declarations = false # Auto-detect and insert .PHONY
group_phony_declarations = false # Group multiple .PHONY lines
phony_at_top = false # Place .PHONY at file topThe location of that file is worth knowing, because it is not in your project directory by default. The project documents it as {XDG_CONFIG_HOME}/bake.toml, so the settings are per user rather than per repository unless you pass a different one. The --config option points the tool at a custom configuration file, and mbake config prints the settings currently in effect, which is the first thing to run when a formatting result surprises you.
Turning alignment on is the option most likely to change how large your diffs are. Aligning consecutive assignments, and continuing that alignment across comments, is a stylistic choice rather than a correctness one, so it is off by default for a reason.
The phony detection reads recipe commands instead of trusting a naming convention
The most interesting thing mbake does is not formatting. Its .PHONY handling is automatic and opt in, and the way it works is by analysing the commands inside each recipe rather than by looking for a name that looks temporary.
The project gives this example.
# These are automatically detected as phony
test:
npm test
clean:
rm -f *.o
deploy:
ssh user@server 'systemctl restart app'
# This creates a file, so it's NOT phony
myapp.o: myapp.c
gcc -c myapp.c -o myapp.oThe reasoning is that a target whose recipe runs a command rather than creating a file is phony, and a target whose recipe produces an output file is not. That is a better heuristic than any list of common phony names, and it is also only a heuristic, since a target that runs a shell command and also writes a file in the same recipe will be judged on the whole recipe. Enabling the behaviour takes one line of config.
[formatter]
auto_insert_phony_declarations = trueThe remaining two options decide where the declaration lands and how it is grouped. group_phony_declarations folds multiple .PHONY lines together, and phony_at_top places the declaration at the top of the file, which matters when a Makefile is read by people as much as by make.
The check mode is what makes this usable in a pull request gate
A formatter that rewrites files in place is only useful in a team if it can also tell you no without touching anything. mbake format --check does that, and the tool documents three exit codes for the result: 0 for success, 1 when formatting is needed, and 2 for an error. That distinction is what makes the check scriptable rather than a yes or no answer.
The documented CI usage is a GitHub Actions step.
# GitHub Actions example
- name: Check Makefile formatting
run: |
pip install mbake
mbake format --check MakefileThe --diff option is the companion for review, showing what would change without modifying the file, and --backup writes a copy before formatting. The --validate option runs a syntax check after formatting, and --timeout sets how long that check may take, which matters because the syntax check shells out to GNU make and can hang on a target that tries to reach the network.
The repository also ships pre-commit configuration, with .pre-commit-config.yaml and .pre-commit-hooks.yaml at the top level, so the same check can run as a local hook instead of only in CI. mbake validate Makefile runs the syntax check on its own, and the project states that it checks the Makefile with GNU make, which means a real make binary has to be on the path for that mode to work.
Region comments let you keep a Makefile that resists the formatter
Every formatter eventually meets a Makefile that is doing something unusual, and mbake has an escape hatch for that. Special comments switch formatting off for a region of the file.
# bake-format off
CUSTOM_FORMAT= \
1 \
45678 \
#bake-format onThe block above keeps the odd alignment it was written with, which is the point. A generated or hand tuned fragment can stay as it is, and the rest of the file still gets normalised. The switch comment name is different from the tool name, since the project is published as mbake while the comment marker is bake-format.
This is a small feature and it changes how the tool can be introduced. A repository that cannot adopt a single style for every Makefile still has a path: mark the exceptions, let mbake handle the rest, and check the result in CI. The alternative to that escape hatch is either refusing to format at all or hand reviewing every diff, and both are worse.
The editor integration spans VSCode, Emacs and pre-commit
The repository carries more than the Python package. There is a vscode-mbake-extension/ directory for a full editor integration, listed in the features as available, and the extension is installed by searching for mbake Makefile Formatter in the VSCode extension marketplace rather than through the package index. On the Emacs side the tree holds bake-format.el, flymake-bake.el and a completions/ directory, which is a meaningful amount of integration for a formatter of this size: format on save, diagnostics while editing, and completion data.
The development setup is conventional and shows the project's own tooling.
# Development setup
git clone https://github.com/ebodshojaei/bake.git
cd mbake
pip install -e ".[dev]"
pytest # Run testsThe dev extras pull in pytest, pytest-cov, black, ruff, mypy and pre-commit, and the project uses black for its own code style. The repository's own Makefile has a single lint target that runs black, ruff and mypy over the package, so the maintainer dogfoods the same linting stack the tool encourages.
One thing the documentation does not spell out is the behaviour of the formatter on the boundaries it cannot parse, such as a recipe that relies on a particular line continuation form or a target whose prerequisites span several lines in a way the parser reads differently from make. The feature list claims syntax validation before and after formatting, which limits the damage, but the details of failure behaviour are not documented.
Version 1.4.6 on PyPI, MIT licensed, and a configuration file you may have to distribute yourself
The package is published on PyPI as mbake, requires Python 3.9 or newer, and is built with hatchling. The licence is MIT, so using it in a company pipeline, wrapping it in a pre-commit hook or shipping it as part of an internal toolchain carries no licence fee, though the MIT notice has to travel with the source if you redistribute it.
The release history is visible and the project is not marked as a stable one. The classifiers call it Development Status :: 4 - Beta, and the published versions are v1.4.6 from 2026-03-31, v1.4.5 from 2026-02-04 and v1.4.4 from 2025-12-23. The last push was on 2026-07-22, and the repository is not archived, so the code is still moving.
The upgrade path is worth planning. mbake update is documented as the command that updates to the latest version, and CHANGELOG.md and CONTRIBUTING.md sit at the repository root, with the changelog also linked as the release page in the project metadata. Because the configuration defaults live in the user's XDG config directory rather than in the repository, a team that wants a shared style has to distribute a config file deliberately and pass it with --config. That is the one piece of setup that a Makefile formatter needs but a project file usually does not carry, and it is where a shared style will quietly diverge if nobody takes responsibility for it.
Editorial conclusion
Adopt mbake if your team edits Makefiles by hand and wants one agreed style enforced by mbake format --check in CI, since the rules are simple, the config is a small toml file and the exit codes make the check usable as a gate. Do not adopt it if your build files rely on formatting that only a human can judge, because the tool rewrites recipe lines and the phony detection is a guess based on the commands inside the recipe. Before you enforce it, run mbake format --diff over the existing Makefiles and confirm that the rewrite of recipe indentation and line continuations matches what your build expects, then commit the result of mbake init configuration to the repository.
Frequently asked questions
How do I install mbake and format a Makefile?
Install it from PyPI with pip install mbake, then run mbake format Makefile to rewrite the file. Use mbake format --check Makefile to report whether formatting is needed without changing anything, and mbake format --diff Makefile to see the proposed changes.
How does mbake decide which Makefile targets are phony?
It analyses the commands in each recipe. A target whose recipe runs a command such as npm test or rm -f *.o is treated as phony, while a target whose recipe creates a file such as myapp.o is not. Automatic insertion is off by default and is enabled with auto_insert_phony_declarations = true in the formatter config.
Where does mbake keep its configuration file?
The project documents the config location as {XDG_CONFIG_HOME}/bake.toml, and mbake init creates it. A different file can be used with the --config option, and mbake config prints the settings currently in effect.
Can I use mbake to check Makefile formatting in CI?
Yes. The documented GitHub Actions example runs pip install mbake and then mbake format --check Makefile, and the tool documents exit codes of 0 for success, 1 when formatting is needed and 2 for an error. The repository also ships pre-commit configuration so the same check can run as a local hook.
Does mbake need GNU make installed to validate a Makefile?
The documentation says the validate mode checks the Makefile syntax with GNU make, so a make binary has to be available on the path. The --timeout option exists to bound how long that check may take, and --validate runs the check after formatting.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ebodshojaei-bake)Was this useful?