From 597cae600408d409e2aadb888a206c9ee82a5d2a Mon Sep 17 00:00:00 2001 From: febrezo Date: Sun, 10 May 2026 08:19:16 +0200 Subject: [PATCH] build: rework Makefile and InfiniSim container workflow --- .gitignore | 11 +++ Makefile | 104 +++++++++++++++++++++ tools/run-infinisim-podman.sh | 166 ++++++++++++++++++++++++++++++++++ 3 files changed, 281 insertions(+) create mode 100644 Makefile create mode 100755 tools/run-infinisim-podman.sh diff --git a/.gitignore b/.gitignore index d6f917cfc4..01ee6705e2 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ cmake_install.cmake Makefile build tools +# Exception: include the root Makefile +!Makefile # Resulting binary files *.a @@ -55,3 +57,12 @@ src/arm-none-eabi node_modules package.json package-lock.json + +# Local simulation and container virtualization artifacts +build_lv_sim/ +InfiniSim/ +.podman/ +.containers/ + +# Local duplicate helper script (tracked copy lives in tools/) +run-infinisim-podman.sh diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..79c667d15e --- /dev/null +++ b/Makefile @@ -0,0 +1,104 @@ +.PHONY: check-runtime ensure-firmware-image build build-infinisim run-infinisim clean help + +# Default target +.DEFAULT_GOAL := build + +# Build directories +BUILD_DIR ?= build +INFINISIM_DIR ?= build_lv_sim/InfiniSim +INFINISIM_BUILD_DIR ?= $(INFINISIM_DIR)/build + +# Container configuration +CONTAINER_RUNTIME ?= $(shell if command -v podman >/dev/null 2>&1; then echo podman; elif command -v docker >/dev/null 2>&1; then echo docker; fi) +CONTAINER_VOLUME_SUFFIX := $(shell if [ "$(CONTAINER_RUNTIME)" = "podman" ]; then echo ":Z"; fi) +FIRMWARE_IMAGE_NAME ?= infinitime-build +INFINISIM_IMAGE_NAME ?= infinisim-build +REBUILD_IMAGE ?= 0 + +check-runtime: + @if [ -z "$(CONTAINER_RUNTIME)" ]; then \ + echo "Error: neither podman nor docker is installed." >&2; \ + echo "Install one container runtime and try again." >&2; \ + echo "Examples:" >&2; \ + echo " Fedora: sudo dnf install podman" >&2; \ + echo " Debian/Ubuntu: sudo apt install podman" >&2; \ + echo " Docker alternative: https://docs.docker.com/engine/install/" >&2; \ + echo "Then verify with: podman --version or docker --version" >&2; \ + exit 1; \ + fi + +ensure-firmware-image: check-runtime + @if [ "$(REBUILD_IMAGE)" = "1" ] || ! $(CONTAINER_RUNTIME) image inspect "$(FIRMWARE_IMAGE_NAME)" >/dev/null 2>&1; then \ + echo "[1/2] Building firmware container image: $(FIRMWARE_IMAGE_NAME)"; \ + $(CONTAINER_RUNTIME) build -t "$(FIRMWARE_IMAGE_NAME)" -f docker/Dockerfile docker; \ + else \ + echo "[1/2] Firmware container image already exists: $(FIRMWARE_IMAGE_NAME)"; \ + fi + +help: + @echo "InfiniTime Build System" + @echo "=======================" + @echo "" + @echo "Targets:" + @echo " make build Build the InfiniTime firmware in container (default)" + @echo " make build-infinisim Build InfiniSim simulator in container" + @echo " make run-infinisim Run the InfiniSim simulator" + @echo " make clean Clean build directories" + @echo "" + @echo "Environment Variables:" + @echo " CONTAINER_RUNTIME Container runtime (auto: podman, fallback: docker)" + @echo " BUILD_DIR Firmware build directory (default: build)" + @echo " INFINISIM_DIR InfiniSim source directory (default: build_lv_sim/InfiniSim)" + @echo " INFINISIM_BUILD_DIR Simulator build directory (default: build_lv_sim/InfiniSim/build)" + @echo " FIRMWARE_IMAGE_NAME Firmware image name (default: infinitime-build)" + @echo " INFINISIM_IMAGE_NAME Simulator image name (default: infinisim-build)" + @echo " REBUILD_IMAGE Rebuild container image when set to 1" + @echo "" + @echo "Examples:" + @echo " make build # Build firmware in container" + @echo " make build REBUILD_IMAGE=1" + @echo " make build-infinisim # Build simulator in container" + @echo " make run-infinisim # Run simulator" + +# Build firmware in container +build: ensure-firmware-image + @if [ -f "$(BUILD_DIR)/CMakeCache.txt" ]; then \ + if ! grep -q '^CMAKE_HOME_DIRECTORY:INTERNAL=/sources$$' "$(BUILD_DIR)/CMakeCache.txt"; then \ + echo "[prep] Removing incompatible CMake cache in $(BUILD_DIR) for container build"; \ + rm -rf "$(BUILD_DIR)"; \ + fi; \ + fi + @echo "[2/2] Building firmware..." + @$(CONTAINER_RUNTIME) run --rm -it \ + -v "$(CURDIR):/sources$(CONTAINER_VOLUME_SUFFIX)" \ + -e "BUILD_DIR=/sources/$(BUILD_DIR)" \ + -e "OUTPUT_DIR=/sources/$(BUILD_DIR)/output" \ + "$(FIRMWARE_IMAGE_NAME)" + +# Build InfiniSim simulator in container +build-infinisim: check-runtime + @echo "[1/3] Preparing InfiniSim build..." + @if [ ! -x "tools/run-infinisim-podman.sh" ]; then \ + echo "Error: tools/run-infinisim-podman.sh is missing or not executable" >&2; \ + exit 1; \ + fi + @INFINISIM_DIR="$(INFINISIM_DIR)" CONTAINER_RUNTIME="$(CONTAINER_RUNTIME)" IMAGE_NAME="$(INFINISIM_IMAGE_NAME)" REBUILD_IMAGE="$(REBUILD_IMAGE)" tools/run-infinisim-podman.sh --no-run + +# Run the InfiniSim simulator +run-infinisim: check-runtime + @if [ ! -x "tools/run-infinisim-podman.sh" ]; then \ + echo "Error: tools/run-infinisim-podman.sh is missing or not executable" >&2; \ + exit 1; \ + fi + @echo "[3/3] Starting simulator..." + @INFINISIM_DIR="$(INFINISIM_DIR)" CONTAINER_RUNTIME="$(CONTAINER_RUNTIME)" IMAGE_NAME="$(INFINISIM_IMAGE_NAME)" REBUILD_IMAGE="$(REBUILD_IMAGE)" tools/run-infinisim-podman.sh + +# Clean build directories +clean: + @echo "Cleaning build directories..." + @rm -rf $(BUILD_DIR) + @rm -rf $(INFINISIM_BUILD_DIR) + @echo "Clean complete" + +# Phony targets +.PHONY: check-runtime ensure-firmware-image build build-infinisim run-infinisim clean help diff --git a/tools/run-infinisim-podman.sh b/tools/run-infinisim-podman.sh new file mode 100755 index 0000000000..80e375e291 --- /dev/null +++ b/tools/run-infinisim-podman.sh @@ -0,0 +1,166 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +if [[ -f "${SCRIPT_DIR}/../CMakeLists.txt" && -d "${SCRIPT_DIR}/../src" ]]; then + ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +elif [[ -f "${SCRIPT_DIR}/CMakeLists.txt" && -d "${SCRIPT_DIR}/src" ]]; then + ROOT_DIR="${SCRIPT_DIR}" +else + echo "Error: could not locate repository root." >&2 + exit 1 +fi +SIM_DIR="${INFINISIM_DIR:-${ROOT_DIR}/build_lv_sim/InfiniSim}" +if [[ "${SIM_DIR}" != /* ]]; then + SIM_DIR="${ROOT_DIR}/${SIM_DIR}" +fi +IMAGE_NAME="${IMAGE_NAME:-infinisim-build}" +CONTAINER_RUNTIME="${CONTAINER_RUNTIME:-}" +BUILD_DIR="${BUILD_DIR:-build}" +INFINISIM_REPO="${INFINISIM_REPO:-https://github.com/InfiniTimeOrg/InfiniSim.git}" +INFINISIM_REF="${INFINISIM_REF:-main}" +UPDATE_INFINISIM="${UPDATE_INFINISIM:-0}" +REBUILD_IMAGE=0 +RUN_BINARY=1 +SIM_ARGS=() + +usage() { + cat <<'EOF' +Usage: tools/run-infinisim-podman.sh [options] [-- ] + +Options: + --rebuild-image Rebuild Podman image without cache + --no-run Only build, do not execute ./build/infinisim + -h, --help Show this help + +Environment variables: + IMAGE_NAME Podman image name (default: infinisim-build) + CONTAINER_RUNTIME Runtime to use (podman or docker, auto-detected if empty) + INFINISIM_DIR InfiniSim source directory (default: build_lv_sim/InfiniSim) + INFINISIM_REPO InfiniSim git repository URL + INFINISIM_REF InfiniSim git reference to clone (default: main) + UPDATE_INFINISIM Set to 1 to update existing clone to INFINISIM_REF + BUILD_DIR Build directory inside InfiniSim (default: build) + +Examples: + tools/run-infinisim-podman.sh + tools/run-infinisim-podman.sh --rebuild-image + tools/run-infinisim-podman.sh -- --hide-status +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --rebuild-image) + REBUILD_IMAGE=1 + shift + ;; + --no-run) + RUN_BINARY=0 + shift + ;; + -h|--help) + usage + exit 0 + ;; + --) + shift + SIM_ARGS=("$@") + break + ;; + *) + echo "Unknown option: $1" >&2 + usage + exit 1 + ;; + esac +done + +if [[ -z "${CONTAINER_RUNTIME}" ]]; then + if command -v podman >/dev/null 2>&1; then + CONTAINER_RUNTIME="podman" + elif command -v docker >/dev/null 2>&1; then + CONTAINER_RUNTIME="docker" + else + echo "Error: neither podman nor docker is installed or available in PATH." >&2 + exit 1 + fi +fi + +if [[ ! -d "${SIM_DIR}" ]]; then + echo "[prep] InfiniSim source not found at ${SIM_DIR}; cloning ${INFINISIM_REF}" + mkdir -p "$(dirname "${SIM_DIR}")" + git clone --depth 1 --branch "${INFINISIM_REF}" "${INFINISIM_REPO}" "${SIM_DIR}" +fi + +if [[ ! -d "${SIM_DIR}/.git" ]]; then + echo "Error: ${SIM_DIR} exists but is not a git checkout." >&2 + exit 1 +fi + +if [[ "${UPDATE_INFINISIM}" == "1" ]]; then + echo "[prep] Updating InfiniSim checkout to ${INFINISIM_REF}" + git -C "${SIM_DIR}" fetch --depth 1 origin "${INFINISIM_REF}" + git -C "${SIM_DIR}" reset --hard FETCH_HEAD +fi + +VOLUME_SUFFIX="" +if [[ "${CONTAINER_RUNTIME}" == "podman" ]]; then + VOLUME_SUFFIX=":Z" +fi + +cd "${SIM_DIR}" + +PATCHED_CMAKELISTS=0 +cleanup() { + if [[ ${PATCHED_CMAKELISTS} -eq 1 && -f "${SIM_DIR}/CMakeLists.txt.copilot-backup" ]]; then + mv "${SIM_DIR}/CMakeLists.txt.copilot-backup" "${SIM_DIR}/CMakeLists.txt" + fi +} +trap cleanup EXIT + +if [[ -f "${SIM_DIR}/CMakeLists.txt" ]] && [[ ! -f "${ROOT_DIR}/src/displayapp/localization/Localization.h" ]] && grep -q "displayapp/localization/Localization.h" "${SIM_DIR}/CMakeLists.txt"; then + echo "[prep] Detected incompatible localization entries in InfiniSim/CMakeLists.txt; patching for current branch" + cp "${SIM_DIR}/CMakeLists.txt" "${SIM_DIR}/CMakeLists.txt.copilot-backup" + sed -i \ + -e '/displayapp\/localization\/Localization\.h/d' \ + -e '/displayapp\/localization\/Localization\.cpp/d' \ + "${SIM_DIR}/CMakeLists.txt" + PATCHED_CMAKELISTS=1 +fi + +echo "[1/4] Initializing submodules" +git submodule update --init --recursive + +if [[ ${REBUILD_IMAGE} -eq 1 ]]; then + echo "[2/4] Rebuilding container image (no cache): ${IMAGE_NAME}" + "${CONTAINER_RUNTIME}" build --no-cache -t "${IMAGE_NAME}" -f .devcontainer/Dockerfile . +else + if ! "${CONTAINER_RUNTIME}" image inspect "${IMAGE_NAME}" >/dev/null 2>&1; then + echo "[2/4] Building container image: ${IMAGE_NAME}" + "${CONTAINER_RUNTIME}" build -t "${IMAGE_NAME}" -f .devcontainer/Dockerfile . + else + echo "[2/4] Container image already exists: ${IMAGE_NAME}" + fi +fi + +echo "[3/4] Building InfiniSim in container" +"${CONTAINER_RUNTIME}" run --rm -it \ + -v "${SIM_DIR}:/sources${VOLUME_SUFFIX}" \ + -v "${ROOT_DIR}:/sources/InfiniTime${VOLUME_SUFFIX}" \ + -e "BUILD_DIRECTORY=${BUILD_DIR}" \ + -w /sources \ + "${IMAGE_NAME}" + +if [[ ${RUN_BINARY} -eq 1 ]]; then + BIN_PATH="${SIM_DIR}/${BUILD_DIR}/infinisim" + if [[ ! -x "${BIN_PATH}" ]]; then + echo "Error: binary not found at ${BIN_PATH}" >&2 + exit 1 + fi + + echo "[4/4] Running simulator: ${BIN_PATH} ${SIM_ARGS[*]:-}" + "${BIN_PATH}" "${SIM_ARGS[@]}" +else + echo "[4/4] Build finished (execution skipped by --no-run)" +fi