diff --git a/scripts/build.sh b/scripts/build.sh index 0bafaab..a116823 100644 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -14,6 +14,10 @@ set -e REPO_URL="${1:-}" REPO_DIR="${2:-$(pwd)/mapper}" +OF_VERSION="0.12.1" +OF_DIR="$REPO_DIR/.build/openFrameworks" +OF_FILE="of_v${OF_VERSION}_linuxaarch64_release.tar.gz" +OF_URL="https://github.com/openframeworks/openFrameworks/releases/download/${OF_VERSION}/${OF_FILE}" BIN_OUT="$REPO_DIR/bin" if [ -z "$REPO_URL" ]; then @@ -65,22 +69,120 @@ npm install --package-lock=false NODE_OPTIONS="--max-old-space-size=512" npm run build echo "Frontend built → $REPO_DIR/frontend/dist/" -# ── 3. Commit and push frontend artifact back to repo ─────────────────────── +# ── 3. Download OpenFrameworks aarch64 release ────────────────────────────── echo "" -echo "=== Pushing frontend/dist to remote ===" +echo "=== Downloading OpenFrameworks ${OF_VERSION} (aarch64) ===" +mkdir -p "$REPO_DIR/.build" +if [ ! -d "$OF_DIR" ]; then + cd "$REPO_DIR/.build" + [ ! -f "$OF_FILE" ] && (wget "$OF_URL" || curl -L -O "$OF_URL") + tar -xzf "$OF_FILE" + mv "of_v${OF_VERSION}_linux"*"_release" openFrameworks + rm -f "$OF_FILE" + echo "OpenFrameworks extracted to $OF_DIR" +else + echo "OpenFrameworks already present, skipping download." +fi + +# ── 4. Clone & patch ofxPiMapper ──────────────────────────────────────────── +echo "" +echo "=== Cloning & patching ofxPiMapper ===" +ADDON_DIR="$OF_DIR/addons/ofxPiMapper" +rm -rf "$ADDON_DIR" +git clone --depth 1 https://github.com/kr15h/ofxPiMapper.git "$ADDON_DIR" +cd "$ADDON_DIR" + +# 4a. OscControl.cpp highlight patch +OSC_FILE=$(find src -name "OscControl.cpp" | head -n 1) +if [ -n "$OSC_FILE" ]; then + sed -i '/if (m.getAddress() == "\/ofxPiMapper\/surface\/select"){/r /dev/stdin' "$OSC_FILE" <<'EOF_PATCH' + if (m.getAddress() == "/ofxPiMapper/surface/highlight"){ + int surfaceIndex = m.getArgAsInt32(0); + mapper->getSurfaceManager()->selectSurface(surfaceIndex); + return; + } +EOF_PATCH +fi + +# 4b. C++11 compat header +cat <<'EOF_COMPAT' > src/cpp11_compat.h +#ifndef OFXPIMAPPER_CPP11_COMPAT_H +#define OFXPIMAPPER_CPP11_COMPAT_H +#include +#include +#include +#include +#include +#if __cplusplus < 201402L +namespace std { + template + std::unique_ptr make_unique(Args&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); + } +} +#endif +using std::unique_ptr; +using std::make_unique; +using std::vector; +using std::string; +#endif +EOF_COMPAT +sed -i '1i #include "cpp11_compat.h"' src/ofxPiMapper.h +find src -type f \( -name "*.h" -o -name "*.cpp" \) \ + -exec sed -i 's/\([^:a-zA-Z0-9]\)unique_ptr\b/\1std::unique_ptr/g' {} + \ + -exec sed -i 's/\([^:a-zA-Z0-9]\)make_unique\b/\1std::make_unique/g' {} + +for f in $(grep -l "unique_ptr" src/*.h 2>/dev/null || true); do + grep -q "" "$f" || sed -i '1i #include ' "$f" +done + +# ── 5. Cross-compile ofxPiMapper for aarch64 ──────────────────────────────── +# OF's Makefile supports PLATFORM_ARCH and CROSS_COMPILING as make variables — +# no need to fake uname. Passing them directly bypasses the uname -m check. +echo "" +echo "=== Cross-compiling ofxPiMapper (aarch64) ===" +if ! command -v aarch64-linux-gnu-g++ > /dev/null 2>&1; then + echo "ERROR: aarch64-linux-gnu-g++ not found. Install gcc-aarch64-linux-gnu." + exit 1 +fi + +cd "$ADDON_DIR/example_basic" +GLOBAL_FLAGS="-Wno-error -Wno-reorder -Wno-sign-compare -Wno-delete-non-virtual-dtor -std=c++11 -O0 -fno-tree-vrp" +make clean 2>/dev/null || true +make -j1 \ + PLATFORM_ARCH=aarch64 \ + CROSS_COMPILING=1 \ + CC=aarch64-linux-gnu-gcc \ + CXX=aarch64-linux-gnu-g++ \ + AR=aarch64-linux-gnu-ar \ + LD=aarch64-linux-gnu-ld \ + PLATFORM_CFLAGS="$GLOBAL_FLAGS -I$ADDON_DIR/src" \ + USER_CFLAGS="$GLOBAL_FLAGS" \ + USER_CPPFLAGS="-std=c++11" \ + OF_PROJECT_OPTIMIZATION_FLAGS="-O0" + +# ── 6. Collect artifacts ───────────────────────────────────────────────────── +echo "" +echo "=== Collecting artifacts ===" +mkdir -p "$BIN_OUT" +cp bin/example_basic "$BIN_OUT/ofxPiMapper" +chmod +x "$BIN_OUT/ofxPiMapper" + +# ── 7. Commit and push artifacts ───────────────────────────────────────────── +echo "" +echo "=== Pushing artifacts to remote ===" cd "$REPO_DIR" git config user.email "build-bot@mpvj" 2>/dev/null || true git config user.name "MPVJ Build Bot" 2>/dev/null || true -git add frontend/dist/ -git commit -m "ci: add pre-built frontend/dist" || echo "(nothing new to commit)" +git add frontend/dist/ bin/ofxPiMapper +git commit -m "ci: add pre-built artifacts (frontend/dist + bin/ofxPiMapper)" || echo "(nothing new to commit)" git push echo "" echo "============================================" echo " BUILD COMPLETE + PUSHED" echo "============================================" -echo " Frontend: $REPO_DIR/frontend/dist/" +echo " Frontend: $REPO_DIR/frontend/dist/" +echo " ofxPiMapper: $BIN_OUT/ofxPiMapper (aarch64)" echo "" -echo " ofxPiMapper will be compiled natively on" -echo " the Pi when you run setup.sh." +echo " Run setup.sh on the Pi to deploy." echo "============================================" diff --git a/scripts/setup.sh b/scripts/setup.sh index c6ca14e..248c4cf 100644 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -125,10 +125,15 @@ echo "Deploying application from $REPO_URL ..." [ -d "$REAL_HOME/mpvj" ] && mv "$REAL_HOME/mpvj" "$REAL_HOME/mpvj.old.$(date +%s)" sudo -u "$REAL_USER" git clone "$REPO_URL" "$REAL_HOME/mpvj" -# Verify pre-built frontend exists +# Verify pre-built artifacts exist if [ ! -d "$REAL_HOME/mpvj/frontend/dist" ]; then echo "ERROR: frontend/dist/ not found in repo." - echo "Run scripts/build.sh on your x86_64 machine first and commit the dist folder." + echo "Run scripts/build.sh on your x86_64 machine first and commit the artifacts." + exit 1 +fi +if [ ! -f "$REAL_HOME/mpvj/bin/ofxPiMapper" ]; then + echo "ERROR: bin/ofxPiMapper not found in repo." + echo "Run scripts/build.sh on your x86_64 machine first and commit the artifacts." exit 1 fi @@ -136,110 +141,13 @@ fi cd "$REAL_HOME/mpvj/backend" sudo -u "$REAL_USER" npm install --omit=optional --package-lock=false +# Install ofxPiMapper binary +install -m 755 "$REAL_HOME/mpvj/bin/ofxPiMapper" /usr/local/bin/ofxPiMapper + # Media directory mkdir -p "$REAL_HOME/media" chown -R "$REAL_USER:$REAL_USER" "$REAL_HOME/mpvj" "$REAL_HOME/media" -# ── 4.5 BUILD ofxPiMapper NATIVELY ─────────────────────────────────────────── -echo "Building ofxPiMapper natively (this takes a while)..." -OF_VERSION="0.12.1" -OF_FILE="of_v${OF_VERSION}_linuxaarch64_release.tar.gz" -OF_URL="https://github.com/openframeworks/openFrameworks/releases/download/${OF_VERSION}/${OF_FILE}" - -# Install build deps -DEBIAN_FRONTEND=noninteractive apt-get install -y \ - build-essential libzmq3-dev \ - libmpg123-dev libsndfile1-dev libopenal-dev libassimp-dev \ - libglew-dev libglfw3-dev liburiparser-dev \ - libcurl4-openssl-dev libpugixml-dev libasound2-dev \ - libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ - gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly gstreamer1.0-libav \ - libgtk-3-dev libboost-filesystem-dev \ - libfontconfig1-dev libfreetype-dev libx11-dev \ - libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev \ - libpulse-dev libudev-dev libfreeimage-dev librtaudio-dev \ - freeglut3-dev libxxf86vm-dev - -# Temporary swap so the Pi doesn't OOM during compilation -if [ ! -f /swapfile_mpvj ]; then - fallocate -l 2G /swapfile_mpvj || dd if=/dev/zero of=/swapfile_mpvj bs=1M count=2048 - chmod 600 /swapfile_mpvj - mkswap /swapfile_mpvj - swapon /swapfile_mpvj -fi - -cd "$REAL_HOME" -if [ ! -d "openFrameworks" ]; then - sudo -u "$REAL_USER" wget "$OF_URL" || sudo -u "$REAL_USER" curl -L -O "$OF_URL" - sudo -u "$REAL_USER" tar -xzf "$OF_FILE" - sudo -u "$REAL_USER" mv "of_v${OF_VERSION}_linux"*"_release" openFrameworks - sudo -u "$REAL_USER" rm -f "$OF_FILE" -fi - -ADDON_DIR="$REAL_HOME/openFrameworks/addons/ofxPiMapper" -rm -rf "$ADDON_DIR" -sudo -u "$REAL_USER" git clone --depth 1 https://github.com/kr15h/ofxPiMapper.git "$ADDON_DIR" -cd "$ADDON_DIR" - -# Patches -OSC_FILE=$(find src -name "OscControl.cpp" | head -n 1) -if [ -n "$OSC_FILE" ]; then - sed -i '/if (m.getAddress() == "\/ofxPiMapper\/surface\/select"){/r /dev/stdin' "$OSC_FILE" <<'EOF_PATCH' - if (m.getAddress() == "/ofxPiMapper/surface/highlight"){ - int surfaceIndex = m.getArgAsInt32(0); - mapper->getSurfaceManager()->selectSurface(surfaceIndex); - return; - } -EOF_PATCH -fi - -cat <<'EOF_COMPAT' > src/cpp11_compat.h -#ifndef OFXPIMAPPER_CPP11_COMPAT_H -#define OFXPIMAPPER_CPP11_COMPAT_H -#include -#include -#include -#include -#include -#if __cplusplus < 201402L -namespace std { - template - std::unique_ptr make_unique(Args&&... args) { - return std::unique_ptr(new T(std::forward(args)...)); - } -} -#endif -using std::unique_ptr; -using std::make_unique; -using std::vector; -using std::string; -#endif -EOF_COMPAT - -sed -i '1i #include "cpp11_compat.h"' src/ofxPiMapper.h -find src -type f \( -name "*.h" -o -name "*.cpp" \) \ - -exec sed -i 's/\([^:a-zA-Z0-9]\)unique_ptr\b/\1std::unique_ptr/g' {} + \ - -exec sed -i 's/\([^:a-zA-Z0-9]\)make_unique\b/\1std::make_unique/g' {} + -for f in $(grep -l "unique_ptr" src/*.h 2>/dev/null || true); do - grep -q "" "$f" || sed -i '1i #include ' "$f" -done - -cd "$ADDON_DIR/example_basic" -GLOBAL_FLAGS="-Wno-error -Wno-reorder -Wno-sign-compare -Wno-delete-non-virtual-dtor -std=c++11 -O0 -fno-tree-vrp" -sudo -u "$REAL_USER" make clean 2>/dev/null || true -sudo -u "$REAL_USER" make -j1 \ - PLATFORM_CFLAGS="$GLOBAL_FLAGS -I$ADDON_DIR/src" \ - USER_CFLAGS="$GLOBAL_FLAGS" \ - USER_CPPFLAGS="-std=c++11" \ - OF_PROJECT_OPTIMIZATION_FLAGS="-O0" - -install -m 755 bin/example_basic /usr/local/bin/ofxPiMapper - -# Remove swap -swapoff /swapfile_mpvj 2>/dev/null || true -rm -f /swapfile_mpvj - # ── 5. SYSTEMD SERVICE ─────────────────────────────────────────────────────── cat < /etc/systemd/system/mpvj-backend.service [Unit]