Makefiles in projects.
Table of Contents
Makefiles are a great way to automate tasks in a project. They are a simple way to define a set of rules to build, test, and deploy a project. In this post, we will see how to use Makefiles in a Python project.
What is a Makefile?
Makefile is a special file containing a set of directives used to build software. It's essentially a script that helps automate common development tasks through a consistent interface.
- Task Automation: Define repeatable commands as simple targets
- Dependencies: Specify relationships between tasks
- Incremental Builds: Only rebuild what's necessary based on file changes
- Cross-platform: Works on Unix-like systems and Windows (with tools like WSL)
Basic Makefile Syntax
target: dependencies
commands
- target: The name of the task
- dependencies: Other targets that must run first
- commands: The actual commands to execute (must be indented with tabs)
Python Makefile
Below is a comprehensive Makefile for a modern Python project using uv for dependency management.
PROJECT_NAME := "myproject"
# Show help by default
.DEFAULT_GOAL := help
# Help target that reads from comments
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
all: setup lint typing test ## Run all essential checks
setup: ## Install dependencies and set up pre-commit
uv sync
uv run pre-commit install
lint: ## Run code linting with ruff
ruff check
format: ## Format code with ruff
ruff format
typing: ## Run static type checking
python -m mypy . --ignore-missing-imports --exclude ".*venv.*/"
test: ## Run unit tests with pytest
uv run pytest tests/ -v --cov=$(PROJECT_NAME) --cov-report=term-missing
run: ## Run the project
uv run python -m $(PROJECT_NAME)
clean: ## Remove build artifacts and cache files
rm -rf build/ dist/ *.egg-info .coverage .mypy_cache .pytest_cache .ruff_cache
build-container: ## Build container image
podman build -t $(PROJECT_NAME):test .
run-container: build-container ## Run container image
podman run --rm $(PROJECT_NAME):test
pre-commit: ## Run pre-commit on staged files
uv run pre-commit run
pre-commit-all: ## Run pre-commit on all files
uv run pre-commit run --all-files