182 lines
9.5 KiB
CMake
182 lines
9.5 KiB
CMake
# cmake/macos/helpers.cmake
|
|||
|
|
#
|
||
|
|
# macOS ".plugin" bundle packaging for the OBS adapter module -- closes the
|
||
|
|
# "macOS packaging gap" documented in README.md.
|
||
|
|
#
|
||
|
|
# Adapted from obsproject/obs-plugintemplate's cmake/macos/helpers.cmake
|
||
|
|
# (fetched 2026-09-07, master branch) -- deliberately NOT vendored as-is.
|
||
|
|
# Upstream's set_target_properties_plugin() builds the bundle almost
|
||
|
|
# entirely through XCODE_ATTRIBUTE_* target properties
|
||
|
|
# (XCODE_ATTRIBUTE_GENERATE_INFOPLIST_FILE for Info.plist, an Xcode "Embed
|
||
|
|
# Frameworks" build phase for bundling its own dependencies, Xcode-driven
|
||
|
|
# codesigning), and upstream's own CI drives that with `xcodebuild -project
|
||
|
|
# <name>.xcodeproj` (.github/scripts/build-macos). None of that is available
|
||
|
|
# here: XCODE_ATTRIBUTE_* properties are silent no-ops under any generator
|
||
|
|
# but Xcode, and this project cannot use the Xcode generator on the `home-mac`
|
||
|
|
# CI runner -- see cmake/common/buildspec_common.cmake's CI-iteration-1
|
||
|
|
# comment, which already established empirically that this runner has only
|
||
|
|
# the Command Line Tools installed, not Xcode.app, so there is no xcodebuild
|
||
|
|
# to drive an .xcodeproj with. This project builds macOS with Ninja
|
||
|
|
# end-to-end (both the from-source libobs bootstrap and this project's own
|
||
|
|
# configure -- see the CI workflow), so this reimplements the same
|
||
|
|
# *outcome* -- a real <name>.plugin bundle with Contents/MacOS,
|
||
|
|
# Contents/Resources and a working Info.plist -- using CMake's own
|
||
|
|
# generator-agnostic bundle support (the BUNDLE / BUNDLE_EXTENSION /
|
||
|
|
# MACOSX_BUNDLE_INFO_PLIST target properties, which the Makefile/Ninja
|
||
|
|
# generators implement natively, not just Xcode's), and does the two things
|
||
|
|
# upstream gets "for free" from Xcode's embed/codesign build phases by hand:
|
||
|
|
#
|
||
|
|
# 0. copies obs-adapter/data/** into Contents/Resources/**, since OBS's own
|
||
|
|
# macOS module search (UI/window-basic-main.cpp AddExtraModulePaths())
|
||
|
|
# passes "<plugin>.plugin/Contents/Resources" as a module's *data path*
|
||
|
|
# -- not a sibling "data/" directory next to "bin/", which is the
|
||
|
|
# Linux/Windows shape and does NOT apply on macOS. Concretely: this
|
||
|
|
# project's OBS_MODULE_USE_DEFAULT_LOCALE(PLUGIN_NAME, "en-US") loads
|
||
|
|
# "<data_path>/locale/en-US.ini", so on macOS that file must land at
|
||
|
|
# Contents/Resources/locale/en-US.ini, not a top-level data/locale/.
|
||
|
|
# Mirrors upstream's own target_install_resources() -- also not
|
||
|
|
# Xcode-specific, since MACOSX_PACKAGE_LOCATION is another generator-
|
||
|
|
# agnostic bundle-content source-file property.
|
||
|
|
# 1. copies the LiveKit runtime dylibs into Contents/Frameworks (the
|
||
|
|
# conventional location for a plugin bundle's own bundled dependencies)
|
||
|
|
# 2. rewrites the libobs dependency from the relative path the from-source
|
||
|
|
# libobs build records as its own install name
|
||
|
|
# (libobs/libobs.framework/Versions/A/libobs) to
|
||
|
|
# @rpath/libobs.framework/Versions/A/libobs -- see
|
||
|
|
# cmake/macos/fixup-libobs-rpath.sh for why that rewrite is needed at
|
||
|
|
# all and cannot be done by our own link step -- and gives the plugin
|
||
|
|
# binary the LC_RPATH entries that make @rpath resolve for both
|
||
|
|
# dependencies: @loader_path/../Frameworks (this bundle's own
|
||
|
|
# Contents/Frameworks, for LiveKit) and @executable_path/../Frameworks
|
||
|
|
# (OBS.app/Contents/Frameworks, for libobs.framework itself).
|
||
|
|
#
|
||
|
|
# Bundle metadata (name/version/bundle id/author) is sourced from
|
||
|
|
# buildspec.json, the same file the OBS-SDK bootstrap (buildspec_common.cmake)
|
||
|
|
# already reads -- see its "platformConfig.macos.bundleId" / "name" /
|
||
|
|
# "version" / "author" fields.
|
||
|
|
|
||
|
|
include_guard(GLOBAL)
|
||
|
|
|
||
|
|
# stplugin_macos_finalize_bundle: turn a MODULE library target into a real
|
||
|
|
# OBS.app-loadable <name>.plugin bundle. No-op on non-Apple hosts so callers
|
||
|
|
# do not need to guard every call site with if(APPLE).
|
||
|
|
function(stplugin_macos_finalize_bundle target)
|
||
|
|
if(NOT APPLE)
|
||
|
|
return()
|
||
|
|
endif()
|
||
|
|
|
||
|
|
if(NOT DEFINED LIVEKIT_SDK_RUNTIME_LIBS)
|
||
|
|
message(FATAL_ERROR
|
||
|
|
"stplugin_macos_finalize_bundle(${target}): LIVEKIT_SDK_RUNTIME_LIBS is "
|
||
|
|
"not set. include(LiveKitSDK) + livekit_sdk_setup() must run before "
|
||
|
|
"this is called (see top-level CMakeLists.txt).")
|
||
|
|
endif()
|
||
|
|
|
||
|
|
# --- bundle metadata, from buildspec.json ---------------------------------
|
||
|
|
file(READ "${CMAKE_SOURCE_DIR}/buildspec.json" _stplugin_buildspec)
|
||
|
|
string(JSON _stplugin_bundle_name GET "${_stplugin_buildspec}" name)
|
||
|
|
string(JSON _stplugin_bundle_version GET "${_stplugin_buildspec}" version)
|
||
|
|
string(JSON _stplugin_bundle_author GET "${_stplugin_buildspec}" author)
|
||
|
|
string(JSON _stplugin_bundle_id GET "${_stplugin_buildspec}" platformConfig macos bundleId)
|
||
|
|
|
||
|
|
string(TIMESTAMP STPLUGIN_BUNDLE_YEAR "%Y" UTC)
|
||
|
|
set(STPLUGIN_BUNDLE_EXECUTABLE "${target}")
|
||
|
|
set(STPLUGIN_BUNDLE_NAME "${_stplugin_bundle_name}")
|
||
|
|
set(STPLUGIN_BUNDLE_VERSION "${_stplugin_bundle_version}")
|
||
|
|
set(STPLUGIN_BUNDLE_AUTHOR "${_stplugin_bundle_author}")
|
||
|
|
set(STPLUGIN_BUNDLE_ID "${_stplugin_bundle_id}")
|
||
|
|
if(CMAKE_OSX_DEPLOYMENT_TARGET)
|
||
|
|
set(STPLUGIN_BUNDLE_MIN_OS "${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||
|
|
else()
|
||
|
|
set(STPLUGIN_BUNDLE_MIN_OS "13.0")
|
||
|
|
endif()
|
||
|
|
|
||
|
|
set(_stplugin_plist_out "${CMAKE_CURRENT_BINARY_DIR}/${target}-Info.plist")
|
||
|
|
configure_file(
|
||
|
|
"${CMAKE_SOURCE_DIR}/cmake/macos/Info.plist.in"
|
||
|
|
"${_stplugin_plist_out}"
|
||
|
|
@ONLY
|
||
|
|
)
|
||
|
|
|
||
|
|
# --- Contents/Resources: the module's data path on macOS ----------------
|
||
|
|
# See the "0." bullet in the file header. CMAKE_CURRENT_SOURCE_DIR here is
|
||
|
|
# obs-adapter (this function is called from obs-adapter/CMakeLists.txt, and
|
||
|
|
# include() does not change directory scope), so this globs
|
||
|
|
# obs-adapter/data/** the same way the flat-layout staging step elsewhere
|
||
|
|
# in that file does.
|
||
|
|
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/data")
|
||
|
|
file(GLOB_RECURSE _stplugin_data_files "${CMAKE_CURRENT_SOURCE_DIR}/data/*")
|
||
|
|
foreach(_stplugin_data_file IN LISTS _stplugin_data_files)
|
||
|
|
cmake_path(
|
||
|
|
RELATIVE_PATH _stplugin_data_file
|
||
|
|
BASE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data"
|
||
|
|
OUTPUT_VARIABLE _stplugin_data_relpath
|
||
|
|
)
|
||
|
|
cmake_path(GET _stplugin_data_relpath PARENT_PATH _stplugin_data_reldir)
|
||
|
|
target_sources(${target} PRIVATE "${_stplugin_data_file}")
|
||
|
|
if(_stplugin_data_reldir)
|
||
|
|
set_property(SOURCE "${_stplugin_data_file}" PROPERTY
|
||
|
|
MACOSX_PACKAGE_LOCATION "Resources/${_stplugin_data_reldir}")
|
||
|
|
else()
|
||
|
|
set_property(SOURCE "${_stplugin_data_file}" PROPERTY
|
||
|
|
MACOSX_PACKAGE_LOCATION "Resources")
|
||
|
|
endif()
|
||
|
|
endforeach()
|
||
|
|
endif()
|
||
|
|
|
||
|
|
# --- bundle shape -----------------------------------------------------
|
||
|
|
# BUNDLE + BUNDLE_EXTENSION is CMake's own generator-agnostic mechanism
|
||
|
|
# (not Xcode-specific) for turning a MODULE library into a CFBundle;
|
||
|
|
# MACOSX_BUNDLE_INFO_PLIST tells the same mechanism which Info.plist to
|
||
|
|
# copy into Contents/. This is the traditional, non-Xcode-only path CMake
|
||
|
|
# has supported since long before XCODE_ATTRIBUTE_GENERATE_INFOPLIST_FILE
|
||
|
|
# existed, and is exactly what makes this work under Ninja.
|
||
|
|
set_target_properties(${target} PROPERTIES
|
||
|
|
BUNDLE TRUE
|
||
|
|
BUNDLE_EXTENSION "plugin"
|
||
|
|
MACOSX_BUNDLE_INFO_PLIST "${_stplugin_plist_out}"
|
||
|
|
)
|
||
|
|
|
||
|
|
# --- rpaths -------------------------------------------------------------
|
||
|
|
# BUILD_WITH_INSTALL_RPATH ON (matching the non-Apple UNIX branch in
|
||
|
|
# obs-adapter/CMakeLists.txt) means these two rpaths get embedded as
|
||
|
|
# LC_RPATH load commands by the linker itself at build time -- the
|
||
|
|
# artifact that ships is a straight copy of what gets built here, so the
|
||
|
|
# build-tree RPATH must never leak in.
|
||
|
|
# @loader_path/../Frameworks -> this bundle's own Contents/Frameworks
|
||
|
|
# (LiveKit dylibs, staged below)
|
||
|
|
# @executable_path/../Frameworks -> OBS.app/Contents/Frameworks
|
||
|
|
# (libobs.framework itself).
|
||
|
|
# @executable_path is always relative
|
||
|
|
# to the process's main executable
|
||
|
|
# (OBS.app/Contents/MacOS/obs), not to
|
||
|
|
# this dlopen'd bundle, regardless of
|
||
|
|
# how deeply the .plugin is nested
|
||
|
|
# under the user's plugin directory.
|
||
|
|
set_target_properties(${target} PROPERTIES
|
||
|
|
BUILD_WITH_INSTALL_RPATH ON
|
||
|
|
INSTALL_RPATH "@loader_path/../Frameworks;@executable_path/../Frameworks"
|
||
|
|
)
|
||
|
|
|
||
|
|
# --- bundled runtime deps + the libobs @rpath fixup --------------------
|
||
|
|
# $<TARGET_BUNDLE_DIR:target> is .../<target>.plugin for a BUNDLE target
|
||
|
|
# (available since CMake 3.0, unlike TARGET_BUNDLE_CONTENT_DIR which needs
|
||
|
|
# CMake >= 3.20 -- this project's cmake_minimum_required(VERSION 3.19)
|
||
|
|
# floor in the top-level CMakeLists.txt), so appending Contents/Frameworks
|
||
|
|
# avoids a ".." in the path TARGET_FILE_DIR would otherwise need.
|
||
|
|
set(_stplugin_frameworks_dir "$<TARGET_BUNDLE_DIR:${target}>/Contents/Frameworks")
|
||
|
|
|
||
|
|
add_custom_command(TARGET ${target} POST_BUILD
|
||
|
|
COMMAND "${CMAKE_COMMAND}" -E make_directory "${_stplugin_frameworks_dir}"
|
||
|
|
COMMAND "${CMAKE_COMMAND}" -E copy_if_different ${LIVEKIT_SDK_RUNTIME_LIBS} "${_stplugin_frameworks_dir}/"
|
||
|
|
COMMENT "Copying LiveKit runtime dylibs into ${target}.plugin/Contents/Frameworks"
|
||
|
|
VERBATIM
|
||
|
|
)
|
||
|
|
|
||
|
|
add_custom_command(TARGET ${target} POST_BUILD
|
||
|
|
COMMAND sh "${CMAKE_SOURCE_DIR}/cmake/macos/fixup-libobs-rpath.sh" "$<TARGET_FILE:${target}>"
|
||
|
|
COMMENT "Rewriting the libobs dependency of ${target} to @rpath"
|
||
|
|
VERBATIM
|
||
|
|
)
|
||
|
|
endfunction()
|