Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save barries/72aa6a96873bf65d4e8a8a8c1c9f295c to your computer and use it in GitHub Desktop.

Select an option

Save barries/72aa6a96873bf65d4e8a8a8c1c9f295c to your computer and use it in GitHub Desktop.
################################################################################
# Make configuration
#
# Most variables are non-recursive ("simple expanded" to be technical) for
# speed. `override` is necessary to rewrite variables that could be in the
# environment or on the command line. This speed improvement is not relevant on
# small projects, but non-recursive variables are easier for non make gurus to
# work with.
# --no-builtin-rules: prevent make from scanning filesystem for many possible
# dependencies.
#
# --output-sync=recurse: Don't intermingle concurrent recipes' output.
#
# --jobs=...: Allow 5 more than number of CPUs (should occupy all CPUs because
# some will block on I/O now and then.
#
# These get passed to $(MAKE) invocations, along with file descriptors to talk
# to the jobserver. This can confuse some projects' (eg buildroot's) Makefiles;
# if so use `$(MAKE) MAKEFLAGS= ...` to prevent that confusion.
MAKEFLAGS := --no-builtin-rules --output-sync=recurse --jobs=$(shell echo $$((`nproc` + 5)))
# Don't search implicit rules
.SUFFIXES:
# Entire recipe is a single bash script
.ONESHELL:
SHELL := bash
# Put bash into strict mode
.SHELLFLAGS := -E -e -u -o pipefail -c
# Don't delete intermediate files
.SECONDARY:
# Delete output files on error.
#
# This doesn't help if `make` is killed by, say, kill -9 or a system crash,
# so rules should use the "output to a temp file, rename the temp file"
# pattern anyway. This is just provided as a helpful default in case a rule
# doesn't do that.
.DELETE_ON_ERROR:
################################################################################
# Configuration
VERSION := TBD
################################################################################
# Usage and Help text
define COMMANDS
make # Make everything
make os # Make output/my_os-$(VERSION).img
make ui # Make output/my_ui-$(VERSION)
make clean # Delete tmp/* and output/*
make sboms # Create SBOM files
make help # Print other commands
make VERBOSE=0 ... # Don't print targets before they're made
make VERBOSE=1 ... # Print shell commands as they are executed
endef
define HELP
Usage:
make [variables] targets...
Common Commands:
$(COMMANDS)
Other Commands:
make buildroot # Create tmp/buildroot/
make clean_buildroot # Delete tmp/buildroot/
endef
################################################################################
# Functions and Special Variables
ifeq ($(VERBOSE),0)
# Squelch "Making $@" messages
TRACE_COMMAND := @
else
TRACE_COMMAND = @echo "Making $@"
ifneq ($(VERBOSE),)
override .SHELLFLAGS := $(.SHELLFLAGS) -x
endif
endif
# ..._TARGET variables
#
# These ..._TARGET variables allow shell scripts to refer to the target
# regardless of what directory they're in, handle spaces in $PWD, and are
# somewhat more self-documenting than "$@".
#
# They're recursive so that the $@s aren't expanded until the recipe is run.
#
ABS_TARGET = $(abspath $@)
TMP_TARGET = $(ABS_TARGET).tmp
MV_TMP_TO_TARGET = mv "$(TMP_TARGET)" "$(ABS_TARGET)"
TOUCH_TARGET = touch "$(ABS_TARGET)"
################################################################################
# Top Level Rules
#
# Don't depend on the .PHONY targets in non-.PHONY rules to prevent unnecessary
# recipe runs.
.PHONY: all
all: os
.PHONY: clean
clean: clean_buildroot
$(TRACE_COMMAND)
rm -rf tmp/* */tmp/*
DIR="$$PWD"
CARGO_DIRS=($(dir $(wildcard */Cargo.toml)))
for CARGO_DIR in "$${CARGO_DIRS[@]}"; do
cd $$CARGO_DIR
cargo clean
cd $$DIR
done
.PHONY: clean_buildroot
clean_buildroot:
$(TRACE_COMMAND)
rm -rf tmp/buildroot tmp/sentinels/buildroot*
.PHONY: buildroot
buildroot: tmp/buildroot/buildroot_configured.sentinel
tmp/buildroot/buildroot_configured.sentinel: tmp/buildroot/buildroot_untarred.sentinel
$(TRACE_COMMAND)
cd tmp/buildroot
# Remove paths with spaces to avoid a make limitation
PATH=`echo "$$PATH" | sed -e 's/\(:\|\)[^:]* [^:]*\(:\|$$\)/\1\2/g' | sed -e 's/::\+/:/g'`
$(MAKE) BR2_EXTERNAL=../../os my_console_1_0_defconfig
$(TOUCH_TARGET)
.PHONY: tmp/buildroot
tmp/buildroot: tmp/buildroot/buildroot_untarred.sentinel
tmp/buildroot/buildroot_untarred.sentinel: | tmp/buildroot_untar/
$(TRACE_COMMAND)
cd tmp/buildroot_untar
tar xf ../../os/buildroot*.*z
rm -rf ../buildroot
mv * ../buildroot
cd ..
rmdir buildroot_untar
$(TOUCH_TARGET)
.PHONY: cargo_vendor
cargo_vendor: tmp/buildroot/.cargo/config.toml
tmp/buildroot/.cargo/config.toml: tmp/buildroot/buildroot_configured.sentinel
$(TRACE_COMMAND)
# Vendor deps because buildroot builds with --offline and can't fetch them. Put the Cargo.toml
# snippet where buildroot's host cargo can find it.
# mkdir here instead of with an order-only dependency because the order-only approach
# causes the directory to be made before tmp/buildroot/buildroot_configured.sentinel runs, and that
# recipe deletes it.
[[ ! -d "$(dir $@)" ]] && mkdir "$(dir $@)"
cd ui
cargo vendor --quiet --locked --versioned-dirs "../tmp/cargo_vendor" | sed "s:/tmp/:/:" > "../$@.tmp"
cd ..
mv "$@.tmp" "$@"
.PHONY: help
help:
@$(info $(HELP))
#
.PHONY: os
os: ../output/my_os-$(VERSION).img ../output/my_os-$(VERSION).cyclonedx.json
.PHONY: print_commands
print_commands:
@$(info $(COMMANDS))
#
.PHONY: sboms
sboms: ../output/my_os-$(VERSION).cyclonedx.json
# TODO: implement UI SBOM generaiton
.PHONY: ui
ui: ../output/my_ui-$(VERSION) # TODO (when cargo SBOM support released): SBOM via cargo
################################################################################
# Internal Rules
OS_PREREQUISITES := $(shell find os -type f -not \( -path "os/docs/*" -o -path os/README.md \))
tmp/buildroot/output/images/disk.img: $(OS_PREREQUISITES) tmp/buildroot/.cargo/config.toml
$(TRACE_COMMAND)
cd tmp/buildroot
# Remove paths with spaces to avoid a make limitation
PATH=`echo "$$PATH" | sed -e 's/\(:\|\)[^:]* [^:]*\(:\|$$\)/\1\2/g' | sed -e 's/::\+/:/g'`
env
$(MAKE) MAKEFLAGS= > ../make_log.txt 2>&1 || (
EXIT_CODE=$$?
tail -n 100 ../make_log.txt
exit $$EXIT_CODE
)
../output/my_os-$(VERSION).img: tmp/buildroot/output/images/disk.img
$(TRACE_COMMAND)
cp $^ output
../output/my_os-$(VERSION).cyclonedx.json: tmp/buildroot/buildroot_configured.sentinel
$(TRACE_COMMAND)
cd tmp/buildroot
# Remove paths with spaces to avoid a make limitation
PATH=`echo "$$PATH" | sed -e 's/\(:\|\)[^:]* [^:]*\(:\|$$\)/\1\2/g' | sed -e 's/::\+/:/g'`
$(MAKE) MAKEFLAGS= --silent show-info | utils/generate-cyclonedx | jaq '.' > "$(TMP_TARGET)"
$(MV_TMP_TO_TARGET)
../output/my_ui-$(VERSION): ui/target/debug/my-ui | ../output/
$(TRACE_COMMAND)
cp $^ "$(TMP_TARGET)"
$(MV_TMP_TO_TARGET)
UI_PREREQUISITES := $(shell find ui/assets ui/Cargo.*; find ui -type f -name "*.toml" -o -name "*.rs")
ui/target/debug/my-ui: $(UI_PREREQUISITES)
$(TRACE_COMMAND)
cd ui
cargo build
################################################################################
# Pattern Rules
%/:
$(TRACE_COMMAND)
mkdir -p $@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment