| name | makefile |
| description | Makefile standards for Scenescape — build targets, conventions, and patterns. |
Makefile Standards for Scenescape
Organization
Directory Structure
Each service has its own Makefile:
scenescape/
├── Makefile # Root orchestrator
├── common.mk # Shared build logic
├── controller/
│ └── Makefile # Controller-specific targets
├── manager/
│ └── Makefile # Manager-specific targets
└── tests/
├── Makefile # Test orchestrator
└── Makefile.sscape # Scenescape-specific test targets
Common.mk Inclusion
Service Makefiles include common.mk:
include ../common.mk
IMAGE_NAME := intel/scenescape-controller
Variables
Naming Conventions
- User-configurable:
UPPER_CASE with ?= (default if not set)
- Internal/derived:
UPPER_CASE with := (immediate expansion)
- Shell commands: Use
$(shell ...) for command output
JOBS ?= $(shell nproc)
BUILD_DIR ?= build
DOCKER_REGISTRY ?= localhost
VERSION := $(shell cat version.txt)
TIMESTAMP := $(shell date +%Y%m%d-%H%M%S)
IMAGE_TAG := $(IMAGE_NAME):$(VERSION)
Assignment Operators
PYTHON ?= python3
CURRENT_DIR := $(shell pwd)
DYNAMIC = $(shell date)
CFLAGS += -Wall -Wextra
Common Variables
BUILD_DIR ?= build
SRC_DIR := src
TEST_DIR := tests
VERSION := $(shell cat version.txt)
BUILD_NUMBER ?= dev
COMPOSE_PROJECT_NAME ?= scenescape
DOCKER_BUILDKIT ?= 1
PYTHON ?= python3
DOCKER ?= docker
DOCKER_COMPOSE ?= docker compose
JOBS ?= $(shell nproc)
MAKEFLAGS += -j$(JOBS)
Code Style
Indentation
- Use tabs for indentation (Makefile standard)
- Commands in recipes must be indented with tabs
Line Length
- Target: 80-100 characters for readability
- Use
\ for line continuation in long commands
Phony Targets
Declaration
Always declare phony targets:
.PHONY: all build clean test help
all: build
build:
@echo "Building..."
clean:
rm -rf $(BUILD_DIR)
test:
pytest $(TEST_DIR)
help:
@echo "Available targets:"
@echo " build - Build all components"
@echo " clean - Remove build artifacts"
@echo " test - Run tests"
Standard Targets
Common phony targets in Scenescape:
.PHONY: build build-core build-all build-experimental
.PHONY: rebuild rebuild-core
.PHONY: clean clean-secrets clean-build
.PHONY: test unit-tests functional-tests
.PHONY: lint lint-python lint-shell
.PHONY: install install-models
.PHONY: help
Target Patterns
Silent Commands
Use @ prefix to suppress echo:
build:
@echo "Building $(IMAGE_NAME)..."
docker build -t $(IMAGE_TAG) .
@echo "Build complete"
Error Handling
Use - prefix to ignore errors:
clean:
-rm -rf $(BUILD_DIR)
-docker rmi $(IMAGE_TAG)
Sequential Execution
Use ; or && for multi-line shell commands:
install:
cd $(SRC_DIR)
pip install -r requirements.txt
install:
cd $(SRC_DIR) && \
pip install -r requirements.txt
install:
cd $(SRC_DIR); pip install -r requirements.txt
Dependencies
Prerequisites
build: check-version validate-config
docker build -t $(IMAGE_TAG) .
check-version:
@test -f version.txt || (echo "version.txt not found" && exit 1)
validate-config:
@echo "Validating configuration..."
Order-Only Prerequisites
build: | $(BUILD_DIR)
docker build -t $(IMAGE_TAG) .
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
Wildcard Dependencies
build: $(wildcard src/**/*.py)
docker build -t $(IMAGE_TAG) .
Parallel Builds
Job Control
JOBS ?= $(shell nproc)
MAKEFLAGS += -j$(JOBS)
.NOTPARALLEL: sequential-target
sequential-target:
command1
command2
Common.mk Pattern
.PHONY: build-images
build-images: $(IMAGE_FOLDERS)
@echo "All images built"
$(IMAGE_FOLDERS):
$(MAKE) -C $@ build
Docker Integration
Build Patterns
build:
docker build \
--build-arg VERSION=$(VERSION) \
--build-arg BUILD_DATE=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ') \
-t $(IMAGE_TAG) \
-f Dockerfile \
.
build-verbose:
DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=plain \
docker build -t $(IMAGE_TAG) .
Docker Compose
up:
docker compose up -d
down:
docker compose down
restart: down build up
logs:
docker compose logs -f $(SERVICE)
Multi-stage Builds
build-deps:
docker build \
--target dependencies \
-t $(IMAGE_NAME)-deps:$(VERSION) \
.
build: build-deps
docker build \
--cache-from $(IMAGE_NAME)-deps:$(VERSION) \
-t $(IMAGE_TAG) \
.
Testing Targets
Test Organization
.PHONY: test unit-tests functional-tests integration-tests
test: unit-tests functional-tests
unit-tests:
pytest $(TEST_DIR)/unit -v
functional-tests:
pytest $(TEST_DIR)/functional -v --tb=short
integration-tests:
pytest $(TEST_DIR)/integration -v -s
Test Configuration
PYTHON ?= python3
PYTEST := $(PYTHON) -m pytest
test-coverage:
$(PYTEST) --cov=src --cov-report=html --cov-report=term
test-one:
$(PYTEST) $(TEST_DIR)/$(TEST_FILE) -v -s
Linting
Dockerfile Linting
- Linter: hadolint
- Command:
make lint-dockerfile
Multi-language
make lint-all
Color Output
ANSI Colors
RED := \033[0;31m
GREEN := \033[0;32m
YELLOW := \033[0;33m
BLUE := \033[0;34m
RESET := \033[0m
build:
@echo "$(GREEN)Building $(IMAGE_NAME)...$(RESET)"
docker build -t $(IMAGE_TAG) .
@echo "$(GREEN)Build complete$(RESET)"
error:
@echo "$(RED)Error: Build failed$(RESET)"
exit 1
Progress Indicators
build-all:
@echo "$(BLUE)Building core services...$(RESET)"
$(MAKE) build-core
@echo "$(GREEN)✓ Core services built$(RESET)"
@echo "$(BLUE)Building experimental services...$(RESET)"
$(MAKE) build-experimental
@echo "$(GREEN)✓ All services built$(RESET)"
Common Patterns
Version Management
VERSION := $(shell cat version.txt)
check-version:
@echo "Version: $(VERSION)"
@echo $(VERSION) | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+' || \
(echo "Invalid version format" && exit 1)
tag-version:
docker tag $(IMAGE_NAME):latest $(IMAGE_NAME):$(VERSION)
Dependency Management
deps:
pip list --format=freeze > $(BUILD_DIR)/dependencies.txt
check-deps:
pip list --outdated
update-deps:
pip install --upgrade -r requirements.txt
Clean Targets
.PHONY: clean clean-build clean-pyc clean-test clean-all
clean: clean-build clean-pyc clean-test
clean-build:
rm -rf $(BUILD_DIR)
rm -rf dist
rm -rf *.egg-info
clean-pyc:
find . -type f -name '*.pyc' -delete
find . -type d -name __pycache__ -delete
clean-test:
rm -rf .pytest_cache
rm -rf htmlcov
rm -f .coverage
clean-all: clean
docker system prune -af
Installation Targets
.PHONY: install install-dev install-test
install:
pip install -r requirements-runtime.txt
install-dev: install
pip install -r requirements-dev.txt
install-test: install-dev
pip install -r requirements-test.txt
Help Target
Auto-generated Help
.PHONY: help
help: ## Show this help message
@echo "Usage: make [target]"
@echo ""
@echo "Available targets:"
@grep -E '^[a-zA-Z_-]+:.*?
awk 'BEGIN {FS = ":.*?## "}; {printf " $(GREEN)%-20s$(RESET) %s\n", $$1, $$2}'
build: ## Build Docker image
docker build -t $(IMAGE_TAG) .
test: ## Run tests
pytest $(TEST_DIR)
clean: ## Remove build artifacts
rm -rf $(BUILD_DIR)
Categorized Help
help:
@echo "$(BLUE)Scenescape Makefile$(RESET)"
@echo ""
@echo "$(YELLOW)Build targets:$(RESET)"
@echo " build - Build core services"
@echo " build-all - Build all services"
@echo " rebuild - Clean and rebuild"
@echo ""
@echo "$(YELLOW)Test targets:$(RESET)"
@echo " test - Run all tests"
@echo " unit-tests - Run unit tests"
@echo " functional-tests - Run functional tests"
@echo ""
@echo "$(YELLOW)Clean targets:$(RESET)"
@echo " clean - Remove build artifacts"
@echo " clean-all - Remove all generated files"
Error Handling
Checking Prerequisites
check-docker:
@which docker > /dev/null || \
(echo "$(RED)Error: docker not found$(RESET)" && exit 1)
check-compose:
@docker compose version > /dev/null 2>&1 || \
(echo "$(RED)Error: docker compose not available$(RESET)" && exit 1)
build: check-docker check-compose
docker compose build
Validating Environment
check-env:
@test -n "$(SUPASS)" || \
(echo "$(RED)Error: SUPASS not set$(RESET)" && exit 1)
@test -n "$(DATABASE_PASSWORD)" || \
(echo "$(RED)Error: DATABASE_PASSWORD not set$(RESET)" && exit 1)
deploy: check-env
docker compose up -d
Anti-Patterns to Avoid
❌ Don't use shell loops in Make:
build:
for dir in controller manager; do \
$(MAKE) -C $$dir build; \
done
SERVICES := controller manager
build: $(SERVICES)
$(SERVICES):
$(MAKE) -C $@ build
❌ Don't hardcode paths:
build:
docker build -t intel/scenescape-controller:2026.0.0 controller/
VERSION := $(shell cat version.txt)
build:
docker build -t $(IMAGE_NAME):$(VERSION) $(IMAGE_DIR)/
❌ Don't ignore errors silently:
test:
-pytest $(TEST_DIR)
test:
pytest $(TEST_DIR)
❌ Don't use recursive assignment for commands:
TIMESTAMP = $(shell date +%s)
TIMESTAMP := $(shell date +%s)
Performance Tips
Minimize Shell Calls
VERSION = $(shell cat version.txt)
BUILD_DATE = $(shell date)
METADATA := $(shell echo "$(shell cat version.txt) $(shell date)")
Use .ONESHELL for Multi-line Commands
.ONESHELL:
deploy:
cd deployment
./configure.sh
./deploy.sh
Avoid Redundant Prerequisites
build: clean
docker build -t $(IMAGE_TAG) .
build:
docker build -t $(IMAGE_TAG) .
rebuild: clean build
Documentation
Inline Comments
build-controller:
docker build \
--build-arg VERSION=$(VERSION) \
-t intel/scenescape-controller:$(VERSION) \
controller/
Target Descriptions
build-core: ## Build core services (controller, manager, autocalibration)
$(MAKE) $(CORE_IMAGE_FOLDERS)
build-all: ## Build all services including experimental
$(MAKE) $(IMAGE_FOLDERS) $(EXPERIMENTAL_FOLDERS)
Testing
Test Makefiles
make -n build
make build --debug=v
make print-VERSION
print-%:
@echo '$*=$($*)'