Compare commits

...

7 Commits

Author SHA1 Message Date
Adeeb Shihadeh
21bb9ab18e raylib: fix setup.py to also trigger offscreen variant build
setup.py had its own cache check that only looked for libraylib.a,
skipping build.sh entirely when the cache had the desktop variant.
Now also checks for libraylib_offscreen.a on x86_64.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 15:15:59 -08:00
Adeeb Shihadeh
2341b89849 raylib: fix idempotency check to include offscreen variant
The build cache had desktop-only libraylib.a, causing build.sh to skip
the offscreen variant entirely. Now requires libraylib_offscreen.a on
x86_64 before considering the build complete.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 15:07:25 -08:00
Adeeb Shihadeh
7d158432af raylib: bump to 5.5.0.6 (re-publish with offscreen libs)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 15:00:47 -08:00
Adeeb Shihadeh
c81badf4a5 raylib: install EGL/GL dev packages for offscreen variant build
The manylinux container doesn't have Mesa packages pre-installed.
Install them before building the offscreen variant and bundling GLVND.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:54:54 -08:00
Adeeb Shihadeh
122939fdf2 raylib: add PLATFORM_OFFSCREEN support (#38)
* raylib: add PLATFORM_OFFSCREEN support for headless CI rendering

- build.sh: use commaai/raylib platform-offscreen commit, build offscreen
  variant (libraylib_offscreen.a) alongside desktop for x86_64, bundle
  GLVND dispatchers (libEGL, libOpenGL, libGLdispatch) in install/lib/mesa/
- build.py: add PLATFORM_OFFSCREEN elif — uses offscreen lib + bundled
  GLVND with RPATH, links -lOpenGL -lEGL instead of -lGL -lX11
- __init__.py: auto-rebuild CFFI when RAYLIB_PLATFORM env changes
  (tracks built platform in .raylib_platform marker file)
- Bump version to 5.5.0.5

This lets openpilot CI render headlessly via EGL surfaceless + Mesa
llvmpipe without needing xvfb or any additional apt packages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* raylib: auto-detect CI and use PLATFORM_OFFSCREEN

__init__.py now auto-detects CI on Linux x86_64 and uses
PLATFORM_OFFSCREEN + LIBGL_ALWAYS_SOFTWARE=1 automatically.
No env vars needed in the consuming CI workflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:44:19 -08:00
Adeeb Shihadeh
9690fd5160 raylib: use stable ABI for CFFI extension (#37)
The CFFI extension was built with py_limited_api=False, producing
version-specific .so files (e.g., cpython-312 on Linux, cpython-314
on macOS). This caused import failures when the build Python version
didn't match the runtime version.

Switch to py_limited_api=True to produce _raylib_cffi.abi3.so which
works across Python 3.x versions.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:07:15 -08:00
Adeeb Shihadeh
c835b206c6 release: include compiled extensions (*.so) in shim package-data (#36)
The shim setup.py extracts .so files from the wheel, but the
generated pyproject.toml didn't include them in package-data, so
they were excluded when uv built a local wheel from the source.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 12:50:07 -08:00
7 changed files with 115 additions and 15 deletions

View File

@@ -6,10 +6,17 @@ cd "$DIR"
INSTALL_DIR="$DIR/raylib/install" INSTALL_DIR="$DIR/raylib/install"
# Idempotent: skip if already built # Idempotent: skip if already fully built
# On x86_64 Linux, also require the offscreen variant
NEED_OFFSCREEN=0
if [[ "$(uname)" == "Linux" && "$(uname -m)" == "x86_64" ]]; then
NEED_OFFSCREEN=1
fi
if [ -f "$INSTALL_DIR/lib/libraylib.a" ]; then if [ -f "$INSTALL_DIR/lib/libraylib.a" ]; then
echo "raylib already present, skipping build." if [ "$NEED_OFFSCREEN" -eq 0 ] || [ -f "$INSTALL_DIR/lib/libraylib_offscreen.a" ]; then
exit 0 echo "raylib already present, skipping build."
exit 0
fi
fi fi
NJOBS="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2)" NJOBS="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2)"
@@ -33,6 +40,15 @@ if [[ "$(uname)" == "Linux" ]]; then
sudo apt-get update && sudo apt-get install -y libdrm-dev libgbm-dev libgles2-mesa-dev libegl1-mesa-dev || true sudo apt-get update && sudo apt-get install -y libdrm-dev libgbm-dev libgles2-mesa-dev libegl1-mesa-dev || true
fi fi
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
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
fi
else else
# desktop: needs X11/GL dev packages # desktop: needs X11/GL dev packages
if command -v dnf &>/dev/null; then if command -v dnf &>/dev/null; then
@@ -48,10 +64,10 @@ if [[ "$(uname)" == "Linux" ]]; then
fi fi
# Clone and build raylib C library # Clone and build raylib C library
RAYLIB_COMMIT="aa6ade09ac4bfb2847a356535f2d9f87e49ab089" RAYLIB_COMMIT="d9d7cc1353ec0f73c97e84ddf0973983d1ee25e2"
if [ ! -d "raylib-src" ]; then if [ ! -d "raylib-src" ]; then
git clone -b master --no-tags https://github.com/commaai/raylib.git raylib-src git clone -b platform-offscreen --no-tags https://github.com/commaai/raylib.git raylib-src
fi fi
cd raylib-src cd raylib-src
@@ -71,6 +87,42 @@ mkdir -p "$INSTALL_DIR"/{lib,include}
cp raylib-src/src/libraylib.a "$INSTALL_DIR/lib/" 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/" cp raylib-src/src/raylib.h raylib-src/src/raymath.h raylib-src/src/rlgl.h "$INSTALL_DIR/include/"
# 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..."
# 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
fi
cd raylib-src/src
make clean
make -j"$NJOBS" PLATFORM=PLATFORM_OFFSCREEN
cp libraylib.a "$INSTALL_DIR/lib/libraylib_offscreen.a"
cd "$DIR"
# Bundle GLVND dispatchers so offscreen rendering works without extra system packages
MESA_DIR="$INSTALL_DIR/lib/mesa"
mkdir -p "$MESA_DIR"
ldconfig 2>/dev/null || true
for lib in libEGL.so.1 libOpenGL.so.0 libGLdispatch.so.0; do
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 # Download raygui header
RAYGUI_COMMIT="76b36b597edb70ffaf96f046076adc20d67e7827" RAYGUI_COMMIT="76b36b597edb70ffaf96f046076adc20d67e7827"
curl -fsSLo "$INSTALL_DIR/include/raygui.h" \ curl -fsSLo "$INSTALL_DIR/include/raygui.h" \

View File

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

View File

@@ -1,26 +1,60 @@
import os import os
import platform as _platform
DIR = os.path.join(os.path.dirname(__file__), "install") DIR = os.path.join(os.path.dirname(__file__), "install")
LIB_DIR = os.path.join(DIR, "lib") LIB_DIR = os.path.join(DIR, "lib")
INCLUDE_DIR = os.path.join(DIR, "include") INCLUDE_DIR = os.path.join(DIR, "include")
def _detect_platform():
"""Auto-detect the raylib platform. In CI on Linux x86_64, use offscreen EGL rendering."""
explicit = os.environ.get("RAYLIB_PLATFORM", "")
if explicit:
return explicit
if os.environ.get("CI") and _platform.system() == "Linux" and _platform.machine() == "x86_64":
return "PLATFORM_OFFSCREEN"
return ""
def smoketest(): def smoketest():
assert os.path.isfile(os.path.join(LIB_DIR, "libraylib.a")), "libraylib.a not found" 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, "raylib.h")), "raylib.h not found"
# Build CFFI extension on first import if not already compiled # Build CFFI extension on first import if not already compiled,
# or rebuild if the target platform changed since last build.
def _ensure_cffi_built(): def _ensure_cffi_built():
import glob import glob
import subprocess import subprocess
import sys import sys
pkg_dir = os.path.dirname(__file__) pkg_dir = os.path.dirname(__file__)
if not glob.glob(os.path.join(pkg_dir, "_raylib_cffi*")): 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")
cffi_files = glob.glob(os.path.join(pkg_dir, "_raylib_cffi*"))
# 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 = []
if not cffi_files:
build_script = os.path.join(pkg_dir, "build.py") 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")): if os.path.isfile(build_script) and os.path.isfile(os.path.join(LIB_DIR, "libraylib.a")):
try: try:
subprocess.check_call([sys.executable, build_script], cwd=os.path.dirname(pkg_dir)) subprocess.check_call([sys.executable, build_script], cwd=os.path.dirname(pkg_dir))
with open(platform_marker, "w") as f:
f.write(requested)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
pass pass

View File

@@ -93,7 +93,7 @@ def build_ffi():
'-framework', 'CoreVideo', '-framework', 'CoreVideo',
] ]
libraries = [] libraries = []
extra_compile_args = ["-Wno-error=incompatible-function-pointer-types", "-D_CFFI_NO_LIMITED_API"] extra_compile_args = ["-Wno-error=incompatible-function-pointer-types"]
else: else:
print("BUILDING FOR LINUX") print("BUILDING FOR LINUX")
extra_link_args = [ extra_link_args = [
@@ -104,15 +104,26 @@ def build_ffi():
if RAYLIB_PLATFORM == "PLATFORM_COMMA": if RAYLIB_PLATFORM == "PLATFORM_COMMA":
extra_link_args.remove('-lGL') extra_link_args.remove('-lGL')
extra_link_args += ['-lGLESv2', '-lEGL', '-lgbm', '-ldrm'] 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')
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']
else: else:
extra_link_args += ['-lX11'] extra_link_args += ['-lX11']
extra_compile_args = ["-Wno-incompatible-pointer-types", "-D_CFFI_NO_LIMITED_API"] extra_compile_args = ["-Wno-incompatible-pointer-types"]
libraries = [] libraries = []
print("extra_link_args: " + str(extra_link_args)) print("extra_link_args: " + str(extra_link_args))
ffibuilder.set_source("raylib._raylib_cffi", ffibuilder.set_source("raylib._raylib_cffi",
ffi_includes, ffi_includes,
py_limited_api=False, py_limited_api=True,
include_dirs=[RAYLIB_INCLUDE_PATH], include_dirs=[RAYLIB_INCLUDE_PATH],
extra_link_args=extra_link_args, extra_link_args=extra_link_args,
extra_compile_args=extra_compile_args, extra_compile_args=extra_compile_args,

View File

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

View File

@@ -18,9 +18,12 @@ class BuildRaylib(build_py):
def run(self): def run(self):
pkg_dir = os.path.dirname(os.path.abspath(__file__)) pkg_dir = os.path.dirname(os.path.abspath(__file__))
marker = os.path.join(pkg_dir, "raylib", "install", "lib", "libraylib.a") lib_dir = os.path.join(pkg_dir, "raylib", "install", "lib")
marker = os.path.join(lib_dir, "libraylib.a")
offscreen_marker = os.path.join(lib_dir, "libraylib_offscreen.a")
need_offscreen = platform.system() == "Linux" and platform.machine() == "x86_64"
if not os.path.exists(marker): if not os.path.exists(marker) or (need_offscreen and not os.path.exists(offscreen_marker)):
build_script = os.path.join(pkg_dir, "build.sh") build_script = os.path.join(pkg_dir, "build.sh")
subprocess.check_call(["bash", build_script], cwd=pkg_dir) subprocess.check_call(["bash", build_script], cwd=pkg_dir)

View File

@@ -107,7 +107,7 @@ for toml in sorted(pathlib.Path(".").glob("*/pyproject.toml")):
f"include = {json.dumps(find_include)}", f"include = {json.dumps(find_include)}",
"", "",
"[tool.setuptools.package-data]", "[tool.setuptools.package-data]",
f'{module} = ["{datadir}/**/*"]', f'{module} = ["{datadir}/**/*", "*.so"]',
"", "",
"[tool.shim]", "[tool.shim]",
f'repo_url = "{repo_url}"', f'repo_url = "{repo_url}"',