🍞 mbake A Makefile formatter and linter. It only took 50 years! A Makefile formatter and linter. It only took 50 years! Table of Contents Features Configurable rules via ~/.bake.toml CI/CD integration with check mode Extensible plugin architecture Rich terminal output with progress indicators Syntax validation before and after formatting Smart .PHONY detection with automatic insertion Formatting Rules Indentation & Spacing Tabs for recipes : Recipe lines use tabs instead of spaces : Recipe lines use tabs instead of spaces Assignment operators : Normalized spacing around := , = , += , ?= : Normalized spacing around , , , Target colons : Consistent spacing around target dependency colons : Consistent spacing around target dependency colons Trailing whitespace: Removes unnecessary trailing spaces Line Continuations Backslash normalization : Proper spacing around backslash continuations : Proper spacing around backslash continuations Smart joining: Consolidates simple continuations while preserving complex structures .PHONY Declarations Grouping : Consolidates multiple .PHONY declarations : Consolidates multiple declarations Auto-insertion : Automatically detects and inserts .PHONY declarations when missing (opt-in) : Automatically detects and inserts declarations when missing (opt-in) Dynamic enhancement : Enhances existing .PHONY declarations with additional detected phony targets : Enhances existing declarations with additional detected phony targets Rule-based analysis : Uses command analysis to determine if targets are phony : Uses command analysis to determine if targets are phony Minimal changes: Only modifies .PHONY lines, preserves file structure Installation PyPI (Recommended) pip install mbake VSCode Extension Open VSCode Go to Extensions (Ctrl+Shift+X) Search for "mbake Makefile Formatter" Click Install From Source git clone https://github.com/ebodshojaei/bake.git cd mbake pip install -e . Development Installation git clone https://github.com/ebodshojaei/bake.git cd mbake pip install -e " .[dev] " Usage mbake uses a subcommand-based CLI. All commands support both bake and mbake aliases. Quick Start # Check version bake --version # Initialize configuration (optional) bake init # Format a Makefile bake format Makefile # Validate Makefile syntax bake validate Makefile Configuration Management # Initialize configuration file with defaults bake init # Initialize with custom path or force overwrite bake init --config /path/to/config.toml --force # Show current configuration bake config # Show configuration file path bake config --path # Use custom configuration file bake config --config /path/to/config.toml Formatting Files # Format a single Makefile bake format Makefile # Format multiple files bake format Makefile src/Makefile tests/ * .mk # Check if files need formatting (CI/CD mode) bake format --check Makefile # Show diff of changes without modifying files bake format --diff Makefile # Format with verbose output bake format --verbose Makefile # Create backup before formatting bake format --backup Makefile # Validate syntax after formatting bake format --validate Makefile # Use custom configuration bake format --config /path/to/config.toml Makefile Syntax Validation # Validate single file bake validate Makefile # Validate multiple files bake validate Makefile src/Makefile tests/ * .mk # Validate with verbose output bake validate --verbose Makefile # Use custom configuration bake validate --config /path/to/config.toml Makefile Version Management # Check current version and for updates bake --version # Check for updates only (without updating) bake update --check # Update to latest version bake update # Update with confirmation prompt bypass bake update --yes # Force update even if already up to date bake update --force Shell Completion # Install completion for current shell bake --install-completion # Show completion script (for manual installation) bake --show-completion Configuration mbake works with sensible defaults. Generate a configuration file with: bake init Sample Configuration [ formatter ] # Indentation settings use_tabs = true tab_width = 4 # Spacing settings space_around_assignment = true space_before_colon = false space_after_colon = true # Line continuation settings normalize_line_continuations = true max_line_length = 120 # PHONY settings group_phony_declarations = true phony_at_top = true auto_insert_phony_declarations = false # General settings remove_trailing_whitespace = true ensure_final_newline = true normalize_empty_lines = true max_consecutive_empty_lines = 2 # Global settings debug = false verbose = false Smart .PHONY Detection mbake includes intelligent .PHONY detection that automatically identifies and manages phony targets. How It Works Detection uses dynamic analysis of recipe commands rather than hardcoded target names: Command Analysis : Examines what each target's recipe actually does : Examines what each target's recipe actually does File Creation Detection : Identifies if commands create files with the target name : Identifies if commands create files with the target name Pattern Recognition: Understands compilation patterns, redirections, and common tools Examples Docker/Container Targets # These are detected as phony because they manage containers, not files up : docker compose up -d down : docker compose down -v logs : docker compose logs -f Build/Development Targets # These are detected as phony because they don't create files with their names test : npm test lint : eslint src/ deploy : ssh user@server 'systemctl restart myapp' File vs Phony Target Detection # NOT phony - creates myapp.o file myapp.o : myapp.c gcc -c myapp.c -o myapp.o # Phony - removes files, doesn't create "clean" clean : rm -f *.o myapp Configuration Enable auto-insertion in your ~/.bake.toml : [ formatter ] auto_insert_phony_declarations = true Behavior Modes Default (Conservative): Groups existing .PHONY declarations declarations No automatic insertion or enhancement Backwards compatible Enhanced (auto_insert_phony_declarations = true): Automatically inserts .PHONY when missing when missing Enhances existing .PHONY with detected targets with detected targets Uses dynamic analysis for accurate detection Before and After Input (no .PHONY ): setup : docker compose up -d npm install test : npm test clean : docker compose down -v rm -rf node_modules Output (with auto-insertion enabled): .PHONY : clean setup test setup : docker compose up -d npm install test : npm test clean : docker compose down -v rm -rf node_modules Examples Basic Formatting Before: # Inconsistent spacing and indentation CC: =gcc CFLAGS = -Wall -g SOURCES =main.c \ utils.c \ helper.c .PHONY : clean all : $( TARGET ) $(CC) $(CFLAGS) -o $@ $^ .PHONY : install clean : rm -f *.o After: # Clean, consistent formatting CC := gcc CFLAGS = -Wall -g SOURCES = main.c utils.c helper.c .PHONY : all clean install all : $( TARGET ) $(CC) $(CFLAGS) -o $@ $^ clean : rm -f *.o Auto-Insertion Example Before (with auto_insert_phony_declarations = true ): # Docker development workflow setup : docker compose down -v docker compose up -d @echo "Services ready!" build : docker compose build --no-cache test : docker compose exec app npm test clean : docker compose down -v docker system prune -af After: # Docker development workflow .PHONY : build clean setup test setup : docker compose down -v docker compose up -d @echo "Services ready!" build : docker compose build --no-cache test : docker compose exec app npm test clean : docker compose down -v docker system prune -af CI/CD Integration Use mbake in continuous integration: # GitHub Actions example - name : Check Makefile formatting run : | pip install mbake bake format --check Makefile Exit codes: 0 - No formatting needed or formatting successful - No formatting needed or formatting successful 1 - Files need formatting (--check mode) or validation failed - Files need formatting (--check mode) or validation failed 2 - Error occurred Development Setup git clone https://github.com/ebodshojaei/bake.git cd mbake pip install -e " .[dev] " pre-commit install Running Tests # Run all tests pytest # Run with coverage pytest --cov=bake --cov-report=html # Run specific test file pytest tests/test_formatter.py -v Code Quality # Format code black bake tests # Lint code ruff check bake tests # Type checking mypy bake Architecture mbake follows a modular, plugin-based architecture: bake/ β”œβ”€β”€ __init__.py # Package initialization β”œβ”€β”€ cli.py # Command-line interface with subcommands β”œβ”€β”€ config.py # Configuration management β”œβ”€β”€ core/ β”‚ β”œβ”€β”€ formatter.py # Main formatting engine β”‚ └── rules/ # Individual formatting rules β”‚ β”œβ”€β”€ tabs.py # Tab/indentation handling β”‚ β”œβ”€β”€ spacing.py # Spacing normalization β”‚ β”œβ”€β”€ continuation.py # Line continuation formatting β”‚ └── phony.py # .PHONY declaration management └── plugins/ └── base.py # Plugin interface Adding Custom Rules Extend the FormatterPlugin base class: from bake . plugins . base import FormatterPlugin , FormatResult class MyCustomRule ( FormatterPlugin ): def __init__ ( self ): super (). __init__ ( "my_rule" , priority = 50 ) def format ( self , lines : List [ str ], config : dict ) -> FormatResult : # Your formatting logic here return FormatResult ( lines = modified_lines , changed = True , errors = [], warnings = [] ) Contributing Contributions are welcome! Read the Contributing Guide for details on development process, submitting pull requests, and reporting issues. Quick Start for Contributors Fork the repository Create a feature branch ( git checkout -b feature/amazing-feature ) Make your changes Add tests for new functionality Run the test suite ( pytest ) Commit your changes ( git commit -m 'Add amazing feature' ) Push to the branch ( git push origin feature/amazing-feature ) Open a Pull Request License This project is licensed under the MIT License - see the LICENSE file for details. Design Philosophy