#!/usr/bin/env bash # Shared with .gitea/workflows/build.yml and .gitea/workflows/release.yml -- # this is the actual macOS configure/build/test/verify sequence. Edit once, # here, so both workflows stay in sync instead of drifting copies. # # The buildspec bootstrap runs here: it fetches obs-deps + the pinned # obs-studio source and builds libobs before this project configures. # # If that fails, fall back to a core-library-only build rather than going # red: the core library and its tests are what this job mainly guards, and # the fallback is loud (a workflow warning, plus the check below reporting no # module) rather than silent. Do not remove the warning -- a green job that # quietly stopped building the plugin is worse than a red one. set -euo pipefail if ! cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release; then echo "::warning::OBS SDK bootstrap failed on macOS; building the core library only. The plugin module was NOT built." rm -rf build cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSTPLUGIN_BOOTSTRAP_OBS=OFF fi cmake --build build ctest --test-dir build --output-on-failure # Show what was built. # # This is not purely informational: the macOS bootstrap has been reliably # building the real module in CI (6/6 tests, artifact uploaded -- see # README), so a missing module here is a regression to fail loudly on, not # the old silent fallback. # # This used to only check for a bare streamer-tools-camera.so, which is # exactly the shape the "macOS packaging gap" in README.md documented as # broken: OBS.app cannot load a bare .so on macOS, it needs a .plugin # bundle, and this check was blind to whether one was actually produced -- # another instance of the same false-positive-green class of bug this check # exists to catch (see the Windows find_package(libobs) incident this # project just had). Now hard-fails unless: # 1. a real streamer-tools-camera.plugin bundle exists at the top level of # build/package (macOS's plugin search wants the whole .plugin dropped # straight into .../obs-studio/plugins/, not nested under a bin/ # subdirectory the way Linux/Windows are -- see # obs-studio/UI/window-basic-main.cpp AddExtraModulePaths()), with # Contents/MacOS/streamer-tools-camera, Contents/Info.plist, # Contents/Resources/locale/en-US.ini (the module's locale data -- OBS # passes Contents/Resources as the module's data path on macOS, not a # sibling data/), and the bundled LiveKit dylibs under # Contents/Frameworks; # 2. the libobs dependency in the built binary resolves via # @rpath/libobs.framework, not the old relative path # (libobs/libobs.framework/...) that a real OBS.app cannot load; # 3. the binary carries LC_RPATH entries for both # @loader_path/../Frameworks (this bundle's own Frameworks) and # @executable_path/../Frameworks (OBS.app/Contents/Frameworks). ls -la .deps/Frameworks/libobs.framework/Resources/cmake || true bundle="build/package/streamer-tools-camera.plugin" binary="${bundle}/Contents/MacOS/streamer-tools-camera" plist="${bundle}/Contents/Info.plist" locale="${bundle}/Contents/Resources/locale/en-US.ini" if [ ! -f "${binary}" ]; then echo "::error::no plugin bundle was built -- ${binary} is missing. The macOS from-source libobs bootstrap is expected to succeed and produce a real .plugin bundle (not a bare .so, and not nested under bin/); treat this as a build failure, not a core-library-only fallback or a silently-reverted bundle." exit 1 fi if [ ! -f "${plist}" ]; then echo "::error::${bundle} exists but has no Contents/Info.plist -- this is not a loadable OBS.app bundle." exit 1 fi if [ ! -f "${locale}" ]; then echo "::error::${locale} is missing -- OBS passes Contents/Resources as this module's data path on macOS (see AddExtraModulePaths() in obs-studio's UI/window-basic-main.cpp), so OBS_MODULE_USE_DEFAULT_LOCALE will fail to load the en-US locale at runtime." exit 1 fi echo "--- bundle contents ---" find "${bundle}" -maxdepth 4 -exec ls -ld {} \; echo "--- Info.plist ---" cat "${plist}" echo "--- otool -L ---" otool -L "${binary}" if ! ls "${bundle}"/Contents/Frameworks/liblivekit*.dylib >/dev/null 2>&1; then echo "::error::no LiveKit dylibs found under ${bundle}/Contents/Frameworks -- the plugin will fail to load at runtime." exit 1 fi if otool -L "${binary}" | grep -q 'libobs/libobs\.framework'; then echo "::error::the libobs dependency is still recorded as the old relative path (libobs/libobs.framework/...) instead of @rpath/libobs.framework/... -- this is the exact macOS packaging gap the bundle fixup exists to close, and it did not take effect." otool -L "${binary}" | grep -E 'obs|livekit' exit 1 fi if ! otool -L "${binary}" | grep -q '@rpath/libobs\.framework'; then echo "::error::expected an @rpath/libobs.framework dependency in ${binary}, found none." otool -L "${binary}" | grep -E 'obs|livekit' exit 1 fi echo "--- LC_RPATH ---" rpath_dump=$(otool -l "${binary}" | grep -A2 LC_RPATH) echo "${rpath_dump}" if ! echo "${rpath_dump}" | grep -q '@loader_path/../Frameworks'; then echo "::error::${binary} has no @loader_path/../Frameworks LC_RPATH (needed to resolve the bundled LiveKit dylibs)." exit 1 fi if ! echo "${rpath_dump}" | grep -q '@executable_path/../Frameworks'; then echo "::error::${binary} has no @executable_path/../Frameworks LC_RPATH (needed to resolve libobs.framework inside OBS.app)." exit 1 fi echo "macOS bundle verification passed: real .plugin bundle, @rpath libobs dependency, both LC_RPATH entries present."