mirror of
https://github.com/Dasharo/heads.git
synced 2026-06-13 10:16:29 -07:00
ca49f14c6d
When the coreboot git commit changes (canary mismatch), remove and recreate the board-specific build directories to prevent stale artifacts from causing compilation failures. This eliminates the need for manual `rm -rf build/x86/BOARD` before rebuilding after coreboot canary updates in development cycles (when creating patches). One currently still has to, eg: echo "bogues repo url + commit hash" | sudo tee /home/user/heads/build/x86/coreboot-25.09/.canary Current logic then: 1. Detects canary changes and triggers repository cleanup 2. Removes both Heads board directory (build/x86/BOARD) and coreboot board directory (build/x86/coreboot-*/BOARD) that contain stale build artifacts 3. Recreates empty board directories for the subsequent build 4. Allows patches to apply cleanly without Ada compilation errors This ensures Ada builds work correctly after coreboot updates without manual intervention (resync repo, apply patches, clean artifact dirs and rebuilds only what changed). Signed-off-by: Thierry Laurion <insurgo@riseup.net>
1139 lines
45 KiB
Makefile
1139 lines
45 KiB
Makefile
# Need to set CB_OUTPUT_FILE before board .config included so
|
|
# that target overrides in x230/x430-flash (eg) are properly handled
|
|
GIT_HASH := $(shell git rev-parse HEAD)
|
|
GIT_STATUS := $(shell \
|
|
if git diff --exit-code >/dev/null ; then \
|
|
echo clean ; \
|
|
else \
|
|
echo dirty ; \
|
|
fi)
|
|
HEADS_GIT_VERSION := $(shell git describe --abbrev=7 --tags --dirty)
|
|
GIT_TIMESTAMP := $(shell git log -1 --format=%cd --date=format:'%Y%m%d-%H%M%S')
|
|
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD | cut -c1-30)
|
|
# Release builds: HEAD is exactly on a tag AND working tree is clean.
|
|
# Dev builds: any untagged commit, commits ahead of a tag, or dirty tree.
|
|
# Dev filenames include timestamp + branch for traceability without
|
|
# polluting release filenames.
|
|
GIT_IS_RELEASE := $(shell git describe --exact-match --tags HEAD >/dev/null 2>&1 \
|
|
&& git diff --exit-code >/dev/null 2>&1 \
|
|
&& echo y || echo n)
|
|
ifeq ($(GIT_IS_RELEASE),y)
|
|
GIT_VERSION_SUFFIX := $(HEADS_GIT_VERSION)
|
|
else
|
|
GIT_VERSION_SUFFIX := $(GIT_TIMESTAMP)-$(GIT_BRANCH)-$(HEADS_GIT_VERSION)
|
|
endif
|
|
|
|
# Override BRAND_NAME to set the name displayed in the UI, filenames, versions, etc.
|
|
BRAND_NAME ?= Heads
|
|
|
|
all:
|
|
-include .config
|
|
|
|
modules-y :=
|
|
pwd := $(shell pwd)
|
|
config := $(pwd)/config
|
|
# These are dynamic, must not expand right here
|
|
build = $(pwd)/build/$(CONFIG_TARGET_ARCH)
|
|
packages = $(pwd)/packages/$(CONFIG_TARGET_ARCH)
|
|
INSTALL = $(pwd)/install/$(CONFIG_TARGET_ARCH)
|
|
log_dir = $(build)/log
|
|
board_build = $(build)/$(BOARD)
|
|
|
|
|
|
# Estimated memory required per job in GB (e.g., 1GB for gcc)
|
|
MEM_PER_JOB_GB ?= 1
|
|
|
|
# Controls how many parallel jobs are invoked in subshells
|
|
CPUS ?= $(shell nproc)
|
|
AVAILABLE_MEM_GB ?= $(shell cat /proc/meminfo | grep MemAvailable | awk '{print int($$2 / 1024)}')
|
|
|
|
# Calculate the maximum number of jobs based on available memory
|
|
MAX_JOBS_MEM := $(shell echo $$(( $(AVAILABLE_MEM_GB) / $(MEM_PER_JOB_GB) )))
|
|
|
|
# Use the minimum of the system's CPUs and the calculated max jobs based on memory
|
|
CPUS := $(shell echo $$(($(CPUS) < $(MAX_JOBS_MEM) ? $(CPUS) : $(MAX_JOBS_MEM))))
|
|
|
|
# Load average can be adjusted to be higher than CPUS to allow for some CPU overcommit
|
|
# Multiply by 3 and then divide by 2 to achieve the effect of multiplying by 1.5 using integer arithmetic
|
|
LOADAVG ?= $(shell echo $$(( ($(CPUS) * 3) / 2 )))
|
|
|
|
# Construct MAKE_JOBS with dynamic CPU count and load average
|
|
MAKE_JOBS := -j$(CPUS) --load-average=$(LOADAVG) # Add other flags as needed to be more adaptive to CIs
|
|
|
|
# Print out the settings and compare system values with actual ones used
|
|
$(info ----------------------------------------------------------------------)
|
|
$(info !!!!!! BUILD SYSTEM INFO !!!!!!)
|
|
$(info System CPUS: $(shell nproc))
|
|
$(info System Available Memory: $(AVAILABLE_MEM_GB) GB)
|
|
$(info System Load Average: $(shell uptime | awk '{print $$10}'))
|
|
$(info ----------------------------------------------------------------------)
|
|
$(info Used **CPUS**: $(CPUS))
|
|
$(info Used **LOADAVG**: $(LOADAVG))
|
|
$(info Used **AVAILABLE_MEM_GB**: $(AVAILABLE_MEM_GB) GB)
|
|
$(info ----------------------------------------------------------------------)
|
|
$(info **MAKE_JOBS**: $(MAKE_JOBS))
|
|
$(info )
|
|
$(info Variables available for override (use 'make VAR_NAME=value'):)
|
|
$(info **CPUS** (default: number of processors, e.g., 'make CPUS=4'))
|
|
$(info **LOADAVG** (default: 1.5 times CPUS, e.g., 'make LOADAVG=54'))
|
|
$(info **AVAILABLE_MEM_GB** (default: memory available on the system in GB, e.g., 'make AVAILABLE_MEM_GB=4'))
|
|
$(info **MEM_PER_JOB_GB** (default: 1GB per job, e.g., 'make MEM_PER_JOB_GB=2'))
|
|
$(info ----------------------------------------------------------------------)
|
|
ifeq "$(V)" ""
|
|
$(info Hint: If the build fails, re-run with V=1 for full configure + validation output)
|
|
$(info Verbose example: ./docker_repro.sh make BOARD=$(BOARD) V=1)
|
|
$(info ----------------------------------------------------------------------)
|
|
endif
|
|
$(info !!!!!! Build starts !!!!!!)
|
|
|
|
|
|
# Timestamps should be in ISO format
|
|
DATE=`date --rfc-3339=seconds`
|
|
|
|
BOARD ?= qemu-coreboot-fbwhiptail-tpm1
|
|
|
|
# If the board name begins with UNMAINTAINED_, use the
|
|
# unmaintained_boards path.
|
|
ifeq "y" "$(shell echo '$(BOARD)' | grep -E '^UNMAINTAINED_' >/dev/null 2>&1 && echo y)"
|
|
CONFIG := $(pwd)/unmaintained_boards/$(BOARD)/$(BOARD).config
|
|
else
|
|
CONFIG := $(pwd)/boards/$(BOARD)/$(BOARD).config
|
|
endif
|
|
|
|
ifneq "y" "$(shell [ -r '$(CONFIG)' ] && echo y)"
|
|
$(error $(CONFIG): board configuration does not exist)
|
|
endif
|
|
|
|
# By default, we are building for x86, up to a board to change this variable
|
|
CONFIG_TARGET_ARCH := x86
|
|
|
|
# Legacy flash boards have to be handled specifically for some functionality
|
|
# (e.g. they don't generate upgrade packages, lack bash, etc.) Use this to
|
|
# guard behavior that is specific to legacy flash boards only. Don't use it for
|
|
# behavior that might be needed for other boards, use specific configs instead.
|
|
CONFIG_LEGACY_FLASH := n
|
|
|
|
include $(CONFIG)
|
|
|
|
# Include site-local/config only if it exists, downstreams can set configs for
|
|
# all boards, including overriding values specified by boards. site-local is
|
|
# not a part of the upstream distribution but is for downstreams to insert
|
|
# customizations at well-defined points, like in coreboot:
|
|
# https://doc.coreboot.org/tutorial/managing_local_additions.html
|
|
-include $(pwd)/site-local/config
|
|
|
|
CB_OUTPUT_BASENAME := $(shell echo $(BRAND_NAME) | tr A-Z a-z)-$(BOARD)-$(GIT_VERSION_SUFFIX)
|
|
CB_OUTPUT_FILE := $(CB_OUTPUT_BASENAME).rom
|
|
CB_OUTPUT_FILE_GPG_INJ := $(CB_OUTPUT_BASENAME)-gpg-injected.rom
|
|
CB_BOOTBLOCK_FILE := $(CB_OUTPUT_BASENAME).bootblock
|
|
CB_UPDATE_PKG_FILE := $(CB_OUTPUT_BASENAME).zip
|
|
LB_OUTPUT_FILE := linuxboot-$(BOARD)-$(GIT_VERSION_SUFFIX).rom
|
|
|
|
# Unless otherwise specified, we are building for heads
|
|
CONFIG_HEADS ?= y
|
|
|
|
# Unless otherwise specified, we are building bash to have non-interactive shell for scripts (arrays and bashisms)
|
|
CONFIG_BASH ?= y
|
|
|
|
# Unless otherwise specified, we build kbd to have setfont, loadkeys and keymaps
|
|
CONFIG_KBD ?= y
|
|
#loadkeys permits to load .map source files directly
|
|
CONFIG_KBD_LOADKEYS ?= y
|
|
|
|
|
|
# USB keyboards can be ignored, optionally supported, or required.
|
|
#
|
|
# To optionally support USB keyboards, export CONFIG_SUPPORT_USB_KEYBOARD=y. To
|
|
# default the setting to 'on', also export CONFIG_USER_USB_KEYBOARD=y.
|
|
#
|
|
# To require USB keyboard support (not user-configurable, for boards with no
|
|
# built-in keyboard), export CONFIG_USB_KEYBOARD_REQUIRED=y.
|
|
ifeq "$(CONFIG_USB_KEYBOARD_REQUIRED)" "y"
|
|
# CONFIG_USB_KEYBOARD_REQUIRED implies CONFIG_SUPPORT_USB_KEYBOARD.
|
|
export CONFIG_SUPPORT_USB_KEYBOARD=y
|
|
endif
|
|
|
|
# Determine arch part for a host triplet
|
|
ifeq "$(CONFIG_TARGET_ARCH)" "x86"
|
|
MUSL_ARCH := x86_64
|
|
else ifeq "$(CONFIG_TARGET_ARCH)" "ppc64"
|
|
MUSL_ARCH := powerpc64le
|
|
else
|
|
$(error "Unexpected value of $$(CONFIG_TARGET_ARCH): $(CONFIG_TARGET_ARCH)")
|
|
endif
|
|
|
|
ifneq "$(BOARD_TARGETS)" ""
|
|
include $(foreach TARGET,$(BOARD_TARGETS),targets/$(TARGET).mk)
|
|
endif
|
|
|
|
# Create directories if they don't already exist
|
|
BUILD_LOG := $(shell mkdir -p "$(log_dir)")
|
|
PACKAGES := $(shell mkdir -p "$(packages)")
|
|
|
|
# record the build date / git hashes and other files here
|
|
HASHES := $(board_build)/hashes.txt
|
|
SIZES := $(board_build)/sizes.txt
|
|
|
|
# Create the board output directory if it doesn't already exist
|
|
BOARD_LOG := $(shell \
|
|
mkdir -p "$(board_build)" ; \
|
|
echo "$(DATE) $(GIT_HASH) $(GIT_STATUS)" > "$(HASHES)" ; \
|
|
echo "$(DATE) $(GIT_HASH) $(GIT_STATUS)" > "$(SIZES)" ; \
|
|
)
|
|
|
|
ifeq "y" "$(CONFIG_LINUX_BUNDLED)"
|
|
# Create empty initrd for initial kernel "without" initrd.
|
|
$(shell cpio -o < /dev/null > $(board_build)/initrd.cpio)
|
|
endif
|
|
|
|
# If V is set in the environment, do not redirect the tee
|
|
# command to /dev/null.
|
|
ifeq "$V" ""
|
|
VERBOSE_REDIRECT := > /dev/null
|
|
# Not verbose, so we only show the header
|
|
define do =
|
|
@echo "$(DATE) $1 $(2:$(pwd)/%=%)"
|
|
@$3
|
|
endef
|
|
else
|
|
# Verbose, so we display what we are doing
|
|
define do =
|
|
@echo "$(DATE) $1 $(2:$(pwd)/%=%)"
|
|
$3
|
|
endef
|
|
endif
|
|
|
|
|
|
# Create a temporary directory for the initrd
|
|
initrd_dir := $(BOARD)
|
|
initrd_tmp_dir := $(shell mktemp -d)
|
|
initrd_tools_dir := $(initrd_tmp_dir)/tools
|
|
initrd_lib_dir := $(initrd_tools_dir)/lib
|
|
initrd_bin_dir := $(initrd_tools_dir)/bin
|
|
initrd_data_dir := $(initrd_tmp_dir)/data
|
|
modules-y += initrd
|
|
|
|
$(shell mkdir -p "$(initrd_lib_dir)" "$(initrd_bin_dir)" "$(initrd_data_dir)")
|
|
|
|
# We are running our own version of make,
|
|
# proceed with the build.
|
|
|
|
# Force pipelines to fail if any of the commands in the pipe fail
|
|
SHELL := /usr/bin/env bash
|
|
.SHELLFLAGS := -o pipefail -c
|
|
|
|
# Include the musl-cross-make module early so that $(CROSS) will
|
|
# be defined prior to any other module.
|
|
include modules/musl-cross-make
|
|
|
|
musl_dep := musl-cross-make
|
|
target := $(shell echo $(CROSS) | grep -Eoe '([^/]*?)-linux-musl')
|
|
arch := $(subst -linux-musl, , $(target))
|
|
heads_cc := $(CROSS)gcc \
|
|
-fdebug-prefix-map=$(pwd)=heads \
|
|
-gno-record-gcc-switches \
|
|
-D__MUSL__ \
|
|
--sysroot $(INSTALL) \
|
|
-isystem $(INSTALL)/include \
|
|
-L$(INSTALL)/lib \
|
|
|
|
# Cross-compiling with pkg-config requires clearing PKG_CONFIG_PATH and setting
|
|
# both PKG_CONFIG_LIBDIR and PKG_CONFIG_SYSROOT_DIR.
|
|
# https://autotools.info/pkgconfig/cross-compiling.html
|
|
CROSS_TOOLS_NOCC := \
|
|
AR="$(CROSS)ar" \
|
|
LD="$(CROSS)ld" \
|
|
STRIP="$(CROSS)strip" \
|
|
NM="$(CROSS)nm" \
|
|
OBJCOPY="$(CROSS)objcopy" \
|
|
OBJDUMP="$(CROSS)objdump" \
|
|
PKG_CONFIG_PATH= \
|
|
PKG_CONFIG_LIBDIR="$(INSTALL)/lib/pkgconfig" \
|
|
PKG_CONFIG_SYSROOT_DIR="$(INSTALL)" \
|
|
|
|
CROSS_TOOLS := \
|
|
CC="$(heads_cc)" \
|
|
$(CROSS_TOOLS_NOCC) \
|
|
|
|
# Targets to build payload only
|
|
.PHONY: payload
|
|
payload: $(build)/$(BOARD)/bzImage $(build)/$(initrd_dir)/initrd.cpio.xz
|
|
|
|
ifeq ($(CONFIG_COREBOOT), y)
|
|
|
|
# Legacy flash boards don't generate an update package, the only purpose of
|
|
# those boards is to be flashed over vendor firmware via an exploit.
|
|
ifneq ($(CONFIG_LEGACY_FLASH), y)
|
|
# Boards containing 'talos-2' build their own update package, which is not integrated with the ZIP method currently
|
|
ifneq ($(findstring talos-2, $(BOARD)),)
|
|
else
|
|
# Coreboot targets create an update package that can be applied with integrity
|
|
# verification before flashing (see flash-gui.sh). The ZIP package format
|
|
# allows other metadata that might be needed to added in the future without
|
|
# breaking backward compatibility.
|
|
$(board_build)/$(CB_UPDATE_PKG_FILE): $(board_build)/$(CB_OUTPUT_FILE)
|
|
rm -rf "$(board_build)/update_pkg"
|
|
mkdir -p "$(board_build)/update_pkg"
|
|
cp "$<" "$(board_build)/update_pkg/"
|
|
cd "$(board_build)/update_pkg" && sha256sum "$(CB_OUTPUT_FILE)" >sha256sum.txt
|
|
cd "$(board_build)/update_pkg" && zip -9 "$@" "$(CB_OUTPUT_FILE)" sha256sum.txt
|
|
|
|
# Only add the hash and size if split_8mb4mb.mk is not included
|
|
ifeq ($(wildcard split_8mb4mb.mk),)
|
|
all: $(board_build)/$(CB_OUTPUT_FILE) $(board_build)/$(CB_UPDATE_PKG_FILE)
|
|
@sha256sum $(board_build)/$(CB_OUTPUT_FILE) | tee -a "$(HASHES)"
|
|
@stat -c "%8s:%n" $(board_build)/$(CB_OUTPUT_FILE) | tee -a "$(SIZES)"
|
|
else
|
|
all: $(board_build)/$(CB_OUTPUT_FILE) $(board_build)/$(CB_UPDATE_PKG_FILE)
|
|
endif
|
|
endif
|
|
endif
|
|
|
|
ifneq ($(CONFIG_COREBOOT_BOOTBLOCK),)
|
|
all: $(board_build)/$(CB_BOOTBLOCK_FILE)
|
|
endif
|
|
|
|
else ifeq ($(CONFIG_LINUXBOOT), y)
|
|
all: $(board_build)/$(LB_OUTPUT_FILE)
|
|
else
|
|
$(error "$(BOARD): neither CONFIG_COREBOOT nor CONFIG_LINUXBOOT is set?")
|
|
endif
|
|
|
|
all payload:
|
|
@sha256sum $< | tee -a "$(HASHES)"
|
|
@stat -c "%8s:%n" $< | tee -a "$(SIZES)"
|
|
|
|
# Validate coreboot CBFS size against IFD BIOS region
|
|
validate_cbfs_ifd:
|
|
ifneq ($(CONFIG_COREBOOT),)
|
|
@echo "Validating $(BOARD) CBFS size against IFD BIOS region..."
|
|
@$(pwd)/bin/validate_cbfs_ifd_fit.sh \
|
|
--coreboot-dir "$(build)/$(coreboot_dir)" \
|
|
--board-dir "$(build)/$(BOARD)" \
|
|
--config "$(pwd)/$(CONFIG_COREBOOT_CONFIG)" || exit 1
|
|
@echo "✓ CBFS configuration is valid"
|
|
else
|
|
@echo "Board $(BOARD) does not use coreboot, skipping validation"
|
|
endif
|
|
|
|
# Auto-fix coreboot CBFS size to match IFD BIOS region
|
|
fix_cbfs_ifd:
|
|
ifneq ($(CONFIG_COREBOOT),)
|
|
@echo "Auto-fixing $(BOARD) CBFS size to match IFD BIOS region..."
|
|
@$(pwd)/bin/validate_cbfs_ifd_fit.sh \
|
|
--coreboot-dir "$(build)/$(coreboot_dir)" \
|
|
--board-dir "$(build)/$(BOARD)" \
|
|
--config "$(pwd)/$(CONFIG_COREBOOT_CONFIG)" \
|
|
--fix || exit 1
|
|
@echo ""
|
|
@echo "If CONFIG_CBFS_SIZE was adjusted, next build will use the new size."
|
|
else
|
|
@echo "Board $(BOARD) does not use coreboot, nothing to fix"
|
|
endif
|
|
|
|
# Disable all built in rules
|
|
.INTERMEDIATE:
|
|
.SUFFIXES:
|
|
FORCE:
|
|
|
|
# Copies config while replacing predefined placeholders with actual values
|
|
# This is used in a command like 'this && $(call install_config ...) && that'
|
|
# so it needs to evaluate to a shell command.
|
|
define install_config =
|
|
$(pwd)/bin/prepare_module_config.sh "$1" "$2" "$(board_build)" "$(BRAND_NAME)"
|
|
endef
|
|
|
|
# Make helpers to operate on lists of things
|
|
# Prefix is "smart" and doesn't add the prefix for absolute file paths
|
|
define prefix =
|
|
$(foreach _, $2, $(if $(patsubst /%,,$_),$1$_,$_))
|
|
endef
|
|
define map =
|
|
$(foreach _,$2,$(eval $(call $1,$_)))
|
|
endef
|
|
|
|
# Data files can be specified in modules/* to be added into data.cpio.
|
|
# Each module should set <modulename>_data += src|dst
|
|
# Example (in modules/ncurses):
|
|
# ncurses_data += $(INSTALL)/usr/lib/terminfo/l/linux|etc/terminfo/l/linux
|
|
#
|
|
# The main Makefile will collect all data files from enabled modules:
|
|
# $(call data,$(modules-y))
|
|
|
|
# Bring in all of the module definitions;
|
|
# these are the external pieces that will be downloaded and built
|
|
# as part of creating the Heads firmware image.
|
|
include modules/*
|
|
|
|
# Collect all data files from enabled modules
|
|
data_files :=
|
|
$(foreach m,$(modules-y),$(eval data_files += $($(m)_data)))
|
|
|
|
define bins =
|
|
$(foreach m,$1,$(call prefix,$(build)/$($m_dir)/,$($m_output)))
|
|
endef
|
|
define data =
|
|
$(foreach m,$1,$(call prefix,$(build)/$($m_dir)/,$($m_data)))
|
|
endef
|
|
define libs =
|
|
$(foreach m,$1,$(call prefix,$(build)/$($m_dir)/,$($m_libraries)))
|
|
endef
|
|
|
|
define outputs =
|
|
$(foreach m,$1,\
|
|
$(call bins,$m)\
|
|
$(call libs,$m)\
|
|
)
|
|
endef
|
|
|
|
#
|
|
# Build a cpio from a directory
|
|
#
|
|
define do-cpio =
|
|
$(call do,CPIO ,$1,\
|
|
( cd "$2"; \
|
|
find . \
|
|
| cpio \
|
|
--quiet \
|
|
-H newc \
|
|
-o \
|
|
) \
|
|
| ./bin/cpio-clean \
|
|
> "$1.tmp" \
|
|
)
|
|
@if ! cmp --quiet "$1.tmp" "$1" ; then \
|
|
mv "$1.tmp" "$1" ; \
|
|
else \
|
|
echo "$(DATE) UNCHANGED $(1:$(pwd)/%=%)" ; \
|
|
rm "$1.tmp" ; \
|
|
fi
|
|
@sha256sum "$1" | tee -a "$(HASHES)"
|
|
@stat -c "%8s:%n" "$1" | tee -a "$(SIZES)"
|
|
$(call do,HASHES , $1,\
|
|
( cd "$2"; \
|
|
echo "-----" ; \
|
|
find . -type f -print0 \
|
|
| xargs -0 sha256sum ; \
|
|
echo "-----" ; \
|
|
) >> "$(HASHES)" \
|
|
)
|
|
$(call do,SIZES , $1,\
|
|
( cd "$2"; \
|
|
echo "-----" ; \
|
|
find . -type f -print0 \
|
|
| xargs -0 stat -c "%8s:%n" ; \
|
|
echo "-----" ; \
|
|
) >> "$(SIZES)" \
|
|
)
|
|
endef
|
|
|
|
define do-copy =
|
|
$(call do,INSTALL ,$1 => $2,\
|
|
if cmp --quiet "$1" "$2" ; then \
|
|
echo "$(DATE) UNCHANGED $(1:$(pwd)/%=%)" ; \
|
|
fi ; \
|
|
cp -a --remove-destination "$1" "$2" ; \
|
|
)
|
|
@sha256sum "$(2:$(pwd)/%=%)"
|
|
@stat -c "%8s:%n" "$(2:$(pwd)/%=%)"
|
|
endef
|
|
|
|
|
|
#
|
|
# Generate the targets for a module.
|
|
#
|
|
# Special variables like $@ must be written as $$@ to avoid
|
|
# expansion during the first evaluation.
|
|
#
|
|
define define_module =
|
|
# if they have not defined a separate base dir, define it
|
|
# as the same as their build dir.
|
|
$(eval $1_base_dir = $(or $($1_base_dir),$($1_dir)))
|
|
# Dynamically defined modules must tell us what module file defined them
|
|
$(eval $1_module_file = $(or $($1_module_file),$1))
|
|
|
|
ifneq ("$($1_repo)","")
|
|
$(eval $1_patch_name = $1$(if $($1_patch_version),-$($1_patch_version),))
|
|
# First time:
|
|
# Checkout the tree instead and create the canary file with repo and
|
|
# revision so that we know that the files are all present and their
|
|
# version. Submodules are _not_ checked out, because coreboot has
|
|
# many submodules that won't be used, let coreboot check out its own
|
|
# submodules during build
|
|
#
|
|
# Other times:
|
|
# If .canary contains the same repo and revision combination, do nothing.
|
|
# Otherwise, pull a new revision and checkout with update of submodules
|
|
#
|
|
# No signature hashes are checked in this case, since we don't have a
|
|
# stable version to compare against.
|
|
#
|
|
# XXX: "git clean -dffx" is a hack for coreboot during commit switching, need
|
|
# module-specific cleanup action to get rid of it.
|
|
$(build)/$($1_base_dir)/.canary: FORCE
|
|
if [ ! -e "$$@" ] && [ ! -d "$(build)/$($1_base_dir)" ]; then \
|
|
echo "INFO: .canary file and directory not found. Cloning repository $($1_repo) into $(build)/$($1_base_dir)" && \
|
|
git clone $($1_repo) "$(build)/$($1_base_dir)" && \
|
|
echo "INFO: Resetting repository to commit $($1_commit_hash)" && \
|
|
git -C "$(build)/$($1_base_dir)" reset --hard $($1_commit_hash) && \
|
|
echo "INFO: Creating .canary file with repo and commit hash" && \
|
|
echo -n '$($1_repo)|$($1_commit_hash)' > "$$@" ; \
|
|
elif [ ! -e "$$@" ] || [ "$$$$(cat "$$@")" != '$($1_repo)|$($1_commit_hash)' ]; then \
|
|
echo "INFO: .canary file missing or differs. Resetting $1 to $($1_repo) at $($1_commit_hash)" && \
|
|
git -C "$(build)/$($1_base_dir)" reset --hard HEAD^ && \
|
|
echo "INFO: Fetching commit $($1_commit_hash) from $($1_repo) (without recursing submodules)" && \
|
|
git -C "$(build)/$($1_base_dir)" fetch $($1_repo) $($1_commit_hash) --recurse-submodules=no && \
|
|
echo "INFO: Resetting repository to commit $($1_commit_hash)" && \
|
|
git -C "$(build)/$($1_base_dir)" reset --hard $($1_commit_hash) && \
|
|
echo "INFO: Cleaning repository directory (including payloads and util/cbmem)" && \
|
|
git -C "$(build)/$($1_base_dir)" clean -df && \
|
|
git -C "$(build)/$($1_base_dir)" clean -dffx payloads util/cbmem && \
|
|
echo "INFO: Synchronizing submodules" && \
|
|
git -C "$(build)/$($1_base_dir)" submodule sync && \
|
|
echo "INFO: Updating submodules (init and checkout)" && \
|
|
git -C "$(build)/$($1_base_dir)" submodule update --init --checkout && \
|
|
echo "INFO: Cleaning board-specific build directories to prevent stale artifacts" && \
|
|
rm -rf "$(build)/$(BOARD)" "$(build)/$($1_base_dir)/$(BOARD)" && \
|
|
echo "INFO: Recreating board directories" && \
|
|
mkdir -p "$(build)/$(BOARD)" "$(build)/$($1_base_dir)/$(BOARD)" && \
|
|
echo "INFO: Updating .canary file with new repo info" && \
|
|
echo -n '$($1_repo)|$($1_commit_hash)' > "$$@" ; \
|
|
fi
|
|
if [ ! -e "$(build)/$($1_base_dir)/.patched" ]; then \
|
|
echo "INFO: .patched file not found. Beginning patch application for $1" && \
|
|
if [ -r patches/$($1_patch_name).patch ]; then \
|
|
echo "INFO: Applying single patch file: patches/$($1_patch_name).patch" && \
|
|
if ! git apply --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < patches/$($1_patch_name).patch; then \
|
|
echo "ERROR: Failed to apply patch: patches/$($1_patch_name).patch. Reversing and reapplying." && \
|
|
git apply --reverse --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < patches/$($1_patch_name).patch || true && \
|
|
git apply --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < patches/$($1_patch_name).patch || exit 1; \
|
|
fi; \
|
|
fi; \
|
|
if [ -d patches/$($1_patch_name) ]; then \
|
|
echo "INFO: Applying multiple patch files from directory: patches/$($1_patch_name)" && \
|
|
for patch in patches/$($1_patch_name)/*.patch; do \
|
|
echo "INFO: Applying patch file: $$$$patch" && \
|
|
if ! git apply --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < "$$$$patch"; then \
|
|
echo "ERROR: Failed to apply patch: $$$$patch. Reversing and reapplying." && \
|
|
git apply --reverse --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < "$$$$patch" || true && \
|
|
git apply --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < "$$$$patch" || exit 1; \
|
|
fi; \
|
|
done; \
|
|
fi; \
|
|
echo "INFO: Patches applied successfully. Creating .patched file." && \
|
|
touch "$(build)/$($1_base_dir)/.patched"; \
|
|
fi
|
|
else
|
|
# Versioned modules (each version a separate module) don't need to include
|
|
# the version a second time. (The '-' separator is also omitted then.)
|
|
# $1_patch_version can still be defined manually.
|
|
$(eval $1_patch_version ?= $(if $(filter %-$($1_version),$1),,$($1_version)))
|
|
$(eval $1_patch_name = $1$(if $($1_patch_version),-,)$($1_patch_version))
|
|
# Fetch and verify the source tar file
|
|
# wget creates it early, so we have to cleanup if it fails
|
|
$(packages)/$($1_tar):
|
|
$(call do,WGET,$($1_url),\
|
|
WGET="$(WGET)" bin/fetch_source_archive.sh "$($1_url)" "$$@" "$($1_hash)"
|
|
)
|
|
|
|
# Target to fetch all packages, for seeding mirrors
|
|
packages: $(packages)/$($1_tar)
|
|
|
|
# Unpack the tar file and touch the canary so that we know
|
|
# that the files are all present
|
|
$(build)/$($1_base_dir)/.canary: $(packages)/$($1_tar)
|
|
mkdir -p "$$(dir $$@)"
|
|
tar -xf "$(packages)/$($1_tar)" $(or $($1_tar_opt),--strip 1) -C "$$(dir $$@)"
|
|
if [ -r patches/$($1_patch_name).patch ]; then \
|
|
echo "INFO: Applying single patch file: patches/$($1_patch_name).patch" && \
|
|
if ! ( git apply --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < patches/$($1_patch_name).patch ); then \
|
|
echo "ERROR: Failed to apply patch: patches/$($1_patch_name).patch. Reversing and reapplying." && \
|
|
( git apply --reverse --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < patches/$($1_patch_name).patch ) || true && \
|
|
( git apply --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < patches/$($1_patch_name).patch ) || exit 1 ; \
|
|
fi ; \
|
|
fi ; \
|
|
if [ -d patches/$($1_patch_name) ]; then \
|
|
echo "INFO: Applying multiple patch files from directory: patches/$($1_patch_name)" && \
|
|
for patch in patches/$($1_patch_name)/*.patch; do \
|
|
echo "INFO: Applying patch file: $$$$patch" && \
|
|
if ! ( git apply --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < $$$$patch ); then \
|
|
echo "ERROR: Failed to apply patch: $$$$patch. Reversing and reapplying." && \
|
|
( git apply --reverse --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < $$$$patch ) || true && \
|
|
echo "INFO: Reapplying patch file: $$$$patch" && \
|
|
( git apply --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < $$$$patch ) || exit 1 ; \
|
|
fi ; \
|
|
done ; \
|
|
fi
|
|
if [ ! -e "$$@" ] && [ -e "$(build)/$($1_base_dir)/.patched" ]; then \
|
|
echo "INFO: .canary file not found but .patched exists. Reversing and reapplying patches for $1" && \
|
|
if [ -r patches/$($1_patch_name).patch ]; then \
|
|
echo "INFO: Reversing single patch file: patches/$($1_patch_name).patch." && \
|
|
( git apply --reverse --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < patches/$($1_patch_name).patch ) || true && \
|
|
echo "INFO: Reapplying single patch file: patches/$($1_patch_name).patch." && \
|
|
( git apply --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < patches/$($1_patch_name).patch ) || exit 1 ; \
|
|
fi ; \
|
|
if [ -d patches/$($1_patch_name) ]; then \
|
|
echo "INFO: Reversing and reapplying multiple patch files from directory: patches/$($1_patch_name)" && \
|
|
for patch in patches/$($1_patch_name)/*.patch; do \
|
|
echo "INFO: Reversing patch file: $$$$patch" && \
|
|
( git apply --reverse --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < $$$$patch ) || true && \
|
|
echo "INFO: Reapplying patch file: $$$$patch" && \
|
|
( git apply --verbose --reject --binary --directory build/$(CONFIG_TARGET_ARCH)/$($1_base_dir) < $$$$patch ) || exit 1 ; \
|
|
done ; \
|
|
fi ; \
|
|
rm -f "$(build)/$($1_base_dir)/.patched" ; \
|
|
fi
|
|
touch "$$@"
|
|
endif
|
|
|
|
# Allow the module to override the destination configuration file
|
|
# via a relative path. Linux uses this to have a per-board build.
|
|
$(eval $1_config_file_path := $(build)/$($1_dir)/$(or $($1_config_file),.config))
|
|
|
|
ifeq "$($1_config)" ""
|
|
# There is no official .config file
|
|
$($1_config_file_path): $(build)/$($1_base_dir)/.canary
|
|
@mkdir -p $$(dir $$@)
|
|
@touch "$$@"
|
|
else
|
|
# Copy the stored config file into the unpacked directory
|
|
$($1_config_file_path): $($1_config) $(build)/$($1_base_dir)/.canary
|
|
@mkdir -p $$(dir $$@)
|
|
$(call do-copy,$($1_config),$$@)
|
|
endif
|
|
|
|
# The first time we have to wait for all the dependencies to be built
|
|
# before we can configure the target. Once the dep has been built,
|
|
# we only depend on it for a rebuild.
|
|
$(eval $1_config_wait := $(foreach d,$($1_depends),\
|
|
$(shell [ -r $(build)/$($d_dir)/.build ] || echo $d)))
|
|
|
|
# Use the module's configure variable to build itself
|
|
# this has to wait for the dependencies to be built since
|
|
# cross compilers and libraries might be messed up
|
|
$(dir $($1_config_file_path)).configured: \
|
|
$(build)/$($1_base_dir)/.canary \
|
|
$(foreach d,$($1_config_wait),$(build)/$($d_dir)/.build) \
|
|
$($1_config_file_path) \
|
|
modules/$($1_module_file)
|
|
@echo "$(DATE) CONFIG $1"
|
|
@( \
|
|
cd "$(build)/$($1_dir)" ; \
|
|
echo "$($1_configure)"; \
|
|
$($1_configure) \
|
|
) \
|
|
< /dev/null \
|
|
2>&1 \
|
|
| tee "$(log_dir)/$1.configure.log" \
|
|
$(VERBOSE_REDIRECT)
|
|
@touch "$$@"
|
|
|
|
# Short hand for our module build target
|
|
$1: \
|
|
$(build)/$($1_dir)/.build \
|
|
$(call outputs,$1) \
|
|
|
|
# Target for all of the outputs, which depend on their dependent modules
|
|
# being built, as well as this module being configured
|
|
$(call outputs,$1): $(build)/$($1_dir)/.build
|
|
|
|
# If any of the outputs are missing, we should force a rebuild
|
|
# of the entire module
|
|
$(eval $1.force = $(shell \
|
|
stat $(call outputs,$1) >/dev/null 2>/dev/null || echo FORCE \
|
|
))
|
|
|
|
#TODO: something better then removing .build: $($1.force) so that newt/ncurses are not rebuilt inconditionally?
|
|
$(build)/$($1_dir)/.build: \
|
|
$(foreach d,$($1_depends),$(build)/$($d_dir)/.build) \
|
|
$(dir $($1_config_file_path)).configured \
|
|
|
|
@echo "$(DATE) MAKE $1"
|
|
+@( \
|
|
echo "$(MAKE) \
|
|
-C \"$(build)/$($1_dir)\" \
|
|
$($1_target)" ; \
|
|
$(MAKE) \
|
|
-C "$(build)/$($1_dir)" \
|
|
$($1_target) \
|
|
) \
|
|
< /dev/null \
|
|
2>&1 \
|
|
| tee "$(log_dir)/$1.log" \
|
|
$(VERBOSE_REDIRECT) \
|
|
|| ( \
|
|
echo "tail $(log_dir)/$1.log"; \
|
|
echo "-----"; \
|
|
tail -20 "$(log_dir)/$1.log"; \
|
|
exit 1; \
|
|
)
|
|
$(call do,DONE,$1,\
|
|
touch $(build)/$($1_dir)/.build \
|
|
)
|
|
|
|
|
|
|
|
$1.clean:
|
|
-$(RM) "$(build)/$($1_dir)/.configured"
|
|
-$(MAKE) -C "$(build)/$($1_dir)" clean
|
|
|
|
endef
|
|
|
|
$(call map, define_module, $(modules-y))
|
|
|
|
# hack to force musl-cross-make to be built before musl
|
|
#$(build)/$(musl_dir)/.configured: $(build)/$(musl-cross-make_dir)/../../crossgcc/x86_64-linux-musl/bin/x86_64-musl-linux-gcc
|
|
|
|
#
|
|
# Install a file into the initrd, if it changed from
|
|
# the destination file.
|
|
#
|
|
define install =
|
|
@-mkdir -p "$(dir $2)"
|
|
$(call do,INSTALL,$2,cp -a --remove-destination "$1" "$2")
|
|
endef
|
|
|
|
#
|
|
# Files that should be copied into the initrd
|
|
# This should probably be done in a more scalable manner
|
|
#
|
|
define initrd_bin_add =
|
|
$(initrd_bin_dir)/$(notdir $1): $1
|
|
$(call do,INSTALL-BIN,$$(<:$(pwd)/%=%),cp -a --remove-destination "$$<" "$$@")
|
|
@$(CROSS)strip --preserve-dates "$$@" 2>&-; true
|
|
initrd_bins += $(initrd_bin_dir)/$(notdir $1)
|
|
endef
|
|
|
|
define initrd_lib_add =
|
|
$(initrd_lib_dir)/$(notdir $1): $1
|
|
$(call do,INSTALL-LIB,$(1:$(pwd)/%=%),\
|
|
$(CROSS)strip --preserve-dates -o "$$@" "$$<")
|
|
initrd_libs += $(initrd_lib_dir)/$(notdir $1)
|
|
endef
|
|
|
|
# Only some modules have binaries that we install
|
|
# Shouldn't this be specified in the module file?
|
|
#bin_modules-$(CONFIG_MUSL) += musl-cross-make
|
|
bin_modules-$(CONFIG_KEXEC) += kexec
|
|
bin_modules-$(CONFIG_TPMTOTP) += tpmtotp
|
|
bin_modules-$(CONFIG_PCIUTILS) += pciutils
|
|
bin_modules-$(CONFIG_FLASHROM) += flashrom
|
|
bin_modules-$(CONFIG_FLASHPROG) += flashprog
|
|
bin_modules-$(CONFIG_CRYPTSETUP) += cryptsetup
|
|
bin_modules-$(CONFIG_CRYPTSETUP2) += cryptsetup2
|
|
bin_modules-$(CONFIG_GPG) += gpg
|
|
bin_modules-$(CONFIG_GPG2) += gpg2
|
|
bin_modules-$(CONFIG_PINENTRY) += pinentry
|
|
bin_modules-$(CONFIG_LVM2) += lvm2
|
|
bin_modules-$(CONFIG_DROPBEAR) += dropbear
|
|
bin_modules-$(CONFIG_FLASHTOOLS) += flashtools
|
|
bin_modules-$(CONFIG_NEWT) += newt
|
|
bin_modules-$(CONFIG_CAIRO) += cairo
|
|
bin_modules-$(CONFIG_FBWHIPTAIL) += fbwhiptail
|
|
bin_modules-$(CONFIG_HOTPKEY) += hotp-verification
|
|
bin_modules-$(CONFIG_MSRTOOLS) += msrtools
|
|
bin_modules-$(CONFIG_NKSTORECLI) += nkstorecli
|
|
bin_modules-$(CONFIG_UTIL_LINUX) += util-linux
|
|
bin_modules-$(CONFIG_OPENSSL) += openssl
|
|
bin_modules-$(CONFIG_TPM2_TOOLS) += tpm2-tools
|
|
bin_modules-$(CONFIG_BASH) += bash
|
|
bin_modules-$(CONFIG_POWERPC_UTILS) += powerpc-utils
|
|
bin_modules-$(CONFIG_IO386) += io386
|
|
bin_modules-$(CONFIG_IOPORT) += ioport
|
|
bin_modules-$(CONFIG_KBD) += kbd
|
|
bin_modules-$(CONFIG_ZSTD) += zstd
|
|
bin_modules-$(CONFIG_E2FSPROGS) += e2fsprogs
|
|
bin_modules-$(CONFIG_EXFATPROGS) += exfatprogs
|
|
|
|
$(foreach m, $(bin_modules-y), \
|
|
$(call map,initrd_bin_add,$(call bins,$m)) \
|
|
)
|
|
|
|
# Install the data for every module that we have built
|
|
$(foreach m, $(modules-y), \
|
|
$(call map,initrd_data_add,$(call data,$m)) \
|
|
)
|
|
# Install the libraries for every module that we have built
|
|
$(foreach m, $(modules-y), \
|
|
$(call map,initrd_lib_add,$(call libs,$m)) \
|
|
)
|
|
|
|
#
|
|
# hack to build cbmem from coreboot
|
|
# this must be built *AFTER* musl, but since coreboot depends on other things
|
|
# that depend on musl it should be ok.
|
|
#
|
|
COREBOOT_UTIL_DIR=$(build)/$(coreboot_base_dir)/util
|
|
ifeq ($(CONFIG_COREBOOT),y)
|
|
$(eval $(call initrd_bin_add,$(COREBOOT_UTIL_DIR)/cbmem/cbmem))
|
|
#$(eval $(call initrd_bin_add,$(COREBOOT_UTIL_DIR)/superiotool/superiotool))
|
|
#$(eval $(call initrd_bin_add,$(COREBOOT_UTIL_DIR)/inteltool/inteltool))
|
|
endif
|
|
|
|
$(COREBOOT_UTIL_DIR)/cbmem/cbmem \
|
|
$(COREBOOT_UTIL_DIR)/superiotool/superiotool \
|
|
$(COREBOOT_UTIL_DIR)/inteltool/inteltool \
|
|
: $(build)/$(coreboot_base_dir)/.canary musl-cross-make
|
|
+$(call do,MAKE,$(notdir $@),\
|
|
$(MAKE) -C "$(dir $@)" $(CROSS_TOOLS) \
|
|
)
|
|
|
|
# superio depends on zlib and pciutils
|
|
$(COREBOOT_UTIL_DIR)/superiotool/superiotool: \
|
|
$(build)/$(zlib_dir)/.build \
|
|
$(build)/$(pciutils_dir)/.build \
|
|
|
|
#
|
|
# --- INITRD IMAGE CREATION ---
|
|
#
|
|
# The initrd is constructed from various bits and pieces
|
|
# The cpio-clean program is used ensure that the files
|
|
# always have the same timestamp and appear in the same order.
|
|
#
|
|
# The blobs/dev.cpio is also included in the Linux kernel
|
|
# and has a reproducible version of /dev/console.
|
|
#
|
|
# The xz parameters are copied from the Linux kernel build scripts.
|
|
# Without them the kernel will not decompress the initrd.
|
|
#
|
|
# The padding is to ensure that if anyone wants to cat another
|
|
# file onto the initrd then the kernel will be able to find it.
|
|
#
|
|
|
|
initrd-y += $(pwd)/blobs/dev.cpio
|
|
initrd-y += $(build)/$(initrd_dir)/modules.cpio
|
|
initrd-y += $(build)/$(initrd_dir)/tools.cpio
|
|
initrd-y += $(build)/$(initrd_dir)/board.cpio
|
|
initrd-$(CONFIG_HEADS) += $(build)/$(initrd_dir)/heads.cpio
|
|
|
|
# --- DATA.CPIO STAGING AND CREATION ---
|
|
|
|
# Macro to handle staging of data files into the initrd temporary data directory
|
|
# Arguments:
|
|
# 1: Source path (file or directory)
|
|
# 2: Destination path inside initrd (relative path inside archive)
|
|
define stage_data_file =
|
|
$(initrd_data_dir)/$2: $1
|
|
$(call do,INSTALL-DATA,$(1:$(pwd)/%=%) => $2,\
|
|
mkdir -p "$(dir $(initrd_data_dir)/$2)"; \
|
|
cp -R "$1" "$(initrd_data_dir)/$2"; \
|
|
)
|
|
data_initrd_files += $(initrd_data_dir)/$2
|
|
endef
|
|
|
|
# Expand all data_files entries. Each entry: "src_path|dest_path"
|
|
$(foreach entry,$(data_files),\
|
|
$(eval src := $(word 1,$(subst |, ,$(entry)))) \
|
|
$(eval dst := $(word 2,$(subst |, ,$(entry)))) \
|
|
$(eval $(call stage_data_file,$(src),$(dst))) \
|
|
)
|
|
|
|
# Rule to build final data.cpio archive from staged files
|
|
ifneq ($(strip $(data_files)),)
|
|
$(build)/$(initrd_dir)/data.cpio: $(data_initrd_files) FORCE
|
|
$(call do-cpio,$@,$(initrd_data_dir))
|
|
@$(RM) -rf "$(initrd_data_dir)"
|
|
initrd-y += $(build)/$(initrd_dir)/data.cpio
|
|
endif
|
|
|
|
# --- MODULES.CPIO ---
|
|
|
|
# modules.cpio is built from kernel modules staged in a temp dir by modules/linux
|
|
# The temp dir is cleaned up after cpio creation.
|
|
# (see modules/linux for details)
|
|
|
|
# --- TOOLS.CPIO ---
|
|
|
|
# tools.cpio is built from all binaries, libraries, and config staged in initrd_tools_dir
|
|
$(build)/$(initrd_dir)/tools.cpio: \
|
|
$(initrd_bins) \
|
|
$(initrd_libs) \
|
|
$(initrd_tools_dir)/etc/config
|
|
$(call do-cpio,$@,$(initrd_tools_dir))
|
|
@$(RM) -rf "$(initrd_tools_dir)"
|
|
|
|
# --- TOOLS.CPIO'S ETC/CONFIG ---
|
|
# This is board's config provided defaults (at compilation time)
|
|
# Those defaults can be overriden by cbfs' config.user applied at init through cbfs-init.
|
|
# To view overriden exports at runtime, simply run 'env' and review CONFIG_ exported variables
|
|
# To view compilation time board's config; check /etc/config under recovery shell.
|
|
$(initrd_tools_dir)/etc/config: $(CONFIG)
|
|
@mkdir -p $(dir $@)
|
|
$(call do,INSTALL,$(CONFIG), \
|
|
export \
|
|
| grep ' CONFIG_' \
|
|
| sed -e 's/^declare -x /export /' \
|
|
-e 's/\\\"//g' \
|
|
> $@ \
|
|
)
|
|
$(call do,HASH,$(GIT_HASH) $(GIT_STATUS) $(BOARD), \
|
|
echo export GIT_HASH=\'$(GIT_HASH)\' \
|
|
>> $@ ; \
|
|
echo export GIT_STATUS=$(GIT_STATUS) \
|
|
>> $@ ; \
|
|
echo export CONFIG_BOARD=$(BOARD) \
|
|
>> $@ ; \
|
|
echo export CONFIG_BRAND_NAME=$(BRAND_NAME) \
|
|
>> $@ ; \
|
|
)
|
|
|
|
# --- BOARD.CPIO ---
|
|
|
|
# board.cpio is built from the board's initrd/ directory and contains
|
|
# board-specific support scripts.
|
|
# FORCE ensures the recipe always runs so do-cpio can show "UNCHANGED" when
|
|
# content is unchanged (efficient rebuild while maintaining consistent output)
|
|
BOARD_INITRD_FILES := $(shell find $(pwd)/boards/$(BOARD)/initrd -type f 2>/dev/null)
|
|
ifeq ($(BOARD_INITRD_FILES),)
|
|
$(build)/$(initrd_dir)/board.cpio:
|
|
# Only create a board.cpio if the board has a initrd directory
|
|
cpio -H newc -o </dev/null >"$@"
|
|
else
|
|
$(build)/$(initrd_dir)/board.cpio: $(BOARD_INITRD_FILES) FORCE
|
|
$(call do-cpio,$@,$(pwd)/boards/$(BOARD)/initrd)
|
|
endif
|
|
|
|
# --- HEADS.CPIO ---
|
|
|
|
# heads.cpio is built from the initrd directory in the Heads tree
|
|
# This is heads security policies, executed by board's CONFIG_BOOTSCRIPT at init
|
|
# FORCE ensures the recipe always runs so do-cpio can show "UNCHANGED" when
|
|
# content is unchanged (efficient rebuild while maintaining consistent output)
|
|
# Use find to get file list - regular files only, evaluated at make time
|
|
HEADS_INITRD_FILES := $(shell find $(pwd)/initrd -type f 2>/dev/null)
|
|
$(build)/$(initrd_dir)/heads.cpio: $(HEADS_INITRD_FILES) FORCE
|
|
$(call do-cpio,$@,$(pwd)/initrd)
|
|
|
|
# --- FINAL INITRD PACKAGING ---
|
|
|
|
$(build)/$(initrd_dir)/initrd.cpio.xz: $(initrd-y)
|
|
$(call do,CPIO-XZ ,$@,\
|
|
$(pwd)/bin/cpio-clean \
|
|
$^ \
|
|
| xz \
|
|
--check=crc32 \
|
|
--lzma2=dict=1MiB \
|
|
-9 \
|
|
| dd bs=512 conv=sync status=none > "$@.tmp" \
|
|
)
|
|
@if ! cmp --quiet "$@.tmp" "$@" ; then \
|
|
mv "$@.tmp" "$@" ; \
|
|
else \
|
|
echo "$(DATE) UNCHANGED $(@:$(pwd)/%=%)" ; \
|
|
rm "$@.tmp" ; \
|
|
fi
|
|
@sha256sum "$(@:$(pwd)/%=%)" | tee -a "$(HASHES)"
|
|
@stat -c "%8s:%n" "$(@:$(pwd)/%=%)" | tee -a "$(SIZES)"
|
|
|
|
# --- BUNDLED INITRD FOR POWERPC ---
|
|
|
|
bundle-$(CONFIG_LINUX_BUNDLED) += $(board_build)/$(LINUX_IMAGE_FILE).bundled
|
|
all: $(bundle-y)
|
|
|
|
# Ensure that the initrd depends on all of the modules that produce
|
|
# binaries for it
|
|
$(build)/$(initrd_dir)/tools.cpio: $(foreach d,$(bin_modules-y),$(build)/$($d_dir)/.build)
|
|
|
|
|
|
# List of all modules, excluding the slow to-build modules
|
|
modules-slow := musl musl-cross-make kernel_headers
|
|
module_dirs := $(foreach m,$(filter-out $(modules-slow),$(modules-y)),$($m_dir))
|
|
|
|
echo_modules:
|
|
echo $(module_dirs)
|
|
|
|
modules.clean:
|
|
for dir in $(module_dirs) \
|
|
; do \
|
|
$(MAKE) -C "build/${CONFIG_TARGET_ARCH}/$$dir" clean ; \
|
|
rm -f "build/${CONFIG_TARGET_ARCH}/$$dir/.configured" ; \
|
|
done
|
|
|
|
# Inject a GPG key into the image - this is most useful when testing in qemu,
|
|
# since we can't reflash the firmware in qemu to update the keychain. Instead,
|
|
# inject the public key ahead of time. Specify the location of the key with
|
|
# PUBKEY_ASC.
|
|
inject_gpg: $(board_build)/$(CB_OUTPUT_FILE_GPG_INJ)
|
|
|
|
$(board_build)/$(CB_OUTPUT_BASENAME)-gpg-injected.rom: $(board_build)/$(CB_OUTPUT_FILE) $(PUBKEY_ASC)
|
|
@set -e; \
|
|
src="$(board_build)/$(CB_OUTPUT_FILE)"; \
|
|
tgt="$(board_build)/$(CB_OUTPUT_FILE_GPG_INJ)"; \
|
|
key="$(PUBKEY_ASC)"; \
|
|
meta="$(board_build)/$(CB_OUTPUT_FILE_GPG_INJ).meta"; \
|
|
if [ -f "$$tgt" ] && [ -f "$$meta" ]; then \
|
|
SRC_SHA256=$$(awk -F= '/^SRC_SHA256=/{print $$2}' "$$meta"); \
|
|
KEY_SHA256=$$(awk -F= '/^KEY_SHA256=/{print $$2}' "$$meta"); \
|
|
src_sum=$$(sha256sum "$$src" | awk '{print $$1}'); \
|
|
key_sum=$$(sha256sum "$$key" | awk '{print $$1}'); \
|
|
if [ "$$src_sum" = "$$SRC_SHA256" ] && [ "$$key_sum" = "$$KEY_SHA256" ]; then \
|
|
echo "GPG injection up-to-date; skipping"; \
|
|
exit 0; \
|
|
fi; \
|
|
fi; \
|
|
cp "$$src" "$$tgt"; \
|
|
./bin/inject_gpg_key.sh --cbfstool "$(build)/$(coreboot_dir)/cbfstool" "$$tgt" "$$key"; \
|
|
SRC_SHA256=$$(sha256sum "$$src" | awk '{print $$1}'); \
|
|
KEY_SHA256=$$(sha256sum "$$key" | awk '{print $$1}'); \
|
|
printf 'SRC_SHA256=%s\nKEY_SHA256=%s\n' "$$SRC_SHA256" "$$KEY_SHA256" > "$$meta"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --- Development helpers ---
|
|
# Development targets for moving boards between states
|
|
|
|
board.move_untested_to_tested:
|
|
@echo "Moving $(BOARD) from UNTESTED to tested status"
|
|
@NEW_BOARD=$$(echo $(BOARD) | sed -E 's/(^EOL_|^)UNTESTED_/\1/'); \
|
|
INCLUDE_BOARD=$$(grep "include \$$(pwd)/boards/" boards/$(BOARD)/$(BOARD).config | sed 's/.*boards\/\(.*\)\/.*/\1/'); \
|
|
NEW_INCLUDE_BOARD=$$(echo $$INCLUDE_BOARD | sed 's/^UNTESTED_//'); \
|
|
echo "Updating config file: boards/$(BOARD)/$(BOARD).config"; \
|
|
sed -i 's/$(BOARD)/'$${NEW_BOARD}'/g' boards/$(BOARD)/$(BOARD).config; \
|
|
sed -i 's/'$$INCLUDE_BOARD'/'$$NEW_INCLUDE_BOARD'/g' boards/$(BOARD)/$(BOARD).config; \
|
|
echo "Renaming config file to $${NEW_BOARD}.config"; \
|
|
git mv boards/$(BOARD)/$(BOARD).config boards/$(BOARD)/$${NEW_BOARD}.config; \
|
|
echo "Renaming board directory to $${NEW_BOARD}"; \
|
|
git mv boards/$(BOARD) boards/$${NEW_BOARD}; \
|
|
echo "Updating .circleci/config.yml"; \
|
|
sed -i "s/$(BOARD)/$${NEW_BOARD}/g" .circleci/config.yml; \
|
|
echo "Operation completed for $(BOARD) -> $${NEW_BOARD}"
|
|
|
|
board.move_unmaintained_to_tested:
|
|
@echo "NEW_BOARD variable will remove UNMAINTAINED_ prefix from $(BOARD)"
|
|
@NEW_BOARD=$$(echo $(BOARD) | sed -E 's/(^EOL_|^)UNMAINTAINED_/\1/'); \
|
|
echo "Renaming unmaintained_boards/$$BOARD/$$BOARD.config to boards/$$BOARD/$$NEW_BOARD.config"; \
|
|
mkdir -p boards/$$BOARD; \
|
|
git mv unmaintained_boards/$$BOARD/$$BOARD.config boards/$$BOARD/$$NEW_BOARD.config; \
|
|
echo "Renaming boards/$$BOARD to boards/$$NEW_BOARD"; \
|
|
rm -rf boards/$$NEW_BOARD unmaintained_boards/$$BOARD; \
|
|
git mv boards/$$BOARD boards/$$NEW_BOARD; \
|
|
echo "Replacing $$BOARD with $$NEW_BOARD in .circleci/config.yml"; \
|
|
sed -i "s/$$BOARD/$$NEW_BOARD/g" .circleci/config.yml; \
|
|
echo "Board $$BOARD has been moved to tested status as $$NEW_BOARD"; \
|
|
echo "Please review and update .circleci/config.yml manually if needed"
|
|
|
|
board.move_untested_to_unmaintained:
|
|
@echo "NEW_BOARD variable will move from UNTESTED_ to UNMAINTAINED_ from $(BOARD)"
|
|
@NEW_BOARD=$$(echo $(BOARD) | sed -E 's/(^EOL_|^)UNTESTED_/\1UNMAINTAINED_/'); \
|
|
echo "Renaming boards/$$BOARD to unmaintained_boards/$$NEW_BOARD"; \
|
|
mkdir -p unmaintained_boards; \
|
|
git mv boards/$$BOARD unmaintained_boards/$$NEW_BOARD; \
|
|
echo "Renaming unmaintained_boards/$$NEW_BOARD/$$BOARD.config to unmaintained_boards/$$NEW_BOARD/$$NEW_BOARD.config"; \
|
|
rm -rf boards/$$NEW_BOARD; \
|
|
git mv unmaintained_boards/$$NEW_BOARD/$$BOARD.config unmaintained_boards/$$NEW_BOARD/$$NEW_BOARD.config; \
|
|
echo "Replacing $$BOARD with $$NEW_BOARD in .circleci/config.yml. Delete manually entries"; \
|
|
sed -i "s/$$BOARD/$$NEW_BOARD/g" .circleci/config.yml
|
|
|
|
board.move_tested_to_untested:
|
|
@echo "NEW_BOARD variable will add UNTESTED_ prefix to $(BOARD)"
|
|
@NEW_BOARD=$$(echo $(BOARD) | sed -E 's/(^EOL_|^)/\1UNTESTED_/'); \
|
|
rm -rf boards/$${NEW_BOARD}; \
|
|
echo "Renaming boards/$(BOARD)/$(BOARD).config to boards/$(BOARD)/$${NEW_BOARD}.config"; \
|
|
git mv boards/$(BOARD)/$(BOARD).config boards/$(BOARD)/$${NEW_BOARD}.config; \
|
|
echo "Renaming boards/$(BOARD) to boards/$${NEW_BOARD}"; \
|
|
git mv boards/$(BOARD) boards/$${NEW_BOARD}; \
|
|
echo "Replacing $(BOARD) with $${NEW_BOARD} in .circleci/config.yml"; \
|
|
sed -i "s/$(BOARD)/$${NEW_BOARD}/g" .circleci/config.yml
|
|
|
|
board.move_tested_to_EOL:
|
|
@echo "NEW_BOARD variable will EOL_$(BOARD)"
|
|
@NEW_BOARD=EOL_$(BOARD); \
|
|
rm -rf boards/$${NEW_BOARD}; \
|
|
echo "Renaming boards/$(BOARD)/$(BOARD).config to boards/$(BOARD)/$${NEW_BOARD}.config"; \
|
|
git mv boards/$(BOARD)/$(BOARD).config boards/$(BOARD)/$${NEW_BOARD}.config; \
|
|
echo "Renaming boards/$(BOARD) to boards/$${NEW_BOARD}"; \
|
|
git mv boards/$(BOARD) boards/$${NEW_BOARD}; \
|
|
echo "Replacing $(BOARD) with $${NEW_BOARD} in .circleci/config.yml"; \
|
|
sed -i "s/$(BOARD)/$${NEW_BOARD}/g" .circleci/config.yml
|
|
|
|
board.move_tested_to_unmaintained:
|
|
@echo "Moving $(BOARD) from tested to unmaintained status"
|
|
@NEW_BOARD=$$(echo $(BOARD) | sed -E 's/(^EOL_|^)/\1UNMAINTAINED_/'); \
|
|
INCLUDE_BOARD=$$(grep "include \$$(pwd)/boards/" boards/$(BOARD)/$(BOARD).config | sed 's/.*boards\/\(.*\)\/.*/\1/'); \
|
|
NEW_INCLUDE_BOARD=UNMAINTAINED_$${INCLUDE_BOARD}; \
|
|
echo "Updating config file: boards/$(BOARD)/$(BOARD).config"; \
|
|
sed -i 's/$(BOARD)/'$${NEW_BOARD}'/g' boards/$(BOARD)/$(BOARD).config; \
|
|
if [ -n "$$INCLUDE_BOARD" ]; then \
|
|
sed -i 's/'$$INCLUDE_BOARD'/'$$NEW_INCLUDE_BOARD'/g' boards/$(BOARD)/$(BOARD).config; \
|
|
fi; \
|
|
echo "Creating unmaintained_boards directory if it doesn't exist"; \
|
|
mkdir -p unmaintained_boards/$${NEW_BOARD}; \
|
|
echo "Moving and renaming config file to unmaintained_boards/$${NEW_BOARD}/$${NEW_BOARD}.config"; \
|
|
git mv boards/$(BOARD)/$(BOARD).config unmaintained_boards/$${NEW_BOARD}/$${NEW_BOARD}.config; \
|
|
echo "Moving board directory contents to unmaintained_boards/$${NEW_BOARD}"; \
|
|
git mv boards/$(BOARD)/* unmaintained_boards/$${NEW_BOARD}/; \
|
|
rmdir boards/$(BOARD); \
|
|
echo "Updating .circleci/config.yml"; \
|
|
sed -i "s/$(BOARD)/$${NEW_BOARD}/g" .circleci/config.yml; \
|
|
echo "Operation completed for $(BOARD) -> $${NEW_BOARD}"; \
|
|
echo "Please manually review and remove any unnecessary entries in .circleci/config.yml"
|
|
|
|
#Dev cycles helpers:
|
|
|
|
# Helper function to overwrite coreboot git repo's .canary file with a bogus commit (.canary checked for matching commit on build)
|
|
# TODO: Implement a cleaner solution to ensure files created by patches are properly deleted instead of requiring manual intervention.
|
|
define overwrite_canary_if_coreboot_git
|
|
@echo "Checking for coreboot directory: build/${CONFIG_TARGET_ARCH}/coreboot-$(CONFIG_COREBOOT_VERSION)"
|
|
if [ -d "build/${CONFIG_TARGET_ARCH}/coreboot-$(CONFIG_COREBOOT_VERSION)" ] && \
|
|
[ -d "build/${CONFIG_TARGET_ARCH}/coreboot-$(CONFIG_COREBOOT_VERSION)/.git" ]; then \
|
|
echo "INFO: Recreating .canary file for 'build/${CONFIG_TARGET_ARCH}/coreboot-$(CONFIG_COREBOOT_VERSION)' with placeholder." && \
|
|
echo BOGUS_COMMIT_ID > "build/${CONFIG_TARGET_ARCH}/coreboot-$(CONFIG_COREBOOT_VERSION)/.canary" && \
|
|
echo "INFO: .canary file has been recreated." ; \
|
|
else \
|
|
echo "INFO: Coreboot directory or .git not found, skipping .canary overwrite." ; \
|
|
fi
|
|
endef
|
|
|
|
real.clean:
|
|
@echo "Cleaning build artifacts and install directories, leaving crossgcc intact."
|
|
for dir in \
|
|
$(module_dirs) \
|
|
$(kernel_headers) \
|
|
; do \
|
|
if [ ! -z "$$dir" ]; then \
|
|
rm -rf "build/${CONFIG_TARGET_ARCH}/$$dir" ; \
|
|
fi ; \
|
|
done
|
|
cd install && rm -rf -- *
|
|
$(call overwrite_canary_if_coreboot_git)
|
|
|
|
real.gitclean:
|
|
@echo "Cleaning the repository using Git ignore file as a base..."
|
|
@echo "This will wipe everything not in the Git tree, but keep downloaded coreboot forks (detected as Git repos)."
|
|
git clean -fxd
|
|
$(call overwrite_canary_if_coreboot_git)
|
|
|
|
real.gitclean_keep_packages:
|
|
@echo "Cleaning the repository using Git ignore file as a base..."
|
|
@echo "This will wipe everything not in the Git tree, but keep the 'packages' directory."
|
|
git clean -fxd -e "packages"
|
|
$(call overwrite_canary_if_coreboot_git)
|
|
|
|
real.remove_canary_files-extract_patch_rebuild_what_changed:
|
|
@echo "Removing 'canary' files to force Heads to restart building board configurations..."
|
|
@echo "This will check package integrity, extract them, redo patching on files, and rebuild what needs to be rebuilt."
|
|
@echo "It will also reinstall the necessary files under './install'."
|
|
@echo "Limitations: If a patch creates a file in an extracted package directory, this approach may fail without further manual actions."
|
|
@echo "In such cases, Git will inform you about the file that couldn't be created as expected. Simply delete those files and relaunch the build."
|
|
@echo "This approach economizes time since most build artifacts do not need to be rebuilt, as the file dates should be the same as when you originally built them."
|
|
@echo "Only a minimal time is needed for rebuilding, which is also good for your SSD."
|
|
@echo "*** USE THIS APPROACH FIRST ***"
|
|
@echo "Removing ./build .canary files..."
|
|
@find ./build/ -type f -name ".canary" -print -delete || true
|
|
@echo "Removing install/*/* content..."
|
|
@find ./install/*/* -print -exec rm -rf {} + 2>/dev/null || true
|
|
@echo "Removing coreboot board related artifact directory: $(build)/$(coreboot_dir)"
|
|
rm -rf "$(build)/$(coreboot_dir)"
|
|
@echo "Removing coreboot board related artifacts directory $(board_build)"
|
|
rm -rf "$(board_build)"
|
|
$(call overwrite_canary_if_coreboot_git)
|
|
|
|
real.gitclean_keep_packages_and_build:
|
|
@echo "Cleaning the repository using Git ignore file as a base..."
|
|
@echo "This will wipe everything not in the Git tree, but keep the 'packages' and 'build' directories."
|
|
git clean -fxd -e "packages" -e "build"
|
|
$(call overwrite_canary_if_coreboot_git)
|