From 23becbf807ecfe3caa13a5b65f78e3c9245ad304 Mon Sep 17 00:00:00 2001 From: Jacob Sabella Date: Mon, 1 Sep 2025 13:07:28 -0500 Subject: [PATCH] build: Arch linux build support --- SConstruct | 24 ++++++- third_party/SConscript | 9 ++- tools/arch_setup.sh | 10 +++ tools/install_arch_dependencies.sh | 108 +++++++++++++++++++++++++++++ tools/op.sh | 59 +++++++++++++--- 5 files changed, 196 insertions(+), 14 deletions(-) create mode 100755 tools/arch_setup.sh create mode 100755 tools/install_arch_dependencies.sh diff --git a/SConstruct b/SConstruct index 56788e5842..1589def104 100644 --- a/SConstruct +++ b/SConstruct @@ -61,6 +61,15 @@ AddOption('--minimal', default=os.path.exists(File('#.lfsconfig').abspath), # minimal by default on release branch (where there's no LFS) help='the minimum build to run openpilot. no tests, tools, etc.') +# Check for arch linux as release +def is_arch_linux(): + if os.path.exists("/etc/os-release"): + with open("/etc/os-release") as f: + data = f.read() + return "ID=arch" in data + return False + + ## Architecture name breakdown (arch) ## - larch64: linux tici aarch64 ## - aarch64: linux pc aarch64 @@ -241,6 +250,18 @@ else: np_version = SCons.Script.Value(np.__version__) Export('envCython', 'np_version') +# JSON build environment +json_env = env.Clone() + +# Arch Linux: GCC/Clang on Arch ships with stricter defaults, +# so suppress a few noisy warnings and ensure is included. +if is_arch_linux(): + json_env.Append(CXXFLAGS=[ + '-Wno-tautological-constant-out-of-range-compare', + '-Wno-sign-compare', + '-include', 'stdint.h', + ]) + # Qt build environment qt_env = env.Clone() qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "DBus", "Xml"] @@ -302,7 +323,7 @@ if GetOption("clazy"): qt_env['ENV']['CLAZY_IGNORE_DIRS'] = qt_dirs[0] qt_env['ENV']['CLAZY_CHECKS'] = ','.join(checks) -Export('env', 'qt_env', 'arch', 'real_arch') +Export('env', 'qt_env', 'arch', 'real_arch', 'json_env') # Build common module SConscript(['common/SConscript']) @@ -360,3 +381,4 @@ if Dir('#tools/cabana/').exists() and GetOption('extras'): external_sconscript = GetOption('external_sconscript') if external_sconscript: SConscript([external_sconscript]) + diff --git a/third_party/SConscript b/third_party/SConscript index 507c17c4a5..e63382ca71 100644 --- a/third_party/SConscript +++ b/third_party/SConscript @@ -1,4 +1,9 @@ -Import('env') +Import('env', 'json_env') + +json_env.Library( + 'json11', + ['json11/json11.cpp'], + CCFLAGS=json_env['CCFLAGS'] + ['-Wno-unqualified-std-cast-call'], +) -env.Library('json11', ['json11/json11.cpp'], CCFLAGS=env['CCFLAGS'] + ['-Wno-unqualified-std-cast-call']) env.Library('kaitai', ['kaitai/kaitaistream.cpp'], CPPDEFINES=['KS_STR_ENCODING_NONE']) diff --git a/tools/arch_setup.sh b/tools/arch_setup.sh new file mode 100755 index 0000000000..289a2f26b4 --- /dev/null +++ b/tools/arch_setup.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" + +# NOTE: this is used in a docker build, so do not run any scripts here. + +"$DIR"/install_arch_dependencies.sh +"$DIR"/install_python_dependencies.sh diff --git a/tools/install_arch_dependencies.sh b/tools/install_arch_dependencies.sh new file mode 100755 index 0000000000..6082a641f7 --- /dev/null +++ b/tools/install_arch_dependencies.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash +set -euo pipefail + +SUDO="" +PACMAN_OPTS="--needed" +INTERACTIVE=0 + +# Use sudo if not root +if [[ "$(id -u)" -ne 0 ]]; then + if ! command -v sudo >/dev/null 2>&1; then + echo "Please install sudo or run as root" + exit 1 + fi + SUDO="sudo" +fi + +# Check if stdin is open (interactive) +if [ -t 0 ]; then + INTERACTIVE=1 +fi + +# Non-interactive pacman opts +if [[ "$INTERACTIVE" -eq 0 ]]; then + PACMAN_OPTS="$PACMAN_OPTS --noconfirm --needed" +fi + +install_arch_requirements() { + + git lfs install || true + + # Core toolchains & libs + $SUDO pacman -S $PACMAN_OPTS \ + ca-certificates \ + clang \ + base-devel \ + arm-none-eabi-gcc arm-none-eabi-binutils arm-none-eabi-newlib \ + xz \ + capnproto \ + curl \ + git git-lfs \ + ffmpeg \ + bzip2 \ + eigen \ + libffi \ + glew \ + mesa \ + glfw \ + glib2 \ + libjpeg-turbo \ + qt5-base qt5-tools qt5-svg qt5-x11extras qt5-charts \ + ncurses \ + openssl \ + libusb \ + zeromq \ + zstd \ + sqlite \ + systemd-libs \ + opencl-headers ocl-icd \ + portaudio \ + xorg-server-xvfb \ + python python-pip \ + arm-none-eabi-newlib + + yay -S qt5-serialbus +} + +# Detect OS using /etc/os-release +if [[ -f "/etc/os-release" ]]; then + . /etc/os-release + if [[ "${ID:-}" == "arch" ]]; then + install_arch_requirements + else + echo "$ID $VERSION_ID is unsupported here. This setup script is written for Arch-based systems." + if [[ "$INTERACTIVE" -eq 1 ]]; then + read -p "Attempt installation anyway? [y/N] " -r + echo "" + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + exit 1 + fi + install_arch_requirements + else + exit 1 + fi + fi + + # udev rules + if [[ -d "/etc/udev/rules.d/" ]]; then + $SUDO tee /etc/udev/rules.d/12-panda_jungle.rules >/dev/null <<'EOF' +SUBSYSTEM=="usb", ATTRS{idVendor}=="3801", ATTRS{idProduct}=="ddcf", MODE="0666" +SUBSYSTEM=="usb", ATTRS{idVendor}=="3801", ATTRS{idProduct}=="ddef", MODE="0666" +SUBSYSTEM=="usb", ATTRS{idVendor}=="bbaa", ATTRS{idProduct}=="ddcf", MODE="0666" +SUBSYSTEM=="usb", ATTRS{idVendor}=="bbaa", ATTRS{idProduct}=="ddef", MODE="0666" +EOF + + $SUDO tee /etc/udev/rules.d/11-panda.rules >/dev/null <<'EOF' +SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0666" +SUBSYSTEM=="usb", ATTRS{idVendor}=="3801", ATTRS{idProduct}=="ddcc", MODE="0666" +SUBSYSTEM=="usb", ATTRS{idVendor}=="3801", ATTRS{idProduct}=="ddee", MODE="0666" +SUBSYSTEM=="usb", ATTRS{idVendor}=="bbaa", ATTRS{idProduct}=="ddcc", MODE="0666" +SUBSYSTEM=="usb", ATTRS{idVendor}=="bbaa", ATTRS{idProduct}=="ddee", MODE="0666" +EOF + + $SUDO udevadm control --reload-rules && $SUDO udevadm trigger || true + fi +else + echo "No /etc/os-release found. Make sure you're on an Arch-based system." + exit 1 +fi diff --git a/tools/op.sh b/tools/op.sh index 54ff8e97e9..01724325bb 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -123,22 +123,33 @@ function op_check_git() { function op_check_os() { echo "Checking for compatible os version..." if [[ "$OSTYPE" == "linux-gnu"* ]]; then - if [ -f "/etc/os-release" ]; then source /etc/os-release - case "$VERSION_CODENAME" in - "jammy" | "kinetic" | "noble" | "focal") - echo -e " ↳ [${GREEN}✔${NC}] Ubuntu $VERSION_CODENAME detected." + case "$ID" in + ubuntu) + case "$VERSION_CODENAME" in + "jammy" | "kinetic" | "noble" | "focal") + echo -e " ↳ [${GREEN}✔${NC}] Ubuntu $VERSION_CODENAME detected." + ;; + *) + echo -e " ↳ [${RED}✗${NC}] Incompatible Ubuntu version $VERSION_CODENAME detected!" + loge "ERROR_INCOMPATIBLE_UBUNTU" "$VERSION_CODENAME" + return 1 + ;; + esac + ;; + arch) + echo -e " ↳ [${GREEN}✔${NC}] Arch-based distro ($NAME) detected." ;; - * ) - echo -e " ↳ [${RED}✗${NC}] Incompatible Ubuntu version $VERSION_CODENAME detected!" - loge "ERROR_INCOMPATIBLE_UBUNTU" "$VERSION_CODENAME" + *) + echo -e " ↳ [${RED}✗${NC}] Unsupported Linux distro: $ID ($VERSION_ID)" + loge "ERROR_UNKNOWN_LINUX_DISTRO" "$ID" return 1 ;; esac else - echo -e " ↳ [${RED}✗${NC}] No /etc/os-release on your system. Make sure you're running on Ubuntu, or similar!" - loge "ERROR_UNKNOWN_UBUNTU" + echo -e " ↳ [${RED}✗${NC}] No /etc/os-release on your system. Make sure you're running on Ubuntu, Arch, or similar!" + loge "ERROR_UNKNOWN_LINUX" return 1 fi @@ -151,6 +162,7 @@ function op_check_os() { fi } + function op_check_python() { echo "Checking for compatible python version..." REQUIRED_PYTHON_VERSION=$(grep "requires-python" $OPENPILOT_ROOT/pyproject.toml) @@ -216,12 +228,37 @@ function op_setup() { echo "Installing dependencies..." st="$(date +%s)" + + SETUP_SCRIPT="" if [[ "$OSTYPE" == "linux-gnu"* ]]; then - SETUP_SCRIPT="tools/ubuntu_setup.sh" + if [[ -r /etc/os-release ]]; then + . /etc/os-release + case "$ID" in + ubuntu) + SETUP_SCRIPT="tools/ubuntu_setup.sh" + ;; + arch) + SETUP_SCRIPT="tools/arch_setup.sh" + ;; + *) + echo -e " ↳ [${RED}✗${NC}] Unknown linux platform" + loge "ERROR_UNSUPPORTED_OS" + return 1 + ;; + esac + else + echo "/etc/os-release not found/readable; defaulting to Ubuntu script." + SETUP_SCRIPT="tools/ubuntu_setup.sh" + fi elif [[ "$OSTYPE" == "darwin"* ]]; then SETUP_SCRIPT="tools/mac_setup.sh" + else + echo "Unsupported OSTYPE='$OSTYPE'" + loge "ERROR_UNSUPPORTED_OS" + return 1 fi - if ! $OPENPILOT_ROOT/$SETUP_SCRIPT; then + + if ! "$OPENPILOT_ROOT/$SETUP_SCRIPT"; then echo -e " ↳ [${RED}✗${NC}] Dependencies installation failed!" loge "ERROR_DEPENDENCIES_INSTALLATION" return 1