├── .clang-format ├── .cmake-format.json ├── .github ├── FUNDING.yml ├── actions │ ├── build-plugin │ │ └── action.yaml │ ├── check-changes │ │ └── action.yaml │ ├── package-plugin │ │ └── action.yaml │ ├── run-clang-format │ │ └── action.yaml │ ├── run-gersemi │ │ └── action.yaml │ └── setup-macos-codesigning │ │ └── action.yaml ├── scripts │ ├── .Aptfile │ ├── .Brewfile │ ├── Build-Windows.ps1 │ ├── Package-Windows.ps1 │ ├── build-macos │ ├── build-ubuntu │ ├── package-macos │ ├── package-ubuntu │ ├── utils.pwsh │ │ ├── Ensure-Location.ps1 │ │ ├── Invoke-External.ps1 │ │ └── Logger.ps1 │ └── utils.zsh │ │ ├── check_macos │ │ ├── check_ubuntu │ │ ├── log_debug │ │ ├── log_error │ │ ├── log_group │ │ ├── log_info │ │ ├── log_output │ │ ├── log_status │ │ ├── log_warning │ │ ├── mkcd │ │ ├── set_loglevel │ │ └── setup_ubuntu └── workflows │ ├── build-project.yaml │ ├── check-format.yaml │ ├── dispatch.yaml │ ├── pr-pull.yaml │ └── push.yaml ├── .gitignore ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── build-aux ├── .functions │ ├── log_debug │ ├── log_error │ ├── log_group │ ├── log_info │ ├── log_output │ ├── log_status │ ├── log_warning │ └── set_loglevel ├── .run-format.zsh ├── run-clang-format ├── run-cmake-format ├── run-gersemi └── run-swift-format ├── buildspec.json ├── cmake ├── common │ ├── bootstrap.cmake │ ├── buildnumber.cmake │ ├── buildspec_common.cmake │ ├── ccache.cmake │ ├── compiler_common.cmake │ ├── helpers_common.cmake │ └── osconfig.cmake ├── linux │ ├── compilerconfig.cmake │ ├── defaults.cmake │ └── helpers.cmake ├── macos │ ├── buildspec.cmake │ ├── compilerconfig.cmake │ ├── defaults.cmake │ ├── helpers.cmake │ ├── resources │ │ ├── ccache-launcher-c.in │ │ ├── ccache-launcher-cxx.in │ │ ├── create-package.cmake.in │ │ ├── distribution.in │ │ └── installer-macos.pkgproj.in │ └── xcode.cmake └── windows │ ├── buildspec.cmake │ ├── compilerconfig.cmake │ ├── defaults.cmake │ ├── helpers.cmake │ └── resources │ ├── installer-Windows.iss.in │ └── resource.rc.in ├── data └── locale │ ├── en-US.ini │ ├── es-ES.ini │ └── zh-CN.ini ├── media ├── icon.ico └── logo.png ├── resource.rc.in ├── source-profiler.cpp ├── source-profiler.hpp └── version.h.in /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: InheritParentConfig 2 | ColumnLimit: 132 -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: exeldro 2 | custom: "https://www.paypal.me/exeldro" 3 | patreon: Exeldro 4 | -------------------------------------------------------------------------------- /.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 | workingDirectory: 20 | description: Working directory for packaging 21 | required: false 22 | default: ${{ github.workspace }} 23 | runs: 24 | using: composite 25 | steps: 26 | - name: Run macOS Build 27 | if: runner.os == 'macOS' 28 | shell: zsh --no-rcs --errexit --pipefail {0} 29 | working-directory: ${{ inputs.workingDirectory }} 30 | env: 31 | CCACHE_DIR: ${{ inputs.workingDirectory }}/.ccache 32 | CODESIGN_IDENT: ${{ inputs.codesignIdent }} 33 | CODESIGN_TEAM: ${{ inputs.codesignTeam }} 34 | run: | 35 | : Run macOS Build 36 | 37 | local -a build_args=(--config ${{ inputs.config }}) 38 | if (( ${+RUNNER_DEBUG} )) build_args+=(--debug) 39 | 40 | if [[ '${{ inputs.codesign }}' == 'true' ]] build_args+=(--codesign) 41 | 42 | .github/scripts/build-macos ${build_args} 43 | 44 | - name: Install Dependencies 🛍️ 45 | if: runner.os == 'Linux' 46 | shell: bash 47 | run: | 48 | : Install Dependencies 🛍️ 49 | echo ::group::Install Dependencies 50 | eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" 51 | echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH 52 | brew install --quiet zsh 53 | echo ::endgroup:: 54 | 55 | - name: Run Ubuntu Build 56 | if: runner.os == 'Linux' 57 | shell: zsh --no-rcs --errexit --pipefail {0} 58 | working-directory: ${{ inputs.workingDirectory }} 59 | env: 60 | CCACHE_DIR: ${{ inputs.workingDirectory }}/.ccache 61 | run: | 62 | : Run Ubuntu Build 63 | 64 | local -a build_args=( 65 | --target ubuntu-${{ inputs.target }} 66 | --config ${{ inputs.config }} 67 | ) 68 | if (( ${+RUNNER_DEBUG} )) build_args+=(--debug) 69 | 70 | .github/scripts/build-ubuntu ${build_args} 71 | 72 | - name: Run Windows Build 73 | if: runner.os == 'Windows' 74 | shell: pwsh 75 | run: | 76 | # Run Windows Build 77 | if ( $Env:RUNNER_DEBUG -ne $null ) { 78 | Set-PSDebug -Trace 1 79 | } 80 | 81 | $BuildArgs = @{ 82 | Target = '${{ inputs.target }}' 83 | Configuration = '${{ inputs.config }}' 84 | } 85 | 86 | .github/scripts/Build-Windows.ps1 @BuildArgs 87 | 88 | - name: Create Summary 📊 89 | if: contains(fromJSON('["Linux", "macOS"]'),runner.os) 90 | shell: zsh --no-rcs --errexit --pipefail {0} 91 | env: 92 | CCACHE_DIR: ${{ inputs.workingDirectory }}/.ccache 93 | run: | 94 | : Create Summary 📊 95 | 96 | local -a ccache_data 97 | if (( ${+RUNNER_DEBUG} )) { 98 | setopt XTRACE 99 | ccache_data=("${(fA)$(ccache -s -vv)}") 100 | } else { 101 | ccache_data=("${(fA)$(ccache -s)}") 102 | } 103 | 104 | print '### ${{ runner.os }} Ccache Stats (${{ inputs.target }})' >> $GITHUB_STEP_SUMMARY 105 | print '```' >> $GITHUB_STEP_SUMMARY 106 | for line (${ccache_data}) { 107 | print ${line} >> $GITHUB_STEP_SUMMARY 108 | } 109 | print '```' >> $GITHUB_STEP_SUMMARY 110 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.github/actions/setup-macos-codesigning/action.yaml: -------------------------------------------------------------------------------- 1 | name: Set up macOS codesigning 2 | description: Sets up code signing certificates, provisioning profiles, and notarization information 3 | inputs: 4 | codesignIdentity: 5 | description: Codesigning identity 6 | required: true 7 | installerIdentity: 8 | description: Codesigning identity for package installer 9 | required: false 10 | codesignCertificate: 11 | description: PKCS12 certificate in base64 format 12 | required: true 13 | certificatePassword: 14 | description: Password required to install PKCS12 certificate 15 | required: true 16 | keychainPassword: 17 | description: Password to use for temporary keychain 18 | required: false 19 | notarizationUser: 20 | description: Apple ID to use for notarization 21 | required: false 22 | notarizationPassword: 23 | description: Application password for notarization 24 | provisioningProfile: 25 | description: Provisioning profile in base64 format 26 | required: false 27 | outputs: 28 | haveCodesignIdent: 29 | description: True if necessary codesigning credentials were found 30 | value: ${{ steps.codesign.outputs.haveCodesignIdent }} 31 | haveProvisioningProfile: 32 | description: True if necessary provisioning profile credentials were found 33 | value: ${{ steps.provisioning.outputs.haveProvisioningProfile || steps.codesign.outputs.haveProvisioningProfile }} 34 | provisioningProfileUUID: 35 | description: UUID of imported provisioning profile 36 | value: ${{ steps.provisioning.outputs.provisioningProfileUUID }} 37 | haveNotarizationUser: 38 | description: True if necessary notarization credentials were found 39 | value: ${{ steps.notarization.outputs.haveNotarizationUser || steps.codesign.outputs.haveNotarizationUser }} 40 | codesignIdent: 41 | description: Codesigning identity 42 | value: ${{ steps.codesign.outputs.codesignIdent }} 43 | installerIdent: 44 | description: Codesigning identity for package installer 45 | value: ${{ steps.codesign.outputs.installerIdent }} 46 | codesignTeam: 47 | description: Codesigning team 48 | value: ${{ steps.codesign.outputs.codesignTeam }} 49 | runs: 50 | using: composite 51 | steps: 52 | - name: Check Runner Operating System 🏃‍♂️ 53 | if: runner.os != 'macOS' 54 | shell: bash 55 | run: | 56 | : Check Runner Operating System 🏃‍♂️ 57 | echo "setup-macos-codesigning action requires a macOS-based runner." 58 | exit 2 59 | 60 | - name: macOS Codesigning ✍️ 61 | shell: zsh --no-rcs --errexit --pipefail {0} 62 | id: codesign 63 | env: 64 | MACOS_SIGNING_IDENTITY: ${{ inputs.codesignIdentity }} 65 | MACOS_SIGNING_IDENTITY_INSTALLER: ${{ inputs.installerIdentity}} 66 | MACOS_SIGNING_CERT: ${{ inputs.codesignCertificate }} 67 | MACOS_SIGNING_CERT_PASSWORD: ${{ inputs.certificatePassword }} 68 | MACOS_KEYCHAIN_PASSWORD: ${{ inputs.keychainPassword }} 69 | run: | 70 | : macOS Code Signing ✍️ 71 | if (( ${+RUNNER_DEBUG} )) setopt XTRACE 72 | 73 | if [[ ${MACOS_SIGNING_IDENTITY} && ${MACOS_SIGNING_IDENTITY_INSTALLER} && ${MACOS_SIGNING_CERT} ]] { 74 | print 'haveCodesignIdent=true' >> $GITHUB_OUTPUT 75 | 76 | local -r certificate_path="${RUNNER_TEMP}/build_certificate.p12" 77 | local -r keychain_path="${RUNNER_TEMP}/app-signing.keychain-db" 78 | 79 | print -n "${MACOS_SIGNING_CERT}" | base64 --decode --output=${certificate_path} 80 | 81 | : "${MACOS_KEYCHAIN_PASSWORD:="$(print ${RANDOM} | shasum | head -c 32)"}" 82 | 83 | print '::group::Keychain setup' 84 | security create-keychain -p "${MACOS_KEYCHAIN_PASSWORD}" ${keychain_path} 85 | security set-keychain-settings -lut 21600 ${keychain_path} 86 | security unlock-keychain -p "${MACOS_KEYCHAIN_PASSWORD}" ${keychain_path} 87 | 88 | security import "${certificate_path}" -P "${MACOS_SIGNING_CERT_PASSWORD}" -A \ 89 | -t cert -f pkcs12 -k ${keychain_path} \ 90 | -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/xcrun 91 | 92 | security set-key-partition-list -S 'apple-tool:,apple:' -k "${MACOS_KEYCHAIN_PASSWORD}" \ 93 | ${keychain_path} &> /dev/null 94 | 95 | security list-keychain -d user -s ${keychain_path} 'login-keychain' 96 | print '::endgroup::' 97 | 98 | local -r team_id="${${MACOS_SIGNING_IDENTITY##* }//(\(|\))/}" 99 | 100 | print "codesignIdent=${MACOS_SIGNING_IDENTITY}" >> $GITHUB_OUTPUT 101 | print "installerIdent=${MACOS_SIGNING_IDENTITY_INSTALLER}" >> $GITHUB_OUTPUT 102 | print "MACOS_KEYCHAIN_PASSWORD=${MACOS_KEYCHAIN_PASSWORD}" >> $GITHUB_ENV 103 | print "codesignTeam=${team_id}" >> $GITHUB_OUTPUT 104 | } else { 105 | print 'haveCodesignIdent=false' >> $GITHUB_OUTPUT 106 | print 'haveProvisioningProfile=false' >> $GITHUB_OUTPUT 107 | print 'haveNotarizationUser=false' >> $GITHUB_OUTPUT 108 | } 109 | 110 | - name: Provisioning Profile 👤 111 | shell: zsh --no-rcs --errexit --pipefail {0} 112 | id: provisioning 113 | if: ${{ fromJSON(steps.codesign.outputs.haveCodesignIdent) }} 114 | env: 115 | MACOS_SIGNING_PROVISIONING_PROFILE: ${{ inputs.provisioningProfile }} 116 | run: | 117 | : Provisioning Profile 👤 118 | if (( ${+RUNNER_DEBUG} )) setopt XTRACE 119 | 120 | if [[ "${MACOS_SIGNING_PROVISIONING_PROFILE}" ]] { 121 | print 'haveProvisioningProfile=true' >> $GITHUB_OUTPUT 122 | 123 | local -r profile_path="${RUNNER_TEMP}/build_profile.provisionprofile" 124 | print -n "${MACOS_SIGNING_PROVISIONING_PROFILE}" \ 125 | | base64 --decode --output="${profile_path}" 126 | 127 | print '::group::Provisioning Profile Setup' 128 | mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles 129 | security cms -D -i ${profile_path} -o ${RUNNER_TEMP}/build_profile.plist 130 | local -r uuid="$(plutil -extract UUID raw ${RUNNER_TEMP}/build_profile.plist)" 131 | local -r team_id="$(plutil -extract TeamIdentifier.0 raw -expect string ${RUNNER_TEMP}/build_profile.plist)" 132 | 133 | if [[ ${team_id} != '${{ steps.codesign.outputs.codesignTeam }}' ]] { 134 | print '::notice::Code Signing team in provisioning profile does not match certificate.' 135 | } 136 | 137 | cp ${profile_path} ~/Library/MobileDevice/Provisioning\ Profiles/${uuid}.provisionprofile 138 | print "provisioningProfileUUID=${uuid}" >> $GITHUB_OUTPUT 139 | print '::endgroup::' 140 | } else { 141 | print 'haveProvisioningProfile=false' >> $GITHUB_OUTPUT 142 | } 143 | 144 | - name: Notarization 🧑‍💼 145 | id: notarization 146 | if: fromJSON(steps.codesign.outputs.haveCodesignIdent) 147 | shell: zsh --no-rcs --errexit --pipefail {0} 148 | env: 149 | MACOS_NOTARIZATION_USERNAME: ${{ inputs.notarizationUser }} 150 | MACOS_NOTARIZATION_PASSWORD: ${{ inputs.notarizationPassword }} 151 | run: | 152 | : Notarization 🧑‍💼 153 | if (( ${+RUNNER_DEBUG} )) setopt XTRACE 154 | 155 | if [[ ${MACOS_NOTARIZATION_USERNAME} && ${MACOS_NOTARIZATION_PASSWORD} ]] { 156 | print 'haveNotarizationUser=true' >> $GITHUB_OUTPUT 157 | } else { 158 | print 'haveNotarizationUser=false' >> $GITHUB_OUTPUT 159 | } 160 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.github/scripts/.Brewfile: -------------------------------------------------------------------------------- 1 | brew "ccache" 2 | brew "coreutils" 3 | brew "cmake" 4 | brew "jq" 5 | brew "xcbeautify" 6 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | 80 | Log-Information 'Creating InnoSetup installer...' 81 | Push-Location -Stack BuildTemp 82 | Ensure-Location -Path "${ProjectRoot}/release" 83 | Invoke-External iscc ${IsccFile} /O. /F"${OutputName}-Installer" 84 | Pop-Location -Stack BuildTemp 85 | 86 | Log-Group "Archiving ${ProductName}..." 87 | $CompressArgs = @{ 88 | Path = (Get-ChildItem -Path "${ProjectRoot}/release/${Configuration}" -Exclude "${OutputName}*.*") 89 | CompressionLevel = 'Optimal' 90 | DestinationPath = "${ProjectRoot}/release/${OutputName}-programdata.zip" 91 | Verbose = ($Env:CI -ne $null) 92 | } 93 | Compress-Archive -Force @CompressArgs 94 | 95 | $CompressArgs = @{ 96 | Path = (Get-ChildItem -Path "${ProjectRoot}/release/Package" -Exclude "${OutputName}*.*") 97 | CompressionLevel = 'Optimal' 98 | DestinationPath = "${ProjectRoot}/release/${OutputName}.zip" 99 | Verbose = ($Env:CI -ne $null) 100 | } 101 | Compress-Archive -Force @CompressArgs 102 | 103 | Log-Group 104 | } 105 | 106 | Package 107 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.github/scripts/build-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 | build() { 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 log_group log_info log_error log_output set_loglevel check_ubuntu setup_ccache 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 | typeset -g -a skips=() 53 | local -i verbosity=1 54 | local -r _version='2.0.0' 55 | local -r -a _valid_targets=( 56 | ubuntu-x86_64 57 | ) 58 | local target 59 | local config='RelWithDebInfo' 60 | local -r -a _valid_configs=(Debug RelWithDebInfo Release MinSizeRel) 61 | local -i codesign=0 62 | 63 | local -r -a _valid_generators=(Ninja 'Unix Makefiles') 64 | local generator='Ninja' 65 | local -r _usage_host=" 66 | %F{yellow} Additional options for Linux builds%f 67 | ----------------------------------------------------------------------------- 68 | %B--generator%b Specify build system to generate 69 | Available generators: 70 | - Ninja 71 | - Unix Makefiles" 72 | 73 | local -i print_config=0 74 | local -r _usage=" 75 | Usage: %B${functrace[1]%:*}%b