├── .clang-format ├── .github ├── scripts │ ├── utils.zsh │ │ ├── log_output │ │ ├── log_info │ │ ├── log_status │ │ ├── log_warning │ │ ├── log_error │ │ ├── mkcd │ │ ├── log_debug │ │ ├── log_group │ │ ├── set_loglevel │ │ ├── check_macos │ │ ├── setup_ubuntu │ │ └── check_ubuntu │ ├── .Brewfile │ ├── .Aptfile │ ├── utils.pwsh │ │ ├── Ensure-Location.ps1 │ │ ├── Invoke-External.ps1 │ │ └── Logger.ps1 │ ├── Build-Windows.ps1 │ ├── Package-Windows.ps1 │ ├── build-macos │ ├── package-macos │ ├── package-ubuntu │ └── build-ubuntu ├── FUNDING.yml ├── workflows │ ├── dispatch.yaml │ ├── check-format.yaml │ ├── pr-pull.yaml │ ├── push.yaml │ └── build-project.yaml └── actions │ ├── run-gersemi │ └── action.yaml │ ├── run-clang-format │ └── action.yaml │ ├── check-changes │ └── action.yaml │ ├── package-plugin │ └── action.yaml │ ├── build-plugin │ └── action.yaml │ └── setup-macos-codesigning │ └── action.yaml ├── media ├── icon.ico └── logo.png ├── version.h.in ├── .gitignore ├── cmake ├── windows │ ├── defaults.cmake │ ├── buildspec.cmake │ ├── resources │ │ ├── resource.rc.in │ │ └── installer-Windows.iss.in │ ├── compilerconfig.cmake │ └── helpers.cmake ├── macos │ ├── resources │ │ ├── ccache-launcher-c.in │ │ ├── ccache-launcher-cxx.in │ │ ├── distribution.in │ │ └── create-package.cmake.in │ ├── buildspec.cmake │ ├── defaults.cmake │ ├── compilerconfig.cmake │ ├── helpers.cmake │ └── xcode.cmake ├── common │ ├── osconfig.cmake │ ├── ccache.cmake │ ├── buildnumber.cmake │ ├── helpers_common.cmake │ ├── compiler_common.cmake │ ├── bootstrap.cmake │ └── buildspec_common.cmake └── linux │ ├── compilerconfig.cmake │ ├── defaults.cmake │ └── helpers.cmake ├── README.md ├── .cmake-format.json ├── resource.rc.in ├── data └── locale │ ├── zh-CN.ini │ ├── es-ES.ini │ └── en-US.ini ├── CMakeLists.txt ├── CMakePresets.json ├── source-profiler.hpp └── LICENSE /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: InheritParentConfig 2 | ColumnLimit: 132 -------------------------------------------------------------------------------- /.github/scripts/utils.zsh/log_output: -------------------------------------------------------------------------------- 1 | print -PR " ${@}" 2 | -------------------------------------------------------------------------------- /.github/scripts/utils.zsh/log_info: -------------------------------------------------------------------------------- 1 | print -PR "%F{4} =>%f %B${@}%b" 2 | -------------------------------------------------------------------------------- /.github/scripts/utils.zsh/log_status: -------------------------------------------------------------------------------- 1 | print -PR "%F{2} >%f ${@}" 2 | -------------------------------------------------------------------------------- /.github/scripts/utils.zsh/log_warning: -------------------------------------------------------------------------------- 1 | print -PR "::warning::%F{3} => ${@}%f" 2 | -------------------------------------------------------------------------------- /.github/scripts/utils.zsh/log_error: -------------------------------------------------------------------------------- 1 | print -u2 -PR "::error::%F{1} ✖︎%f ${@}" 2 | -------------------------------------------------------------------------------- /.github/scripts/utils.zsh/mkcd: -------------------------------------------------------------------------------- 1 | [[ -n ${1} ]] && mkdir -p ${1} && builtin cd ${1} 2 | -------------------------------------------------------------------------------- /media/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exeldro/obs-source-profiler/HEAD/media/icon.ico -------------------------------------------------------------------------------- /media/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exeldro/obs-source-profiler/HEAD/media/logo.png -------------------------------------------------------------------------------- /.github/scripts/utils.zsh/log_debug: -------------------------------------------------------------------------------- 1 | if (( debug )) print -PR -e "::debug::%F{220}DEBUG: ${@}%f" 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: exeldro 2 | custom: "https://www.paypal.me/exeldro" 3 | patreon: Exeldro 4 | -------------------------------------------------------------------------------- /.github/scripts/.Brewfile: -------------------------------------------------------------------------------- 1 | brew "ccache" 2 | brew "coreutils" 3 | brew "cmake" 4 | brew "jq" 5 | brew "xcbeautify" 6 | -------------------------------------------------------------------------------- /.github/scripts/.Aptfile: -------------------------------------------------------------------------------- 1 | package 'cmake' 2 | package 'ccache' 3 | package 'git' 4 | package 'jq' 5 | package 'ninja-build', bin: 'ninja' 6 | package 'pkg-config' 7 | -------------------------------------------------------------------------------- /version.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define PROJECT_VERSION "${PROJECT_VERSION}" 4 | #define PROJECT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} 5 | #define PROJECT_VERSION_MINOR ${PROJECT_VERSION_MINOR} 6 | #define PROJECT_VERSION_PATCH ${PROJECT_VERSION_PATCH} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .DS_Store 3 | /build/ 4 | /build_*/ 5 | /release/ 6 | /installer/Output/ 7 | 8 | .vscode 9 | .idea 10 | .deps/ 11 | 12 | # ignore generated files 13 | *.generated.* 14 | **/.Brewfile.lock.json 15 | version.h 16 | cmake/.CMakeBuildNumber 17 | .ccache.conf 18 | -------------------------------------------------------------------------------- /.github/scripts/utils.zsh/log_group: -------------------------------------------------------------------------------- 1 | autoload -Uz log_info 2 | 3 | if (( ! ${+_log_group} )) typeset -g _log_group=0 4 | 5 | if (( _log_group )) { 6 | print "::endgroup::" 7 | typeset -g _log_group=0 8 | } 9 | if (( # )) { 10 | print "::group::${@}" 11 | typeset -g _log_group=1 12 | } 13 | -------------------------------------------------------------------------------- /cmake/windows/defaults.cmake: -------------------------------------------------------------------------------- 1 | # CMake Windows defaults module 2 | 3 | include_guard(GLOBAL) 4 | 5 | # Enable find_package targets to become globally available targets 6 | set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL TRUE) 7 | 8 | include(buildspec) 9 | 10 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 11 | set( 12 | CMAKE_INSTALL_PREFIX 13 | "$ENV{ALLUSERSPROFILE}/obs-studio/plugins" 14 | CACHE STRING 15 | "Default plugin installation directory" 16 | FORCE 17 | ) 18 | endif() 19 | -------------------------------------------------------------------------------- /.github/workflows/dispatch.yaml: -------------------------------------------------------------------------------- 1 | name: Dispatch 2 | run-name: Dispatched Repository Actions - ${{ inputs.job }} ⌛️ 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | job: 7 | description: Dispatch job to run 8 | required: true 9 | type: choice 10 | options: 11 | - build 12 | permissions: 13 | contents: write 14 | jobs: 15 | check-and-build: 16 | if: inputs.job == 'build' 17 | uses: ./.github/workflows/build-project.yaml 18 | secrets: inherit 19 | -------------------------------------------------------------------------------- /.github/scripts/utils.zsh/set_loglevel: -------------------------------------------------------------------------------- 1 | autoload -Uz log_debug log_error 2 | 3 | local -r _usage="Usage: %B${0}%b 4 | 5 | Set log level, following levels are supported: 0 (quiet), 1 (normal), 2 (verbose), 3 (debug)" 6 | 7 | if (( ! # )); then 8 | log_error 'Called without arguments.' 9 | log_output ${_usage} 10 | return 2 11 | elif (( ${1} >= 4 )); then 12 | log_error 'Called with loglevel > 3.' 13 | log_output ${_usage} 14 | fi 15 | 16 | typeset -g -i -r _loglevel=${1} 17 | log_debug "Log level set to '${1}'" 18 | -------------------------------------------------------------------------------- /.github/scripts/utils.zsh/check_macos: -------------------------------------------------------------------------------- 1 | autoload -Uz is-at-least log_group log_info log_error log_status 2 | 3 | local macos_version=$(sw_vers -productVersion) 4 | 5 | log_group 'Install macOS build requirements' 6 | log_info 'Checking macOS version...' 7 | if ! is-at-least 12.0 ${macos_version}; then 8 | log_error "Minimum required macOS version is 12.0, but running on macOS ${macos_version}" 9 | return 2 10 | else 11 | log_status "macOS ${macos_version} is recent" 12 | fi 13 | 14 | log_info 'Checking for Homebrew...' 15 | if (( ! ${+commands[brew]} )) { 16 | log_error 'No Homebrew command found. Please install Homebrew (https://brew.sh)' 17 | return 2 18 | } 19 | 20 | brew bundle --file ${SCRIPT_HOME}/.Brewfile 21 | rehash 22 | log_group 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Source profiler for OBS Studio 2 | 3 | Plugin for [OBS Studio](https://github.com/obsproject/obs-studio) to add Source Profiler to tools menu 4 | 5 | Based on [source profiling ui](https://github.com/derrod/obs-studio/tree/source-profiling-ui) by @derrod 6 | 7 | # Build 8 | - In-tree build 9 | - Build OBS Studio: https://obsproject.com/wiki/Install-Instructions 10 | - Check out this repository to UI/frontend-plugins/source-profiler 11 | - Add `add_subdirectory(source-profiler)` to UI/frontend-plugins/CMakeLists.txt 12 | - Rebuild OBS Studio 13 | - Stand-alone build 14 | - Verify that you have development files for OBS 15 | - Check out this repository and run `cmake -S . -B build -DBUILD_OUT_OF_TREE=On && cmake --build build` 16 | -------------------------------------------------------------------------------- /.github/workflows/check-format.yaml: -------------------------------------------------------------------------------- 1 | name: Check Code Formatting 🛠️ 2 | on: 3 | workflow_call: 4 | jobs: 5 | clang-format: 6 | if: false 7 | runs-on: ubuntu-24.04 8 | steps: 9 | - uses: actions/checkout@v4 10 | with: 11 | fetch-depth: 0 12 | - name: clang-format check 🐉 13 | id: clang-format 14 | uses: ./.github/actions/run-clang-format 15 | with: 16 | failCondition: error 17 | 18 | gersemi: 19 | runs-on: ubuntu-24.04 20 | if: false 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | - name: gersemi Check 🎛️ 26 | id: gersemi 27 | uses: ./.github/actions/run-gersemi 28 | with: 29 | failCondition: error 30 | -------------------------------------------------------------------------------- /cmake/macos/resources/ccache-launcher-c.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [[ "$1" == "${CMAKE_C_COMPILER}" ]] ; then 4 | shift 5 | fi 6 | 7 | export CCACHE_DIR='${CMAKE_SOURCE_DIR}/.ccache' 8 | export CCACHE_MAXSIZE='1G' 9 | export CCACHE_CPP2=true 10 | export CCACHE_DEPEND=true 11 | export CCACHE_DIRECT=true 12 | export CCACHE_FILECLONE=true 13 | export CCACHE_INODECACHE=true 14 | export CCACHE_COMPILERCHECK='content' 15 | 16 | CCACHE_SLOPPINESS='file_stat_matches,include_file_mtime,include_file_ctime,system_headers' 17 | 18 | if [[ "${CMAKE_C_COMPILER_ID}" == "AppleClang" ]]; then 19 | CCACHE_SLOPPINESS="${CCACHE_SLOPPINESS},modules,clang_index_store" 20 | fi 21 | export CCACHE_SLOPPINESS 22 | 23 | if [[ "${CI}" ]]; then 24 | export CCACHE_NOHASHDIR=true 25 | fi 26 | exec "${CMAKE_C_COMPILER_LAUNCHER}" "${CMAKE_C_COMPILER}" "$@" 27 | -------------------------------------------------------------------------------- /cmake/macos/resources/ccache-launcher-cxx.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [[ "$1" == "${CMAKE_CXX_COMPILER}" ]] ; then 4 | shift 5 | fi 6 | 7 | export CCACHE_DIR='${CMAKE_SOURCE_DIR}/.ccache' 8 | export CCACHE_MAXSIZE='1G' 9 | export CCACHE_CPP2=true 10 | export CCACHE_DEPEND=true 11 | export CCACHE_DIRECT=true 12 | export CCACHE_FILECLONE=true 13 | export CCACHE_INODECACHE=true 14 | export CCACHE_COMPILERCHECK='content' 15 | 16 | CCACHE_SLOPPINESS='file_stat_matches,include_file_mtime,include_file_ctime,system_headers' 17 | 18 | if [[ "${CMAKE_C_COMPILER_ID}" == "AppleClang" ]]; then 19 | CCACHE_SLOPPINESS="${CCACHE_SLOPPINESS},modules,clang_index_store" 20 | fi 21 | export CCACHE_SLOPPINESS 22 | 23 | if [[ "${CI}" ]]; then 24 | export CCACHE_NOHASHDIR=true 25 | fi 26 | exec "${CMAKE_CXX_COMPILER_LAUNCHER}" "${CMAKE_CXX_COMPILER}" "$@" 27 | -------------------------------------------------------------------------------- /.github/workflows/pr-pull.yaml: -------------------------------------------------------------------------------- 1 | name: Pull Request 2 | run-name: ${{ github.event.pull_request.title }} pull request run 🚀 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | paths-ignore: 7 | - '**.md' 8 | branches: [master, main] 9 | types: [ opened, synchronize, reopened ] 10 | permissions: 11 | contents: read 12 | concurrency: 13 | group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' 14 | cancel-in-progress: true 15 | jobs: 16 | check-format: 17 | name: Check Formatting 🔍 18 | uses: ./.github/workflows/check-format.yaml 19 | permissions: 20 | contents: read 21 | 22 | build-project: 23 | name: Build Project 🧱 24 | uses: ./.github/workflows/build-project.yaml 25 | secrets: inherit 26 | permissions: 27 | contents: read 28 | -------------------------------------------------------------------------------- /cmake/common/osconfig.cmake: -------------------------------------------------------------------------------- 1 | # CMake operating system bootstrap module 2 | 3 | include_guard(GLOBAL) 4 | 5 | if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") 6 | set(CMAKE_C_EXTENSIONS FALSE) 7 | set(CMAKE_CXX_EXTENSIONS FALSE) 8 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows") 9 | set(OS_WINDOWS TRUE) 10 | elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") 11 | set(CMAKE_C_EXTENSIONS FALSE) 12 | set(CMAKE_CXX_EXTENSIONS FALSE) 13 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos") 14 | set(OS_MACOS TRUE) 15 | elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|FreeBSD|OpenBSD") 16 | set(CMAKE_CXX_EXTENSIONS FALSE) 17 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/linux") 18 | string(TOUPPER "${CMAKE_HOST_SYSTEM_NAME}" _SYSTEM_NAME_U) 19 | set(OS_${_SYSTEM_NAME_U} TRUE) 20 | endif() 21 | -------------------------------------------------------------------------------- /cmake/windows/buildspec.cmake: -------------------------------------------------------------------------------- 1 | # CMake Windows build dependencies module 2 | 3 | include_guard(GLOBAL) 4 | 5 | include(buildspec_common) 6 | 7 | # _check_dependencies_windows: Set up Windows slice for _check_dependencies 8 | function(_check_dependencies_windows) 9 | set(arch ${CMAKE_VS_PLATFORM_NAME}) 10 | set(platform windows-${arch}) 11 | 12 | set(dependencies_dir "${CMAKE_CURRENT_SOURCE_DIR}/.deps") 13 | set(prebuilt_filename "windows-deps-VERSION-ARCH-REVISION.zip") 14 | set(prebuilt_destination "obs-deps-VERSION-ARCH") 15 | set(qt6_filename "windows-deps-qt6-VERSION-ARCH-REVISION.zip") 16 | set(qt6_destination "obs-deps-qt6-VERSION-ARCH") 17 | set(obs-studio_filename "VERSION.zip") 18 | set(obs-studio_destination "obs-studio-VERSION") 19 | set(dependencies_list prebuilt qt6 obs-studio) 20 | 21 | _check_dependencies() 22 | endfunction() 23 | 24 | _check_dependencies_windows() 25 | -------------------------------------------------------------------------------- /.github/scripts/utils.pwsh/Ensure-Location.ps1: -------------------------------------------------------------------------------- 1 | function Ensure-Location { 2 | <# 3 | .SYNOPSIS 4 | Ensures current location to be set to specified directory. 5 | .DESCRIPTION 6 | If specified directory exists, switch to it. Otherwise create it, 7 | then switch. 8 | .EXAMPLE 9 | Ensure-Location "My-Directory" 10 | Ensure-Location -Path "Path-To-My-Directory" 11 | #> 12 | 13 | param( 14 | [Parameter(Mandatory)] 15 | [string] $Path 16 | ) 17 | 18 | if ( ! ( Test-Path $Path ) ) { 19 | $_Params = @{ 20 | ItemType = "Directory" 21 | Path = ${Path} 22 | ErrorAction = "SilentlyContinue" 23 | } 24 | 25 | New-Item @_Params | Set-Location 26 | } else { 27 | Set-Location -Path ${Path} 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /cmake/common/ccache.cmake: -------------------------------------------------------------------------------- 1 | # OBS CMake ccache module 2 | 3 | include_guard(GLOBAL) 4 | 5 | if(NOT DEFINED CCACHE_PROGRAM) 6 | message(DEBUG "Trying to find ccache on build host") 7 | find_program(CCACHE_PROGRAM "ccache") 8 | mark_as_advanced(CCACHE_PROGRAM) 9 | endif() 10 | 11 | if(CCACHE_PROGRAM) 12 | message(DEBUG "Trying to find ccache on build host - done") 13 | message(DEBUG "Ccache found as ${CCACHE_PROGRAM}") 14 | option(ENABLE_CCACHE "Enable compiler acceleration with ccache" OFF) 15 | 16 | if(ENABLE_CCACHE) 17 | set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") 18 | set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") 19 | set(CMAKE_OBJC_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") 20 | set(CMAKE_OBJCXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") 21 | set(CMAKE_CUDA_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") 22 | endif() 23 | else() 24 | message(DEBUG "Trying to find ccache on build host - skipped") 25 | endif() 26 | -------------------------------------------------------------------------------- /cmake/common/buildnumber.cmake: -------------------------------------------------------------------------------- 1 | # CMake build number module 2 | 3 | include_guard(GLOBAL) 4 | 5 | # Define build number cache file 6 | set( 7 | _BUILD_NUMBER_CACHE 8 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/.CMakeBuildNumber" 9 | CACHE INTERNAL 10 | "OBS build number cache file" 11 | ) 12 | 13 | # Read build number from cache file or manual override 14 | if(NOT DEFINED PLUGIN_BUILD_NUMBER) 15 | if(EXISTS "${_BUILD_NUMBER_CACHE}") 16 | file(READ "${_BUILD_NUMBER_CACHE}" PLUGIN_BUILD_NUMBER) 17 | math(EXPR PLUGIN_BUILD_NUMBER "${PLUGIN_BUILD_NUMBER}+1") 18 | else() 19 | if("$ENV{CI}") 20 | if("$ENV{GITHUB_RUN_ID}") 21 | set(PLUGIN_BUILD_NUMBER "$ENV{GITHUB_RUN_ID}") 22 | elseif("$ENV{GITLAB_RUN_ID}") 23 | set(PLUGIN_BUILD_NUMBER "$ENV{GITLAB_RUN_ID}") 24 | else() 25 | set(PLUGIN_BUILD_NUMBER "1") 26 | endif() 27 | endif() 28 | endif() 29 | file(WRITE "${_BUILD_NUMBER_CACHE}" "${PLUGIN_BUILD_NUMBER}") 30 | endif() 31 | -------------------------------------------------------------------------------- /.cmake-format.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": { 3 | "line_width": 120, 4 | "tab_size": 2, 5 | "enable_sort": true, 6 | "autosort": true 7 | }, 8 | "additional_commands": { 9 | "find_qt": { 10 | "flags": [], 11 | "kwargs": { 12 | "COMPONENTS": "+", 13 | "COMPONENTS_WIN": "+", 14 | "COMPONENTS_MACOS": "+", 15 | "COMPONENTS_LINUX": "+" 16 | } 17 | }, 18 | "set_target_properties_obs": { 19 | "pargs": 1, 20 | "flags": [], 21 | "kwargs": { 22 | "PROPERTIES": { 23 | "kwargs": { 24 | "PREFIX": 1, 25 | "OUTPUT_NAME": 1, 26 | "FOLDER": 1, 27 | "VERSION": 1, 28 | "SOVERSION": 1, 29 | "AUTOMOC": 1, 30 | "AUTOUIC": 1, 31 | "AUTORCC": 1, 32 | "AUTOUIC_SEARCH_PATHS": 1, 33 | "BUILD_RPATH": 1, 34 | "INSTALL_RPATH": 1 35 | } 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /resource.rc.in: -------------------------------------------------------------------------------- 1 | 1 VERSIONINFO 2 | FILEVERSION ${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0 3 | PRODUCTVERSION ${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0 4 | FILEFLAGSMASK 0x0L 5 | #ifdef _DEBUG 6 | FILEFLAGS 0x1L 7 | #else 8 | FILEFLAGS 0x0L 9 | #endif 10 | FILEOS 0x0L 11 | FILETYPE 0x2L 12 | FILESUBTYPE 0x0L 13 | BEGIN 14 | BLOCK "StringFileInfo" 15 | BEGIN 16 | BLOCK "040904b0" 17 | BEGIN 18 | VALUE "CompanyName", "Aitum" 19 | VALUE "FileDescription", "${PROJECT_FULL_NAME}" 20 | VALUE "FileVersion", "${PROJECT_VERSION}" 21 | VALUE "InternalName", "${PROJECT_NAME}" 22 | VALUE "LegalCopyright", "(C) Aitum" 23 | VALUE "OriginalFilename", "${PROJECT_NAME}" 24 | VALUE "ProductName", "${PROJECT_FULL_NAME}" 25 | VALUE "ProductVersion", "${PROJECT_VERSION}" 26 | END 27 | END 28 | BLOCK "VarFileInfo" 29 | BEGIN 30 | VALUE "Translation", 0x409, 1200 31 | END 32 | END 33 | -------------------------------------------------------------------------------- /cmake/windows/resources/resource.rc.in: -------------------------------------------------------------------------------- 1 | 1 VERSIONINFO 2 | FILEVERSION ${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0 3 | PRODUCTVERSION ${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0 4 | FILEFLAGSMASK 0x0L 5 | #ifdef _DEBUG 6 | FILEFLAGS 0x1L 7 | #else 8 | FILEFLAGS 0x0L 9 | #endif 10 | FILEOS 0x0L 11 | FILETYPE 0x2L 12 | FILESUBTYPE 0x0L 13 | BEGIN 14 | BLOCK "StringFileInfo" 15 | BEGIN 16 | BLOCK "040904b0" 17 | BEGIN 18 | VALUE "CompanyName", "${PLUGIN_AUTHOR}" 19 | VALUE "FileDescription", "${PROJECT_NAME}" 20 | VALUE "FileVersion", "${PROJECT_VERSION}" 21 | VALUE "InternalName", "${PROJECT_NAME}" 22 | VALUE "LegalCopyright", "(C) ${CURRENT_YEAR} ${PLUGIN_AUTHOR}" 23 | VALUE "OriginalFilename", "${PROJECT_NAME}" 24 | VALUE "ProductName", "${PROJECT_NAME}" 25 | VALUE "ProductVersion", "${PROJECT_VERSION}" 26 | END 27 | END 28 | BLOCK "VarFileInfo" 29 | BEGIN 30 | VALUE "Translation", 0x409, 1200 31 | END 32 | END 33 | -------------------------------------------------------------------------------- /.github/scripts/utils.pwsh/Invoke-External.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-External { 2 | <# 3 | .SYNOPSIS 4 | Invokes a non-PowerShell command. 5 | .DESCRIPTION 6 | Runs a non-PowerShell command, and captures its return code. 7 | Throws an exception if the command returns non-zero. 8 | .EXAMPLE 9 | Invoke-External 7z x $MyArchive 10 | #> 11 | 12 | if ( $args.Count -eq 0 ) { 13 | throw 'Invoke-External called without arguments.' 14 | } 15 | 16 | if ( ! ( Test-Path function:Log-Information ) ) { 17 | . $PSScriptRoot/Logger.ps1 18 | } 19 | 20 | $Command = $args[0] 21 | $CommandArgs = @() 22 | 23 | if ( $args.Count -gt 1) { 24 | $CommandArgs = $args[1..($args.Count - 1)] 25 | } 26 | 27 | $_EAP = $ErrorActionPreference 28 | $ErrorActionPreference = "Continue" 29 | 30 | Log-Debug "Invoke-External: ${Command} ${CommandArgs}" 31 | 32 | & $command $commandArgs 33 | $Result = $LASTEXITCODE 34 | 35 | $ErrorActionPreference = $_EAP 36 | 37 | if ( $Result -ne 0 ) { 38 | throw "${Command} ${CommandArgs} exited with non-zero code ${Result}." 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /cmake/macos/buildspec.cmake: -------------------------------------------------------------------------------- 1 | # CMake macOS build dependencies module 2 | 3 | include_guard(GLOBAL) 4 | 5 | include(buildspec_common) 6 | 7 | # _check_dependencies_macos: Set up macOS slice for _check_dependencies 8 | function(_check_dependencies_macos) 9 | set(arch universal) 10 | set(platform macos) 11 | 12 | file(READ "${CMAKE_CURRENT_SOURCE_DIR}/buildspec.json" buildspec) 13 | 14 | set(dependencies_dir "${CMAKE_CURRENT_SOURCE_DIR}/.deps") 15 | set(prebuilt_filename "macos-deps-VERSION-ARCH_REVISION.tar.xz") 16 | set(prebuilt_destination "obs-deps-VERSION-ARCH") 17 | set(qt6_filename "macos-deps-qt6-VERSION-ARCH-REVISION.tar.xz") 18 | set(qt6_destination "obs-deps-qt6-VERSION-ARCH") 19 | set(obs-studio_filename "VERSION.tar.gz") 20 | set(obs-studio_destination "obs-studio-VERSION") 21 | set(dependencies_list prebuilt qt6 obs-studio) 22 | 23 | _check_dependencies() 24 | 25 | execute_process( 26 | COMMAND "xattr" -r -d com.apple.quarantine "${dependencies_dir}" 27 | RESULT_VARIABLE result 28 | COMMAND_ERROR_IS_FATAL ANY 29 | ) 30 | 31 | list(APPEND CMAKE_FRAMEWORK_PATH "${dependencies_dir}/Frameworks") 32 | set(CMAKE_FRAMEWORK_PATH ${CMAKE_FRAMEWORK_PATH} PARENT_SCOPE) 33 | endfunction() 34 | 35 | _check_dependencies_macos() 36 | -------------------------------------------------------------------------------- /data/locale/zh-CN.ini: -------------------------------------------------------------------------------- 1 | PerfViewer="源性能分析器" 2 | PerfViewer.NoName="(无名称)" 3 | PerfViewer.Search="过滤源..." 4 | PerfViewer.RefreshInterval="刷新间隔" 5 | PerfViewer.OnlyActive="仅显示激活项" 6 | # 列 7 | PerfViewer.Name="名称" 8 | PerfViewer.SourceDisplayName="类型" 9 | PerfViewer.Active="激活" 10 | PerfViewer.Rendered="渲染" 11 | PerfViewer.Enabled="启用" 12 | PerfViewer.TickAvg="平均时钟" 13 | PerfViewer.TickMax="最大时钟" 14 | PerfViewer.RenderAvg="CPU 平均" 15 | PerfViewer.RenderMax="CPU 最大" 16 | PerfViewer.RenderTotal="CPU 总计" 17 | PerfViewer.CpuPercentage="CPU 百分比" 18 | PerfViewer.RenderGpuAvg="GPU 平均" 19 | PerfViewer.RenderGpuMax="GPU 最大" 20 | PerfViewer.RenderGpuTotal="GPU 总计" 21 | PerfViewer.GpuPercentage="GPU 百分比" 22 | PerfViewer.AsyncFps="输入 FPS" 23 | PerfViewer.AsyncBest="输入最佳" 24 | PerfViewer.AsyncWorst="输入最差" 25 | PerfViewer.AsyncRenderedFps="输出 FPS" 26 | PerfViewer.AsyncRenderedBest="输出最佳" 27 | PerfViewer.AsyncRenderedWorst="输出最差" 28 | PerfViewer.Total="总计" 29 | PerfViewer.TotalPercentage="总计百分比" 30 | PerfViewer.SubItems="子项" 31 | PerfViewer.Private="私有" 32 | PerfViewer.SourceType="类型" 33 | PerfViewer.Width="宽度" 34 | PerfViewer.Height="高度" 35 | # 36 | PerfViewer.Columns="列" 37 | PerfViewer.Sort="排序" 38 | PerfViewer.None="无" 39 | # 显示模式 40 | PerfViewer.Scene="场景" 41 | PerfViewer.SceneNested="嵌套场景" 42 | PerfViewer.Source="源" 43 | PerfViewer.Filter="滤镜" 44 | PerfViewer.Transition="过渡" 45 | PerfViewer.All="全部" 46 | -------------------------------------------------------------------------------- /cmake/macos/defaults.cmake: -------------------------------------------------------------------------------- 1 | # CMake macOS defaults module 2 | 3 | include_guard(GLOBAL) 4 | 5 | # Set empty codesigning team if not specified as cache variable 6 | if(NOT CODESIGN_TEAM) 7 | set(CODESIGN_TEAM "" CACHE STRING "OBS code signing team for macOS" FORCE) 8 | 9 | # Set ad-hoc codesigning identity if not specified as cache variable 10 | if(NOT CODESIGN_IDENTITY) 11 | set(CODESIGN_IDENTITY "-" CACHE STRING "OBS code signing identity for macOS" FORCE) 12 | endif() 13 | endif() 14 | 15 | include(xcode) 16 | 17 | include(buildspec) 18 | 19 | # Use Applications directory as default install destination 20 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 21 | set( 22 | CMAKE_INSTALL_PREFIX 23 | "$ENV{HOME}/Library/Application Support/obs-studio/plugins" 24 | CACHE STRING 25 | "Default plugin installation directory" 26 | FORCE 27 | ) 28 | endif() 29 | 30 | # Enable find_package targets to become globally available targets 31 | set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL TRUE) 32 | # Enable RPATH support for generated binaries 33 | set(CMAKE_MACOSX_RPATH TRUE) 34 | # Use RPATHs from build tree _in_ the build tree 35 | set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) 36 | # Do not add default linker search paths to RPATH 37 | set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) 38 | # Use common bundle-relative RPATH for installed targets 39 | set(CMAKE_INSTALL_RPATH "@executable_path/../Frameworks") 40 | -------------------------------------------------------------------------------- /cmake/macos/resources/distribution.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | @CMAKE_PROJECT_NAME@ 10 | 11 | 12 | 13 | 14 | 15 | 16 | #@CMAKE_PROJECT_NAME@.pkg 17 | 18 | 33 | 34 | -------------------------------------------------------------------------------- /data/locale/es-ES.ini: -------------------------------------------------------------------------------- 1 | PerfViewer="Analizador de fuentes" 2 | PerfViewer.NoName="(Sin nombre)" 3 | PerfViewer.Search="Filtrar fuentes..." 4 | PerfViewer.RefreshInterval="Intervalo de refresco" 5 | PerfViewer.OnlyActive="Sólo activos" 6 | # Columns 7 | PerfViewer.Name="Nombre" 8 | PerfViewer.SourceDisplayName="Tipo" 9 | PerfViewer.Active="Activo" 10 | PerfViewer.Rendered="Renderizado" 11 | PerfViewer.Enabled="Activo" 12 | PerfViewer.TickAvg="Marca media" 13 | PerfViewer.TickMax="Marca máx" 14 | PerfViewer.RenderAvg="CPU media" 15 | PerfViewer.RenderMax="CPU máx" 16 | PerfViewer.RenderTotal="CPU total" 17 | PerfViewer.CpuPercentage="CPU %" 18 | PerfViewer.RenderGpuAvg="GPU media" 19 | PerfViewer.RenderGpuMax="GPU máx" 20 | PerfViewer.RenderGpuTotal="GPU total" 21 | PerfViewer.GpuPercentage="GPU %" 22 | PerfViewer.AsyncFps="FPS de entrada" 23 | PerfViewer.AsyncBest="Mejor entrada" 24 | PerfViewer.AsyncWorst="Peor entrada" 25 | PerfViewer.AsyncRenderedFps="FPS de salida" 26 | PerfViewer.AsyncRenderedBest="Mejor salida" 27 | PerfViewer.AsyncRenderedWorst="Peor salida" 28 | PerfViewer.Total="Total" 29 | PerfViewer.TotalPercentage="Total %" 30 | PerfViewer.SubItems="Sub items" 31 | PerfViewer.Private="Privado" 32 | PerfViewer.SourceType="Tipo" 33 | PerfViewer.Width="Ancho" 34 | PerfViewer.Height="Alto" 35 | # 36 | PerfViewer.Columns="Columnas" 37 | PerfViewer.Sort="Ordenar" 38 | PerfViewer.None="Ninguno" 39 | # show mode 40 | PerfViewer.Scene="Escena" 41 | PerfViewer.SceneNested="Escena anidada" 42 | PerfViewer.Source="Fuente" 43 | PerfViewer.Filter="Filtro" 44 | PerfViewer.Transition="Transición" 45 | PerfViewer.All="Todos" 46 | -------------------------------------------------------------------------------- /data/locale/en-US.ini: -------------------------------------------------------------------------------- 1 | PerfViewer="Source Profiler" 2 | PerfViewer.NoName="(No Name)" 3 | PerfViewer.Search="Filter sources..." 4 | PerfViewer.RefreshInterval="Refresh interval" 5 | PerfViewer.OnlyActive="Only Active" 6 | # Columns 7 | PerfViewer.Name="Name" 8 | PerfViewer.SourceDisplayName="Type" 9 | PerfViewer.Active="Active" 10 | PerfViewer.Rendered="Rendered" 11 | PerfViewer.Enabled="Enabled" 12 | PerfViewer.TickAvg="Tick avg" 13 | PerfViewer.TickMax="Tick max" 14 | PerfViewer.RenderAvg="CPU avg" 15 | PerfViewer.RenderMax="CPU max" 16 | PerfViewer.RenderTotal="CPU total" 17 | PerfViewer.CpuPercentage="CPU %" 18 | PerfViewer.RenderGpuAvg="GPU avg" 19 | PerfViewer.RenderGpuMax="GPU max" 20 | PerfViewer.RenderGpuTotal="GPU total" 21 | PerfViewer.GpuPercentage="GPU %" 22 | PerfViewer.AsyncFps="Input FPS" 23 | PerfViewer.AsyncBest="Input best" 24 | PerfViewer.AsyncWorst="Input worst" 25 | PerfViewer.AsyncRenderedFps="Output FPS" 26 | PerfViewer.AsyncRenderedBest="Output best" 27 | PerfViewer.AsyncRenderedWorst="Output worst" 28 | PerfViewer.Total="Total" 29 | PerfViewer.TotalPercentage="Total %" 30 | PerfViewer.SubItems="Sub items" 31 | PerfViewer.Private="Private" 32 | PerfViewer.SourceType="Type" 33 | PerfViewer.Width="Width" 34 | PerfViewer.Height="Height" 35 | PerfViewer.TotalPercentageGraph="Graph total %" 36 | # 37 | PerfViewer.Columns="Columns" 38 | PerfViewer.Sort="Sort" 39 | PerfViewer.None="None" 40 | # show mode 41 | PerfViewer.Scene="Scene" 42 | PerfViewer.SceneNested="Scene Nested" 43 | PerfViewer.Source="Source" 44 | PerfViewer.Filter="Filter" 45 | PerfViewer.Transition="Transition" 46 | PerfViewer.All="All" 47 | -------------------------------------------------------------------------------- /.github/scripts/utils.zsh/setup_ubuntu: -------------------------------------------------------------------------------- 1 | autoload -Uz log_error log_status log_info mkcd 2 | 3 | if (( ! ${+project_root} )) { 4 | log_error "'project_root' not set. Please set before running ${0}." 5 | return 2 6 | } 7 | 8 | if (( ! ${+target} )) { 9 | log_error "'target' not set. Please set before running ${0}." 10 | return 2 11 | } 12 | 13 | pushd ${project_root} 14 | 15 | typeset -g QT_VERSION 16 | 17 | local -a apt_args=( 18 | ${CI:+-y} 19 | --no-install-recommends 20 | ) 21 | if (( _loglevel == 0 )) apt_args+=(--quiet) 22 | 23 | if (( ! (${skips[(Ie)all]} + ${skips[(Ie)deps]}) )) { 24 | log_group 'Installing obs-studio build dependencies...' 25 | 26 | local suffix 27 | if [[ ${CPUTYPE} != "${target##*-}" ]] { 28 | local -A arch_mappings=( 29 | aarch64 arm64 30 | x86_64 amd64 31 | ) 32 | 33 | suffix=":${arch_mappings[${target##*-}]}" 34 | 35 | sudo apt-get install ${apt_args} gcc-${${target##*-}//_/-}-linux-gnu g++-${${target##*-}//_/-}-linux-gnu 36 | } 37 | 38 | sudo add-apt-repository --yes ppa:obsproject/obs-studio 39 | sudo apt update 40 | 41 | sudo apt-get install ${apt_args} \ 42 | build-essential \ 43 | libgles2-mesa-dev \ 44 | libsimde-dev \ 45 | obs-studio 46 | 47 | local -a _qt_packages=() 48 | 49 | if (( QT_VERSION == 5 )) { 50 | _qt_packages+=( 51 | qtbase5-dev${suffix} 52 | libqt5svg5-dev${suffix} 53 | qtbase5-private-dev${suffix} 54 | libqt5x11extras5-dev${suffix} 55 | ) 56 | } else { 57 | _qt_packages+=( 58 | qt6-base-dev${suffix} 59 | libqt6svg6-dev${suffix} 60 | qt6-base-private-dev${suffix} 61 | ) 62 | } 63 | 64 | sudo apt-get install ${apt_args} ${_qt_packages} 65 | log_group 66 | } 67 | -------------------------------------------------------------------------------- /.github/scripts/utils.zsh/check_ubuntu: -------------------------------------------------------------------------------- 1 | autoload -Uz log_info log_status log_error log_debug log_warning log_group 2 | 3 | log_group 'Check Linux build requirements' 4 | log_debug 'Checking Linux distribution name and version...' 5 | 6 | # Check for Ubuntu version 22.10 or later, which have srt and librist available via apt-get 7 | typeset -g -i UBUNTU_2210_OR_LATER=0 8 | if [[ -f /etc/os_release ]] { 9 | local dist_name 10 | local dist_version 11 | read -r dist_name dist_version <<< "$(source /etc/os_release; print "${NAME} ${VERSION_ID}")" 12 | 13 | autoload -Uz is-at-least 14 | if [[ ${dist_name} == Ubuntu ]] && is-at-least 22.10 ${dist_version}; then 15 | typeset -g -i UBUNTU_2210_OR_LATER=1 16 | fi 17 | } 18 | 19 | log_debug 'Checking for apt-get...' 20 | if (( ! ${+commands[apt-get]} )) { 21 | log_error 'No apt-get command found. Please install apt' 22 | return 2 23 | } else { 24 | log_debug "Apt-get located at ${commands[apt-get]}" 25 | } 26 | 27 | local -a dependencies=("${(fA)$(<${SCRIPT_HOME}/.Aptfile)}") 28 | local -a install_list 29 | local binary 30 | 31 | sudo apt-get update -qq 32 | 33 | for dependency (${dependencies}) { 34 | local -a tokens=(${=dependency//(,|:|\')/}) 35 | 36 | if [[ ! ${tokens[1]} == 'package' ]] continue 37 | 38 | if [[ ${#tokens} -gt 2 && ${tokens[3]} == 'bin' ]] { 39 | binary=${tokens[4]} 40 | } else { 41 | binary=${tokens[2]} 42 | } 43 | 44 | if (( ! ${+commands[${binary}]} )) install_list+=(${tokens[2]}) 45 | } 46 | 47 | log_debug "List of dependencies to install: ${install_list}" 48 | if (( ${#install_list} )) { 49 | if (( ! ${+CI} )) log_warning 'Dependency installation via apt may require elevated privileges' 50 | 51 | local -a apt_args=( 52 | ${CI:+-y} 53 | --no-install-recommends 54 | ) 55 | if (( _loglevel == 0 )) apt_args+=(--quiet) 56 | 57 | sudo apt-get ${apt_args} install ${install_list} 58 | } 59 | 60 | rehash 61 | log_group 62 | -------------------------------------------------------------------------------- /cmake/common/helpers_common.cmake: -------------------------------------------------------------------------------- 1 | # CMake common helper functions module 2 | 3 | include_guard(GLOBAL) 4 | 5 | # check_uuid: Helper function to check for valid UUID 6 | function(check_uuid uuid_string return_value) 7 | set(valid_uuid TRUE) 8 | # gersemi: off 9 | set(uuid_token_lengths 8 4 4 4 12) 10 | # gersemi: on 11 | set(token_num 0) 12 | 13 | string(REPLACE "-" ";" uuid_tokens ${uuid_string}) 14 | list(LENGTH uuid_tokens uuid_num_tokens) 15 | 16 | if(uuid_num_tokens EQUAL 5) 17 | message(DEBUG "UUID ${uuid_string} is valid with 5 tokens.") 18 | foreach(uuid_token IN LISTS uuid_tokens) 19 | list(GET uuid_token_lengths ${token_num} uuid_target_length) 20 | string(LENGTH "${uuid_token}" uuid_actual_length) 21 | if(uuid_actual_length EQUAL uuid_target_length) 22 | string(REGEX MATCH "[0-9a-fA-F]+" uuid_hex_match ${uuid_token}) 23 | if(NOT uuid_hex_match STREQUAL uuid_token) 24 | set(valid_uuid FALSE) 25 | break() 26 | endif() 27 | else() 28 | set(valid_uuid FALSE) 29 | break() 30 | endif() 31 | math(EXPR token_num "${token_num}+1") 32 | endforeach() 33 | else() 34 | set(valid_uuid FALSE) 35 | endif() 36 | message(DEBUG "UUID ${uuid_string} valid: ${valid_uuid}") 37 | set(${return_value} ${valid_uuid} PARENT_SCOPE) 38 | endfunction() 39 | 40 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/plugin-support.c.in") 41 | configure_file(src/plugin-support.c.in plugin-support.c @ONLY) 42 | add_library(plugin-support STATIC) 43 | target_sources(plugin-support PRIVATE plugin-support.c PUBLIC src/plugin-support.h) 44 | target_include_directories(plugin-support PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src") 45 | if(OS_LINUX OR OS_FREEBSD OR OS_OPENBSD) 46 | # add fPIC on Linux to prevent shared object errors 47 | set_property(TARGET plugin-support PROPERTY POSITION_INDEPENDENT_CODE ON) 48 | endif() 49 | endif() 50 | -------------------------------------------------------------------------------- /cmake/windows/compilerconfig.cmake: -------------------------------------------------------------------------------- 1 | # CMake Windows compiler configuration module 2 | 3 | include_guard(GLOBAL) 4 | 5 | include(compiler_common) 6 | 7 | set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT ProgramDatabase) 8 | 9 | message(DEBUG "Current Windows API version: ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}") 10 | if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM) 11 | message(DEBUG "Maximum Windows API version: ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM}") 12 | endif() 13 | 14 | if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION VERSION_LESS 10.0.20348) 15 | message( 16 | FATAL_ERROR 17 | "OBS requires Windows 10 SDK version 10.0.20348.0 or more recent.\n" 18 | "Please download and install the most recent Windows platform SDK." 19 | ) 20 | endif() 21 | 22 | set(_obs_msvc_c_options /MP /Zc:__cplusplus /Zc:preprocessor) 23 | set(_obs_msvc_cpp_options /MP /Zc:__cplusplus /Zc:preprocessor) 24 | 25 | if(CMAKE_CXX_STANDARD GREATER_EQUAL 20) 26 | list(APPEND _obs_msvc_cpp_options /Zc:char8_t-) 27 | endif() 28 | 29 | add_compile_options( 30 | /W3 31 | /utf-8 32 | /Brepro 33 | /permissive- 34 | "$<$:${_obs_msvc_c_options}>" 35 | "$<$:${_obs_msvc_cpp_options}>" 36 | "$<$:${_obs_clang_c_options}>" 37 | "$<$:${_obs_clang_cxx_options}>" 38 | $<$>:/Gy> 39 | $<$>:/GL> 40 | $<$>:/Oi> 41 | ) 42 | 43 | add_compile_definitions( 44 | UNICODE 45 | _UNICODE 46 | _CRT_SECURE_NO_WARNINGS 47 | _CRT_NONSTDC_NO_WARNINGS 48 | $<$:DEBUG> 49 | $<$:_DEBUG> 50 | ) 51 | 52 | add_link_options( 53 | $<$>:/OPT:REF> 54 | $<$>:/OPT:ICF> 55 | $<$>:/LTCG> 56 | $<$>:/INCREMENTAL:NO> 57 | /DEBUG 58 | /Brepro 59 | ) 60 | 61 | if(CMAKE_COMPILE_WARNING_AS_ERROR) 62 | add_link_options(/WX) 63 | endif() 64 | -------------------------------------------------------------------------------- /cmake/macos/resources/create-package.cmake.in: -------------------------------------------------------------------------------- 1 | make_directory("$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/package/Library/Application Support/obs-studio/plugins") 2 | 3 | if(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/@CMAKE_PROJECT_NAME@.plugin" AND NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/@CMAKE_PROJECT_NAME@.plugin") 4 | file(INSTALL DESTINATION "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/package/Library/Application Support/obs-studio/plugins" 5 | TYPE DIRECTORY FILES "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/@CMAKE_PROJECT_NAME@.plugin" USE_SOURCE_PERMISSIONS) 6 | 7 | if(CMAKE_INSTALL_CONFIG_NAME MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$" OR CMAKE_INSTALL_CONFIG_NAME MATCHES "^([Mm][Ii][Nn][Ss][Ii][Zz][Ee][Rr][Ee][Ll])$") 8 | if(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/@CMAKE_PROJECT_NAME@.plugin.dSYM" AND NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/@CMAKE_PROJECT_NAME@.plugin.dSYM") 9 | file(INSTALL DESTINATION "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/package/Library/Application Support/obs-studio/plugins" TYPE DIRECTORY FILES "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/@CMAKE_PROJECT_NAME@.plugin.dSYM" USE_SOURCE_PERMISSIONS) 10 | endif() 11 | endif() 12 | endif() 13 | 14 | make_directory("$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/temp") 15 | 16 | execute_process( 17 | COMMAND /usr/bin/pkgbuild 18 | --identifier '@MACOS_BUNDLEID@' 19 | --version '@CMAKE_PROJECT_VERSION@' 20 | --root "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/package" 21 | "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/temp/@CMAKE_PROJECT_NAME@.pkg" 22 | COMMAND_ERROR_IS_FATAL ANY 23 | ) 24 | 25 | execute_process( 26 | COMMAND /usr/bin/productbuild 27 | --distribution "@CMAKE_CURRENT_BINARY_DIR@/distribution" 28 | --package-path "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/temp" 29 | "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/@CMAKE_PROJECT_NAME@.pkg" 30 | COMMAND_ERROR_IS_FATAL ANY) 31 | 32 | if(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/@CMAKE_PROJECT_NAME@.pkg") 33 | file(REMOVE_RECURSE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/temp") 34 | file(REMOVE_RECURSE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/package") 35 | endif() 36 | -------------------------------------------------------------------------------- /.github/actions/run-gersemi/action.yaml: -------------------------------------------------------------------------------- 1 | name: Run gersemi 2 | description: Runs gersemi and checks for any changes introduced by it 3 | inputs: 4 | failCondition: 5 | description: Controls whether failed checks also fail the workflow run 6 | required: false 7 | default: never 8 | workingDirectory: 9 | description: Working directory for checks 10 | required: false 11 | default: ${{ github.workspace }} 12 | runs: 13 | using: composite 14 | steps: 15 | - name: Check Runner Operating System 🏃‍♂️ 16 | if: runner.os == 'Windows' 17 | shell: bash 18 | run: | 19 | : Check Runner Operating System 🏃‍♂️ 20 | echo "::notice::run-gersemi action requires a macOS-based or Linux-based runner." 21 | exit 2 22 | 23 | - name: Check for Changed Files ✅ 24 | uses: ./.github/actions/check-changes 25 | id: checks 26 | with: 27 | checkGlob: "'*.cmake' '*CMakeLists.txt'" 28 | diffFilter: 'ACM' 29 | 30 | - name: Install Dependencies 🛍️ 31 | if: runner.os == 'Linux' && fromJSON(steps.checks.outputs.hasChangedFiles) 32 | shell: bash 33 | run: | 34 | : Install Dependencies 🛍️ 35 | echo ::group::Install Dependencies 36 | eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" 37 | echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH 38 | brew install --quiet zsh 39 | echo ::endgroup:: 40 | 41 | - name: Run gersemi 🎛️ 42 | if: fromJSON(steps.checks.outputs.hasChangedFiles) 43 | id: result 44 | shell: zsh --no-rcs --errexit --pipefail {0} 45 | working-directory: ${{ github.workspace }} 46 | env: 47 | CHANGED_FILES: ${{ steps.checks.outputs.changedFiles }} 48 | run: | 49 | : Run gersemi 🎛️ 50 | if (( ${+RUNNER_DEBUG} )) setopt XTRACE 51 | 52 | print ::group::Install gersemi 53 | brew install --quiet obsproject/tools/gersemi 54 | print ::endgroup:: 55 | 56 | print ::group::Run gersemi 57 | local -a changes=(${(s:,:)CHANGED_FILES//[\[\]\'\"]/}) 58 | ./build-aux/run-gersemi --fail-${{ inputs.failCondition }} --check ${changes} 59 | print ::endgroup:: 60 | -------------------------------------------------------------------------------- /cmake/common/compiler_common.cmake: -------------------------------------------------------------------------------- 1 | # CMake common compiler options module 2 | 3 | include_guard(GLOBAL) 4 | 5 | # Set C and C++ language standards to C17 and C++17 6 | set(CMAKE_C_STANDARD 17) 7 | set(CMAKE_C_STANDARD_REQUIRED TRUE) 8 | set(CMAKE_CXX_STANDARD 17) 9 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 10 | 11 | # Set symbols to be hidden by default for C and C++ 12 | set(CMAKE_C_VISIBILITY_PRESET hidden) 13 | set(CMAKE_CXX_VISIBILITY_PRESET hidden) 14 | set(CMAKE_VISIBILITY_INLINES_HIDDEN TRUE) 15 | 16 | # clang options for C, C++, ObjC, and ObjC++ 17 | set( 18 | _obs_clang_common_options 19 | -fno-strict-aliasing 20 | -Wno-trigraphs 21 | -Wno-missing-field-initializers 22 | -Wno-missing-prototypes 23 | -Werror=return-type 24 | -Wunreachable-code 25 | -Wquoted-include-in-framework-header 26 | -Wno-missing-braces 27 | -Wparentheses 28 | -Wswitch 29 | -Wno-unused-function 30 | -Wno-unused-label 31 | -Wunused-parameter 32 | -Wunused-variable 33 | -Wunused-value 34 | -Wempty-body 35 | -Wuninitialized 36 | -Wno-unknown-pragmas 37 | -Wfour-char-constants 38 | -Wconstant-conversion 39 | -Wno-conversion 40 | -Wint-conversion 41 | -Wbool-conversion 42 | -Wenum-conversion 43 | -Wnon-literal-null-conversion 44 | -Wsign-compare 45 | -Wshorten-64-to-32 46 | -Wpointer-sign 47 | -Wnewline-eof 48 | -Wno-implicit-fallthrough 49 | -Wdeprecated-declarations 50 | -Wno-sign-conversion 51 | -Winfinite-recursion 52 | -Wcomma 53 | -Wno-strict-prototypes 54 | -Wno-semicolon-before-method-body 55 | -Wformat-security 56 | -Wvla 57 | -Wno-error=shorten-64-to-32 58 | ) 59 | 60 | # clang options for C 61 | set(_obs_clang_c_options ${_obs_clang_common_options} -Wno-shadow -Wno-float-conversion) 62 | 63 | # clang options for C++ 64 | set( 65 | _obs_clang_cxx_options 66 | ${_obs_clang_common_options} 67 | -Wno-non-virtual-dtor 68 | -Wno-overloaded-virtual 69 | -Wno-exit-time-destructors 70 | -Wno-shadow 71 | -Winvalid-offsetof 72 | -Wmove 73 | -Werror=block-capture-autoreleasing 74 | -Wrange-loop-analysis 75 | ) 76 | 77 | if(CMAKE_CXX_STANDARD GREATER_EQUAL 20) 78 | list(APPEND _obs_clang_cxx_options -fno-char8_t) 79 | endif() 80 | 81 | if(NOT DEFINED CMAKE_COMPILE_WARNING_AS_ERROR) 82 | set(CMAKE_COMPILE_WARNING_AS_ERROR ON) 83 | endif() 84 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # --- Detect if the plugin is build out of tree or not --- 2 | if(CMAKE_PROJECT_NAME STREQUAL "obs-studio") 3 | set(BUILD_OUT_OF_TREE OFF) 4 | else() 5 | set(BUILD_OUT_OF_TREE ON) 6 | cmake_minimum_required(VERSION 3.16...3.26) 7 | endif() 8 | include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake" NO_POLICY_SCOPE) 9 | 10 | project(${_name} VERSION ${_version}) 11 | 12 | include(compilerconfig) 13 | include(defaults) 14 | include(helpers) 15 | 16 | add_library(${PROJECT_NAME} MODULE) 17 | 18 | target_link_libraries(${PROJECT_NAME} PRIVATE OBS::libobs) 19 | 20 | if(BUILD_OUT_OF_TREE) 21 | find_package(libobs REQUIRED) 22 | find_package(obs-frontend-api REQUIRED) 23 | target_link_libraries(${PROJECT_NAME} PRIVATE OBS::obs-frontend-api) 24 | else() 25 | target_link_libraries(${PROJECT_NAME} PRIVATE OBS::frontend-api) 26 | endif() 27 | 28 | find_package(Qt6 COMPONENTS Widgets Core) 29 | if(BUILD_OUT_OF_TREE) 30 | if(OS_LINUX OR OS_FREEBSD OR OS_OPENBSD) 31 | find_package(Qt6 REQUIRED Gui) 32 | endif() 33 | endif() 34 | target_link_libraries(${PROJECT_NAME} PRIVATE Qt::Core Qt::Widgets) 35 | 36 | if((OS_LINUX OR OS_FREEBSD OR OS_OPENBSD) AND Qt_VERSION VERSION_LESS "6.9.0") 37 | target_link_libraries(${PROJECT_NAME} PRIVATE Qt::GuiPrivate) 38 | endif() 39 | 40 | target_compile_options( 41 | ${PROJECT_NAME} PRIVATE $<$:-Wno-quoted-include-in-framework-header 42 | -Wno-comma>) 43 | set_target_properties(${PROJECT_NAME} PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") 44 | set_target_properties( 45 | ${PROJECT_NAME} 46 | PROPERTIES AUTOMOC ON 47 | AUTOUIC ON 48 | AUTORCC ON) 49 | 50 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_SOURCE_DIR}/version.h) 51 | 52 | if(OS_WINDOWS) 53 | configure_file(cmake/windows/resources/installer-Windows.iss.in "${CMAKE_CURRENT_BINARY_DIR}/installer-Windows.generated.iss") 54 | endif() 55 | 56 | target_sources(${PROJECT_NAME} PRIVATE 57 | source-profiler.cpp 58 | source-profiler.hpp 59 | version.h) 60 | 61 | if(BUILD_OUT_OF_TREE) 62 | set_target_properties_plugin(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${_name}) 63 | else() 64 | set_target_properties_obs(${PROJECT_NAME} PROPERTIES FOLDER "plugins/exeldro" PREFIX "") 65 | endif() 66 | -------------------------------------------------------------------------------- /.github/actions/run-clang-format/action.yaml: -------------------------------------------------------------------------------- 1 | name: Run clang-format 2 | description: Runs clang-format and checks for any changes introduced by it 3 | inputs: 4 | failCondition: 5 | description: Controls whether failed checks also fail the workflow run 6 | required: false 7 | default: never 8 | workingDirectory: 9 | description: Working directory for checks 10 | required: false 11 | default: ${{ github.workspace }} 12 | runs: 13 | using: composite 14 | steps: 15 | - name: Check Runner Operating System 🏃‍♂️ 16 | if: runner.os == 'Windows' 17 | shell: bash 18 | run: | 19 | : Check Runner Operating System 🏃‍♂️ 20 | echo "::notice::run-clang-format action requires a macOS-based or Linux-based runner." 21 | exit 2 22 | 23 | - name: Check for Changed Files ✅ 24 | uses: ./.github/actions/check-changes 25 | id: checks 26 | with: 27 | checkGlob: "'*.c' '*.h' '*.cpp' '*.hpp' '*.m' '*.mm'" 28 | diffFilter: 'ACM' 29 | 30 | - name: Install Dependencies 🛍️ 31 | if: runner.os == 'Linux' && fromJSON(steps.checks.outputs.hasChangedFiles) 32 | shell: bash 33 | run: | 34 | : Install Dependencies 🛍️ 35 | echo ::group::Install Dependencies 36 | eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" 37 | echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH 38 | echo "/home/linuxbrew/.linuxbrew/opt/clang-format@17/bin" >> $GITHUB_PATH 39 | brew install --quiet zsh 40 | echo ::endgroup:: 41 | 42 | - name: Run clang-format 🐉 43 | if: fromJSON(steps.checks.outputs.hasChangedFiles) 44 | id: result 45 | shell: zsh --no-rcs --errexit --pipefail {0} 46 | working-directory: ${{ inputs.workingDirectory }} 47 | env: 48 | CHANGED_FILES: ${{ steps.checks.outputs.changedFiles }} 49 | run: | 50 | : Run clang-format 🐉 51 | if (( ${+RUNNER_DEBUG} )) setopt XTRACE 52 | 53 | print ::group::Install clang-format-17 54 | brew install --quiet obsproject/tools/clang-format@17 55 | print ::endgroup:: 56 | 57 | print ::group::Run clang-format-17 58 | local -a changes=(${(s:,:)CHANGED_FILES//[\[\]\'\"]/}) 59 | ./build-aux/run-clang-format --fail-${{ inputs.failCondition }} --check ${changes} 60 | print ::endgroup:: 61 | -------------------------------------------------------------------------------- /cmake/common/bootstrap.cmake: -------------------------------------------------------------------------------- 1 | # Plugin bootstrap module 2 | 3 | include_guard(GLOBAL) 4 | 5 | # Map fallback configurations for optimized build configurations 6 | # gersemi: off 7 | set( 8 | CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO 9 | RelWithDebInfo 10 | Release 11 | MinSizeRel 12 | None 13 | "" 14 | ) 15 | set( 16 | CMAKE_MAP_IMPORTED_CONFIG_MINSIZEREL 17 | MinSizeRel 18 | Release 19 | RelWithDebInfo 20 | None 21 | "" 22 | ) 23 | set( 24 | CMAKE_MAP_IMPORTED_CONFIG_RELEASE 25 | Release 26 | RelWithDebInfo 27 | MinSizeRel 28 | None 29 | "" 30 | ) 31 | # gersemi: on 32 | 33 | # Add common module directories to default search path 34 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/common") 35 | 36 | file(READ "${CMAKE_CURRENT_SOURCE_DIR}/buildspec.json" buildspec) 37 | 38 | string(JSON _name GET ${buildspec} name) 39 | string(JSON _website GET ${buildspec} website) 40 | string(JSON _author GET ${buildspec} author) 41 | string(JSON _email GET ${buildspec} email) 42 | string(JSON _version GET ${buildspec} version) 43 | string(JSON _bundleId GET ${buildspec} platformConfig macos bundleId) 44 | string(JSON _uuidApp GET ${buildspec} uuids windowsApp) 45 | 46 | set(PLUGIN_AUTHOR ${_author}) 47 | set(PLUGIN_WEBSITE ${_website}) 48 | set(PLUGIN_EMAIL ${_email}) 49 | set(PLUGIN_VERSION ${_version}) 50 | set(MACOS_BUNDLEID ${_bundleId}) 51 | set(UUID_APP ${_uuidApp}) 52 | 53 | string(REPLACE "." ";" _version_canonical "${_version}") 54 | list(GET _version_canonical 0 PLUGIN_VERSION_MAJOR) 55 | list(GET _version_canonical 1 PLUGIN_VERSION_MINOR) 56 | list(GET _version_canonical 2 PLUGIN_VERSION_PATCH) 57 | unset(_version_canonical) 58 | 59 | include(buildnumber) 60 | include(osconfig) 61 | 62 | # Allow selection of common build types via UI 63 | if(NOT CMAKE_GENERATOR MATCHES "(Xcode|Visual Studio .+)") 64 | if(NOT CMAKE_BUILD_TYPE) 65 | set( 66 | CMAKE_BUILD_TYPE 67 | "RelWithDebInfo" 68 | CACHE STRING 69 | "OBS build type [Release, RelWithDebInfo, Debug, MinSizeRel]" 70 | FORCE 71 | ) 72 | set_property( 73 | CACHE CMAKE_BUILD_TYPE 74 | PROPERTY STRINGS Release RelWithDebInfo Debug MinSizeRel 75 | ) 76 | endif() 77 | endif() 78 | 79 | # Disable exports automatically going into the CMake package registry 80 | set(CMAKE_EXPORT_PACKAGE_REGISTRY FALSE) 81 | # Enable default inclusion of targets' source and binary directory 82 | set(CMAKE_INCLUDE_CURRENT_DIR TRUE) 83 | -------------------------------------------------------------------------------- /.github/scripts/Build-Windows.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param( 3 | [ValidateSet('x64')] 4 | [string] $Target = 'x64', 5 | [ValidateSet('Debug', 'RelWithDebInfo', 'Release', 'MinSizeRel')] 6 | [string] $Configuration = 'RelWithDebInfo' 7 | ) 8 | 9 | $ErrorActionPreference = 'Stop' 10 | 11 | if ( $DebugPreference -eq 'Continue' ) { 12 | $VerbosePreference = 'Continue' 13 | $InformationPreference = 'Continue' 14 | } 15 | 16 | if ( $env:CI -eq $null ) { 17 | throw "Build-Windows.ps1 requires CI environment" 18 | } 19 | 20 | if ( ! ( [System.Environment]::Is64BitOperatingSystem ) ) { 21 | throw "A 64-bit system is required to build the project." 22 | } 23 | 24 | if ( $PSVersionTable.PSVersion -lt '7.2.0' ) { 25 | Write-Warning 'The obs-studio PowerShell build script requires PowerShell Core 7. Install or upgrade your PowerShell version: https://aka.ms/pscore6' 26 | exit 2 27 | } 28 | 29 | function Build { 30 | trap { 31 | Pop-Location -Stack BuildTemp -ErrorAction 'SilentlyContinue' 32 | Write-Error $_ 33 | Log-Group 34 | exit 2 35 | } 36 | 37 | $ScriptHome = $PSScriptRoot 38 | $ProjectRoot = Resolve-Path -Path "$PSScriptRoot/../.." 39 | 40 | $UtilityFunctions = Get-ChildItem -Path $PSScriptRoot/utils.pwsh/*.ps1 -Recurse 41 | 42 | foreach($Utility in $UtilityFunctions) { 43 | Write-Debug "Loading $($Utility.FullName)" 44 | . $Utility.FullName 45 | } 46 | 47 | Push-Location -Stack BuildTemp 48 | Ensure-Location $ProjectRoot 49 | 50 | $CmakeArgs = @('--preset', "windows-ci-${Target}") 51 | $CmakeBuildArgs = @('--build') 52 | $CmakeInstallArgs = @() 53 | 54 | if ( $DebugPreference -eq 'Continue' ) { 55 | $CmakeArgs += ('--debug-output') 56 | $CmakeBuildArgs += ('--verbose') 57 | $CmakeInstallArgs += ('--verbose') 58 | } 59 | 60 | $CmakeBuildArgs += @( 61 | '--preset', "windows-${Target}" 62 | '--config', $Configuration 63 | '--parallel' 64 | '--', '/consoleLoggerParameters:Summary', '/noLogo' 65 | ) 66 | 67 | $CmakeInstallArgs += @( 68 | '--install', "build_${Target}" 69 | '--prefix', "${ProjectRoot}/release/${Configuration}" 70 | '--config', $Configuration 71 | ) 72 | 73 | Log-Group "Configuring ${ProductName}..." 74 | Invoke-External cmake @CmakeArgs 75 | 76 | Log-Group "Building ${ProductName}..." 77 | Invoke-External cmake @CmakeBuildArgs 78 | 79 | Log-Group "Installing ${ProductName}..." 80 | Invoke-External cmake @CmakeInstallArgs 81 | 82 | Pop-Location -Stack BuildTemp 83 | Log-Group 84 | } 85 | 86 | Build 87 | -------------------------------------------------------------------------------- /cmake/linux/compilerconfig.cmake: -------------------------------------------------------------------------------- 1 | # CMake Linux compiler configuration module 2 | 3 | include_guard(GLOBAL) 4 | 5 | include(ccache) 6 | include(compiler_common) 7 | 8 | option(ENABLE_COMPILER_TRACE "Enable Clang time-trace (required Clang and Ninja)" OFF) 9 | mark_as_advanced(ENABLE_COMPILER_TRACE) 10 | 11 | # gcc options for C 12 | set( 13 | _obs_gcc_c_options 14 | -fno-strict-aliasing 15 | -fopenmp-simd 16 | -Wdeprecated-declarations 17 | -Wempty-body 18 | -Wenum-conversion 19 | -Werror=return-type 20 | -Wextra 21 | -Wformat 22 | -Wformat-security 23 | -Wno-conversion 24 | -Wno-float-conversion 25 | -Wno-implicit-fallthrough 26 | -Wno-missing-braces 27 | -Wno-missing-field-initializers 28 | -Wno-shadow 29 | -Wno-sign-conversion 30 | -Wno-trigraphs 31 | -Wno-unknown-pragmas 32 | -Wno-unused-function 33 | -Wno-unused-label 34 | -Wparentheses 35 | -Wuninitialized 36 | -Wunreachable-code 37 | -Wunused-parameter 38 | -Wunused-value 39 | -Wunused-variable 40 | -Wvla 41 | ) 42 | 43 | add_compile_options( 44 | -fopenmp-simd 45 | "$<$:${_obs_gcc_c_options}>" 46 | "$<$:-Wint-conversion;-Wno-missing-prototypes;-Wno-strict-prototypes;-Wpointer-sign>" 47 | "$<$:${_obs_gcc_c_options}>" 48 | "$<$:-Winvalid-offsetof;-Wno-overloaded-virtual>" 49 | "$<$:${_obs_clang_c_options}>" 50 | "$<$:${_obs_clang_cxx_options}>" 51 | ) 52 | 53 | if(CMAKE_CXX_COMPILER_ID STREQUAL GNU) 54 | # * Disable false-positive warning in GCC 12.1.0 and later 55 | # * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105562 56 | if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.1.0) 57 | add_compile_options(-Wno-error=maybe-uninitialized) 58 | endif() 59 | 60 | # * Add warning for infinite recursion (added in GCC 12) 61 | # * Also disable warnings for stringop-overflow due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106297 62 | if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0.0) 63 | add_compile_options(-Winfinite-recursion -Wno-stringop-overflow) 64 | endif() 65 | 66 | if(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64) 67 | add_compile_options(-Wno-error=type-limits) 68 | endif() 69 | endif() 70 | 71 | # Enable compiler and build tracing (requires Ninja generator) 72 | if(ENABLE_COMPILER_TRACE AND CMAKE_GENERATOR STREQUAL "Ninja") 73 | add_compile_options($<$:-ftime-trace> $<$:-ftime-trace>) 74 | else() 75 | set(ENABLE_COMPILER_TRACE OFF CACHE STRING "Enable Clang time-trace (required Clang and Ninja)" FORCE) 76 | endif() 77 | 78 | add_compile_definitions($<$:DEBUG> $<$:_DEBUG> SIMDE_ENABLE_OPENMP) 79 | -------------------------------------------------------------------------------- /cmake/linux/defaults.cmake: -------------------------------------------------------------------------------- 1 | # CMake Linux defaults module 2 | 3 | include_guard(GLOBAL) 4 | 5 | # Set default installation directories 6 | include(GNUInstallDirs) 7 | 8 | if(CMAKE_INSTALL_LIBDIR MATCHES "(CMAKE_SYSTEM_PROCESSOR)") 9 | string(REPLACE "CMAKE_SYSTEM_PROCESSOR" "${CMAKE_SYSTEM_PROCESSOR}" CMAKE_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}") 10 | endif() 11 | 12 | # Enable find_package targets to become globally available targets 13 | set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL TRUE) 14 | 15 | set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}") 16 | set(CPACK_PACKAGE_VERSION "${CMAKE_PROJECT_VERSION}") 17 | set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_C_LIBRARY_ARCHITECTURE}") 18 | 19 | set(CPACK_GENERATOR "DEB") 20 | set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) 21 | set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${PLUGIN_EMAIL}") 22 | set(CPACK_SET_DESTDIR ON) 23 | 24 | if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.25.0 OR NOT CMAKE_CROSSCOMPILING) 25 | set(CPACK_DEBIAN_DEBUGINFO_PACKAGE ON) 26 | endif() 27 | 28 | set(CPACK_OUTPUT_FILE_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/release") 29 | 30 | set(CPACK_SOURCE_GENERATOR "TXZ") 31 | set( 32 | CPACK_SOURCE_IGNORE_FILES 33 | ".*~$" 34 | \\.git/ 35 | \\.github/ 36 | \\.gitignore 37 | \\.ccache/ 38 | build_.* 39 | cmake/\\.CMakeBuildNumber 40 | release/ 41 | ) 42 | 43 | set(CPACK_VERBATIM_VARIABLES YES) 44 | set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-source") 45 | set(CPACK_ARCHIVE_THREADS 0) 46 | 47 | include(CPack) 48 | 49 | find_package(libobs QUIET) 50 | 51 | if(NOT TARGET OBS::libobs) 52 | find_package(LibObs REQUIRED) 53 | add_library(OBS::libobs ALIAS libobs) 54 | 55 | if(ENABLE_FRONTEND_API) 56 | find_path( 57 | obs-frontend-api_INCLUDE_DIR 58 | NAMES obs-frontend-api.h 59 | PATHS /usr/include /usr/local/include 60 | PATH_SUFFIXES obs 61 | ) 62 | 63 | find_library(obs-frontend-api_LIBRARY NAMES obs-frontend-api PATHS /usr/lib /usr/local/lib) 64 | 65 | if(obs-frontend-api_LIBRARY) 66 | if(NOT TARGET OBS::obs-frontend-api) 67 | if(IS_ABSOLUTE "${obs-frontend-api_LIBRARY}") 68 | add_library(OBS::obs-frontend-api UNKNOWN IMPORTED) 69 | set_property(TARGET OBS::obs-frontend-api PROPERTY IMPORTED_LOCATION "${obs-frontend-api_LIBRARY}") 70 | else() 71 | add_library(OBS::obs-frontend-api INTERFACE IMPORTED) 72 | set_property(TARGET OBS::obs-frontend-api PROPERTY IMPORTED_LIBNAME "${obs-frontend-api_LIBRARY}") 73 | endif() 74 | 75 | set_target_properties( 76 | OBS::obs-frontend-api 77 | PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${obs-frontend-api_INCLUDE_DIR}" 78 | ) 79 | endif() 80 | endif() 81 | endif() 82 | 83 | macro(find_package) 84 | if(NOT "${ARGV0}" STREQUAL libobs AND NOT "${ARGV0}" STREQUAL obs-frontend-api) 85 | _find_package(${ARGV}) 86 | endif() 87 | endmacro() 88 | endif() 89 | -------------------------------------------------------------------------------- /.github/actions/check-changes/action.yaml: -------------------------------------------------------------------------------- 1 | name: Check For Changed Files 2 | description: Checks for changed files compared to specific git reference and glob expression 3 | inputs: 4 | baseRef: 5 | description: Git reference to check against 6 | required: false 7 | ref: 8 | description: Git reference to check with 9 | required: false 10 | default: HEAD 11 | checkGlob: 12 | description: Glob expression to limit check to specific files 13 | required: false 14 | useFallback: 15 | description: Use fallback compare against prior commit 16 | required: false 17 | default: 'true' 18 | diffFilter: 19 | description: git diff-filter string to use 20 | required: false 21 | default: '' 22 | outputs: 23 | hasChangedFiles: 24 | value: ${{ steps.checks.outputs.hasChangedFiles }} 25 | description: True if specified files were changed in comparison to specified git reference 26 | changedFiles: 27 | value: ${{ steps.checks.outputs.changedFiles }} 28 | description: List of changed files 29 | runs: 30 | using: composite 31 | steps: 32 | - name: Check For Changed Files ✅ 33 | shell: bash 34 | id: checks 35 | env: 36 | GIT_BASE_REF: ${{ inputs.baseRef }} 37 | GIT_REF: ${{ inputs.ref }} 38 | GITHUB_EVENT_FORCED: ${{ github.event.forced }} 39 | GITHUB_REF_BEFORE: ${{ github.event.before }} 40 | USE_FALLBACK: ${{ inputs.useFallback }} 41 | DIFF_FILTER: ${{ inputs.diffFilter }} 42 | run: | 43 | : Check for Changed Files ✅ 44 | if [[ "${RUNNER_DEBUG}" ]]; then set -x; fi 45 | shopt -s extglob 46 | shopt -s dotglob 47 | 48 | if [[ "${GIT_BASE_REF}" ]]; then 49 | if ! git cat-file -e "${GIT_BASE_REF}" &> /dev/null; then 50 | echo "::warning::Provided base reference ${GIT_BASE_REF} is invalid" 51 | if [[ "${USE_FALLBACK}" == 'true' ]]; then 52 | GIT_BASE_REF='HEAD~1' 53 | fi 54 | fi 55 | else 56 | if ! git cat-file -e ${GITHUB_REF_BEFORE} &> /dev/null; then 57 | GITHUB_REF_BEFORE='4b825dc642cb6eb9a060e54bf8d69288fbee4904' 58 | fi 59 | 60 | GIT_BASE_REF='HEAD~1' 61 | case "${GITHUB_EVENT_NAME}" in 62 | pull_request) GIT_BASE_REF="origin/${GITHUB_BASE_REF}" ;; 63 | push) if [[ "${GITHUB_EVENT_FORCED}" != 'true' ]]; then GIT_BASE_REF="${GITHUB_REF_BEFORE}"; fi ;; 64 | *) ;; 65 | esac 66 | fi 67 | 68 | changes=($(git diff --name-only --diff-filter="${DIFF_FILTER}" ${GIT_BASE_REF} ${GIT_REF} -- ${{ inputs.checkGlob }})) 69 | 70 | if (( ${#changes[@]} )); then 71 | file_string="${changes[*]}" 72 | echo "hasChangedFiles=true" >> $GITHUB_OUTPUT 73 | echo "changedFiles=[\"${file_string// /\",\"}\"]" >> $GITHUB_OUTPUT 74 | else 75 | echo "hasChangedFiles=false" >> $GITHUB_OUTPUT 76 | echo "changedFiles=[]" >> GITHUB_OUTPUT 77 | fi 78 | -------------------------------------------------------------------------------- /cmake/macos/compilerconfig.cmake: -------------------------------------------------------------------------------- 1 | # OBS CMake macOS compiler configuration module 2 | 3 | include_guard(GLOBAL) 4 | 5 | option(ENABLE_COMPILER_TRACE "Enable clang time-trace" OFF) 6 | mark_as_advanced(ENABLE_COMPILER_TRACE) 7 | 8 | if(NOT XCODE) 9 | message(FATAL_ERROR "Building OBS Studio on macOS requires Xcode generator.") 10 | endif() 11 | 12 | include(ccache) 13 | include(compiler_common) 14 | 15 | add_compile_options("$<$>:-fopenmp-simd>") 16 | 17 | # Enable selection between arm64 and x86_64 targets 18 | if(NOT CMAKE_OSX_ARCHITECTURES) 19 | set(CMAKE_OSX_ARCHITECTURES arm64 CACHE STRING "Build architectures for macOS" FORCE) 20 | endif() 21 | set_property(CACHE CMAKE_OSX_ARCHITECTURES PROPERTY STRINGS arm64 x86_64) 22 | 23 | # Ensure recent enough Xcode and platform SDK 24 | function(check_sdk_requirements) 25 | set(obs_macos_minimum_sdk 15.0) # Keep in sync with Xcode 26 | set(obs_macos_minimum_xcode 16.0) # Keep in sync with SDK 27 | execute_process( 28 | COMMAND xcrun --sdk macosx --show-sdk-platform-version 29 | OUTPUT_VARIABLE obs_macos_current_sdk 30 | RESULT_VARIABLE result 31 | OUTPUT_STRIP_TRAILING_WHITESPACE 32 | ) 33 | if(NOT result EQUAL 0) 34 | message( 35 | FATAL_ERROR 36 | "Failed to fetch macOS SDK version. " 37 | "Ensure that the macOS SDK is installed and that xcode-select points at the Xcode developer directory." 38 | ) 39 | endif() 40 | message(DEBUG "macOS SDK version: ${obs_macos_current_sdk}") 41 | if(obs_macos_current_sdk VERSION_LESS obs_macos_minimum_sdk) 42 | message( 43 | FATAL_ERROR 44 | "Your macOS SDK version (${obs_macos_current_sdk}) is too low. " 45 | "The macOS ${obs_macos_minimum_sdk} SDK (Xcode ${obs_macos_minimum_xcode}) is required to build OBS." 46 | ) 47 | endif() 48 | execute_process(COMMAND xcrun --find xcodebuild OUTPUT_VARIABLE obs_macos_xcodebuild RESULT_VARIABLE result) 49 | if(NOT result EQUAL 0) 50 | message( 51 | FATAL_ERROR 52 | "Xcode was not found. " 53 | "Ensure you have installed Xcode and that xcode-select points at the Xcode developer directory." 54 | ) 55 | endif() 56 | message(DEBUG "Path to xcodebuild binary: ${obs_macos_xcodebuild}") 57 | if(XCODE_VERSION VERSION_LESS obs_macos_minimum_xcode) 58 | message( 59 | FATAL_ERROR 60 | "Your Xcode version (${XCODE_VERSION}) is too low. Xcode ${obs_macos_minimum_xcode} is required to build OBS." 61 | ) 62 | endif() 63 | endfunction() 64 | 65 | check_sdk_requirements() 66 | 67 | # Enable dSYM generator for release builds 68 | string(APPEND CMAKE_C_FLAGS_RELEASE " -g") 69 | string(APPEND CMAKE_CXX_FLAGS_RELEASE " -g") 70 | string(APPEND CMAKE_OBJC_FLAGS_RELEASE " -g") 71 | string(APPEND CMAKE_OBJCXX_FLAGS_RELEASE " -g") 72 | 73 | # Default ObjC compiler options used by Xcode: 74 | # 75 | # * -Wno-implicit-atomic-properties 76 | # * -Wno-objc-interface-ivars 77 | # * -Warc-repeated-use-of-weak 78 | # * -Wno-arc-maybe-repeated-use-of-weak 79 | # * -Wimplicit-retain-self 80 | # * -Wduplicate-method-match 81 | # * -Wshadow 82 | # * -Wfloat-conversion 83 | # * -Wobjc-literal-conversion 84 | # * -Wno-selector 85 | # * -Wno-strict-selector-match 86 | # * -Wundeclared-selector 87 | # * -Wdeprecated-implementations 88 | # * -Wprotocol 89 | # * -Werror=block-capture-autoreleasing 90 | # * -Wrange-loop-analysis 91 | 92 | # Default ObjC++ compiler options used by Xcode: 93 | # 94 | # * -Wno-non-virtual-dtor 95 | 96 | add_compile_definitions( 97 | $<$>:$<$:DEBUG>> 98 | $<$>:$<$:_DEBUG>> 99 | $<$>:SIMDE_ENABLE_OPENMP> 100 | ) 101 | 102 | if(ENABLE_COMPILER_TRACE) 103 | add_compile_options( 104 | $<$>:-ftime-trace> 105 | "$<$:SHELL:-Xfrontend -debug-time-expression-type-checking>" 106 | "$<$:SHELL:-Xfrontend -debug-time-function-bodies>" 107 | ) 108 | add_link_options(LINKER:-print_statistics) 109 | endif() 110 | -------------------------------------------------------------------------------- /.github/scripts/Package-Windows.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param( 3 | [ValidateSet('x64')] 4 | [string] $Target = 'x64', 5 | [ValidateSet('Debug', 'RelWithDebInfo', 'Release', 'MinSizeRel')] 6 | [string] $Configuration = 'RelWithDebInfo' 7 | ) 8 | 9 | $ErrorActionPreference = 'Stop' 10 | 11 | if ( $DebugPreference -eq 'Continue' ) { 12 | $VerbosePreference = 'Continue' 13 | $InformationPreference = 'Continue' 14 | } 15 | 16 | if ( $env:CI -eq $null ) { 17 | throw "Package-Windows.ps1 requires CI environment" 18 | } 19 | 20 | if ( ! ( [System.Environment]::Is64BitOperatingSystem ) ) { 21 | throw "Packaging script requires a 64-bit system to build and run." 22 | } 23 | 24 | if ( $PSVersionTable.PSVersion -lt '7.2.0' ) { 25 | Write-Warning 'The packaging script requires PowerShell Core 7. Install or upgrade your PowerShell version: https://aka.ms/pscore6' 26 | exit 2 27 | } 28 | 29 | function Package { 30 | trap { 31 | Write-Error $_ 32 | exit 2 33 | } 34 | 35 | $ScriptHome = $PSScriptRoot 36 | $ProjectRoot = Resolve-Path -Path "$PSScriptRoot/../.." 37 | $BuildSpecFile = "${ProjectRoot}/buildspec.json" 38 | 39 | $UtilityFunctions = Get-ChildItem -Path $PSScriptRoot/utils.pwsh/*.ps1 -Recurse 40 | 41 | foreach( $Utility in $UtilityFunctions ) { 42 | Write-Debug "Loading $($Utility.FullName)" 43 | . $Utility.FullName 44 | } 45 | 46 | $BuildSpec = Get-Content -Path ${BuildSpecFile} -Raw | ConvertFrom-Json 47 | $ProductName = $BuildSpec.name 48 | $ProductVersion = $BuildSpec.version 49 | 50 | $OutputName = "${ProductName}-${ProductVersion}-windows-${Target}" 51 | 52 | $RemoveArgs = @{ 53 | ErrorAction = 'SilentlyContinue' 54 | Path = @( 55 | "${ProjectRoot}/release/${ProductName}-*-windows-*.zip" 56 | ) 57 | } 58 | 59 | Remove-Item @RemoveArgs 60 | 61 | $RemoveArgs = @{ 62 | ErrorAction = 'SilentlyContinue' 63 | Path = @( 64 | "${ProjectRoot}/release/${ProductName}-*-windows-*.exe" 65 | ) 66 | } 67 | 68 | Remove-Item @RemoveArgs 69 | 70 | $IsccFile = "${ProjectRoot}/build_${Target}/installer-Windows.generated.iss" 71 | 72 | if ( ! ( Test-Path -Path $IsccFile ) ) { 73 | throw 'InnoSetup install script not found. Run the build script or the CMake build and install procedures first.' 74 | } 75 | 76 | Copy-Item -Path "${ProjectRoot}/release/${Configuration}/${ProductName}/bin" -Destination "${ProjectRoot}/release/Package/obs-plugins" -Recurse 77 | Copy-Item -Path "${ProjectRoot}/release/${Configuration}/${ProductName}/data" -Destination "${ProjectRoot}/release/Package/data/obs-plugins/${ProductName}" -Recurse 78 | Copy-Item "${IsccFile}" -Destination "${ProjectRoot}/release" 79 | Copy-Item "${ProjectRoot}/media/icon.ico" -Destination "${ProjectRoot}/release" 80 | 81 | Log-Information 'Creating InnoSetup installer...' 82 | Push-Location -Stack BuildTemp 83 | Ensure-Location -Path "${ProjectRoot}/release" 84 | Invoke-External iscc ${IsccFile} /O. /F"${OutputName}-Installer" 85 | Pop-Location -Stack BuildTemp 86 | 87 | Log-Group "Archiving ${ProductName}..." 88 | $CompressArgs = @{ 89 | Path = (Get-ChildItem -Path "${ProjectRoot}/release/${Configuration}" -Exclude "${OutputName}*.*") 90 | CompressionLevel = 'Optimal' 91 | DestinationPath = "${ProjectRoot}/release/${OutputName}-programdata.zip" 92 | Verbose = ($Env:CI -ne $null) 93 | } 94 | Compress-Archive -Force @CompressArgs 95 | 96 | $CompressArgs = @{ 97 | Path = (Get-ChildItem -Path "${ProjectRoot}/release/Package" -Exclude "${OutputName}*.*") 98 | CompressionLevel = 'Optimal' 99 | DestinationPath = "${ProjectRoot}/release/${OutputName}.zip" 100 | Verbose = ($Env:CI -ne $null) 101 | } 102 | Compress-Archive -Force @CompressArgs 103 | 104 | Log-Group 105 | } 106 | 107 | Package 108 | -------------------------------------------------------------------------------- /cmake/linux/helpers.cmake: -------------------------------------------------------------------------------- 1 | # CMake Linux helper functions module 2 | 3 | include_guard(GLOBAL) 4 | 5 | include(helpers_common) 6 | 7 | # set_target_properties_plugin: Set target properties for use in obs-studio 8 | function(set_target_properties_plugin target) 9 | set(options "") 10 | set(oneValueArgs "") 11 | set(multiValueArgs PROPERTIES) 12 | cmake_parse_arguments(PARSE_ARGV 0 _STPO "${options}" "${oneValueArgs}" "${multiValueArgs}") 13 | 14 | message(DEBUG "Setting additional properties for target ${target}...") 15 | 16 | while(_STPO_PROPERTIES) 17 | list(POP_FRONT _STPO_PROPERTIES key value) 18 | set_property(TARGET ${target} PROPERTY ${key} "${value}") 19 | endwhile() 20 | 21 | set_target_properties( 22 | ${target} 23 | PROPERTIES VERSION ${PLUGIN_VERSION} SOVERSION ${PLUGIN_VERSION_MAJOR} PREFIX "" 24 | ) 25 | 26 | install( 27 | TARGETS ${target} 28 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 29 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/obs-plugins 30 | ) 31 | 32 | if(TARGET plugin-support) 33 | target_link_libraries(${target} PRIVATE plugin-support) 34 | endif() 35 | 36 | add_custom_command( 37 | TARGET ${target} 38 | POST_BUILD 39 | COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/rundir/$" 40 | COMMAND 41 | "${CMAKE_COMMAND}" -E copy_if_different "$" "${CMAKE_CURRENT_BINARY_DIR}/rundir/$" 42 | COMMENT "Copy ${target} to rundir" 43 | VERBATIM 44 | ) 45 | 46 | target_install_resources(${target}) 47 | 48 | get_target_property(target_sources ${target} SOURCES) 49 | set(target_ui_files ${target_sources}) 50 | list(FILTER target_ui_files INCLUDE REGEX ".+\\.(ui|qrc)") 51 | source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "UI Files" FILES ${target_ui_files}) 52 | endfunction() 53 | 54 | # Helper function to add resources into bundle 55 | function(target_install_resources target) 56 | message(DEBUG "Installing resources for target ${target}...") 57 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/data") 58 | file(GLOB_RECURSE data_files "${CMAKE_CURRENT_SOURCE_DIR}/data/*") 59 | foreach(data_file IN LISTS data_files) 60 | cmake_path( 61 | RELATIVE_PATH 62 | data_file 63 | BASE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data/" 64 | OUTPUT_VARIABLE relative_path 65 | ) 66 | cmake_path(GET relative_path PARENT_PATH relative_path) 67 | target_sources(${target} PRIVATE "${data_file}") 68 | source_group("Resources/${relative_path}" FILES "${data_file}") 69 | endforeach() 70 | 71 | install( 72 | DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data/" 73 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/obs/obs-plugins/${target} 74 | USE_SOURCE_PERMISSIONS 75 | ) 76 | 77 | add_custom_command( 78 | TARGET ${target} 79 | POST_BUILD 80 | COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/rundir/$/${target}" 81 | COMMAND 82 | "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/data" 83 | "${CMAKE_CURRENT_BINARY_DIR}/rundir/$/${target}" 84 | COMMENT "Copy ${target} resources to rundir" 85 | VERBATIM 86 | ) 87 | endif() 88 | endfunction() 89 | 90 | # Helper function to add a specific resource to a bundle 91 | function(target_add_resource target resource) 92 | message(DEBUG "Add resource '${resource}' to target ${target} at destination '${target_destination}'...") 93 | 94 | install(FILES "${resource}" DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/obs/obs-plugins/${target}) 95 | 96 | add_custom_command( 97 | TARGET ${target} 98 | POST_BUILD 99 | COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/rundir/$/${target}" 100 | COMMAND "${CMAKE_COMMAND}" -E copy "${resource}" "${CMAKE_CURRENT_BINARY_DIR}/rundir/$/${target}" 101 | COMMENT "Copy ${target} resource ${resource} to rundir" 102 | VERBATIM 103 | ) 104 | 105 | source_group("Resources" FILES "${resource}") 106 | endfunction() 107 | -------------------------------------------------------------------------------- /.github/actions/package-plugin/action.yaml: -------------------------------------------------------------------------------- 1 | name: Package plugin 2 | description: Packages the plugin for specified architecture and build config. 3 | inputs: 4 | target: 5 | description: Build target for dependencies 6 | required: true 7 | config: 8 | description: Build configuration 9 | required: false 10 | default: RelWithDebInfo 11 | codesign: 12 | description: Enable codesigning (macOS only) 13 | required: false 14 | default: 'false' 15 | notarize: 16 | description: Enable notarization (macOS only) 17 | required: false 18 | default: 'false' 19 | codesignIdent: 20 | description: Developer ID for application codesigning (macOS only) 21 | required: false 22 | default: '-' 23 | installerIdent: 24 | description: Developer ID for installer package codesigning (macOS only) 25 | required: false 26 | default: '' 27 | codesignTeam: 28 | description: Developer team for codesigning (macOS only) 29 | required: false 30 | default: '' 31 | codesignUser: 32 | description: Apple ID username for notarization (macOS only) 33 | required: false 34 | default: '' 35 | codesignPass: 36 | description: Apple ID password for notarization (macOS only) 37 | required: false 38 | default: '' 39 | package: 40 | description: Create Windows or macOS installation package 41 | required: false 42 | default: 'false' 43 | workingDirectory: 44 | description: Working directory for packaging 45 | required: false 46 | default: ${{ github.workspace }} 47 | runs: 48 | using: composite 49 | steps: 50 | - name: Run macOS Packaging 51 | if: runner.os == 'macOS' 52 | shell: zsh --no-rcs --errexit --pipefail {0} 53 | working-directory: ${{ inputs.workingDirectory }} 54 | env: 55 | CODESIGN_IDENT: ${{ inputs.codesignIdent }} 56 | CODESIGN_IDENT_INSTALLER: ${{ inputs.installerIdent }} 57 | CODESIGN_TEAM: ${{ inputs.codesignTeam }} 58 | CODESIGN_IDENT_USER: ${{ inputs.codesignUser }} 59 | CODESIGN_IDENT_PASS: ${{ inputs.codesignPass }} 60 | run: | 61 | : Run macOS Packaging 62 | 63 | local -a package_args=(--config ${{ inputs.config }}) 64 | if (( ${+RUNNER_DEBUG} )) package_args+=(--debug) 65 | 66 | if [[ '${{ inputs.codesign }}' == 'true' ]] package_args+=(--codesign) 67 | if [[ '${{ inputs.notarize }}' == 'true' ]] package_args+=(--notarize) 68 | if [[ '${{ inputs.package }}' == 'true' ]] package_args+=(--package) 69 | 70 | .github/scripts/package-macos ${package_args} 71 | 72 | - name: Install Dependencies 🛍️ 73 | if: runner.os == 'Linux' 74 | shell: bash 75 | run: | 76 | : Install Dependencies 🛍️ 77 | echo ::group::Install Dependencies 78 | eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" 79 | echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH 80 | brew install --quiet zsh 81 | echo ::endgroup:: 82 | 83 | - name: Run Ubuntu Packaging 84 | if: runner.os == 'Linux' 85 | shell: zsh --no-rcs --errexit --pipefail {0} 86 | working-directory: ${{ inputs.workingDirectory }} 87 | run: | 88 | : Run Ubuntu Packaging 89 | package_args=( 90 | --target ubuntu-${{ inputs.target }} 91 | --config ${{ inputs.config }} 92 | ) 93 | if (( ${+RUNNER_DEBUG} )) build_args+=(--debug) 94 | 95 | if [[ '${{ inputs.package }}' == 'true' ]] package_args+=(--package) 96 | 97 | .github/scripts/package-ubuntu ${package_args} 98 | 99 | - name: Run Windows Packaging 100 | if: runner.os == 'Windows' 101 | shell: pwsh 102 | run: | 103 | # Run Windows Packaging 104 | if ( $Env:RUNNER_DEBUG -ne $null ) { 105 | Set-PSDebug -Trace 1 106 | } 107 | 108 | $PackageArgs = @{ 109 | Target = '${{ inputs.target }}' 110 | Configuration = '${{ inputs.config }}' 111 | } 112 | 113 | .github/scripts/Package-Windows.ps1 @PackageArgs 114 | -------------------------------------------------------------------------------- /cmake/windows/resources/installer-Windows.iss.in: -------------------------------------------------------------------------------- 1 | #define MyAppName "@CMAKE_PROJECT_NAME@" 2 | #define MyAppVersion "@CMAKE_PROJECT_VERSION@" 3 | #define MyAppPublisher "@PLUGIN_AUTHOR@" 4 | #define MyAppURL "@PLUGIN_WEBSITE@" 5 | 6 | [Setup] 7 | ; NOTE: The value of AppId uniquely identifies this application. 8 | ; Do not use the same AppId value in installers for other applications. 9 | ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) 10 | AppId={{@UUID_APP@}} 11 | AppName={#MyAppName} 12 | AppVersion={#MyAppVersion} 13 | AppPublisher={#MyAppPublisher} 14 | AppPublisherURL={#MyAppURL} 15 | AppSupportURL={#MyAppURL} 16 | AppUpdatesURL={#MyAppURL} 17 | DefaultDirName={code:GetDirName} 18 | AppendDefaultDirName=no 19 | DefaultGroupName={#MyAppName} 20 | OutputBaseFilename={#MyAppName}-{#MyAppVersion}-windows-installer 21 | Compression=lzma 22 | SolidCompression=yes 23 | DirExistsWarning=no 24 | AllowNoIcons=yes 25 | ; Wizard Information 26 | WizardStyle=modern 27 | WizardResizable=yes 28 | SetupIconFile="../media/icon.ico" 29 | 30 | [Languages] 31 | Name: "english"; MessagesFile: "compiler:Default.isl" 32 | 33 | [Files] 34 | Source: "..\release\Package\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs 35 | Source: "..\LICENSE"; Flags: dontcopy 36 | ; NOTE: Don't use "Flags: ignoreversion" on any shared system files 37 | 38 | [Icons] 39 | Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}" 40 | Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" 41 | 42 | [Code] 43 | procedure InitializeWizard(); 44 | var 45 | GPLText: AnsiString; 46 | Page: TOutputMsgMemoWizardPage; 47 | begin 48 | ExtractTemporaryFile('LICENSE'); 49 | LoadStringFromFile(ExpandConstant('{tmp}\LICENSE'), GPLText); 50 | Page := CreateOutputMsgMemoPage(wpWelcome, 51 | 'License Information', 'Please review the license terms before installing {#MyAppName}', 52 | 'Press Page Down to see the rest of the agreement. Once you are aware of your rights, click Next to continue.', 53 | String(GPLText) 54 | ); 55 | end; 56 | 57 | // credit where it's due : 58 | // following function come from https://github.com/Xaymar/obs-studio_amf-encoder-plugin/blob/master/%23Resources/Installer.in.iss#L45 59 | function GetDirName(Value: string): string; 60 | var 61 | InstallPath: string; 62 | begin 63 | // initialize default path, which will be returned when the following registry 64 | // key queries fail due to missing keys or for some different reason 65 | Result := ExpandConstant('{pf}\obs-studio'); 66 | // query the first registry value; if this succeeds, return the obtained value 67 | if RegQueryStringValue(HKLM32, 'SOFTWARE\OBS Studio', '', InstallPath) then 68 | Result := InstallPath; 69 | if RegQueryStringValue(HKLM64, 'SOFTWARE\OBS Studio', '', InstallPath) then 70 | Result := InstallPath; 71 | end; 72 | 73 | ///////////////////////////////////////////////////////////////////// 74 | function NextButtonClick(PageId: Integer): Boolean; 75 | var 76 | ObsFileName: string; 77 | ObsMS, ObsLS: Cardinal; 78 | ObsMajorVersion, ObsMinorVersion: Cardinal; 79 | begin 80 | Result := True; 81 | if not (PageId = wpSelectDir) then begin 82 | exit; 83 | end; 84 | ObsFileName := ExpandConstant('{app}\bin\64bit\obs64.exe'); 85 | if not FileExists(ObsFileName) then begin 86 | MsgBox('OBS Studio (bin\64bit\obs64.exe) does not seem to be installed in that folder. Please select the correct folder.', mbError, MB_OK); 87 | Result := False; 88 | exit; 89 | end; 90 | Result := GetVersionNumbers(ObsFileName, ObsMS, ObsLS); 91 | if not Result then begin 92 | MsgBox('Failed to read version from OBS Studio (bin\64bit\obs64.exe).', mbError, MB_OK); 93 | Result := False; 94 | exit; 95 | end; 96 | { shift 16 bits to the right to get major version } 97 | ObsMajorVersion := ObsMS shr 16; 98 | { select only low 16 bits } 99 | ObsMinorVersion := ObsMS and $FFFF; 100 | if ObsMajorVersion < 31 then begin 101 | MsgBox('Version of OBS Studio (bin\64bit\obs64.exe) is lower than the version 31 required.', mbError, MB_OK); 102 | Result := False; 103 | exit; 104 | end; 105 | end; 106 | -------------------------------------------------------------------------------- /.github/workflows/push.yaml: -------------------------------------------------------------------------------- 1 | name: Push 2 | run-name: ${{ github.ref_name }} push run 🚀 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | - 'release/**' 9 | tags: 10 | - '*' 11 | permissions: 12 | contents: write 13 | jobs: 14 | check-format: 15 | name: Check Formatting 🔍 16 | if: github.ref_name == 'master' || github.ref_name == 'main' 17 | uses: ./.github/workflows/check-format.yaml 18 | permissions: 19 | contents: read 20 | 21 | build-project: 22 | name: Build Project 🧱 23 | uses: ./.github/workflows/build-project.yaml 24 | secrets: inherit 25 | permissions: 26 | contents: read 27 | 28 | create-release: 29 | name: Create Release 🛫 30 | if: github.ref_type == 'tag' 31 | runs-on: ubuntu-24.04 32 | needs: build-project 33 | defaults: 34 | run: 35 | shell: bash 36 | steps: 37 | - name: Check Release Tag ☑️ 38 | id: check 39 | run: | 40 | : Check Release Tag ☑️ 41 | if [[ "${RUNNER_DEBUG}" ]]; then set -x; fi 42 | shopt -s extglob 43 | 44 | case "${GITHUB_REF_NAME}" in 45 | +([0-9]).+([0-9]).+([0-9]) ) 46 | echo 'validTag=true' >> $GITHUB_OUTPUT 47 | echo 'prerelease=false' >> $GITHUB_OUTPUT 48 | echo "version=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT 49 | ;; 50 | +([0-9]).+([0-9]).+([0-9])-@(beta|rc)*([0-9]) ) 51 | echo 'validTag=true' >> $GITHUB_OUTPUT 52 | echo 'prerelease=true' >> $GITHUB_OUTPUT 53 | echo "version=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT 54 | ;; 55 | *) echo 'validTag=false' >> $GITHUB_OUTPUT ;; 56 | esac 57 | 58 | - name: Download Build Artifacts 📥 59 | uses: actions/download-artifact@v4 60 | if: fromJSON(steps.check.outputs.validTag) 61 | id: download 62 | 63 | - name: Rename Files 🏷️ 64 | if: fromJSON(steps.check.outputs.validTag) 65 | run: | 66 | : Rename Files 🏷️ 67 | if [[ "${RUNNER_DEBUG}" ]]; then set -x; fi 68 | shopt -s extglob 69 | shopt -s nullglob 70 | 71 | root_dir="$(pwd)" 72 | commit_hash="${GITHUB_SHA:0:9}" 73 | 74 | variants=( 75 | 'windows-x64;zip|exe' 76 | 'macos-universal;tar.xz|pkg' 77 | 'ubuntu-24.04-x86_64;tar.xz|deb|ddeb' 78 | 'sources;tar.xz' 79 | ) 80 | 81 | for variant_data in "${variants[@]}"; do 82 | IFS=';' read -r variant suffix <<< "${variant_data}" 83 | 84 | candidates=(*-${variant}-${commit_hash}/@(*|*-dbgsym).@(${suffix})) 85 | 86 | for candidate in "${candidates[@]}"; do 87 | mv "${candidate}" "${root_dir}" 88 | done 89 | done 90 | 91 | - name: Generate Checksums 🪪 92 | if: fromJSON(steps.check.outputs.validTag) 93 | run: | 94 | : Generate Checksums 🪪 95 | if [[ "${RUNNER_DEBUG}" ]]; then set -x; fi 96 | shopt -s extglob 97 | 98 | echo "### Checksums" > ${{ github.workspace }}/CHECKSUMS.txt 99 | for file in ${{ github.workspace }}/@(*.exe|*.deb|*.ddeb|*.pkg|*.tar.xz|*.zip); do 100 | echo " ${file##*/}: $(sha256sum "${file}" | cut -d " " -f 1)" >> ${{ github.workspace }}/CHECKSUMS.txt 101 | done 102 | 103 | - name: Create Release 🛫 104 | if: fromJSON(steps.check.outputs.validTag) 105 | id: create_release 106 | uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564 107 | with: 108 | draft: true 109 | prerelease: ${{ fromJSON(steps.check.outputs.prerelease) }} 110 | tag_name: ${{ steps.check.outputs.version }} 111 | name: ${{ needs.build-project.outputs.pluginName }} ${{ steps.check.outputs.version }} 112 | body_path: ${{ github.workspace }}/CHECKSUMS.txt 113 | files: | 114 | ${{ github.workspace }}/*.exe 115 | ${{ github.workspace }}/*.zip 116 | ${{ github.workspace }}/*.pkg 117 | ${{ github.workspace }}/*.deb 118 | ${{ github.workspace }}/*.ddeb 119 | ${{ github.workspace }}/*.tar.xz 120 | -------------------------------------------------------------------------------- /.github/scripts/utils.pwsh/Logger.ps1: -------------------------------------------------------------------------------- 1 | function Log-Debug { 2 | [CmdletBinding()] 3 | param( 4 | [Parameter(Mandatory,ValueFromPipeline)] 5 | [ValidateNotNullOrEmpty()] 6 | [string[]] $Message 7 | ) 8 | 9 | Process { 10 | foreach($m in $Message) { 11 | Write-Debug "$(if ( $env:CI -ne $null ) { '::debug::' })$m" 12 | } 13 | } 14 | } 15 | 16 | function Log-Verbose { 17 | [CmdletBinding()] 18 | param( 19 | [Parameter(Mandatory,ValueFromPipeline)] 20 | [ValidateNotNullOrEmpty()] 21 | [string[]] $Message 22 | ) 23 | 24 | Process { 25 | foreach($m in $Message) { 26 | Write-Verbose $m 27 | } 28 | } 29 | } 30 | 31 | function Log-Warning { 32 | [CmdletBinding()] 33 | param( 34 | [Parameter(Mandatory,ValueFromPipeline)] 35 | [ValidateNotNullOrEmpty()] 36 | [string[]] $Message 37 | ) 38 | 39 | Process { 40 | foreach($m in $Message) { 41 | Write-Warning "$(if ( $env:CI -ne $null ) { '::warning::' })$m" 42 | } 43 | } 44 | } 45 | 46 | function Log-Error { 47 | [CmdletBinding()] 48 | param( 49 | [Parameter(Mandatory,ValueFromPipeline)] 50 | [ValidateNotNullOrEmpty()] 51 | [string[]] $Message 52 | ) 53 | 54 | Process { 55 | foreach($m in $Message) { 56 | Write-Error "$(if ( $env:CI -ne $null ) { '::error::' })$m" 57 | } 58 | } 59 | } 60 | 61 | function Log-Information { 62 | [CmdletBinding()] 63 | param( 64 | [Parameter(Mandatory,ValueFromPipeline)] 65 | [ValidateNotNullOrEmpty()] 66 | [string[]] $Message 67 | ) 68 | 69 | Process { 70 | if ( ! ( $script:Quiet ) ) { 71 | $StageName = $( if ( $script:StageName -ne $null ) { $script:StageName } else { '' }) 72 | $Icon = ' =>' 73 | 74 | foreach($m in $Message) { 75 | Write-Host -NoNewLine -ForegroundColor Blue " ${StageName} $($Icon.PadRight(5)) " 76 | Write-Host "${m}" 77 | } 78 | } 79 | } 80 | } 81 | 82 | function Log-Group { 83 | [CmdletBinding()] 84 | param( 85 | [Parameter(ValueFromPipeline)] 86 | [string[]] $Message 87 | ) 88 | 89 | Process { 90 | if ( $Env:CI -ne $null ) { 91 | if ( $script:LogGroup ) { 92 | Write-Output '::endgroup::' 93 | $script:LogGroup = $false 94 | } 95 | 96 | if ( $Message.count -ge 1 ) { 97 | Write-Output "::group::$($Message -join ' ')" 98 | $script:LogGroup = $true 99 | } 100 | } else { 101 | if ( $Message.count -ge 1 ) { 102 | Log-Information $Message 103 | } 104 | } 105 | } 106 | } 107 | 108 | function Log-Status { 109 | [CmdletBinding()] 110 | param( 111 | [Parameter(Mandatory,ValueFromPipeline)] 112 | [ValidateNotNullOrEmpty()] 113 | [string[]] $Message 114 | ) 115 | 116 | Process { 117 | if ( ! ( $script:Quiet ) ) { 118 | $StageName = $( if ( $StageName -ne $null ) { $StageName } else { '' }) 119 | $Icon = ' >' 120 | 121 | foreach($m in $Message) { 122 | Write-Host -NoNewLine -ForegroundColor Green " ${StageName} $($Icon.PadRight(5)) " 123 | Write-Host "${m}" 124 | } 125 | } 126 | } 127 | } 128 | 129 | function Log-Output { 130 | [CmdletBinding()] 131 | param( 132 | [Parameter(Mandatory,ValueFromPipeline)] 133 | [ValidateNotNullOrEmpty()] 134 | [string[]] $Message 135 | ) 136 | 137 | Process { 138 | if ( ! ( $script:Quiet ) ) { 139 | $StageName = $( if ( $script:StageName -ne $null ) { $script:StageName } else { '' }) 140 | $Icon = '' 141 | 142 | foreach($m in $Message) { 143 | Write-Output " ${StageName} $($Icon.PadRight(5)) ${m}" 144 | } 145 | } 146 | } 147 | } 148 | 149 | $Columns = (Get-Host).UI.RawUI.WindowSize.Width - 5 150 | -------------------------------------------------------------------------------- /cmake/windows/helpers.cmake: -------------------------------------------------------------------------------- 1 | # CMake Windows helper functions module 2 | 3 | include_guard(GLOBAL) 4 | 5 | include(helpers_common) 6 | 7 | # set_target_properties_plugin: Set target properties for use in obs-studio 8 | function(set_target_properties_plugin target) 9 | set(options "") 10 | set(oneValueArgs "") 11 | set(multiValueArgs PROPERTIES) 12 | cmake_parse_arguments(PARSE_ARGV 0 _STPO "${options}" "${oneValueArgs}" "${multiValueArgs}") 13 | 14 | message(DEBUG "Setting additional properties for target ${target}...") 15 | 16 | while(_STPO_PROPERTIES) 17 | list(POP_FRONT _STPO_PROPERTIES key value) 18 | set_property(TARGET ${target} PROPERTY ${key} "${value}") 19 | endwhile() 20 | 21 | string(TIMESTAMP CURRENT_YEAR "%Y") 22 | 23 | set_target_properties(${target} PROPERTIES VERSION 0 SOVERSION ${PLUGIN_VERSION}) 24 | 25 | install(TARGETS ${target} RUNTIME DESTINATION "${target}/bin/64bit" LIBRARY DESTINATION "${target}/bin/64bit") 26 | 27 | install( 28 | FILES "$" 29 | CONFIGURATIONS RelWithDebInfo Debug Release 30 | DESTINATION "${target}/bin/64bit" 31 | OPTIONAL 32 | ) 33 | 34 | if(TARGET plugin-support) 35 | target_link_libraries(${target} PRIVATE plugin-support) 36 | endif() 37 | 38 | add_custom_command( 39 | TARGET ${target} 40 | POST_BUILD 41 | COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/rundir/$" 42 | COMMAND 43 | "${CMAKE_COMMAND}" -E copy_if_different "$" 44 | "$<$:$>" 45 | "${CMAKE_CURRENT_BINARY_DIR}/rundir/$" 46 | COMMENT "Copy ${target} to rundir" 47 | VERBATIM 48 | ) 49 | 50 | target_install_resources(${target}) 51 | 52 | get_target_property(target_sources ${target} SOURCES) 53 | set(target_ui_files ${target_sources}) 54 | list(FILTER target_ui_files INCLUDE REGEX ".+\\.(ui|qrc)") 55 | source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "UI Files" FILES ${target_ui_files}) 56 | 57 | configure_file(cmake/windows/resources/resource.rc.in "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.rc") 58 | target_sources(${CMAKE_PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.rc") 59 | endfunction() 60 | 61 | # Helper function to add resources into bundle 62 | function(target_install_resources target) 63 | message(DEBUG "Installing resources for target ${target}...") 64 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/data") 65 | file(GLOB_RECURSE data_files "${CMAKE_CURRENT_SOURCE_DIR}/data/*") 66 | foreach(data_file IN LISTS data_files) 67 | cmake_path( 68 | RELATIVE_PATH 69 | data_file 70 | BASE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data/" 71 | OUTPUT_VARIABLE relative_path 72 | ) 73 | cmake_path(GET relative_path PARENT_PATH relative_path) 74 | target_sources(${target} PRIVATE "${data_file}") 75 | source_group("Resources/${relative_path}" FILES "${data_file}") 76 | endforeach() 77 | 78 | install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data/" DESTINATION "${target}/data" USE_SOURCE_PERMISSIONS) 79 | 80 | add_custom_command( 81 | TARGET ${target} 82 | POST_BUILD 83 | COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/rundir/$/${target}" 84 | COMMAND 85 | "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/data" 86 | "${CMAKE_CURRENT_BINARY_DIR}/rundir/$/${target}" 87 | COMMENT "Copy ${target} resources to rundir" 88 | VERBATIM 89 | ) 90 | endif() 91 | endfunction() 92 | 93 | # Helper function to add a specific resource to a bundle 94 | function(target_add_resource target resource) 95 | message(DEBUG "Add resource '${resource}' to target ${target} at destination '${target_destination}'...") 96 | 97 | install(FILES "${resource}" DESTINATION "${target}/data" COMPONENT Runtime) 98 | 99 | add_custom_command( 100 | TARGET ${target} 101 | POST_BUILD 102 | COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/rundir/$/${target}" 103 | COMMAND "${CMAKE_COMMAND}" -E copy "${resource}" "${CMAKE_CURRENT_BINARY_DIR}/rundir/$/${target}" 104 | COMMENT "Copy ${target} resource ${resource} to rundir" 105 | VERBATIM 106 | ) 107 | source_group("Resources" FILES "${resource}") 108 | endfunction() 109 | -------------------------------------------------------------------------------- /.github/scripts/build-macos: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | builtin emulate -L zsh 4 | setopt EXTENDED_GLOB 5 | setopt PUSHD_SILENT 6 | setopt ERR_EXIT 7 | setopt ERR_RETURN 8 | setopt NO_UNSET 9 | setopt PIPE_FAIL 10 | setopt NO_AUTO_PUSHD 11 | setopt NO_PUSHD_IGNORE_DUPS 12 | setopt FUNCTION_ARGZERO 13 | 14 | ## Enable for script debugging 15 | # setopt WARN_CREATE_GLOBAL 16 | # setopt WARN_NESTED_VAR 17 | # setopt XTRACE 18 | 19 | if (( ! ${+CI} )) { 20 | print -u2 -PR "%F{1} ✖︎ ${ZSH_ARGZERO:t:r} requires CI environment.%f" 21 | exit 1 22 | } 23 | 24 | autoload -Uz is-at-least && if ! is-at-least 5.9; then 25 | print -u2 -PR "${CI:+::error::}%F{1}${funcstack[1]##*/}:%f Running on Zsh version %B${ZSH_VERSION}%b, but Zsh %B5.2%b is the minimum supported version. Upgrade Zsh to fix this issue." 26 | exit 1 27 | fi 28 | 29 | TRAPZERR() { 30 | print -u2 -PR "::error::%F{1} ✖︎ script execution error%f" 31 | print -PR -e " 32 | Callstack: 33 | ${(j:\n :)funcfiletrace} 34 | " 35 | 36 | exit 2 37 | } 38 | 39 | build() { 40 | if (( ! ${+SCRIPT_HOME} )) typeset -g SCRIPT_HOME=${ZSH_ARGZERO:A:h} 41 | local host_os='macos' 42 | local project_root=${SCRIPT_HOME:A:h:h} 43 | local buildspec_file=${project_root}/buildspec.json 44 | 45 | fpath=("${SCRIPT_HOME}/utils.zsh" ${fpath}) 46 | autoload -Uz log_group log_info log_error log_output check_macos setup_ccache 47 | 48 | if [[ ! -r ${buildspec_file} ]] { 49 | log_error \ 50 | 'No buildspec.json found. Please create a build specification for your project.' 51 | return 2 52 | } 53 | 54 | local -i debug=0 55 | 56 | local config='RelWithDebInfo' 57 | local -r -a _valid_configs=(Debug RelWithDebInfo Release MinSizeRel) 58 | local -i codesign=0 59 | 60 | local -a args 61 | while (( # )) { 62 | case ${1} { 63 | -c|--config) 64 | if (( # == 1 )) || [[ ${2:0:1} == '-' ]] { 65 | log_error "Missing value for option %B${1}%b" 66 | log_output ${_usage} 67 | exit 2 68 | } 69 | ;; 70 | } 71 | case ${1} { 72 | --) shift; args+=($@); break ;; 73 | -c|--config) 74 | if (( ! ${_valid_configs[(Ie)${2}]} )) { 75 | log_error "Invalid value %B${2}%b for option %B${1}%b" 76 | exit 2 77 | } 78 | config=${2} 79 | shift 2 80 | ;; 81 | -s|--codesign) codesign=1; shift ;; 82 | --debug) debug=1; shift ;; 83 | *) log_error "Unknown option: %B${1}%b"; exit 2 ;; 84 | } 85 | } 86 | 87 | set -- ${(@)args} 88 | 89 | check_macos 90 | 91 | local product_name 92 | local product_version 93 | read -r product_name product_version <<< \ 94 | "$(jq -r '. | {name, version} | join(" ")' ${buildspec_file})" 95 | 96 | pushd ${project_root} 97 | 98 | local -a cmake_args=() 99 | local -a cmake_build_args=(--build) 100 | local -a cmake_install_args=(--install) 101 | 102 | if (( debug )) cmake_args+=(--debug-output) 103 | 104 | cmake_args+=(--preset 'macos-ci') 105 | 106 | typeset -gx NSUnbufferedIO=YES 107 | 108 | typeset -gx CODESIGN_IDENT="${CODESIGN_IDENT:--}" 109 | if (( codesign )) && [[ -z ${CODESIGN_TEAM} ]] { 110 | typeset -gx CODESIGN_TEAM="$(print "${CODESIGN_IDENT}" | /usr/bin/sed -En 's/.+\((.+)\)/\1/p')" 111 | } 112 | 113 | log_group "Configuring ${product_name}..." 114 | cmake -S ${project_root} ${cmake_args} 115 | 116 | log_group "Building ${product_name}..." 117 | run_xcodebuild() { 118 | if (( debug )) { 119 | xcodebuild ${@} 120 | } else { 121 | if [[ ${GITHUB_EVENT_NAME} == push ]] { 122 | xcodebuild ${@} 2>&1 | xcbeautify --renderer terminal 123 | } else { 124 | xcodebuild ${@} 2>&1 | xcbeautify --renderer github-actions 125 | } 126 | } 127 | } 128 | 129 | local -a build_args=( 130 | ONLY_ACTIVE_ARCH=NO 131 | -arch arm64 132 | -arch x86_64 133 | -project ${product_name}.xcodeproj 134 | -target ${product_name} 135 | -destination "generic/platform=macOS,name=Any Mac" 136 | -configuration ${config} 137 | -parallelizeTargets 138 | -hideShellScriptEnvironment 139 | build 140 | ) 141 | 142 | pushd build_macos 143 | run_xcodebuild ${build_args} 144 | popd 145 | 146 | log_group "Installing ${product_name}..." 147 | cmake --install build_macos --config ${config} --prefix "${project_root}/release/${config}" 148 | 149 | popd 150 | log_group 151 | } 152 | 153 | build ${@} 154 | -------------------------------------------------------------------------------- /cmake/macos/helpers.cmake: -------------------------------------------------------------------------------- 1 | # CMake macOS helper functions module 2 | 3 | include_guard(GLOBAL) 4 | 5 | include(helpers_common) 6 | 7 | # set_target_properties_obs: Set target properties for use in obs-studio 8 | function(set_target_properties_plugin target) 9 | set(options "") 10 | set(oneValueArgs "") 11 | set(multiValueArgs PROPERTIES) 12 | cmake_parse_arguments(PARSE_ARGV 0 _STPO "${options}" "${oneValueArgs}" "${multiValueArgs}") 13 | 14 | message(DEBUG "Setting additional properties for target ${target}...") 15 | 16 | while(_STPO_PROPERTIES) 17 | list(POP_FRONT _STPO_PROPERTIES key value) 18 | set_property(TARGET ${target} PROPERTY ${key} "${value}") 19 | endwhile() 20 | 21 | string(TIMESTAMP CURRENT_YEAR "%Y") 22 | set_target_properties( 23 | ${target} 24 | PROPERTIES 25 | BUNDLE TRUE 26 | BUNDLE_EXTENSION plugin 27 | XCODE_ATTRIBUTE_PRODUCT_NAME ${target} 28 | XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${MACOS_BUNDLEID} 29 | XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION ${PLUGIN_BUILD_NUMBER} 30 | XCODE_ATTRIBUTE_MARKETING_VERSION ${PLUGIN_VERSION} 31 | XCODE_ATTRIBUTE_GENERATE_INFOPLIST_FILE YES 32 | XCODE_ATTRIBUTE_INFOPLIST_FILE "" 33 | XCODE_ATTRIBUTE_INFOPLIST_KEY_CFBundleDisplayName ${target} 34 | XCODE_ATTRIBUTE_INFOPLIST_KEY_NSHumanReadableCopyright "(c) ${CURRENT_YEAR} ${PLUGIN_AUTHOR}" 35 | XCODE_ATTRIBUTE_INSTALL_PATH "$(USER_LIBRARY_DIR)/Application Support/obs-studio/plugins" 36 | ) 37 | 38 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/entitlements.plist") 39 | set_target_properties( 40 | ${target} 41 | PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/entitlements.plist" 42 | ) 43 | endif() 44 | 45 | if(TARGET plugin-support) 46 | target_link_libraries(${target} PRIVATE plugin-support) 47 | endif() 48 | 49 | target_install_resources(${target}) 50 | 51 | add_custom_command( 52 | TARGET ${target} 53 | POST_BUILD 54 | COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/rundir/$" 55 | COMMAND 56 | "${CMAKE_COMMAND}" -E copy_directory "$" 57 | "${CMAKE_CURRENT_BINARY_DIR}/rundir/$/$" 58 | COMMENT "Copy ${target} to rundir" 59 | VERBATIM 60 | ) 61 | 62 | get_target_property(target_sources ${target} SOURCES) 63 | set(target_ui_files ${target_sources}) 64 | list(FILTER target_ui_files INCLUDE REGEX ".+\\.(ui|qrc)") 65 | source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "UI Files" FILES ${target_ui_files}) 66 | 67 | install(TARGETS ${target} LIBRARY DESTINATION .) 68 | install(FILES "$.dsym" CONFIGURATIONS Release DESTINATION . OPTIONAL) 69 | 70 | configure_file(cmake/macos/resources/distribution.in "${CMAKE_CURRENT_BINARY_DIR}/distribution" @ONLY) 71 | configure_file(cmake/macos/resources/create-package.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/create-package.cmake" @ONLY) 72 | install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/create-package.cmake") 73 | endfunction() 74 | 75 | # target_install_resources: Helper function to add resources into bundle 76 | function(target_install_resources target) 77 | message(DEBUG "Installing resources for target ${target}...") 78 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/data") 79 | file(GLOB_RECURSE data_files "${CMAKE_CURRENT_SOURCE_DIR}/data/*") 80 | list(FILTER data_files EXCLUDE REGEX "\\.DS_Store$") 81 | foreach(data_file IN LISTS data_files) 82 | cmake_path( 83 | RELATIVE_PATH 84 | data_file 85 | BASE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data/" 86 | OUTPUT_VARIABLE relative_path 87 | ) 88 | cmake_path(GET relative_path PARENT_PATH relative_path) 89 | target_sources(${target} PRIVATE "${data_file}") 90 | set_property(SOURCE "${data_file}" PROPERTY MACOSX_PACKAGE_LOCATION "Resources/${relative_path}") 91 | source_group("Resources/${relative_path}" FILES "${data_file}") 92 | endforeach() 93 | endif() 94 | endfunction() 95 | 96 | # target_add_resource: Helper function to add a specific resource to a bundle 97 | function(target_add_resource target resource) 98 | message(DEBUG "Add resource ${resource} to target ${target} at destination ${destination}...") 99 | target_sources(${target} PRIVATE "${resource}") 100 | set_property(SOURCE "${resource}" PROPERTY MACOSX_PACKAGE_LOCATION Resources) 101 | source_group("Resources" FILES "${resource}") 102 | endfunction() 103 | -------------------------------------------------------------------------------- /.github/actions/build-plugin/action.yaml: -------------------------------------------------------------------------------- 1 | name: Set up and build plugin 2 | description: Builds the plugin for specified architecture and build config 3 | inputs: 4 | target: 5 | description: Target architecture for dependencies 6 | required: true 7 | config: 8 | description: Build configuration 9 | required: false 10 | default: RelWithDebInfo 11 | codesign: 12 | description: Enable codesigning (macOS only) 13 | required: false 14 | default: 'false' 15 | codesignIdent: 16 | description: Developer ID for application codesigning (macOS only) 17 | required: false 18 | default: '-' 19 | codesignTeam: 20 | description: Team ID for application codesigning (macOS only) 21 | required: false 22 | default: '' 23 | workingDirectory: 24 | description: Working directory for packaging 25 | required: false 26 | default: ${{ github.workspace }} 27 | runs: 28 | using: composite 29 | steps: 30 | - name: Run macOS Build 31 | if: runner.os == 'macOS' 32 | shell: zsh --no-rcs --errexit --pipefail {0} 33 | working-directory: ${{ inputs.workingDirectory }} 34 | env: 35 | CCACHE_DIR: ${{ inputs.workingDirectory }}/.ccache 36 | CODESIGN_IDENT: ${{ inputs.codesignIdent }} 37 | CODESIGN_TEAM: ${{ inputs.codesignTeam }} 38 | run: | 39 | : Run macOS Build 40 | 41 | local -a build_args=(--config ${{ inputs.config }}) 42 | if (( ${+RUNNER_DEBUG} )) build_args+=(--debug) 43 | 44 | if [[ '${{ inputs.codesign }}' == 'true' ]] build_args+=(--codesign) 45 | 46 | git fetch origin --no-tags --no-recurse-submodules -q 47 | .github/scripts/build-macos ${build_args} 48 | 49 | - name: Install Dependencies 🛍️ 50 | if: runner.os == 'Linux' 51 | shell: bash 52 | run: | 53 | : Install Dependencies 🛍️ 54 | echo ::group::Install Dependencies 55 | sudo apt update 56 | 57 | : Install system dependencies 🛍️ 58 | sudo apt install cmake ninja-build pkg-config clang clang-format build-essential curl ccache git zsh 59 | 60 | : Install OBS dependencies 🛍️ 61 | sudo apt install libavcodec-dev libavdevice-dev libavfilter-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev libx264-dev libcurl4-openssl-dev libmbedtls-dev libgl1-mesa-dev libjansson-dev libluajit-5.1-dev python3-dev libx11-dev libxcb-randr0-dev libxcb-shm0-dev libxcb-xinerama0-dev libxcb-composite0-dev libxcomposite-dev libxinerama-dev libxcb1-dev libx11-xcb-dev libxcb-xfixes0-dev swig libcmocka-dev libxss-dev libglvnd-dev libgles2-mesa-dev libwayland-dev librist-dev libsrt-openssl-dev libpci-dev libpipewire-0.3-dev libqrcodegencpp-dev uthash-dev 62 | 63 | : Install OBS Qt6 dependencies 🛍️ 64 | sudo apt install qt6-base-dev qt6-base-private-dev libqt6svg6-dev qt6-wayland qt6-image-formats-plugins 65 | eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" 66 | echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH 67 | brew install --quiet zsh 68 | echo ::endgroup:: 69 | 70 | - name: Run Ubuntu Build 71 | if: runner.os == 'Linux' 72 | shell: zsh --no-rcs --errexit --pipefail {0} 73 | working-directory: ${{ inputs.workingDirectory }} 74 | env: 75 | CCACHE_DIR: ${{ inputs.workingDirectory }}/.ccache 76 | run: | 77 | : Run Ubuntu Build 78 | 79 | local -a build_args=( 80 | --target ubuntu-${{ inputs.target }} 81 | --config ${{ inputs.config }} 82 | ) 83 | if (( ${+RUNNER_DEBUG} )) build_args+=(--debug) 84 | 85 | .github/scripts/build-ubuntu ${build_args} 86 | 87 | - name: Run Windows Build 88 | if: runner.os == 'Windows' 89 | shell: pwsh 90 | run: | 91 | # Run Windows Build 92 | if ( $Env:RUNNER_DEBUG -ne $null ) { 93 | Set-PSDebug -Trace 1 94 | } 95 | 96 | $BuildArgs = @{ 97 | Target = '${{ inputs.target }}' 98 | Configuration = '${{ inputs.config }}' 99 | } 100 | 101 | .github/scripts/Build-Windows.ps1 @BuildArgs 102 | 103 | - name: Create Summary 📊 104 | if: contains(fromJSON('["Linux", "macOS"]'),runner.os) 105 | shell: zsh --no-rcs --errexit --pipefail {0} 106 | env: 107 | CCACHE_DIR: ${{ inputs.workingDirectory }}/.ccache 108 | run: | 109 | : Create Summary 📊 110 | 111 | local -a ccache_data 112 | if (( ${+RUNNER_DEBUG} )) { 113 | setopt XTRACE 114 | ccache_data=("${(fA)$(ccache -s -vv)}") 115 | } else { 116 | ccache_data=("${(fA)$(ccache -s)}") 117 | } 118 | 119 | print '### ${{ runner.os }} Ccache Stats (${{ inputs.target }})' >> $GITHUB_STEP_SUMMARY 120 | print '```' >> $GITHUB_STEP_SUMMARY 121 | for line (${ccache_data}) { 122 | print ${line} >> $GITHUB_STEP_SUMMARY 123 | } 124 | print '```' >> $GITHUB_STEP_SUMMARY 125 | -------------------------------------------------------------------------------- /.github/scripts/package-macos: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | builtin emulate -L zsh 4 | setopt EXTENDED_GLOB 5 | setopt PUSHD_SILENT 6 | setopt ERR_EXIT 7 | setopt ERR_RETURN 8 | setopt NO_UNSET 9 | setopt PIPE_FAIL 10 | setopt NO_AUTO_PUSHD 11 | setopt NO_PUSHD_IGNORE_DUPS 12 | setopt FUNCTION_ARGZERO 13 | 14 | ## Enable for script debugging 15 | # setopt WARN_CREATE_GLOBAL 16 | # setopt WARN_NESTED_VAR 17 | # setopt XTRACE 18 | 19 | if (( ! ${+CI} )) { 20 | print -u2 -PR "%F{1} ✖︎ ${ZSH_ARGZERO:t:r} requires CI environment%f" 21 | exit 1 22 | } 23 | 24 | autoload -Uz is-at-least && if ! is-at-least 5.9; then 25 | print -u2 -PR "${CI:+::error::}%F{1}${funcstack[1]##*/}:%f Running on Zsh version %B${ZSH_VERSION}%b, but Zsh %B5.2%b is the minimum supported version. Upgrade Zsh to fix this issue." 26 | exit 1 27 | fi 28 | 29 | TRAPZERR() { 30 | print -u2 -PR "::error::%F{1} ✖︎ script execution error%f" 31 | print -PR -e " 32 | Callstack: 33 | ${(j:\n :)funcfiletrace} 34 | " 35 | 36 | exit 2 37 | } 38 | 39 | package() { 40 | if (( ! ${+SCRIPT_HOME} )) typeset -g SCRIPT_HOME=${ZSH_ARGZERO:A:h} 41 | local host_os='macos' 42 | local project_root=${SCRIPT_HOME:A:h:h} 43 | local buildspec_file=${project_root}/buildspec.json 44 | 45 | fpath=("${SCRIPT_HOME}/utils.zsh" ${fpath}) 46 | autoload -Uz log_group log_error log_output check_macos 47 | 48 | if [[ ! -r ${buildspec_file} ]] { 49 | log_error \ 50 | 'No buildspec.json found. Please create a build specification for your project.' 51 | return 2 52 | } 53 | 54 | local -i debug=0 55 | 56 | local config='RelWithDebInfo' 57 | local -r -a _valid_configs=(Debug RelWithDebInfo Release MinSizeRel) 58 | 59 | local -i codesign=0 60 | local -i notarize=0 61 | local -i package=0 62 | 63 | local -a args 64 | while (( # )) { 65 | case ${1} { 66 | -c|--config) 67 | if (( # == 1 )) || [[ ${2:0:1} == '-' ]] { 68 | log_error "Missing value for option %B${1}%b" 69 | exit 2 70 | } 71 | ;; 72 | } 73 | case ${1} { 74 | --) shift; args+=($@); break ;; 75 | -c|--config) 76 | if (( !${_valid_configs[(Ie)${2}]} )) { 77 | log_error "Invalid value %B${2}%b for option %B${1}%b" 78 | exit 2 79 | } 80 | config=${2} 81 | shift 2 82 | ;; 83 | -s|--codesign) typeset -g codesign=1; shift ;; 84 | -n|--notarize) typeset -g notarize=1; typeset -g codesign=1; shift ;; 85 | -p|--package) typeset -g package=1; shift ;; 86 | --debug) debug=1; shift ;; 87 | *) log_error "Unknown option: %B${1}%b"; exit 2 ;; 88 | } 89 | } 90 | 91 | set -- ${(@)args} 92 | 93 | check_macos 94 | 95 | local product_name 96 | local product_version 97 | read -r product_name product_version <<< \ 98 | "$(jq -r '. | {name, version} | join(" ")' ${buildspec_file})" 99 | 100 | local output_name="${product_name}-${product_version}-${host_os}-universal" 101 | 102 | if [[ ! -d ${project_root}/release/${config}/${product_name}.plugin ]] { 103 | log_error 'No release artifact found. Run the build script or the CMake install procedure first.' 104 | return 2 105 | } 106 | 107 | if (( package )) { 108 | if [[ ! -f ${project_root}/release/${config}/${product_name}.pkg ]] { 109 | log_error 'Installer Package not found. Run the build script or the CMake build and install procedures first.' 110 | return 2 111 | } 112 | 113 | log_group "Packaging ${product_name}..." 114 | pushd ${project_root} 115 | 116 | typeset -gx CODESIGN_IDENT="${CODESIGN_IDENT:--}" 117 | typeset -gx CODESIGN_IDENT_INSTALLER="${CODESIGN_IDENT_INSTALLER:--}" 118 | typeset -gx CODESIGN_TEAM="$(print "${CODESIGN_IDENT}" | /usr/bin/sed -En 's/.+\((.+)\)/\1/p')" 119 | 120 | if (( codesign )) { 121 | productsign \ 122 | --sign "${CODESIGN_IDENT_INSTALLER}" \ 123 | ${project_root}/release/${config}/${product_name}.pkg \ 124 | ${project_root}/release/${output_name}.pkg 125 | 126 | rm ${project_root}/release/${config}/${product_name}.pkg 127 | } else { 128 | mv ${project_root}/release/${config}/${product_name}.pkg \ 129 | ${project_root}/release/${output_name}.pkg 130 | } 131 | 132 | if (( codesign && notarize )) { 133 | if ! [[ ${CODESIGN_IDENT} != '-' && ${CODESIGN_TEAM} && {CODESIGN_IDENT_USER} && ${CODESIGN_IDENT_PASS} ]] { 134 | log_error "Notarization requires Apple ID and application password." 135 | return 2 136 | } 137 | 138 | if [[ ! -f ${project_root}/release/${output_name}.pkg ]] { 139 | log_error "No package for notarization found." 140 | return 2 141 | } 142 | 143 | xcrun notarytool store-credentials "${product_name}-Codesign-Password" --apple-id "${CODESIGN_IDENT_USER}" --team-id "${CODESIGN_TEAM}" --password "${CODESIGN_IDENT_PASS}" 144 | xcrun notarytool submit ${project_root}/release/${output_name}.pkg --keychain-profile "${product_name}-Codesign-Password" --wait 145 | 146 | local -i _status=0 147 | 148 | xcrun stapler staple ${project_root}/release/${output_name}.pkg || _status=1 149 | 150 | if (( _status )) { 151 | log_error "Notarization failed. Use 'xcrun notarytool log ' to check for errors." 152 | return 2 153 | } 154 | } 155 | popd 156 | } else { 157 | log_group "Archiving ${product_name}..." 158 | pushd ${project_root}/release/${config} 159 | XZ_OPT=-T0 tar -cvJf ${project_root}/release/${output_name}.tar.xz ${product_name}.plugin 160 | popd 161 | } 162 | 163 | if [[ ${config} == Release ]] { 164 | log_group "Archiving ${product_name} Debug Symbols..." 165 | pushd ${project_root}/release/${config} 166 | XZ_OPT=-T0 tar -cvJf ${project_root}/release/${output_name}-dSYMs.tar.xz ${product_name}.plugin.dSYM 167 | popd 168 | } 169 | 170 | log_group 171 | } 172 | 173 | package ${@} 174 | -------------------------------------------------------------------------------- /.github/scripts/package-ubuntu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | builtin emulate -L zsh 4 | setopt EXTENDED_GLOB 5 | setopt PUSHD_SILENT 6 | setopt ERR_EXIT 7 | setopt ERR_RETURN 8 | setopt NO_UNSET 9 | setopt PIPE_FAIL 10 | setopt NO_AUTO_PUSHD 11 | setopt NO_PUSHD_IGNORE_DUPS 12 | setopt FUNCTION_ARGZERO 13 | 14 | ## Enable for script debugging 15 | # setopt WARN_CREATE_GLOBAL 16 | # setopt WARN_NESTED_VAR 17 | # setopt XTRACE 18 | 19 | autoload -Uz is-at-least && if ! is-at-least 5.2; then 20 | print -u2 -PR "${CI:+::error::}%F{1}${funcstack[1]##*/}:%f Running on Zsh version %B${ZSH_VERSION}%b, but Zsh %B5.2%b is the minimum supported version. Upgrade Zsh to fix this issue." 21 | exit 1 22 | fi 23 | 24 | TRAPZERR() { 25 | if (( ${_loglevel:-3} > 2 )) { 26 | print -u2 -PR "${CI:+::error::}%F{1} ✖︎ script execution error%f" 27 | print -PR -e " 28 | Callstack: 29 | ${(j:\n :)funcfiletrace} 30 | " 31 | } 32 | 33 | exit 2 34 | } 35 | 36 | package() { 37 | if (( ! ${+SCRIPT_HOME} )) typeset -g SCRIPT_HOME=${ZSH_ARGZERO:A:h} 38 | local host_os='ubuntu' 39 | local project_root=${SCRIPT_HOME:A:h:h} 40 | local buildspec_file=${project_root}/buildspec.json 41 | 42 | fpath=("${SCRIPT_HOME}/utils.zsh" ${fpath}) 43 | autoload -Uz set_loglevel log_info log_group log_error log_output check_${host_os} 44 | 45 | if [[ ! -r ${buildspec_file} ]] { 46 | log_error \ 47 | 'No buildspec.json found. Please create a build specification for your project.' 48 | return 2 49 | } 50 | 51 | local -i debug=0 52 | local -i verbosity=1 53 | local -r _version='2.0.0' 54 | local -r -a _valid_targets=( 55 | ubuntu-x86_64 56 | ) 57 | local target 58 | local config='RelWithDebInfo' 59 | local -r -a _valid_configs=(Debug RelWithDebInfo Release MinSizeRel) 60 | local -i codesign=0 61 | local -i notarize=0 62 | local -i package=0 63 | local -i skip_deps=0 64 | 65 | local -r _usage=" 66 | Usage: %B${functrace[1]%:*}%b