Vendor comma raylib in dependency package

This commit is contained in:
Adeeb Shihadeh
2026-04-25 11:49:19 -07:00
parent 9f9bc38a3e
commit 47e6adeb3d
6 changed files with 204 additions and 114 deletions

View File

@@ -1,5 +1,8 @@
#!/usr/bin/env bash
set -e
set -euo pipefail
export SOURCE_DATE_EPOCH=0
export ZERO_AR_DATE=1
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
cd "$DIR"
@@ -7,30 +10,36 @@ cd "$DIR"
INSTALL_DIR="$DIR/raylib/install"
NJOBS="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2)"
CC="ccache ${CC:-cc}"
# Detect platform: PLATFORM_COMMA for comma devices, PLATFORM_DESKTOP otherwise
RAYLIB_PLATFORM="${RAYLIB_PLATFORM:-PLATFORM_DESKTOP}"
if [ -f /TICI ]; then
RAYLIB_PLATFORM="PLATFORM_COMMA"
if command -v ccache >/dev/null 2>&1; then
CC="${CC:-ccache cc}"
else
CC="${CC:-cc}"
fi
export RAYLIB_PLATFORM
# Install build dependencies
if [[ "$(uname)" == "Linux" ]]; then
if [ "$RAYLIB_PLATFORM" = "PLATFORM_COMMA" ]; then
is_linux() {
[[ "$(uname)" == "Linux" ]]
}
install_linux_deps() {
local platform="$1"
if ! is_linux; then
return
fi
if [ "$platform" = "PLATFORM_COMMA" ]; then
# comma device: needs DRM/EGL/GLES headers (usually already present on AGNOS)
# apt may fail on devices due to read-only rootfs or package conflicts that's OK
if command -v apt-get &>/dev/null; then
# apt may fail on devices due to read-only rootfs or package conflicts; that's OK.
if command -v apt-get >/dev/null 2>&1; then
if [ "$(id -u)" -eq 0 ]; then
apt-get update && apt-get install -y libdrm-dev libgbm-dev libgles2-mesa-dev libegl1-mesa-dev || true
else
sudo apt-get update && sudo apt-get install -y libdrm-dev libgbm-dev libgles2-mesa-dev libegl1-mesa-dev || true
fi
fi
elif [ "$RAYLIB_PLATFORM" = "PLATFORM_OFFSCREEN" ]; then
# offscreen (CI): needs EGL/GL dev packages (no X11)
if command -v apt-get &>/dev/null; then
elif [ "$platform" = "PLATFORM_OFFSCREEN" ]; then
if command -v dnf >/dev/null 2>&1; then
dnf install -y mesa-libEGL-devel mesa-libGL-devel libglvnd-opengl libglvnd-core-devel 2>/dev/null || true
elif command -v apt-get >/dev/null 2>&1; then
if [ "$(id -u)" -eq 0 ]; then
apt-get update && apt-get install -y libegl-dev libgl-dev
else
@@ -38,10 +47,9 @@ if [[ "$(uname)" == "Linux" ]]; then
fi
fi
else
# desktop: needs X11/GL dev packages
if command -v dnf &>/dev/null; then
if command -v dnf >/dev/null 2>&1; then
dnf install -y libX11-devel libXcursor-devel libXrandr-devel libXinerama-devel libXi-devel mesa-libGL-devel
elif command -v apt-get &>/dev/null; then
elif command -v apt-get >/dev/null 2>&1; then
if [ "$(id -u)" -eq 0 ]; then
apt-get update && apt-get install -y libxcursor-dev libxi-dev libxinerama-dev libxrandr-dev libgl-dev
else
@@ -49,55 +57,72 @@ if [[ "$(uname)" == "Linux" ]]; then
fi
fi
fi
fi
}
# Clone and build raylib C library
RAYLIB_COMMIT="d9d7cc1353ec0f73c97e84ddf0973983d1ee25e2"
# RAYLIB_COMMIT matches the openpilot third_party/raylib pin this package replaces.
RAYLIB_COMMIT="${RAYLIB_COMMIT:-3425bd9d1fb292ede4d80f97a1f4f258f614cffc}"
RAYLIB_OFFSCREEN_COMMIT="${RAYLIB_OFFSCREEN_COMMIT:-d9d7cc1353ec0f73c97e84ddf0973983d1ee25e2}"
RAYGUI_COMMIT="${RAYGUI_COMMIT:-76b36b597edb70ffaf96f046076adc20d67e7827}"
if [ ! -d "raylib-src/.git" ]; then
rm -rf raylib-src
git clone --depth 1 -b platform-offscreen --no-tags https://github.com/commaai/raylib.git raylib-src
git clone --depth 1 -b master --no-tags https://github.com/commaai/raylib.git raylib-src
fi
cd raylib-src
git fetch --depth 1 origin "$RAYLIB_COMMIT"
git reset --hard "$RAYLIB_COMMIT"
cd src
make clean
make -j"$NJOBS" PLATFORM="$RAYLIB_PLATFORM" CC="${CC:-gcc}"
cd "$DIR"
# Install lib + headers
rm -rf "$INSTALL_DIR"
mkdir -p "$INSTALL_DIR"/{lib,include}
cp raylib-src/src/libraylib.a "$INSTALL_DIR/lib/"
cp raylib-src/src/raylib.h raylib-src/src/raymath.h raylib-src/src/rlgl.h "$INSTALL_DIR/include/"
if [ -n "${RAYLIB_VARIANTS:-}" ]; then
read -r -a VARIANTS <<< "$RAYLIB_VARIANTS"
elif [[ -f /TICI || -f /AGNOS ]]; then
VARIANTS=(comma)
elif is_linux && [[ "$(uname -m)" == "x86_64" ]]; then
VARIANTS=(desktop offscreen)
elif is_linux && [[ "$(uname -m)" == "aarch64" ]]; then
VARIANTS=(desktop comma)
else
VARIANTS=(desktop)
fi
# On x86_64 Linux, also build the offscreen variant for CI headless rendering
if [[ "$(uname)" == "Linux" && "$(uname -m)" == "x86_64" && "$RAYLIB_PLATFORM" != "PLATFORM_OFFSCREEN" ]]; then
echo "Building offscreen variant..."
build_variant() {
local variant="$1"
local platform="PLATFORM_DESKTOP"
local commit="$RAYLIB_COMMIT"
# Install EGL/GL dev packages needed for offscreen build + bundling
if command -v dnf &>/dev/null; then
dnf install -y mesa-libEGL-devel mesa-libGL-devel libglvnd-opengl libglvnd-core-devel 2>/dev/null || true
elif command -v apt-get &>/dev/null; then
if [ "$(id -u)" -eq 0 ]; then
apt-get update && apt-get install -y libegl-dev libgl-dev
else
sudo apt-get update && sudo apt-get install -y libegl-dev libgl-dev
fi
if [ "$variant" = "comma" ]; then
platform="PLATFORM_COMMA"
elif [ "$variant" = "offscreen" ]; then
platform="PLATFORM_OFFSCREEN"
commit="$RAYLIB_OFFSCREEN_COMMIT"
fi
cd raylib-src/src
echo "Building raylib $variant ($platform)"
install_linux_deps "$platform"
cd "$DIR/raylib-src"
git fetch --depth 1 origin "$commit"
git reset --hard "$commit"
git clean -xdff .
cd src
make clean
make -j"$NJOBS" PLATFORM=PLATFORM_OFFSCREEN CC="${CC:-gcc}"
cp libraylib.a "$INSTALL_DIR/lib/libraylib_offscreen.a"
cd "$DIR"
make -j"$NJOBS" PLATFORM="$platform" CC="$CC"
# Bundle GLVND dispatchers so offscreen rendering works without extra system packages
mkdir -p "$INSTALL_DIR/lib/$variant"
cp libraylib.a "$INSTALL_DIR/lib/$variant/libraylib.a"
if [ "$variant" = "${VARIANTS[0]}" ]; then
cp raylib.h raymath.h rlgl.h "$INSTALL_DIR/include/"
cp libraylib.a "$INSTALL_DIR/lib/libraylib.a"
fi
}
for variant in "${VARIANTS[@]}"; do
build_variant "$variant"
done
cd "$DIR"
if is_linux && [[ "$(uname -m)" == "x86_64" && " ${VARIANTS[*]} " == *" offscreen "* ]]; then
MESA_DIR="$INSTALL_DIR/lib/mesa"
mkdir -p "$MESA_DIR"
ldconfig 2>/dev/null || true
@@ -105,17 +130,21 @@ if [[ "$(uname)" == "Linux" && "$(uname -m)" == "x86_64" && "$RAYLIB_PLATFORM" !
src="$(ldconfig -p 2>/dev/null | grep "$lib" | grep -E 'x86.64|libc6,' | awk '{print $NF}' | head -1)"
if [ -n "$src" ] && [ -f "$src" ]; then
cp -L "$src" "$MESA_DIR/"
# Create unversioned symlink for the linker
base="${lib%%.so.*}"
ln -sf "$lib" "$MESA_DIR/${base}.so"
fi
done
fi
# Download raygui header
RAYGUI_COMMIT="76b36b597edb70ffaf96f046076adc20d67e7827"
curl -fsSLo "$INSTALL_DIR/include/raygui.h" \
"https://raw.githubusercontent.com/raysan5/raygui/$RAYGUI_COMMIT/src/raygui.h"
cat > "$INSTALL_DIR/build-info.txt" <<EOF
raylib_commit=$RAYLIB_COMMIT
raylib_offscreen_commit=$RAYLIB_OFFSCREEN_COMMIT
raygui_commit=$RAYGUI_COMMIT
variants=${VARIANTS[*]}
EOF
echo "Installed raylib to $INSTALL_DIR"
du -sh "$INSTALL_DIR"

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "raylib"
version = "5.5.0.8"
version = "5.5.0.10"
description = "raylib + pyray Python bindings (commaai fork)"
requires-python = ">=3.8"
dependencies = ["cffi>=1.17.1"]

View File

@@ -1,71 +1,111 @@
import importlib
import os
import platform as _platform
DIR = os.path.join(os.path.dirname(__file__), "install")
LIB_DIR = os.path.join(DIR, "lib")
LIB_ROOT = os.path.join(DIR, "lib")
INCLUDE_DIR = os.path.join(DIR, "include")
BUILD_INFO = os.path.join(DIR, "build-info.txt")
_PLATFORM_BY_VARIANT = {
"comma": "PLATFORM_COMMA",
"desktop": "PLATFORM_DESKTOP",
"offscreen": "PLATFORM_OFFSCREEN",
}
def _detect_platform():
"""Auto-detect the raylib platform. In CI on Linux x86_64, use offscreen EGL rendering."""
explicit = os.environ.get("RAYLIB_PLATFORM", "")
def _normalize_variant(value):
if value in ("PLATFORM_COMMA", "comma"):
return "comma"
if value in ("PLATFORM_OFFSCREEN", "offscreen"):
return "offscreen"
if value in ("PLATFORM_DESKTOP", "desktop", ""):
return "desktop"
return value
def _detect_variant():
explicit = os.environ.get("RAYLIB_VARIANT") or os.environ.get("RAYLIB_PLATFORM", "")
if explicit:
return explicit
return _normalize_variant(explicit)
if os.path.isfile("/TICI") or os.path.isfile("/AGNOS"):
return "comma"
if os.environ.get("CI") and _platform.system() == "Linux" and _platform.machine() == "x86_64":
return "PLATFORM_OFFSCREEN"
return ""
return "offscreen"
return "desktop"
VARIANT = _detect_variant()
LIB_DIR = os.path.join(LIB_ROOT, VARIANT)
if not os.path.isfile(os.path.join(LIB_DIR, "libraylib.a")):
LIB_DIR = LIB_ROOT
def _module_name(variant):
return f"_raylib_cffi_{variant}" if variant else "_raylib_cffi"
def _import_cffi_module():
names = [_module_name(VARIANT), "_raylib_cffi"]
seen = set()
for name in names:
if name in seen:
continue
seen.add(name)
try:
return importlib.import_module(f".{name}", __name__)
except ImportError:
continue
return None
def smoketest():
assert os.path.isfile(os.path.join(LIB_DIR, "libraylib.a")), "libraylib.a not found"
assert os.path.isfile(os.path.join(INCLUDE_DIR, "raylib.h")), "raylib.h not found"
assert os.path.isfile(os.path.join(INCLUDE_DIR, "raymath.h")), "raymath.h not found"
assert os.path.isfile(os.path.join(INCLUDE_DIR, "rlgl.h")), "rlgl.h not found"
assert os.path.isfile(os.path.join(INCLUDE_DIR, "raygui.h")), "raygui.h not found"
assert os.path.isfile(BUILD_INFO), "build-info.txt not found"
try:
import _cffi_backend # noqa: F401
except ModuleNotFoundError:
return
assert _import_cffi_module() is not None, f"CFFI module for {VARIANT} not found"
import pyray # noqa: F401
# Build CFFI extension on first import if not already compiled,
# or rebuild if the target platform changed since last build.
def _ensure_cffi_built():
import glob
import subprocess
import sys
pkg_dir = os.path.dirname(__file__)
platform_marker = os.path.join(pkg_dir, ".raylib_platform")
requested = _detect_platform()
# Export so build.py picks it up
if requested:
os.environ["RAYLIB_PLATFORM"] = requested
# Mesa llvmpipe for software rendering in headless CI
if requested == "PLATFORM_OFFSCREEN":
os.environ.setdefault("LIBGL_ALWAYS_SOFTWARE", "1")
if _import_cffi_module() is not None:
return
cffi_files = glob.glob(os.path.join(pkg_dir, "_raylib_cffi*"))
build_script = os.path.join(os.path.dirname(__file__), "build.py")
if not os.path.isfile(build_script) or not os.path.isfile(os.path.join(LIB_DIR, "libraylib.a")):
return
# Rebuild if platform changed
if cffi_files and requested:
built_for = open(platform_marker).read().strip() if os.path.isfile(platform_marker) else ""
if built_for != requested:
for f in cffi_files:
os.remove(f)
cffi_files = []
env = os.environ.copy()
env["RAYLIB_VARIANT"] = VARIANT
env["RAYLIB_PLATFORM"] = _PLATFORM_BY_VARIANT.get(VARIANT, "PLATFORM_DESKTOP")
env["RAYLIB_CFFI_MODULE"] = f"raylib.{_module_name(VARIANT)}"
if not cffi_files:
build_script = os.path.join(pkg_dir, "build.py")
if os.path.isfile(build_script) and os.path.isfile(os.path.join(LIB_DIR, "libraylib.a")):
try:
subprocess.check_call([sys.executable, build_script], cwd=os.path.dirname(pkg_dir))
with open(platform_marker, "w") as f:
f.write(requested)
subprocess.check_call([sys.executable, build_script], cwd=os.path.dirname(os.path.dirname(__file__)), env=env)
except subprocess.CalledProcessError:
pass
_ensure_cffi_built()
# CFFI bindings (available when graphics libraries are present)
try:
from ._raylib_cffi import ffi, lib as rl
from raylib._raylib_cffi.lib import * # noqa: F403
_cffi_module = _import_cffi_module()
if _cffi_module is not None:
ffi = _cffi_module.ffi
rl = _cffi_module.lib
for _name in dir(rl):
if not _name.startswith("_"):
globals()[_name] = getattr(rl, _name)
from raylib.colors import * # noqa: F403
from raylib.defines import * # noqa: F403
from .version import __version__
except (ImportError, OSError):
pass

View File

@@ -11,8 +11,11 @@ from cffi import FFI
HERE = os.path.dirname(os.path.abspath(__file__))
RAYLIB_INCLUDE_PATH = os.path.join(HERE, "install", "include")
RAYLIB_LIB_PATH = os.path.join(HERE, "install", "lib")
RAYLIB_VARIANT = os.getenv("RAYLIB_VARIANT", "")
RAYLIB_LIB_ROOT = os.path.join(HERE, "install", "lib")
RAYLIB_LIB_PATH = os.path.join(RAYLIB_LIB_ROOT, RAYLIB_VARIANT) if RAYLIB_VARIANT else RAYLIB_LIB_ROOT
RAYLIB_PLATFORM = os.getenv("RAYLIB_PLATFORM", "")
RAYLIB_CFFI_MODULE = os.getenv("RAYLIB_CFFI_MODULE", "raylib._raylib_cffi")
ffibuilder = FFI()
@@ -105,13 +108,9 @@ def build_ffi():
extra_link_args.remove('-lGL')
extra_link_args += ['-lGLESv2', '-lEGL', '-lgbm', '-ldrm']
elif RAYLIB_PLATFORM == "PLATFORM_OFFSCREEN":
# Use offscreen variant if available, otherwise fall back to default
offscreen_lib = os.path.join(RAYLIB_LIB_PATH, 'libraylib_offscreen.a')
if os.path.isfile(offscreen_lib):
extra_link_args[extra_link_args.index('-lraylib')] = '-lraylib_offscreen'
extra_link_args.remove('-lGL')
# Use bundled GLVND dispatchers if available, with RPATH for runtime
mesa_dir = os.path.join(RAYLIB_LIB_PATH, 'mesa')
mesa_dir = os.path.join(RAYLIB_LIB_ROOT, 'mesa')
if os.path.isdir(mesa_dir):
extra_link_args += [f'-L{mesa_dir}', f'-Wl,-rpath,$ORIGIN/install/lib/mesa']
extra_link_args += ['-lOpenGL', '-lEGL']
@@ -121,7 +120,7 @@ def build_ffi():
libraries = []
print("extra_link_args: " + str(extra_link_args))
ffibuilder.set_source("raylib._raylib_cffi",
ffibuilder.set_source(RAYLIB_CFFI_MODULE,
ffi_includes,
py_limited_api=True,
include_dirs=[RAYLIB_INCLUDE_PATH],

View File

@@ -1 +1 @@
__version__ = "5.5.0.8"
__version__ = "5.5.0.10"

View File

@@ -18,15 +18,37 @@ class BuildRaylib(build_py):
def run(self):
pkg_dir = os.path.dirname(os.path.abspath(__file__))
raylib_pkg_dir = os.path.join(pkg_dir, "raylib")
build_script = os.path.join(pkg_dir, "build.sh")
subprocess.check_call(["bash", build_script], cwd=pkg_dir)
# Build CFFI extension so it's included in the wheel
cffi_so = glob.glob(os.path.join(pkg_dir, "raylib", "_raylib_cffi*"))
if not cffi_so:
build_cffi = os.path.join(pkg_dir, "raylib", "build.py")
# Build CFFI extensions so they are included in the wheel, and make sure stale
# local extensions from another raylib platform do not leak into the wheel.
for path in glob.glob(os.path.join(raylib_pkg_dir, "_raylib_cffi*")):
os.remove(path)
build_cffi = os.path.join(raylib_pkg_dir, "build.py")
if os.path.isfile(build_cffi):
subprocess.check_call([sys.executable, build_cffi], cwd=pkg_dir)
variants = [
os.path.basename(path)
for path in sorted(glob.glob(os.path.join(raylib_pkg_dir, "install", "lib", "*")))
if os.path.isfile(os.path.join(path, "libraylib.a"))
]
if not variants:
variants = [""]
platform_by_variant = {
"comma": "PLATFORM_COMMA",
"desktop": "PLATFORM_DESKTOP",
"offscreen": "PLATFORM_OFFSCREEN",
"": os.environ.get("RAYLIB_PLATFORM", ""),
}
for variant in variants:
env = os.environ.copy()
env["RAYLIB_VARIANT"] = variant
env["RAYLIB_PLATFORM"] = platform_by_variant.get(variant, "PLATFORM_DESKTOP")
env["RAYLIB_CFFI_MODULE"] = f"raylib._raylib_cffi_{variant}" if variant else "raylib._raylib_cffi"
subprocess.check_call([sys.executable, build_cffi], cwd=pkg_dir, env=env)
super().run()