full-build-macos.sh 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. #!/bin/bash
  2. ##############################################################################
  3. # macOS full build script
  4. ##############################################################################
  5. #
  6. # This script contains all steps necessary to:
  7. #
  8. # * Build OBS with all default plugins and dependencies
  9. # * Create a macOS application bundle
  10. # * Code-sign the macOS application-bundle
  11. # * Package a macOS installation image
  12. # * Notarize macOS application-bundle and/or installation image
  13. #
  14. # Parameters:
  15. # -b: Create macOS bundle
  16. # -d: Skip dependency checks
  17. # -p: Create macOS distribution image
  18. # -n: Notarize macOS app and disk image (implies bundling)
  19. # -s: Skip the build process (useful for bundling/packaging only)
  20. # -h: Print usage help
  21. #
  22. # Environment Variables (optional):
  23. # MACOS_DEPS_VERSION : Pre-compiled macOS dependencies version
  24. # MACOS_CEF_BUILD_VERSION : Chromium Embedded Framework version
  25. # VLC_VERISON : VLC version
  26. # SPARKLE_VERSION : Sparke Framework version
  27. # BUILD_DIR : Alternative directory to build OBS in
  28. #
  29. ##############################################################################
  30. # Halt on errors
  31. set -eE
  32. ## SET UP ENVIRONMENT ##
  33. PRODUCT_NAME="OBS-Studio"
  34. CHECKOUT_DIR="$(/usr/bin/git rev-parse --show-toplevel)"
  35. DEPS_BUILD_DIR="${CHECKOUT_DIR}/../obs-build-dependencies"
  36. BUILD_DIR="${BUILD_DIR:-build}"
  37. BUILD_CONFIG=${BUILD_CONFIG:-RelWithDebInfo}
  38. CI_SCRIPTS="${CHECKOUT_DIR}/CI/scripts/macos"
  39. CI_WORKFLOW="${CHECKOUT_DIR}/.github/workflows/main.yml"
  40. CI_MACOS_CEF_VERSION=$(/bin/cat "${CI_WORKFLOW}" | /usr/bin/sed -En "s/[ ]+MACOS_CEF_BUILD_VERSION: '([0-9]+)'/\1/p")
  41. CI_DEPS_VERSION=$(/bin/cat "${CI_WORKFLOW}" | /usr/bin/sed -En "s/[ ]+MACOS_DEPS_VERSION: '([0-9\-]+)'/\1/p")
  42. CI_VLC_VERSION=$(/bin/cat "${CI_WORKFLOW}" | /usr/bin/sed -En "s/[ ]+VLC_VERSION: '([0-9\.]+)'/\1/p")
  43. CI_SPARKLE_VERSION=$(/bin/cat "${CI_WORKFLOW}" | /usr/bin/sed -En "s/[ ]+SPARKLE_VERSION: '([0-9\.]+)'/\1/p")
  44. CI_QT_VERSION=$(/bin/cat "${CI_WORKFLOW}" | /usr/bin/sed -En "s/[ ]+QT_VERSION: '([0-9\.]+)'/\1/p" | /usr/bin/head -1)
  45. CI_MIN_MACOS_VERSION=$(/bin/cat "${CI_WORKFLOW}" | /usr/bin/sed -En "s/[ ]+MIN_MACOS_VERSION: '([0-9\.]+)'/\1/p")
  46. NPROC="${NPROC:-$(sysctl -n hw.ncpu)}"
  47. CURRENT_ARCH=$(uname -m)
  48. BUILD_DEPS=(
  49. "obs-deps ${MACOS_DEPS_VERSION:-${CI_DEPS_VERSION}}"
  50. "qt-deps ${QT_VERSION:-${CI_QT_VERSION}} ${MACOS_DEPS_VERSION:-${CI_DEPS_VERSION}}"
  51. "cef ${MACOS_CEF_BUILD_VERSION:-${CI_MACOS_CEF_VERSION}}"
  52. "vlc ${VLC_VERSION:-${CI_VLC_VERSION}}"
  53. "sparkle ${SPARKLE_VERSION:-${CI_SPARKLE_VERSION}}"
  54. )
  55. if [ -n "${TERM-}" ]; then
  56. COLOR_RED=$(/usr/bin/tput setaf 1)
  57. COLOR_GREEN=$(/usr/bin/tput setaf 2)
  58. COLOR_BLUE=$(/usr/bin/tput setaf 4)
  59. COLOR_ORANGE=$(/usr/bin/tput setaf 3)
  60. COLOR_RESET=$(/usr/bin/tput sgr0)
  61. else
  62. COLOR_RED=""
  63. COLOR_GREEN=""
  64. COLOR_BLUE=""
  65. COLOR_ORANGE=""
  66. COLOR_RESET=""
  67. fi
  68. MACOS_VERSION="$(/usr/bin/sw_vers -productVersion)"
  69. MACOS_MAJOR="$(/bin/echo ${MACOS_VERSION} | /usr/bin/cut -d '.' -f 1)"
  70. MACOS_MINOR="$(/bin/echo ${MACOS_VERSION} | /usr/bin/cut -d '.' -f 2)"
  71. ## DEFINE UTILITIES ##
  72. hr() {
  73. /bin/echo "${COLOR_BLUE}[${PRODUCT_NAME}] ${1}${COLOR_RESET}"
  74. }
  75. step() {
  76. /bin/echo "${COLOR_GREEN} + ${1}${COLOR_RESET}"
  77. }
  78. info() {
  79. /bin/echo "${COLOR_ORANGE} + ${1}${COLOR_RESET}"
  80. }
  81. error() {
  82. /bin/echo "${COLOR_RED} + ${1}${COLOR_RESET}"
  83. }
  84. exists() {
  85. /usr/bin/command -v "$1" >/dev/null 2>&1
  86. }
  87. ensure_dir() {
  88. [[ -n "${1}" ]] && /bin/mkdir -p "${1}" && builtin cd "${1}"
  89. }
  90. cleanup() {
  91. /bin/rm -rf "${CHECKOUT_DIR}/${BUILD_DIR}/settings.json"
  92. unset CODESIGN_IDENT
  93. unset CODESIGN_IDENT_USER
  94. unset CODESIGN_IDENT_PASS
  95. }
  96. caught_error() {
  97. error "ERROR during build step: ${1}"
  98. cleanup
  99. exit 1
  100. }
  101. ## CHECK AND INSTALL DEPENDENCIES ##
  102. check_macos_version() {
  103. MIN_VERSION=${MIN_MACOS_VERSION:-${CI_MIN_MACOS_VERSION}}
  104. MIN_MAJOR=$(/bin/echo ${MIN_VERSION} | /usr/bin/cut -d '.' -f 1)
  105. MIN_MINOR=$(/bin/echo ${MIN_VERSION} | /usr/bin/cut -d '.' -f 2)
  106. if [ "${MACOS_MAJOR}" -lt "11" ] && [ "${MACOS_MINOR}" -lt "${MIN_MINOR}" ]; then
  107. error "WARNING: Minimum required macOS version is ${MIN_VERSION}, but running on ${MACOS_VERSION}"
  108. fi
  109. }
  110. install_homebrew_deps() {
  111. if ! exists brew; then
  112. error "Homebrew not found - please install homebrew (https://brew.sh)"
  113. exit 1
  114. fi
  115. if [ -d /usr/local/opt/[email protected] ]; then
  116. brew uninstall [email protected]
  117. brew untap local/openssl
  118. fi
  119. if [ -d /usr/local/opt/[email protected] ]; then
  120. brew uninstall [email protected]
  121. brew untap local/python2
  122. fi
  123. brew bundle --file "${CI_SCRIPTS}/Brewfile"
  124. check_curl
  125. }
  126. check_curl() {
  127. if [ "${MACOS_MAJOR}" -lt "11" ] && [ "${MACOS_MINOR}" -lt "15" ]; then
  128. if [ ! -d /usr/local/opt/curl ]; then
  129. step "Installing Homebrew curl.."
  130. brew install curl
  131. fi
  132. export CURLCMD="/usr/local/opt/curl/bin/curl"
  133. else
  134. export CURLCMD="curl"
  135. fi
  136. }
  137. check_ccache() {
  138. export PATH="/usr/local/opt/ccache/libexec:${PATH}"
  139. CCACHE_STATUS=$(ccache -s >/dev/null 2>&1 && /bin/echo "CCache available." || /bin/echo "CCache is not available.")
  140. info "${CCACHE_STATUS}"
  141. }
  142. install_obs-deps() {
  143. hr "Setting up pre-built macOS OBS dependencies v${1}"
  144. ensure_dir "${DEPS_BUILD_DIR}"
  145. step "Download..."
  146. ${CURLCMD} --progress-bar -L -C - -O https://github.com/obsproject/obs-deps/releases/download/${1}/macos-deps-${1}-${CURRENT_ARCH}.tar.xz
  147. step "Unpack..."
  148. mkdir -p /tmp/obsdeps
  149. /usr/bin/tar -xf "./macos-deps-${1}-${CURRENT_ARCH}.tar.xz" -C /tmp/obsdeps
  150. /usr/bin/xattr -r -d com.apple.quarantine /tmp/obsdeps
  151. }
  152. install_qt-deps() {
  153. hr "Setting up pre-built dependency QT v${1}"
  154. ensure_dir "${DEPS_BUILD_DIR}"
  155. step "Download..."
  156. ${CURLCMD} --progress-bar -L -C - -O https://github.com/obsproject/obs-deps/releases/download/${2}/macos-deps-qt-${2}-${CURRENT_ARCH}.tar.xz
  157. step "Unpack..."
  158. mkdir -p /tmp/obsdeps
  159. /usr/bin/tar -xf ./macos-deps-qt-${2}-${CURRENT_ARCH}.tar.xz -C /tmp/obsdeps
  160. /usr/bin/xattr -r -d com.apple.quarantine /tmp/obsdeps
  161. }
  162. install_vlc() {
  163. hr "Setting up dependency VLC v${1}"
  164. ensure_dir "${DEPS_BUILD_DIR}"
  165. step "Download..."
  166. ${CURLCMD} --progress-bar -L -C - -O https://downloads.videolan.org/vlc/${1}/vlc-${1}.tar.xz
  167. step "Unpack ..."
  168. /usr/bin/tar -xf vlc-${1}.tar.xz
  169. }
  170. install_sparkle() {
  171. hr "Setting up dependency Sparkle v${1} (might prompt for password)"
  172. ensure_dir "${DEPS_BUILD_DIR}/sparkle"
  173. step "Download..."
  174. ${CURLCMD} --progress-bar -L -C - -o sparkle.tar.bz2 https://github.com/sparkle-project/Sparkle/releases/download/${1}/Sparkle-${1}.tar.bz2
  175. step "Unpack..."
  176. /usr/bin/tar -xf ./sparkle.tar.bz2
  177. step "Copy to destination..."
  178. if [ -d /Library/Frameworks/Sparkle.framework/ ]; then
  179. info "Warning - Sparkle framework already found in /Library/Frameworks"
  180. else
  181. sudo /bin/cp -R ./Sparkle.framework/ /Library/Frameworks/Sparkle.framework/
  182. fi
  183. }
  184. install_cef() {
  185. hr "Building dependency CEF v${1}"
  186. ensure_dir "${DEPS_BUILD_DIR}"
  187. step "Download..."
  188. ${CURLCMD} --progress-bar -L -C - -O https://cdn-fastly.obsproject.com/downloads/cef_binary_${1}_macos_x86_64.tar.xz
  189. step "Unpack..."
  190. /usr/bin/tar -xf ./cef_binary_${1}_macos_x86_64.tar.xz
  191. cd ./cef_binary_${1}_macos_x86_64
  192. step "Fix tests..."
  193. /usr/bin/sed -i '.orig' '/add_subdirectory(tests\/ceftests)/d' ./CMakeLists.txt
  194. /usr/bin/sed -i '.orig' 's/"'$(test "${MACOS_CEF_BUILD_VERSION:-${CI_MACOS_CEF_VERSION}}" -le 3770 && echo "10.9" || echo "10.10")'"/"'${MIN_MACOS_VERSION:-${CI_MIN_MACOS_VERSION}}'"/' ./cmake/cef_variables.cmake
  195. ensure_dir ./build
  196. step "Run CMAKE..."
  197. cmake \
  198. -DCMAKE_CXX_FLAGS="-std=c++11 -stdlib=libc++ -Wno-deprecated-declarations"\
  199. -DCMAKE_EXE_LINKER_FLAGS="-std=c++11 -stdlib=libc++"\
  200. -DCMAKE_OSX_DEPLOYMENT_TARGET=${MIN_MACOS_VERSION:-${CI_MIN_MACOS_VERSION}} \
  201. ..
  202. step "Build..."
  203. /usr/bin/make -j${NPROC}
  204. if [ ! -d libcef_dll ]; then /bin/mkdir libcef_dll; fi
  205. }
  206. ## CHECK AND INSTALL PACKAGING DEPENDENCIES ##
  207. install_dmgbuild() {
  208. if ! exists dmgbuild; then
  209. if exists "pip3"; then
  210. PIPCMD="pip3"
  211. elif exists "pip"; then
  212. PIPCMD="pip"
  213. else
  214. error "Pip not found - please install pip via 'python -m ensurepip'"
  215. exit 1
  216. fi
  217. ${PIPCMD} install dmgbuild
  218. fi
  219. }
  220. ## OBS BUILD FROM SOURCE ##
  221. configure_obs_build() {
  222. ensure_dir "${CHECKOUT_DIR}/${BUILD_DIR}"
  223. CUR_DATE=$(/bin/date +"%Y-%m-%d@%H%M%S")
  224. NIGHTLY_DIR="${CHECKOUT_DIR}/nightly-${CUR_DATE}"
  225. PACKAGE_NAME=$(/usr/bin/find . -name "*.dmg")
  226. if [ -d ./OBS.app ]; then
  227. ensure_dir "${NIGHTLY_DIR}"
  228. /bin/mv "../${BUILD_DIR}/OBS.app" .
  229. info "You can find OBS.app in ${NIGHTLY_DIR}"
  230. fi
  231. ensure_dir "${CHECKOUT_DIR}/${BUILD_DIR}"
  232. if ([ -n "${PACKAGE_NAME}" ] && [ -f ${PACKAGE_NAME} ]); then
  233. ensure_dir "${NIGHTLY_DIR}"
  234. /bin/mv "../${BUILD_DIR}/$(basename "${PACKAGE_NAME}")" .
  235. info "You can find ${PACKAGE_NAME} in ${NIGHTLY_DIR}"
  236. fi
  237. ensure_dir "${CHECKOUT_DIR}/${BUILD_DIR}"
  238. hr "Run CMAKE for OBS..."
  239. cmake -DENABLE_SPARKLE_UPDATER=ON \
  240. -DCMAKE_OSX_DEPLOYMENT_TARGET=${MIN_MACOS_VERSION:-${CI_MIN_MACOS_VERSION}} \
  241. -DQTDIR="/tmp/obsdeps" \
  242. -DSWIGDIR="/tmp/obsdeps" \
  243. -DDepsPath="/tmp/obsdeps" \
  244. -DVLCPath="${DEPS_BUILD_DIR}/vlc-${VLC_VERSION:-${CI_VLC_VERSION}}" \
  245. -DBUILD_BROWSER=ON \
  246. -DBROWSER_LEGACY="$(test "${MACOS_CEF_BUILD_VERSION:-${CI_MACOS_CEF_VERSION}}" -le 3770 && echo "ON" || echo "OFF")" \
  247. -DWITH_RTMPS=ON \
  248. -DCEF_ROOT_DIR="${DEPS_BUILD_DIR}/cef_binary_${MACOS_CEF_BUILD_VERSION:-${CI_MACOS_CEF_VERSION}}_macos_x86_64" \
  249. -DCMAKE_BUILD_TYPE="${BUILD_CONFIG}" \
  250. ..
  251. }
  252. run_obs_build() {
  253. ensure_dir "${CHECKOUT_DIR}/${BUILD_DIR}"
  254. hr "Build OBS..."
  255. /usr/bin/make -j${NPROC}
  256. }
  257. ## OBS BUNDLE AS MACOS APPLICATION ##
  258. bundle_dylibs() {
  259. ensure_dir "${CHECKOUT_DIR}/${BUILD_DIR}"
  260. if [ ! -d ./OBS.app ]; then
  261. error "No OBS.app bundle found"
  262. exit 1
  263. fi
  264. hr "Bundle dylibs for macOS application"
  265. step "Run dylibBundler.."
  266. BUNDLE_PLUGINS=(
  267. ./OBS.app/Contents/PlugIns/coreaudio-encoder.so
  268. ./OBS.app/Contents/PlugIns/decklink-ouput-ui.so
  269. ./OBS.app/Contents/PlugIns/decklink-captions.so
  270. ./OBS.app/Contents/PlugIns/frontend-tools.so
  271. ./OBS.app/Contents/PlugIns/image-source.so
  272. ./OBS.app/Contents/PlugIns/mac-avcapture.so
  273. ./OBS.app/Contents/PlugIns/mac-capture.so
  274. ./OBS.app/Contents/PlugIns/mac-decklink.so
  275. ./OBS.app/Contents/PlugIns/mac-syphon.so
  276. ./OBS.app/Contents/PlugIns/mac-vth264.so
  277. ./OBS.app/Contents/PlugIns/mac-virtualcam.so
  278. ./OBS.app/Contents/PlugIns/obs-browser.so
  279. ./OBS.app/Contents/PlugIns/obs-ffmpeg.so
  280. ./OBS.app/Contents/PlugIns/obs-filters.so
  281. ./OBS.app/Contents/PlugIns/obs-transitions.so
  282. ./OBS.app/Contents/PlugIns/obs-vst.so
  283. ./OBS.app/Contents/PlugIns/rtmp-services.so
  284. ./OBS.app/Contents/MacOS/obs-ffmpeg-mux
  285. ./OBS.app/Contents/MacOS/obslua.so
  286. ./OBS.app/Contents/MacOS/_obspython.so
  287. ./OBS.app/Contents/PlugIns/obs-x264.so
  288. ./OBS.app/Contents/PlugIns/text-freetype2.so
  289. ./OBS.app/Contents/PlugIns/obs-outputs.so
  290. ./OBS.app/Contents/PlugIns/aja.so
  291. ./OBS.app/Contents/PlugIns/aja-output-ui.so
  292. )
  293. SEARCH_PATHS=(
  294. /tmp/obsdeps/lib
  295. /tmp/obsdeps/lib/QtSvg.framework
  296. /tmp/obsdeps/lib/QtXml.framework
  297. /tmp/obsdeps/lib/QtNetwork.framework
  298. /tmp/obsdeps/lib/QtCore.framework
  299. /tmp/obsdeps/lib/QtGui.framework
  300. /tmp/obsdeps/lib/QtWidgets.framework
  301. /tmp/obsdeps/lib/QtDBus.framework
  302. /tmp/obsdeps/lib/QtPrintSupport.framework
  303. )
  304. if ! [ "${MACOS_CEF_BUILD_VERSION:-${CI_MACOS_CEF_VERSION}}" -le 3770 ]; then
  305. "${CI_SCRIPTS}/app/dylibbundler" -cd -of -a ./OBS.app -q -f \
  306. -s ./OBS.app/Contents/MacOS \
  307. -s "${DEPS_BUILD_DIR}/sparkle/Sparkle.framework" \
  308. -s ./rundir/${BUILD_CONFIG}/bin/ \
  309. $(echo "${SEARCH_PATHS[@]/#/-s }") \
  310. $(echo "${BUNDLE_PLUGINS[@]/#/-x }")
  311. else
  312. "${CI_SCRIPTS}/app/dylibbundler" -cd -of -a ./OBS.app -q -f \
  313. -s ./OBS.app/Contents/MacOS \
  314. -s "${DEPS_BUILD_DIR}/sparkle/Sparkle.framework" \
  315. -s ./rundir/${BUILD_CONFIG}/bin/ \
  316. $(echo "${SEARCH_PATHS[@]/#/-s }") \
  317. $(echo "${BUNDLE_PLUGINS[@]/#/-x }") \
  318. -x ./OBS.app/Contents/PlugIns/obs-browser-page
  319. fi
  320. step "Move libobs-opengl to final destination"
  321. if [ -f "./libobs-opengl/libobs-opengl.so" ]; then
  322. /bin/cp ./libobs-opengl/libobs-opengl.so ./OBS.app/Contents/Frameworks
  323. else
  324. /bin/cp ./libobs-opengl/${BUILD_CONFIG}/libobs-opengl.so ./OBS.app/Contents/Frameworks
  325. fi
  326. }
  327. install_frameworks() {
  328. ensure_dir "${CHECKOUT_DIR}/${BUILD_DIR}"
  329. if [ ! -d ./OBS.app ]; then
  330. error "No OBS.app bundle found"
  331. exit 1
  332. fi
  333. hr "Adding Chromium Embedded Framework"
  334. step "Copy Framework..."
  335. /bin/cp -R "${DEPS_BUILD_DIR}/cef_binary_${MACOS_CEF_BUILD_VERSION:-${CI_MACOS_CEF_VERSION}}_macos_x86_64/Release/Chromium Embedded Framework.framework" ./OBS.app/Contents/Frameworks/
  336. }
  337. prepare_macos_bundle() {
  338. ensure_dir "${CHECKOUT_DIR}/${BUILD_DIR}"
  339. if [ ! -d ./rundir/${BUILD_CONFIG}/bin ]; then
  340. error "No OBS build found"
  341. return
  342. fi
  343. if [ -d ./OBS.app ]; then /bin/rm -rf ./OBS.app; fi
  344. hr "Preparing OBS.app bundle"
  345. step "Copy binary and plugins..."
  346. /bin/mkdir -p OBS.app/Contents/MacOS
  347. /bin/mkdir OBS.app/Contents/PlugIns
  348. /bin/mkdir OBS.app/Contents/Resources
  349. /bin/mkdir OBS.app/Contents/Frameworks
  350. /bin/cp rundir/${BUILD_CONFIG}/bin/obs ./OBS.app/Contents/MacOS
  351. /bin/cp rundir/${BUILD_CONFIG}/bin/obs-ffmpeg-mux ./OBS.app/Contents/MacOS
  352. /bin/cp rundir/${BUILD_CONFIG}/bin/libobsglad.0.dylib ./OBS.app/Contents/MacOS
  353. if ! [ "${MACOS_CEF_BUILD_VERSION:-${CI_MACOS_CEF_VERSION}}" -le 3770 ]; then
  354. /bin/cp -R "rundir/${BUILD_CONFIG}/bin/OBS Helper.app" "./OBS.app/Contents/Frameworks/OBS Helper.app"
  355. /bin/cp -R "rundir/${BUILD_CONFIG}/bin/OBS Helper (GPU).app" "./OBS.app/Contents/Frameworks/OBS Helper (GPU).app"
  356. /bin/cp -R "rundir/${BUILD_CONFIG}/bin/OBS Helper (Plugin).app" "./OBS.app/Contents/Frameworks/OBS Helper (Plugin).app"
  357. /bin/cp -R "rundir/${BUILD_CONFIG}/bin/OBS Helper (Renderer).app" "./OBS.app/Contents/Frameworks/OBS Helper (Renderer).app"
  358. fi
  359. /bin/cp -R rundir/${BUILD_CONFIG}/data ./OBS.app/Contents/Resources
  360. /bin/cp "${CI_SCRIPTS}/app/AppIcon.icns" ./OBS.app/Contents/Resources
  361. /bin/cp -R rundir/${BUILD_CONFIG}/obs-plugins/ ./OBS.app/Contents/PlugIns
  362. /bin/cp "${CI_SCRIPTS}/app/Info.plist" ./OBS.app/Contents
  363. # Scripting plugins are required to be placed in same directory as binary
  364. if [ -d ./OBS.app/Contents/Resources/data/obs-scripting ]; then
  365. /bin/mv ./OBS.app/Contents/Resources/data/obs-scripting/obslua.so ./OBS.app/Contents/MacOS/
  366. /bin/mv ./OBS.app/Contents/Resources/data/obs-scripting/_obspython.so ./OBS.app/Contents/MacOS/
  367. /bin/mv ./OBS.app/Contents/Resources/data/obs-scripting/obspython.py ./OBS.app/Contents/MacOS/
  368. /bin/rm -rf ./OBS.app/Contents/Resources/data/obs-scripting/
  369. fi
  370. # dylibbundler will only copy actually linked files into bundle, but not symlinks
  371. /bin/cp -cpR /tmp/obsdeps/lib/*.dylib ./OBS.app/Contents/Frameworks
  372. bundle_dylibs
  373. install_frameworks
  374. /bin/cp "${CI_SCRIPTS}/app/OBSPublicDSAKey.pem" ./OBS.app/Contents/Resources
  375. step "Set bundle meta information..."
  376. /usr/bin/plutil -insert CFBundleVersion -string ${GIT_TAG}-${GIT_HASH} ./OBS.app/Contents/Info.plist
  377. /usr/bin/plutil -insert CFBundleShortVersionString -string ${GIT_TAG}-${GIT_HASH} ./OBS.app/Contents/Info.plist
  378. /usr/bin/plutil -insert OBSFeedsURL -string https://obsproject.com/osx_update/feeds.xml ./OBS.app/Contents/Info.plist
  379. /usr/bin/plutil -insert SUFeedURL -string https://obsproject.com/osx_update/stable/updates.xml ./OBS.app/Contents/Info.plist
  380. /usr/bin/plutil -insert SUPublicDSAKeyFile -string OBSPublicDSAKey.pem ./OBS.app/Contents/Info.plist
  381. }
  382. ## CREATE MACOS DISTRIBUTION AND INSTALLER IMAGE ##
  383. prepare_macos_image() {
  384. ensure_dir "${CHECKOUT_DIR}/${BUILD_DIR}"
  385. if [ ! -d ./OBS.app ]; then
  386. error "No OBS.app bundle found"
  387. return
  388. fi
  389. hr "Preparing macOS installation image"
  390. if [ -f "${FILE_NAME}" ]; then
  391. /bin/rm "${FILE_NAME}"
  392. fi
  393. step "Run dmgbuild..."
  394. /bin/cp "${CI_SCRIPTS}/package/settings.json.template" ./settings.json
  395. /usr/bin/sed -i '' 's#\$\$VERSION\$\$#'"${GIT_TAG}"'#g' ./settings.json
  396. /usr/bin/sed -i '' 's#\$\$CI_PATH\$\$#'"${CI_SCRIPTS}"'#g' ./settings.json
  397. /usr/bin/sed -i '' 's#\$\$BUNDLE_PATH\$\$#'"${CHECKOUT_DIR}"'/build#g' ./settings.json
  398. /bin/echo -n "${COLOR_ORANGE}"
  399. dmgbuild "OBS-Studio ${GIT_TAG}" "${FILE_NAME}" -s ./settings.json
  400. /bin/echo -n "${COLOR_RESET}"
  401. if [ -n "${CODESIGN_OBS}" ]; then
  402. codesign_image
  403. fi
  404. }
  405. ## SET UP CODE SIGNING AND NOTARIZATION CREDENTIALS ##
  406. ##############################################################################
  407. # Apple Developer Identity needed:
  408. #
  409. # + Signing the code requires a developer identity in the system's keychain
  410. # + codesign will look up and find the identity automatically
  411. #
  412. ##############################################################################
  413. read_codesign_ident() {
  414. if [ ! -n "${CODESIGN_IDENT}" ]; then
  415. step "Code-signing Setup"
  416. /usr/bin/read -p "${COLOR_ORANGE} + Apple developer identity: ${COLOR_RESET}" CODESIGN_IDENT
  417. fi
  418. }
  419. ##############################################################################
  420. # Apple Developer credentials necessary:
  421. #
  422. # + Signing for distribution and notarization require an active Apple
  423. # Developer membership
  424. # + An Apple Development identity is needed for code signing
  425. # (i.e. 'Apple Development: YOUR APPLE ID (PROVIDER)')
  426. # + Your Apple developer ID is needed for notarization
  427. # + An app-specific password is necessary for notarization from CLI
  428. # + This password will be stored in your macOS keychain under the identifier
  429. # 'OBS-Codesign-Password'with access Apple's 'altool' only.
  430. ##############################################################################
  431. read_codesign_pass() {
  432. if [ ! -n "${CODESIGN_IDENT_PASS}" ]; then
  433. step "Notarization Setup"
  434. /usr/bin/read -p "${COLOR_ORANGE} + Apple account id: ${COLOR_RESET}" CODESIGN_IDENT_USER
  435. CODESIGN_IDENT_PASS=$(stty -echo; /usr/bin/read -p "${COLOR_ORANGE} + Apple developer password: ${COLOR_RESET}" pwd; stty echo; /bin/echo $pwd)
  436. /bin/echo -n "${COLOR_ORANGE}"
  437. /usr/bin/xcrun altool --store-password-in-keychain-item "OBS-Codesign-Password" -u "${CODESIGN_IDENT_USER}" -p "${CODESIGN_IDENT_PASS}"
  438. /bin/echo -n "${COLOR_RESET}"
  439. CODESIGN_IDENT_SHORT=$(/bin/echo "${CODESIGN_IDENT}" | /usr/bin/sed -En "s/.+\((.+)\)/\1/p")
  440. fi
  441. }
  442. codesign_bundle() {
  443. if [ ! -n "${CODESIGN_OBS}" ]; then step "Skipping application bundle code signing"; return; fi
  444. ensure_dir "${CHECKOUT_DIR}/${BUILD_DIR}"
  445. trap "caught_error 'code-signing app'" ERR
  446. if [ ! -d ./OBS.app ]; then
  447. error "No OBS.app bundle found"
  448. return
  449. fi
  450. hr "Code-signing application bundle"
  451. /usr/bin/xattr -crs ./OBS.app
  452. read_codesign_ident
  453. step "Code-sign Sparkle framework..."
  454. /bin/echo -n "${COLOR_ORANGE}"
  455. /usr/bin/codesign --force --options runtime --sign "${CODESIGN_IDENT}" "./OBS.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/fileop"
  456. /usr/bin/codesign --force --options runtime --sign "${CODESIGN_IDENT}" "./OBS.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/Autoupdate"
  457. /usr/bin/codesign --force --options runtime --sign "${CODESIGN_IDENT}" --deep ./OBS.app/Contents/Frameworks/Sparkle.framework
  458. /bin/echo -n "${COLOR_RESET}"
  459. step "Code-sign CEF framework..."
  460. /bin/echo -n "${COLOR_ORANGE}"
  461. /usr/bin/codesign --force --options runtime --entitlements "${CI_SCRIPTS}/app/entitlements.plist" --sign "${CODESIGN_IDENT}" "./OBS.app/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries/libEGL.dylib"
  462. /usr/bin/codesign --force --options runtime --entitlements "${CI_SCRIPTS}/app/entitlements.plist" --sign "${CODESIGN_IDENT}" "./OBS.app/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries/libswiftshader_libEGL.dylib"
  463. /usr/bin/codesign --force --options runtime --entitlements "${CI_SCRIPTS}/app/entitlements.plist" --sign "${CODESIGN_IDENT}" "./OBS.app/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries/libGLESv2.dylib"
  464. /usr/bin/codesign --force --options runtime --entitlements "${CI_SCRIPTS}/app/entitlements.plist" --sign "${CODESIGN_IDENT}" "./OBS.app/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries/libswiftshader_libGLESv2.dylib"
  465. if ! [ "${MACOS_CEF_BUILD_VERSION:-${CI_MACOS_CEF_VERSION}}" -le 3770 ]; then
  466. /usr/bin/codesign --force --options runtime --entitlements "${CI_SCRIPTS}/app/entitlements.plist" --sign "${CODESIGN_IDENT}" "./OBS.app/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries/libvk_swiftshader.dylib"
  467. fi
  468. /bin/echo -n "${COLOR_RESET}"
  469. if ! [ "${MACOS_CEF_BUILD_VERSION:-${CI_MACOS_CEF_VERSION}}" -le 3770 ]; then
  470. step "Code-sign CEF helper apps..."
  471. /bin/echo -n "${COLOR_ORANGE}"
  472. /usr/bin/codesign --force --options runtime --entitlements "${CI_SCRIPTS}/helpers/helper-entitlements.plist" --sign "${CODESIGN_IDENT}" --deep "./OBS.app/Contents/Frameworks/OBS Helper.app"
  473. /usr/bin/codesign --force --options runtime --entitlements "${CI_SCRIPTS}/helpers/helper-gpu-entitlements.plist" --sign "${CODESIGN_IDENT}" --deep "./OBS.app/Contents/Frameworks/OBS Helper (GPU).app"
  474. /usr/bin/codesign --force --options runtime --entitlements "${CI_SCRIPTS}/helpers/helper-plugin-entitlements.plist" --sign "${CODESIGN_IDENT}" --deep "./OBS.app/Contents/Frameworks/OBS Helper (Plugin).app"
  475. /usr/bin/codesign --force --options runtime --entitlements "${CI_SCRIPTS}/helpers/helper-renderer-entitlements.plist" --sign "${CODESIGN_IDENT}" --deep "./OBS.app/Contents/Frameworks/OBS Helper (Renderer).app"
  476. /bin/echo -n "${COLOR_RESET}"
  477. fi
  478. step "Code-sign DAL Plugin..."
  479. /bin/echo -n "${COLOR_ORANGE}"
  480. /usr/bin/codesign --force --options runtime --deep --sign "${CODESIGN_IDENT}" "./OBS.app/Contents/Resources/data/obs-plugins/mac-virtualcam/obs-mac-virtualcam.plugin"
  481. /bin/echo -n "${COLOR_RESET}"
  482. step "Code-sign OBS code..."
  483. /bin/echo -n "${COLOR_ORANGE}"
  484. /usr/bin/codesign --force --options runtime --entitlements "${CI_SCRIPTS}/app/entitlements.plist" --sign "${CODESIGN_IDENT}" --deep ./OBS.app
  485. /bin/echo -n "${COLOR_RESET}"
  486. step "Check code-sign result..."
  487. /usr/bin/codesign -dvv ./OBS.app
  488. }
  489. codesign_image() {
  490. if [ ! -n "${CODESIGN_OBS}" ]; then step "Skipping installer image code signing"; return; fi
  491. ensure_dir "${CHECKOUT_DIR}/${BUILD_DIR}"
  492. trap "caught_error 'code-signing image'" ERR
  493. if [ ! -f "${FILE_NAME}" ]; then
  494. error "No OBS disk image found"
  495. return
  496. fi
  497. hr "Code-signing installation image"
  498. read_codesign_ident
  499. step "Code-sign OBS installer image..."
  500. /bin/echo -n "${COLOR_ORANGE}";
  501. /usr/bin/codesign --force --sign "${CODESIGN_IDENT}" "${FILE_NAME}"
  502. /bin/echo -n "${COLOR_RESET}"
  503. step "Check code-sign result..."
  504. /usr/bin/codesign -dvv "${FILE_NAME}"
  505. }
  506. ## BUILD FROM SOURCE META FUNCTION ##
  507. full-build-macos() {
  508. if [ -n "${SKIP_BUILD}" ]; then step "Skipping full build"; return; fi
  509. if [ ! -n "${SKIP_DEPS}" ]; then
  510. hr "Installing Homebrew dependencies"
  511. install_homebrew_deps
  512. for DEPENDENCY in "${BUILD_DEPS[@]}"; do
  513. set -- ${DEPENDENCY}
  514. trap "caught_error ${DEPENDENCY}" ERR
  515. FUNC_NAME="install_${1}"
  516. ${FUNC_NAME} ${2} ${3}
  517. done
  518. check_ccache
  519. trap "caught_error 'cmake'" ERR
  520. fi
  521. configure_obs_build
  522. run_obs_build
  523. }
  524. ## BUNDLE MACOS APPLICATION META FUNCTION ##
  525. bundle_macos() {
  526. if [ ! -n "${BUNDLE_OBS}" ]; then step "Skipping application bundle creation"; return; fi
  527. hr "Creating macOS app bundle"
  528. trap "caught_error 'bundle app'" ERR
  529. ensure_dir ${CHECKOUT_DIR}
  530. prepare_macos_bundle
  531. }
  532. ## PACKAGE MACOS DISTRIBUTION IMAGE META FUNCTION ##
  533. package_macos() {
  534. if [ ! -n "${PACKAGE_OBS}" ]; then step "Skipping installer image creation"; return; fi
  535. hr "Creating macOS .dmg image"
  536. trap "caught_error 'package app'" ERR
  537. install_dmgbuild
  538. prepare_macos_image
  539. }
  540. ## NOTARIZATION META FUNCTION ##
  541. notarize_macos() {
  542. if [ ! -n "${NOTARIZE_OBS}" ]; then step "Skipping macOS notarization"; return; fi;
  543. hr "Notarizing OBS for macOS"
  544. trap "caught_error 'notarizing app'" ERR
  545. ensure_dir "${CHECKOUT_DIR}/${BUILD_DIR}"
  546. if [ -f "${FILE_NAME}" ]; then
  547. NOTARIZE_TARGET="${FILE_NAME}"
  548. xcnotary precheck "./OBS.app"
  549. elif [ -d "OBS.app" ]; then
  550. NOTARIZE_TARGET="./OBS.app"
  551. else
  552. error "No notarization app bundle ('OBS.app') or disk image ('${FILE_NAME}') found"
  553. return
  554. fi
  555. if [ "$?" -eq 0 ]; then
  556. read_codesign_ident
  557. read_codesign_pass
  558. step "Run xcnotary with ${NOTARIZE_TARGET}..."
  559. xcnotary notarize "${NOTARIZE_TARGET}" --developer-account "${CODESIGN_IDENT_USER}" --developer-password-keychain-item "OBS-Codesign-Password" --provider "${CODESIGN_IDENT_SHORT}"
  560. fi
  561. }
  562. ## MAIN SCRIPT FUNCTIONS ##
  563. print_usage() {
  564. /bin/echo "full-build-macos.sh - Build helper script for OBS-Studio\n"
  565. /bin/echo "Usage: ${0}\n" \
  566. "-d: Skip dependency checks\n" \
  567. "-b: Create macOS app bundle\n" \
  568. "-c: Codesign macOS app bundle\n" \
  569. "-p: Package macOS app into disk image\n" \
  570. "-n: Notarize macOS app and disk image (implies -b)\n" \
  571. "-s: Skip build process (useful for bundling/packaging only)\n" \
  572. "-h: Print this help"
  573. exit 0
  574. }
  575. obs-build-main() {
  576. ensure_dir ${CHECKOUT_DIR}
  577. check_macos_version
  578. step "Fetching OBS tags..."
  579. /usr/bin/git fetch origin --tags
  580. GIT_BRANCH=$(/usr/bin/git rev-parse --abbrev-ref HEAD)
  581. GIT_HASH=$(/usr/bin/git rev-parse --short HEAD)
  582. GIT_TAG=$(/usr/bin/git describe --tags --abbrev=0)
  583. FILE_NAME="obs-studio-${GIT_TAG}-${GIT_HASH}-macOS.dmg"
  584. ##########################################################################
  585. # IMPORTANT:
  586. #
  587. # Be careful when choosing to notarize and code-sign. The script will try
  588. # to sign any pre-existing bundle but also pre-existing images.
  589. #
  590. # This could lead to a package containing a non-signed bundle, which
  591. # will then fail notarization.
  592. #
  593. # To avoid this, run this script with -b -c first, then -p -c or -p -n
  594. # after to make sure that a code-signed bundle will be packaged.
  595. #
  596. ##########################################################################
  597. while getopts ":hdsbnpc" OPTION; do
  598. case ${OPTION} in
  599. h) print_usage ;;
  600. d) SKIP_DEPS=1 ;;
  601. s) SKIP_BUILD=1 ;;
  602. b) BUNDLE_OBS=1 ;;
  603. n) CODESIGN_OBS=1; NOTARIZE_OBS=1 ;;
  604. p) PACKAGE_OBS=1 ;;
  605. c) CODESIGN_OBS=1 ;;
  606. \?) ;;
  607. esac
  608. done
  609. full-build-macos
  610. bundle_macos
  611. codesign_bundle
  612. package_macos
  613. codesign_image
  614. notarize_macos
  615. cleanup
  616. }
  617. obs-build-main $*