macOS: real .plugin bundle packaging, libobs @rpath fixup, hard-fail CI check
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
This commit is contained in:
+61
-22
@@ -42,18 +42,32 @@ set_target_properties(${STPLUGIN_PROJECT_NAME} PROPERTIES
|
||||
# straight copy of the built module (see the staging step below), so the
|
||||
# build-tree RPATH must never be baked in -- it would work on the build
|
||||
# machine and nowhere else.
|
||||
if(APPLE)
|
||||
set_target_properties(${STPLUGIN_PROJECT_NAME} PROPERTIES
|
||||
BUILD_WITH_INSTALL_RPATH ON
|
||||
INSTALL_RPATH "@loader_path"
|
||||
)
|
||||
elseif(UNIX)
|
||||
#
|
||||
# APPLE's rpath (and its whole bundle shape) is handled by
|
||||
# stplugin_macos_finalize_bundle() below instead -- a bundle needs two
|
||||
# rpaths (its own Contents/Frameworks *and* the host OBS.app's
|
||||
# Contents/Frameworks for libobs.framework), not the single flat
|
||||
# "@loader_path" this used to set back when macOS staged a bare .so. See
|
||||
# cmake/macos/helpers.cmake.
|
||||
if(UNIX AND NOT APPLE)
|
||||
set_target_properties(${STPLUGIN_PROJECT_NAME} PROPERTIES
|
||||
BUILD_WITH_INSTALL_RPATH ON
|
||||
INSTALL_RPATH "$ORIGIN"
|
||||
)
|
||||
endif()
|
||||
|
||||
# --- macOS: turn the flat MODULE library into a real OBS.app-loadable
|
||||
# <name>.plugin bundle (Contents/MacOS, Contents/Resources, Info.plist,
|
||||
# Contents/Frameworks for the bundled LiveKit dylibs, and the libobs
|
||||
# @rpath fixup). Closes the "macOS packaging gap" in README.md. Must run
|
||||
# before the staging step below, which copies the finished bundle directory
|
||||
# -- add_custom_command(POST_BUILD) commands attached to the same target run
|
||||
# in the order they were registered.
|
||||
if(APPLE)
|
||||
include(helpers)
|
||||
stplugin_macos_finalize_bundle(${STPLUGIN_PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
# --- staged, runnable layout ------------------------------------------------
|
||||
# Everything a human needs to copy into an OBS plugin directory ends up under
|
||||
# build/package/, with the LiveKit shared libraries and the licence files
|
||||
@@ -68,27 +82,52 @@ set(STPLUGIN_PACKAGE_DIR "${CMAKE_BINARY_DIR}/package")
|
||||
# <config>/obs-studio/plugins/<name>/data/
|
||||
# so staging into bin/64bit makes build/package/ a straight drop-in.
|
||||
#
|
||||
# macOS is NOT this shape -- there OBS looks for a
|
||||
# <name>.plugin/Contents/MacOS bundle -- and this build does not produce one.
|
||||
# See the macOS packaging gap in README.md; the flat bin/ here is honest
|
||||
# about being unfinished rather than pretending to be installable.
|
||||
# macOS is a COMPLETELY different shape, not just "bin without 64bit": the
|
||||
# same AddExtraModulePaths() passes GetConfigPath(...,
|
||||
# "obs-studio/plugins/%module%.plugin") as the base, then
|
||||
# obs_add_module_path(base + "/Contents/MacOS", base + "/Contents/Resources")
|
||||
# -- i.e. OBS wants the ENTIRE <name>.plugin bundle dropped directly into
|
||||
# .../obs-studio/plugins/, not nested under a bin/ subdirectory the way
|
||||
# Linux/Windows are. So build/package/ on macOS holds the bundle itself at
|
||||
# its top level (build/package/<name>.plugin), not build/package/bin/....
|
||||
# stplugin_macos_finalize_bundle() (cmake/macos/helpers.cmake) makes
|
||||
# ${STPLUGIN_PROJECT_NAME} an actual BUNDLE target for APPLE and also copies
|
||||
# obs-adapter/data/** into Contents/Resources/** -- see that file for why
|
||||
# Contents/Resources (not a sibling data/) is where OBS looks for this
|
||||
# module's data on macOS.
|
||||
if(APPLE)
|
||||
set(STPLUGIN_PACKAGE_BIN_DIR "${STPLUGIN_PACKAGE_DIR}/bin")
|
||||
add_custom_command(TARGET ${STPLUGIN_PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_DIR}"
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -rf "${STPLUGIN_PACKAGE_DIR}/${STPLUGIN_PROJECT_NAME}.plugin"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"$<TARGET_BUNDLE_DIR:${STPLUGIN_PROJECT_NAME}>"
|
||||
"${STPLUGIN_PACKAGE_DIR}/${STPLUGIN_PROJECT_NAME}.plugin"
|
||||
COMMENT "Staging the ${STPLUGIN_PROJECT_NAME}.plugin bundle into ${STPLUGIN_PACKAGE_DIR}"
|
||||
VERBATIM
|
||||
)
|
||||
else()
|
||||
set(STPLUGIN_PACKAGE_BIN_DIR "${STPLUGIN_PACKAGE_DIR}/bin/64bit")
|
||||
add_custom_command(TARGET ${STPLUGIN_PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_BIN_DIR}"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:${STPLUGIN_PROJECT_NAME}>" "${STPLUGIN_PACKAGE_BIN_DIR}/"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${LIVEKIT_SDK_RUNTIME_LIBS} "${STPLUGIN_PACKAGE_BIN_DIR}/"
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_DIR}/data/locale"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/data/locale/en-US.ini"
|
||||
"${STPLUGIN_PACKAGE_DIR}/data/locale/"
|
||||
COMMENT "Staging plugin + LiveKit runtime libraries + locale data into ${STPLUGIN_PACKAGE_DIR}"
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
|
||||
# Licence files: not something OBS's module loader looks for at all (unlike
|
||||
# the locale data above), so these always land in the same top-level spot
|
||||
# regardless of platform -- next to the bundle on macOS, next to bin/ on
|
||||
# Linux/Windows. Redistributing LiveKit's prebuilt binaries means shipping
|
||||
# their licence and notice with them; see third_party/livekit/README.md,
|
||||
# including what upstream does NOT ship, which is an open question, not a
|
||||
# solved one.
|
||||
add_custom_command(TARGET ${STPLUGIN_PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_BIN_DIR}"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:${STPLUGIN_PROJECT_NAME}>" "${STPLUGIN_PACKAGE_BIN_DIR}/"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${LIVEKIT_SDK_RUNTIME_LIBS} "${STPLUGIN_PACKAGE_BIN_DIR}/"
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_DIR}/data/locale"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/data/locale/en-US.ini"
|
||||
"${STPLUGIN_PACKAGE_DIR}/data/locale/"
|
||||
# Redistributing LiveKit's prebuilt binaries means shipping their licence
|
||||
# and notice with them. See third_party/livekit/README.md -- including
|
||||
# what upstream does NOT ship, which is an open question, not a solved one.
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_DIR}/licenses/livekit"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${CMAKE_SOURCE_DIR}/third_party/livekit/LICENSE"
|
||||
@@ -98,6 +137,6 @@ add_custom_command(TARGET ${STPLUGIN_PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${CMAKE_SOURCE_DIR}/LICENSE"
|
||||
"${STPLUGIN_PACKAGE_DIR}/licenses/"
|
||||
COMMENT "Staging plugin + LiveKit runtime libraries + licences into ${STPLUGIN_PACKAGE_DIR}"
|
||||
COMMENT "Staging licences into ${STPLUGIN_PACKAGE_DIR}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user