Closes the "macOS packaging gap" documented in README.md: CI built a real
adapter module on macOS but staged it as a bare streamer-tools-camera.so,
which OBS.app cannot load (it needs a <name>.plugin bundle), and otool -L
showed the libobs dependency as the relative path
libobs/libobs.framework/Versions/A/libobs instead of an @rpath reference.
cmake/macos/helpers.cmake adapts (not vendors as-is) obs-plugintemplate's
cmake/macos/helpers.cmake: upstream builds the bundle almost entirely
through XCODE_ATTRIBUTE_* properties and its own CI drives that with
`xcodebuild -project <name>.xcodeproj`, but this project's home-mac runner
has only the Command Line Tools, not Xcode.app (already established by
buildspec_common.cmake's CI-iteration-1 comment), and the whole project
builds with Ninja end to end. So this reimplements the same outcome --
Contents/MacOS, Contents/Resources, a real Info.plist -- with CMake's own
generator-agnostic BUNDLE/BUNDLE_EXTENSION/MACOSX_BUNDLE_INFO_PLIST/
MACOSX_PACKAGE_LOCATION target properties (verified working under Ninja via
a dry-run configure with APPLE spoofed), and does by hand what upstream gets
from Xcode's embed/codesign build phases:
- copies obs-adapter/data/** into Contents/Resources/**, since OBS's
AddExtraModulePaths() (UI/window-basic-main.cpp) passes
Contents/Resources as a macOS module's *data path* -- not a sibling
data/ the way Linux/Windows work -- so the locale ini has to land at
Contents/Resources/locale/en-US.ini for OBS_MODULE_USE_DEFAULT_LOCALE
to find it
- copies the LiveKit runtime dylibs into Contents/Frameworks
- fixes up the libobs dependency: cmake/macos/fixup-libobs-rpath.sh
rewrites the relative install name the from-source libobs build records
to @rpath/libobs.framework/Versions/A/libobs (LiveKit's own dylibs
already record @rpath references, confirmed in prior CI otool -L
output, so only libobs needs the rewrite)
- gives the plugin binary two LC_RPATH entries via INSTALL_RPATH:
@loader_path/../Frameworks (this bundle's own Frameworks, for LiveKit)
and @executable_path/../Frameworks (OBS.app/Contents/Frameworks, for
libobs.framework -- @executable_path is always relative to the host
process's main executable, not this dlopen'd bundle)
obs-adapter/CMakeLists.txt: calls stplugin_macos_finalize_bundle() before
staging, and corrects the staged layout for macOS -- OBS's module search
wants the whole <name>.plugin dropped directly into .../obs-studio/plugins/,
not nested under a bin/ subdirectory the way Linux/Windows are, so
build/package/ now holds the bundle at its own top level on macOS instead of
build/package/bin/<name>.plugin.
.gitea/scripts/macos-build.sh (this project's macOS steps were factored out
of build.yml into this shared script, used by both build.yml and
release.yml, in a concurrent commit -- rebased onto that): the "Show what
was built" section now hard-fails unless a real .plugin bundle (with
Info.plist, bundled LiveKit dylibs, and locale data) was produced, the
libobs dependency resolves via @rpath rather than the old relative path,
and both LC_RPATH entries are present -- closing the same
false-positive-green gap this project's Windows find_package(libobs)
incident just exposed, which this check previously did not cover (it only
checked for a bare .so). release.yml's macOS packaging step already globs
for any `*.plugin` under build/ (added in the concurrent commit,
anticipating this fix), so it picks up the new layout with no change
needed.
Verified: Linux configure/build/ctest (STPLUGIN_BOOTSTRAP_OBS=OFF) still
passes 6/6, unaffected -- the new macOS CMake logic is fully guarded by
if(APPLE). The bundle/Info.plist/Resources-mapping logic itself was dry-run
verified by configuring a throwaway CMake project with APPLE spoofed to
TRUE, confirming buildspec.json values substitute correctly into Info.plist
and obs-adapter/data/locale/en-US.ini maps to Resources/locale/en-US.ini.
Not verified: an actual macOS build/link/otool pass, or loading the result
in real OBS.app -- this is a Linux sandbox with no way to do either: this
commit is going to the home-mac CI runner to get that verification next.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
47 lines
2.3 KiB
Bash
Executable File
47 lines
2.3 KiB
Bash
Executable File
#!/bin/sh
|
|
# cmake/macos/fixup-libobs-rpath.sh <plugin-binary>
|
|
#
|
|
# The from-source libobs build this project's macOS bootstrap runs
|
|
# (cmake/common/buildspec_common.cmake) records its own install name (its
|
|
# LC_ID_DYLIB) as a relative path -- "libobs/libobs.framework/Versions/A/libobs"
|
|
# -- rather than an @rpath reference. That is a property of that from-source
|
|
# OBS build itself, not something this project's own link step controls: the
|
|
# LC_LOAD_DYLIB entry our plugin binary gets for a dependency is copied
|
|
# straight from that dependency's own LC_ID_DYLIB by the linker. A relative
|
|
# path is not resolvable at runtime from inside an OBS.app plugin bundle --
|
|
# see the "macOS packaging gap" this script fixes, documented in README.md.
|
|
#
|
|
# Rewrite that one dependency entry to @rpath/libobs.framework/Versions/A/libobs.
|
|
# stplugin_macos_finalize_bundle() (cmake/macos/helpers.cmake) gives the
|
|
# plugin binary an LC_RPATH of @executable_path/../Frameworks, which resolves
|
|
# @rpath against the *host* OBS.app's own Contents/Frameworks/libobs.framework
|
|
# at runtime (@executable_path is always relative to the process's main
|
|
# executable -- OBS.app/Contents/MacOS/obs -- not to this dlopen'd bundle, no
|
|
# matter how deeply the .plugin is nested under
|
|
# ~/Library/Application Support/obs-studio/plugins/<name>/bin/).
|
|
#
|
|
# The LiveKit runtime dylibs this same helper copies into the bundle's own
|
|
# Contents/Frameworks are NOT touched here: client-sdk-cpp's own release
|
|
# build already records their install names as @rpath references (confirmed
|
|
# by otool -L on prior CI runs -- see README's "Where the macOS bootstrap
|
|
# actually got to"), so the @loader_path/../Frameworks half of the same
|
|
# LC_RPATH already resolves them with no rewrite needed.
|
|
set -eu
|
|
|
|
binary="$1"
|
|
|
|
if [ ! -f "$binary" ]; then
|
|
echo "fixup-libobs-rpath: no such file: $binary" >&2
|
|
exit 1
|
|
fi
|
|
|
|
old_ref=$(otool -L "$binary" \
|
|
| awk '/libobs\.framework\/Versions\/A\/libobs/ && $1 !~ /^@rpath/ {print $1; exit}')
|
|
|
|
if [ -n "${old_ref:-}" ]; then
|
|
echo "fixup-libobs-rpath: rewriting '$old_ref' -> '@rpath/libobs.framework/Versions/A/libobs' in $binary"
|
|
install_name_tool -change "$old_ref" "@rpath/libobs.framework/Versions/A/libobs" "$binary"
|
|
else
|
|
echo "fixup-libobs-rpath: libobs dependency in $binary is already @rpath-relative (or was not found via otool -L); nothing to rewrite"
|
|
fi
|