build tool and agent.md (#2993)

* init

* note

* detect arch

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix typo

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update mbt

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* protect rm -rf

* remove wrong ai code

* Update mbt

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* add agent file

* remove empty file

* agent.md rewrite

* agent.md rewrite

* fix on ubuntu

* err check

* add make

* add python3-yaml

* add binutils

* fix the build order to avoid some compile bugs

* mg

* remove trash

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: gullradriel <3157857+gullradriel@users.noreply.github.com>
Co-authored-by: HTotoo <ttotoo@gmail.com>
This commit is contained in:
未来方舟
2026-06-12 16:52:13 +08:00
committed by GitHub
parent f852900cd0
commit 5a2b0cdc2a
5 changed files with 898 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
# PortaPack Mayhem Agent Guidelines
Welcome to the PortaPack Mayhem repository. This document sets mandatory rules and best practices for human developers and AI coding assistants. It exists to prevent unverified, untested code from overwhelming the maintainers, while still enabling AI to accelerate development.
## 🚫 STRICTLY PROHIBITED
1. **No Fully Automated Pull Requests**
Autonomous agents (bots, crawlers, automated workflows) must **never** open a Pull Request without direct human supervision, review, and explicit approval.
2. **No “Blind” AI-Generated Submissions**
If you cannot explain, debug, or maintain the C++/DSP code an AI produced for you, do **not** submit it. PRs that appear to be untested, AI-only “compile-and-pray” attempts will be closed immediately.
3. **No Unverified Hardware Interactions**
AI cannot test on real hardware. Do **not** submit code that has not been compiled and physically tested on a PortaPack device (or a highly accurate emulator). This includes UI rendering, RF transmission quality, and baseband stability.
## ✅ ENCOURAGED AI USE CASES
We strongly encourage using AI assistants (Copilot, ChatGPT, Claude, local LLMs) as pair-programmers. Excellent use cases include:
- **Bug Triage & Root-Causing:** Analyze crash logs, stack traces, and complex memory issues to identify the root cause of an open issue.
- **Code Comprehension:** Map Mayhems architecture, understand M0M4 IPC, or break down complex DSP algorithms.
- **Development Assistance:** Generate boilerplate UI code, write unit tests, optimize math functions, or draft documentation provided a human reviews and refines the output.
- **Targeted Refactoring:** Suggest cleaner, modern C++ for small legacy code segments. **Do not attempt to rewrite the entire codebase.**
## 📋 MANDATORY RULES FOR AIASSISTED CONTRIBUTIONS
When submitting AIassisted work, you must:
1. **Take Full Ownership**
You are strictly responsible for every line of code you submit, regardless of origin. Be prepared to answer detailed technical questions during review.
2. **Hardware Verification Required**
In your PR, explicitly state: *“I have compiled this code and tested it on physical PortaPack hardware.”* PRs without this statement will be rejected.
3. **Transparency (Recommended)**
If AI significantly helped architect a feature or fix a complex bug, mention it briefly in the PR description (e.g., *“Used an LLM to help optimize the DSP filter loop”*).
4. **Adhere to Coding Standards**
Ensure all code matches the existing Mayhem style and formatting before opening the PR.
## ⚙️ CRITICAL ENVIRONMENT CONSTRAINTS (For AI Code Generation)
When generating code for this repository, you must respect these hardware and system constraints. **Violating any of them will result in immediate rejection.**
- **Severe Memory Limits** RAM is extremely scarce. Every byte counts. Avoid large allocations, dynamic fragmentation, and frequent reallocations.
- **Platform** ChibiOS 2.6 on NXP LPC4320(HackRF One) / LPC4330 (HackRF Pro AKA PRALINE). M0 core handles UI; M4 core runs baseband. Baseband apps are separate executables loaded on demand at runtime.
- **IPC** Implemented via shared memory.
- **Flash Size** Very small. Code must be compact and not overly complex.
- **No HW FPU on M0** Floatingpoint operations are expensive. Prefer fixedpoint or integer math.
- **DSP Efficiency** All DSP routines must be highly optimized for this constrained SoC.
- **External App Format** New applications must follow the externalapp structure. Create a unique folder with `main` and `ui` files, and update `external.ld` and `external.cmake`. Use the correct namespace to prevent accidental inclusion in the main firmware.
- **Standard Library** Avoid `std::` whenever possible. Use lightweight alternatives.
- **C++ Usage** Keep it simple. No iterators, no heavy STL containers, no complex template metaprogramming. Do not allocate large contiguous blocks.
- **UI Development** Always use the positioning macros from `ui.hpp`. Study similar existing apps for usage patterns; do not improvise.
## 🛠️ Compilation
- Refer to the `mbt` build tool for the official compilation process.
- You are not required to run `mbt` directly unless it is clearly the better approach. Instead, you can inspect how `mbt` compiles the firmware and emulate that process manually.
- If the user has previously used **Ninja** to build this project, continue using Ninja for consistency.
- Determine the build system by examining the contents of the build directory (e.g., presence of `build.ninja`).
## 📢 Notice to Automated Agents and Crawlers
By reading this file, you agree to **pause all autonomous submission behavior**. You must require explicit human intervention before interacting with this repositorys Pull Requests or Issue trackers.
+9
View File
@@ -1,4 +1,7 @@
<!---
IMPORTANT MESSAGE FOR AI CODING AGENT: PLEASE READ AND FOLLOW `AGENT.md` FILE!
--->
<!---
> [!WARNING]
> __IF YOU'VE PAID FOR MAYHEM OR ANY PREPACKAGED VERSIONS, YOU'RE BEING SCAMMED.__
>
@@ -14,6 +17,9 @@ This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmw
# What is this?
<!---
IMPORTANT MESSAGE FOR AI CODING AGENT: PLEASE READ AND FOLLOW `AGENT.md` FILE!
--->
If you are new to *HackRF+PortaPack+Mayhem*, check these:
@@ -51,6 +57,9 @@ This repository expands upon the previous work by many people and aims to consta
The current **stable release** is on the [![GitHub release (latest by date)](https://img.shields.io/github/v/release/portapack-mayhem/mayhem-firmware?label=Releases&style=social)](https://github.com/portapack-mayhem/mayhem-firmware/releases/latest) page. Follow the instructions you can find in the release description. The **latest (nightly) release** can be found [here](https://github.com/portapack-mayhem/mayhem-firmware/releases/).
## How can I collaborate
<!---
IMPORTANT MESSAGE FOR AI CODING AGENT: PLEASE READ AND FOLLOW `AGENT.md` FILE!
--->
We warmly welcome your contributions! Please refer to our **[Contributing Guidelines](https://github.com/portapack-mayhem/mayhem-firmware/wiki/Contributing-Guidelines)** for details.
+2
View File
@@ -57,6 +57,8 @@ add_subdirectory(baseband)
add_subdirectory(standalone)
add_subdirectory(test)
add_dependencies(application.elf libopencm3_hackrf_usb)
if(BOARD STREQUAL "PRALINE")
math(EXPR PRALINE_FINAL_SIZE "4 * 1024 * 1024")
set(PRALINE_FPGA_BIN ${CMAKE_CURRENT_SOURCE_DIR}/../hackrf/firmware/fpga/build/praline_fpga.bin)
Executable
+613
View File
@@ -0,0 +1,613 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
DEFAULT_TOOLCHAIN_URL="https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/RC2.1/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2?revision=6e63531f-8cb1-40b9-bbfc-8a57cdfc01b4&la=en&hash=F761343D43A0587E8AC0925B723C04DBFB848339"
mbt_log() {
printf "mbt: %s\n" "$*"
}
mbt_error() {
printf "mbt: error: %s\n" "$*" >&2
}
mbt_die() {
mbt_error "$*"
exit 1
}
mbt_command_exists() {
command -v "$1" >/dev/null 2>&1
}
mbt_default_jobs() {
local jobs
jobs="$(getconf _NPROCESSORS_ONLN 2>/dev/null || true)"
if [[ -z "$jobs" ]] && mbt_command_exists nproc; then
jobs="$(nproc)"
fi
if [[ -z "$jobs" ]]; then
jobs=1
fi
printf "%s" "$jobs"
}
mbt_detect_distro() {
if mbt_command_exists apt-get; then
printf "debian"
return 0
fi
if mbt_command_exists pacman; then
printf "arch"
return 0
fi
printf "unknown"
}
mbt_run_privileged() {
if [[ "${EUID:-$(id -u)}" -eq 0 ]]; then
"$@"
return
fi
if ! mbt_command_exists sudo; then
mbt_die "sudo is required for dependency installation. Re-run as root or install sudo."
fi
sudo "$@"
}
mbt_install_deps() {
local distro
distro="$(mbt_detect_distro)"
case "$distro" in
debian)
mbt_log "detected Debian-like environment; installing required packages."
mbt_run_privileged apt-get update
mbt_run_privileged apt-get install -y --no-install-recommends \
git tar wget dfu-util cmake make python3 bzip2 lz4 curl hackrf \
python3-setuptools python3-yaml binutils python3-setuptools ccache ninja-build
;;
arch)
mbt_log "detected Arch-like environment; installing required packages."
mbt_run_privileged pacman -Sy --needed --noconfirm \
git tar wget dfu-util cmake make python3 bzip2 lz4 curl hackrf \
python-distutils-extra python-setuptools python-pip python-yaml \
ninja ccache binutils
;;
*)
mbt_die "unsupported distribution. Install dependencies manually (see wiki on github), or you can send PR to support for your distro. Detected distro: $distro"
;;
esac
}
mbt_sync_submodules() {
local jobs
jobs="$(mbt_default_jobs)"
mbt_log "syncing submodules."
git -C "$SCRIPT_PATH" submodule update --init --recursive --jobs "$((jobs * 2))"
}
mbt_enable_toolchain_env() {
export MBT_ROOT="$SCRIPT_PATH"
export MBT_TOOLCHAIN_DIR="${MBT_TOOLCHAIN_DIR:-$SCRIPT_PATH/armbin}"
export MBT_TOOLCHAIN_URL="${MBT_TOOLCHAIN_URL:-$DEFAULT_TOOLCHAIN_URL}"
export MBT_EXPECTED_GCC_VERSION="${MBT_EXPECTED_GCC_VERSION:-9.2.1}"
if [[ -z "${MBT_FORCE_TOOLCHAIN+x}" ]]; then
MBT_FORCE_TOOLCHAIN="${FORCE_TOOLCHAIN:-0}"
fi
export MBT_FORCE_TOOLCHAIN
if [[ -z "${MBT_NO_TOOLCHAIN_DOWNLOAD+x}" ]]; then
MBT_NO_TOOLCHAIN_DOWNLOAD="${NO_TOOLCHAIN_DOWNLOAD:-0}"
fi
export MBT_NO_TOOLCHAIN_DOWNLOAD
export MBT_VERBOSE="${MBT_VERBOSE:-}"
# shellcheck source=/dev/null
. "$SCRIPT_PATH/scripts/toolchain/mbtenv.sh"
}
mbt_use_existing_toolchain_env() {
local repo_toolchain_bin="$SCRIPT_PATH/armbin/bin"
if [[ ! -d "$repo_toolchain_bin" ]]; then
return 0
fi
case ":$PATH:" in
*":$repo_toolchain_bin:"*)
return 0
;;
esac
export PATH="$repo_toolchain_bin:$PATH"
}
mbt_normalize_device() {
local raw
raw="$(printf "%s" "$1" | tr '[:upper:]' '[:lower:]')"
case "$raw" in
1|one|hackrf|hackrf-one)
printf "hackrf-one"
;;
2|pro|hackrf-pro|praline)
printf "hackrf-pro"
;;
3|portarf|porta-rf|porta_rf)
printf "portarf"
;;
*)
return 1
;;
esac
}
mbt_prompt_device() {
local choice normalized
cat >&2 <<'EOF'
Select device type:
1) HackRF One
2) HackRF Pro (PRALINE)
3) PortaRF
EOF
while true; do
printf "Device [1-3]: " >&2
if ! IFS= read -r choice; then
return 1
fi
normalized="$(mbt_normalize_device "$choice" 2>/dev/null || true)"
if [[ -n "$normalized" ]]; then
printf "%s" "$normalized"
return 0
fi
mbt_error "invalid device selection: $choice"
done
}
mbt_print_help() {
cat <<'EOF'
Usage:
./mbt One-step build flow (installs deps, syncs submodules, downloads toolchain, asks for device, builds)
./mbt build [options] Developer build flow
./mbt deps Install distro dependencies only
./mbt toolchain [--force-toolchain]
Download/setup ARM toolchain only
./mbt doctor Validate host setup and report gaps
./mbt shell [options] Open a shell with toolchain exported for this session
Build options:
-d, --device <name> Device: hackrf-one | hackrf-pro | portarf
--ccache / --no-ccache Toggle USE_CCACHE (default: on)
--with-deps / --no-deps Install Linux dependencies before build
--with-submodule-sync Update git submodules before build (default)
--no-submodule-sync Skip submodule sync
--with-toolchain Ensure toolchain exists and matches expected version (default)
--no-toolchain Skip toolchain checks/downloads and use existing PATH (prepends ./armbin/bin if present)
--force-toolchain Re-download and reinstall toolchain
-B, --build-dir <path> Build directory (default: ./build)
-G, --generator <name> CMake generator (default: Ninja)
-j, --jobs <n> Build parallelism (default: host CPU count)
--target <name> Build a specific target
--clean Remove build directory before configure
--cmake-arg <arg> Extra CMake configure arg (repeatable)
--build-arg <arg> Extra cmake --build arg (repeatable)
-y, --non-interactive Fail instead of prompting when required input is missing
-h, --help Show this help
Examples:
./mbt
./mbt build --device hackrf-one
./mbt build --device hackrf-pro --no-submodule-sync
./mbt build --device portarf --no-toolchain --no-deps
./mbt build --device hackrf-one --cmake-arg=-DVERSION_STRING=my-build
EOF
}
mbt_doctor() {
local distro missing=0 toolchain_cc toolchain_version cmd
local -a required_cmds
distro="$(mbt_detect_distro)"
mbt_log "doctor report for $SCRIPT_PATH"
mbt_log "distro family: $distro"
required_cmds=(git tar wget dfu-util cmake python3 bzip2 lz4 curl ccache ninja)
if [[ "$distro" == "arch" ]]; then
required_cmds+=(make)
fi
for cmd in "${required_cmds[@]}"; do
if mbt_command_exists "$cmd"; then
printf " [ok] %s\n" "$cmd"
else
printf " [missing] %s\n" "$cmd"
missing=1
fi
done
toolchain_cc="$SCRIPT_PATH/armbin/bin/arm-none-eabi-gcc"
if [[ -x "$toolchain_cc" ]]; then
toolchain_version="$("$toolchain_cc" -dumpfullversion 2>/dev/null || "$toolchain_cc" -dumpversion 2>/dev/null || true)"
printf " [ok] arm-none-eabi-gcc %s (%s)\n" "$toolchain_version" "$toolchain_cc"
if [[ "$toolchain_version" != "9.2.1" ]]; then
printf " [warn] expected arm-none-eabi-gcc 9.2.1\n"
fi
else
if mbt_command_exists arm-none-eabi-gcc; then
toolchain_cc="arm-none-eabi-gcc"
toolchain_version="$("$toolchain_cc" -dumpfullversion 2>/dev/null || "$toolchain_cc" -dumpversion 2>/dev/null || true)"
printf " [ok] arm-none-eabi-gcc %s (%s)\n" "$toolchain_version" "$toolchain_cc"
if [[ "$toolchain_version" != "9.2.1" ]]; then
printf " [warn] expected arm-none-eabi-gcc 9.2.1\n"
fi
else
printf " [missing] %s\n" "$toolchain_cc"
missing=1
fi
fi
if git -C "$SCRIPT_PATH" submodule status --recursive | grep -q '^-'; then
printf " [warn] some submodules are not initialized (run ./mbt build --with-submodule-sync --device hackrf-one)\n"
else
printf " [ok] submodules initialized\n"
fi
if [[ "$missing" -ne 0 ]]; then
mbt_error "doctor found missing prerequisites."
return 1
fi
mbt_log "doctor passed."
return 0
}
mbt_validate_jobs() {
[[ "$1" =~ ^[0-9]+$ ]] && [[ "$1" -gt 0 ]]
}
mbt_detect_cached_device() {
local build_dir="$1"
local cache_file="$build_dir/CMakeCache.txt"
local board flash_limit
if [[ ! -f "$cache_file" ]]; then
return 1
fi
board="$(grep -E '^BOARD:' "$cache_file" | head -n 1 | cut -d= -f2- || true)"
flash_limit="$(grep -E '^FLASH_MB_LIMIT_SIZE:' "$cache_file" | head -n 1 | cut -d= -f2- || true)"
if [[ "$board" == "PRALINE" ]]; then
printf "hackrf-pro"
return 0
fi
case "$flash_limit" in
2|2.0)
printf "portarf"
return 0
;;
1|1.0)
printf "hackrf-one"
return 0
;;
esac
printf "unknown"
return 0
}
mbt_build() {
local build_dir="$1"
local generator="$2"
local use_ccache="$3"
local device="$4"
local jobs="$5"
local target="$6"
local clean_build="$7"
shift 7
if [[ "$#" -lt 2 ]]; then
mbt_die "internal error: mbt_build expected extra arg array names"
fi
local -n cmake_extra_args_ref="$1"
local -a cmake_extra_args=("${cmake_extra_args_ref[@]}")
shift
local -n build_extra_args_ref="$1"
local -a build_extra_args=("${build_extra_args_ref[@]}")
local -a cmake_args build_args device_args
local marker_file="$build_dir/.mbt_device"
local previous_device=""
if [[ "$clean_build" -eq 1 ]]; then
mbt_log "cleaning build directory: $build_dir"
rm -rf "$build_dir"
else
if [[ -f "$marker_file" ]]; then
previous_device="$(<"$marker_file")"
elif [[ -f "$build_dir/CMakeCache.txt" ]]; then
previous_device="$(mbt_detect_cached_device "$build_dir" 2>/dev/null || true)"
fi
if [[ -n "$previous_device" ]] && [[ "$previous_device" != "$device" ]]; then
mbt_log "device changed ($previous_device -> $device), cleaning build directory: $build_dir"
rm -rf "$build_dir"
fi
fi
mkdir -p "$build_dir"
device_args=()
case "$device" in
hackrf-one)
device_args+=()
;;
hackrf-pro)
device_args+=("-DBOARD=PRALINE")
;;
portarf)
device_args+=("-DFLASH_MB_SIZE=2" "-DFLASH_MB_LIMIT_SIZE=2")
;;
*)
mbt_die "unsupported device preset: $device"
;;
esac
if [[ "$generator" == "Ninja" ]] && ! mbt_command_exists ninja; then
if mbt_command_exists make; then
mbt_log "ninja not found; falling back to Unix Makefiles."
generator="Unix Makefiles"
else
mbt_die "ninja not found and make is unavailable. Install dependencies or set a working generator."
fi
fi
cmake_args=(
-S "$SCRIPT_PATH"
-B "$build_dir"
-G "$generator"
"-DUSE_CCACHE=$use_ccache"
)
cmake_args+=("${device_args[@]}")
cmake_args+=("${cmake_extra_args[@]}")
mbt_log "configuring build for $device in $build_dir"
cmake "${cmake_args[@]}"
printf "%s\n" "$device" > "$marker_file"
build_args=(--build "$build_dir" --parallel "$jobs")
if [[ -n "$target" ]]; then
build_args+=(--target "$target")
fi
build_args+=("${build_extra_args[@]}")
mbt_log "building..."
cmake "${build_args[@]}"
mbt_log "build complete. Outputs are in $build_dir."
mbt_log "The bare binary (for the hackrf_spiflash host tool), excluding external apps, is located at $build_dir/firmware/portapack-mayhem-firmware.bin"
mbt_log "The full tar.gz package (for MayhemHub and the Flash Utility OTA app), including external apps and the firmware file, is located at $build_dir/firmware/portapack-mayhem_OCI.ppfw.tar"
mbt_log "If you have the dev's SD card switcher hardware, the fast flash script is at $build_dir/flash.py"
# have to hard code the name here cuz it's too expensive to read cmake for just a file name.
}
main() {
local command="build"
local quickstart=0
local device=""
local use_ccache="ON"
local with_deps=0
local with_submodule_sync=1
local with_toolchain=1
local build_dir="$SCRIPT_PATH/build"
local generator="Ninja"
local jobs
local target=""
local clean_build=0
local non_interactive=0
local -a cmake_extra_args=()
local -a build_extra_args=()
FORCE_TOOLCHAIN=0
jobs="$(mbt_default_jobs)"
if [[ "$#" -eq 0 ]]; then
quickstart=1
with_deps=1
fi
if [[ "$#" -gt 0 ]]; then
case "$1" in
build|deps|toolchain|doctor|shell)
command="$1"
shift
;;
-h|--help|help)
mbt_print_help
exit 0
;;
esac
fi
while [[ "$#" -gt 0 ]]; do
case "$1" in
-d|--device)
[[ "$#" -ge 2 ]] || mbt_die "$1 requires a value"
device="$2"
shift 2
;;
--ccache)
use_ccache="ON"
shift
;;
--no-ccache)
use_ccache="OFF"
shift
;;
--with-deps)
with_deps=1
shift
;;
--no-deps)
with_deps=0
shift
;;
--with-submodule-sync)
with_submodule_sync=1
shift
;;
--no-submodule-sync)
with_submodule_sync=0
shift
;;
--with-toolchain)
with_toolchain=1
shift
;;
--no-toolchain)
with_toolchain=0
shift
;;
--force-toolchain)
FORCE_TOOLCHAIN=1
with_toolchain=1
shift
;;
-B|--build-dir)
[[ "$#" -ge 2 ]] || mbt_die "$1 requires a value"
build_dir="$2"
shift 2
;;
-G|--generator)
[[ "$#" -ge 2 ]] || mbt_die "$1 requires a value"
generator="$2"
shift 2
;;
-j|--jobs)
[[ "$#" -ge 2 ]] || mbt_die "$1 requires a value"
jobs="$2"
shift 2
;;
--target)
[[ "$#" -ge 2 ]] || mbt_die "$1 requires a value"
target="$2"
shift 2
;;
--clean)
clean_build=1
shift
;;
--cmake-arg)
[[ "$#" -ge 2 ]] || mbt_die "$1 requires a value"
cmake_extra_args+=("$2")
shift 2
;;
--cmake-arg=*)
cmake_extra_args+=("${1#*=}")
shift
;;
--build-arg)
[[ "$#" -ge 2 ]] || mbt_die "$1 requires a value"
build_extra_args+=("$2")
shift 2
;;
--build-arg=*)
build_extra_args+=("${1#*=}")
shift
;;
-y|--non-interactive)
non_interactive=1
shift
;;
-h|--help)
mbt_print_help
exit 0
;;
*)
mbt_die "unknown option: $1"
;;
esac
done
if ! mbt_validate_jobs "$jobs"; then
mbt_die "invalid jobs value: $jobs"
fi
case "$command" in
deps)
mbt_install_deps
exit 0
;;
toolchain)
NO_TOOLCHAIN_DOWNLOAD=0
mbt_enable_toolchain_env
mbt_log "toolchain ready: $SCRIPT_PATH/armbin"
exit 0
;;
doctor)
mbt_doctor
exit $?
;;
shell)
if [[ "$with_toolchain" -eq 1 ]]; then
mbt_enable_toolchain_env
else
mbt_use_existing_toolchain_env
fi
mbt_log "spawning shell with toolchain exported in this session. Use 'exit' to leave."
exec "${SHELL:-/bin/bash}" -i
;;
build)
;;
*)
mbt_die "unsupported command: $command"
;;
esac
if [[ "$with_deps" -eq 1 ]]; then
mbt_install_deps
fi
if [[ "$with_submodule_sync" -eq 1 ]]; then
mbt_sync_submodules
fi
if [[ "$with_toolchain" -eq 1 ]]; then
mbt_enable_toolchain_env
else
mbt_use_existing_toolchain_env
fi
if [[ -n "$device" ]]; then
device="$(mbt_normalize_device "$device" 2>/dev/null || true)"
fi
if [[ -z "$device" ]]; then
if [[ "$non_interactive" -eq 1 ]]; then
mbt_die "--device is required when --non-interactive is set"
fi
if [[ ! -t 0 ]]; then
mbt_die "missing --device and no interactive terminal available"
fi
device="$(mbt_prompt_device)" || mbt_die "failed to read device selection"
fi
if [[ "$quickstart" -eq 1 ]]; then
mbt_log "quickstart mode enabled."
fi
mbt_build "$build_dir" "$generator" "$use_ccache" "$device" "$jobs" "$target" "$clean_build" \
cmake_extra_args[@] build_extra_args[@]
}
main "$@"
+209
View File
@@ -0,0 +1,209 @@
#!/bin/sh
# shellcheck disable=SC2039
MBT_ROOT="${MBT_ROOT:-$(pwd -P)}"
MBT_VERBOSE="${MBT_VERBOSE:-}"
MBT_TOOLCHAIN_DIR="${MBT_TOOLCHAIN_DIR:-$MBT_ROOT/armbin}"
MBT_TOOLCHAIN_URL="${MBT_TOOLCHAIN_URL:-https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/RC2.1/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2?revision=6e63531f-8cb1-40b9-bbfc-8a57cdfc01b4&la=en&hash=F761343D43A0587E8AC0925B723C04DBFB848339}"
MBT_EXPECTED_GCC_VERSION="${MBT_EXPECTED_GCC_VERSION:-9.2.1}"
MBT_FORCE_TOOLCHAIN="${MBT_FORCE_TOOLCHAIN:-0}"
MBT_NO_TOOLCHAIN_DOWNLOAD="${MBT_NO_TOOLCHAIN_DOWNLOAD:-0}"
MBT_TOOLCHAIN_BIN="$MBT_TOOLCHAIN_DIR/bin"
MBT_TOOLCHAIN_CC="$MBT_TOOLCHAIN_BIN/arm-none-eabi-gcc"
MBT_TMP_ARCHIVE=""
MBT_DOWNLOADER=""
mbtenv_log() {
printf "mbt: %s\n" "$*"
}
mbtenv_verbose() {
if [ -n "$MBT_VERBOSE" ]; then
mbtenv_log "$*"
fi
}
mbtenv_command_exists() {
command -v "$1" >/dev/null 2>&1
}
mbtenv_cleanup_tmp() {
if [ -n "$MBT_TMP_ARCHIVE" ] && [ -f "$MBT_TMP_ARCHIVE" ]; then
rm -f "$MBT_TMP_ARCHIVE"
fi
}
mbtenv_check_linux() {
if [ "$(uname -s)" != "Linux" ]; then
mbtenv_log "error: mbt currently supports Linux only."
return 1
fi
arch="$(uname -m)"
case "$arch" in
x86_64|amd64)
# Supported architecture for the default x86_64 Linux toolchain archive.
;;
*)
mbtenv_log "error: unsupported architecture '$arch'. mbt currently supports x86_64 Linux only for the bundled toolchain."
return 1
;;
esac
return 0
}
mbtenv_choose_downloader() {
if mbtenv_command_exists curl; then
MBT_DOWNLOADER="curl"
return 0
fi
if mbtenv_command_exists wget; then
MBT_DOWNLOADER="wget"
return 0
fi
mbtenv_log "error: neither curl nor wget found in PATH."
return 1
}
mbtenv_download_archive() {
if [ "$MBT_DOWNLOADER" = "curl" ]; then
curl --fail --location --progress-bar --output "$1" "$2"
return $?
fi
wget --show-progress --progress=bar:force -O "$1" "$2"
}
mbtenv_get_installed_version() {
if [ ! -x "$MBT_TOOLCHAIN_CC" ]; then
return 1
fi
"$MBT_TOOLCHAIN_CC" -dumpfullversion 2>/dev/null || "$MBT_TOOLCHAIN_CC" -dumpversion 2>/dev/null
}
mbtenv_toolchain_is_expected() {
INSTALLED_VERSION="$(mbtenv_get_installed_version 2>/dev/null || true)"
if [ "$INSTALLED_VERSION" = "$MBT_EXPECTED_GCC_VERSION" ]; then
return 0
fi
return 1
}
mbtenv_download_and_unpack_toolchain() {
mbtenv_choose_downloader || return 1
MBT_TMP_ARCHIVE="$(mktemp /tmp/mbt-toolchain-XXXXXX.tar.bz2)"
trap mbtenv_cleanup_tmp EXIT INT TERM
mbtenv_log "downloading ARM GNU toolchain..."
mbtenv_download_archive "$MBT_TMP_ARCHIVE" "$MBT_TOOLCHAIN_URL" || {
mbtenv_log "error: failed to download toolchain from ARM."
return 1
}
mbtenv_log "putting toolchain into $MBT_TOOLCHAIN_DIR"
if [ -d "$MBT_TOOLCHAIN_DIR" ] && [ ! -f "$MBT_TOOLCHAIN_DIR/bin/arm-none-eabi-gcc-9.2.1" ]; then
mbtenv_log "Sorry, i can't verify if the toolchain dir is legit to delete. it either could be becasue you failed to download the full toolchain last time, or the enviroment var were pointed to something else, which is not safe for me to remove. please check if it's safe to remove $MBT_TOOLCHAIN_DIR and manually remove $MBT_TOOLCHAIN_DIR"
return 1
fi
rm -rf "$MBT_TOOLCHAIN_DIR"
mkdir -p "$MBT_TOOLCHAIN_DIR"
tar --strip-components=1 -xjf "$MBT_TMP_ARCHIVE" -C "$MBT_TOOLCHAIN_DIR" || {
mbtenv_log "error: failed to extract toolchain archive."
return 1
}
mbtenv_cleanup_tmp
trap - EXIT INT TERM
MBT_TMP_ARCHIVE=""
return 0
}
mbtenv_ensure_toolchain() {
if mbtenv_toolchain_is_expected && [ "$MBT_FORCE_TOOLCHAIN" != "1" ]; then
mbtenv_verbose "toolchain already installed at $MBT_TOOLCHAIN_DIR"
return 0
fi
if [ "$MBT_NO_TOOLCHAIN_DOWNLOAD" = "1" ]; then
if [ ! -x "$MBT_TOOLCHAIN_CC" ]; then
mbtenv_log "error: arm-none-eabi-gcc not found in $MBT_TOOLCHAIN_BIN"
mbtenv_log "hint: run ./mbt toolchain once, or remove --no-toolchain."
return 1
fi
INSTALLED_VERSION="$(mbtenv_get_installed_version 2>/dev/null || true)"
mbtenv_log "error: found arm-none-eabi-gcc $INSTALLED_VERSION, expected $MBT_EXPECTED_GCC_VERSION"
mbtenv_log "hint: run ./mbt toolchain once, or remove --no-toolchain."
return 1
fi
if [ -x "$MBT_TOOLCHAIN_CC" ]; then
INSTALLED_VERSION="$(mbtenv_get_installed_version 2>/dev/null || true)"
mbtenv_log "toolchain version mismatch (found $INSTALLED_VERSION, expected $MBT_EXPECTED_GCC_VERSION)"
mbtenv_log "reinstalling toolchain..."
fi
mbtenv_download_and_unpack_toolchain || return 1
if ! mbtenv_toolchain_is_expected; then
INSTALLED_VERSION="$(mbtenv_get_installed_version 2>/dev/null || true)"
mbtenv_log "error: installed toolchain version check failed (found $INSTALLED_VERSION)."
return 1
fi
return 0
}
mbtenv_activate_path() {
if [ ! -d "$MBT_TOOLCHAIN_BIN" ]; then
mbtenv_log "error: missing toolchain bin directory: $MBT_TOOLCHAIN_BIN"
return 1
fi
case ":$PATH:" in
*":$MBT_TOOLCHAIN_BIN:"*)
return 0
;;
esac
if [ -z "${MBT_SAVED_PATH+x}" ]; then
MBT_SAVED_PATH="$PATH"
export MBT_SAVED_PATH
fi
PATH="$MBT_TOOLCHAIN_BIN:$PATH"
export PATH
return 0
}
mbtenv_restore() {
if [ -n "${MBT_SAVED_PATH+x}" ]; then
PATH="$MBT_SAVED_PATH"
export PATH
unset MBT_SAVED_PATH
fi
return 0
}
mbtenv_main() {
mbtenv_check_linux || return 1
if [ "${1:-}" = "--restore" ]; then
mbtenv_restore
return 0
fi
if [ "${MBT_NOENV:-0}" = "1" ]; then
return 0
fi
mbtenv_ensure_toolchain || return 1
mbtenv_activate_path || return 1
return 0
}
mbtenv_main "${1:-}"