Files
dependencies/acados/build.sh
2026-04-30 16:18:27 -07:00

140 lines
5.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
cd "$DIR"
# v0.2.2
VERSION="8af9b0ad180940ef611884574a0b27a43504311d"
INSTALL_DIR="$DIR/acados/install"
TEMPLATE_DIR="$DIR/acados/acados_template"
CASADI_DIR="$DIR/casadi"
CASADI_VERSION="3.6.7"
NJOBS="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2)"
# pick BLAS target per host arch
ARCH="$(uname -m)"
if [[ "$OSTYPE" == "darwin"* ]]; then
# this BLASFEO version doesn't have an Apple Silicon target; Cortex-A57
# baseline ARMv8 SIMD compiles and runs fine on M1+.
BLAS_TARGET="ARMV8A_ARM_CORTEX_A57"
elif [[ "$ARCH" == "aarch64" ]]; then
# Cortex-A57 = TICI baseline; safe for any modern aarch64
BLAS_TARGET="ARMV8A_ARM_CORTEX_A57"
else
BLAS_TARGET="X64_AUTOMATIC"
fi
ACADOS_FLAGS=(
-DACADOS_WITH_QPOASES=ON
-UBLASFEO_TARGET
-DBLASFEO_TARGET="$BLAS_TARGET"
-DACADOS_INSTALL_DIR="$INSTALL_DIR"
# acados (and several of its submodules) still pin cmake_minimum_required <3.5;
# CMake 4 removed that compatibility, so re-enable it here.
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
# qpOASES + blasfeo both call malloc()/posix_memalign() without including
# <stdlib.h>. C99/C2x and modern gcc/clang reject implicit declarations as
# errors. qpOASES also has a real Constraints*/Constraints** pointer bug
# that gcc 14+ now flags as an error too. Downgrade both so the upstream
# (pinned) sources keep compiling.
"-DCMAKE_C_FLAGS=-Wno-implicit-function-declaration -Wno-incompatible-pointer-types"
)
if [[ "$OSTYPE" == "darwin"* ]]; then
ACADOS_FLAGS+=(
-DCMAKE_OSX_ARCHITECTURES=arm64
-DCMAKE_MACOSX_RPATH=1
)
fi
# clone/update source
if [ ! -d "acados-src/.git" ]; then
rm -rf acados-src
git clone https://github.com/acados/acados.git acados-src
fi
git -C acados-src fetch --all --tags
git -C acados-src checkout --force "$VERSION"
git -C acados-src submodule update --init --recursive --depth=1
# build acados
mkdir -p build
cd build
cmake "${ACADOS_FLAGS[@]}" "$DIR/acados-src"
make -j"$NJOBS" install
cd "$DIR"
# we don't ship sample json templates
rm -f "$INSTALL_DIR"/lib/*.json
# python interface package (acados_template)
rm -rf "$TEMPLATE_DIR"
cp -r acados-src/interfaces/acados_template/acados_template "$TEMPLATE_DIR"
# strip future_fstrings (avoids needing the compatibility package on py>=3.6).
# Cython chokes on the unknown encoding in .pyx/.pxd too, not just .py.
find "$TEMPLATE_DIR" -type f \( -name '*.py' -o -name '*.pyx' -o -name '*.pxd' \) \
-exec sed -i.bak '/future.fstrings/d' {} +
find "$TEMPLATE_DIR" -name '*.bak' -delete
# acados_template's gnsf/check_reformulation.py uses an absolute `from
# acados_template.utils import ...` that only worked when acados_template was
# itself a top-level package on the path. We ship it as `acados.acados_template`,
# so rewrite to the relative form the rest of gnsf already uses.
if [ -f "$TEMPLATE_DIR/gnsf/check_reformulation.py" ]; then
sed -i.bak 's/^from acados_template\.utils /from ..utils /' "$TEMPLATE_DIR/gnsf/check_reformulation.py"
rm -f "$TEMPLATE_DIR/gnsf/check_reformulation.py.bak"
fi
# build tera renderer (needs cargo)
if ! command -v cargo >/dev/null 2>&1; then
echo "installing rust toolchain (needed for tera_renderer)..."
curl -LsSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
# shellcheck disable=SC1091
source "$HOME/.cargo/env"
fi
mkdir -p "$INSTALL_DIR/bin"
cd "$DIR/acados-src/interfaces/acados_template/tera_renderer/"
if [[ "$OSTYPE" == "darwin"* ]]; then
cargo build --release --target aarch64-apple-darwin
cp target/aarch64-apple-darwin/release/t_renderer "$INSTALL_DIR/bin/t_renderer"
else
cargo build --release
cp target/release/t_renderer "$INSTALL_DIR/bin/t_renderer"
fi
cd "$DIR"
# vendor a slim casadi: install the upstream wheel into a throwaway cp312 venv
# (uv resolves the right platform wheel automatically), then move the casadi/
# tree out and slim it.
echo "vendoring casadi $CASADI_VERSION ..."
rm -rf "$CASADI_DIR" casadi-venv
uv venv --python 3.12 --quiet casadi-venv
uv pip install --python casadi-venv/bin/python --no-deps --quiet "casadi==$CASADI_VERSION"
mv casadi-venv/lib/python3.12/site-packages/casadi "$CASADI_DIR"
rm -rf casadi-venv
# drop everything except the bits openpilot actually needs:
# - __init__.py, casadi.py, tools/ (Python wrapper)
# - _casadi.so (CPython extension; same name on linux+darwin)
# - libcasadi.{so,dylib}* (the C++ runtime that _casadi.so links to)
# openpilot only uses symbolic SX/MX/Function/jacobian etc., which live in
# libcasadi + _casadi. Solver plugins (conic_*, nlpsol_*, integrator_*, ...)
# and their third-party backends (ipopt, bonmin, hpipm, fatrop, ...) are
# loaded lazily via dlopen and never reached.
cd "$CASADI_DIR"
shopt -s extglob
# libc++.*.dylib only exists on darwin and is needed by _casadi.so via @rpath
rm -rf !(__init__.py|casadi.py|_casadi.so|tools|libcasadi.*|libc++.*)
shopt -u extglob
cd "$DIR"
rm -rf casadi-wheel
echo "Installed acados to $INSTALL_DIR"
du -sh "$INSTALL_DIR"
echo "Vendored casadi (slim) at $CASADI_DIR"
du -sh "$CASADI_DIR"