obs-cross-compiling

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OBS Cross-Compilation

OBS交叉编译

Purpose

目的

Cross-compile OBS Studio plugins from Linux to Windows using MinGW-w64. Covers CMake presets, toolchain configuration, headers-only linking, CI/CD workflows, and artifact packaging.
使用MinGW-w64从Linux交叉编译OBS Studio插件至Windows。内容涵盖CMake预设、工具链配置、仅头文件链接、CI/CD工作流以及制品打包。

When NOT to Use

不适用场景

  • Native Windows builds with MSVC → Use obs-windows-building
  • Qt/C++ frontend development → Use obs-cpp-qt-patterns
  • Audio plugin implementation → Use obs-audio-plugin-writing
  • Code review → Use obs-plugin-reviewing
  • 使用MSVC进行原生Windows构建 → 请使用obs-windows-building
  • Qt/C++前端开发 → 请使用obs-cpp-qt-patterns
  • 音频插件实现 → 请使用obs-audio-plugin-writing
  • 代码评审 → 请使用obs-plugin-reviewing

Quick Start: Cross-Compile in 5 Steps

快速开始:5步完成交叉编译

Step 1: Install MinGW on Linux

步骤1:在Linux上安装MinGW

bash
undefined
bash
undefined

Ubuntu/Debian

Ubuntu/Debian

sudo apt install mingw-w64 gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64
sudo apt install mingw-w64 gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64

Verify

Verify

x86_64-w64-mingw32-gcc --version
undefined
x86_64-w64-mingw32-gcc --version
undefined

Step 2: Create Toolchain File

步骤2:创建工具链文件

Create
cmake/mingw-w64-toolchain.cmake
:
cmake
undefined
创建
cmake/mingw-w64-toolchain.cmake
:
cmake
undefined

Target Windows from Linux

Target Windows from Linux

set(CMAKE_SYSTEM_NAME Windows) set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(CMAKE_SYSTEM_NAME Windows) set(CMAKE_SYSTEM_PROCESSOR x86_64)

Cross-compilers

Cross-compilers

set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)

Target environment (search for libraries here)

Target environment (search for libraries here)

set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)

Host programs (cmake, etc.) - use from host system

Host programs (cmake, etc.) - use from host system

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

Target libraries/includes - only search in target environment

Target libraries/includes - only search in target environment

set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

Windows flags

Windows flags

set(WIN32 TRUE) set(MINGW TRUE) set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll") set(CMAKE_EXECUTABLE_SUFFIX ".exe")
set(WIN32 TRUE) set(MINGW TRUE) set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll") set(CMAKE_EXECUTABLE_SUFFIX ".exe")

Static link C runtime (avoid DLL dependencies)

Static link C runtime (avoid DLL dependencies)

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc -static-libstdc++") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc -static-libstdc++") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -static-libgcc -static-libstdc++")

CRITICAL: Allow unresolved OBS symbols (resolved at runtime)

CRITICAL: Allow unresolved OBS symbols (resolved at runtime)

set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--unresolved-symbols=ignore-all,--warn-unresolved-symbols,--noinhibit-exec")
undefined
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--unresolved-symbols=ignore-all,--warn-unresolved-symbols,--noinhibit-exec")
undefined

Step 3: Create CMakePresets.json

步骤3:创建CMakePresets.json

json
{
  "version": 8,
  "configurePresets": [
    {
      "name": "linux-cross-windows-x64",
      "displayName": "Cross-compile Windows x64 (from Linux)",
      "description": "Cross-compile for Windows x64 using MinGW-w64 on Linux",
      "binaryDir": "${sourceDir}/build_windows_x64",
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Linux"
      },
      "generator": "Ninja",
      "toolchainFile": "${sourceDir}/cmake/mingw-w64-toolchain.cmake",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "RelWithDebInfo",
        "CROSS_COMPILE_WINDOWS": true
      }
    }
  ],
  "buildPresets": [
    {
      "name": "linux-cross-windows-x64",
      "configurePreset": "linux-cross-windows-x64"
    }
  ]
}
json
{
  "version": 8,
  "configurePresets": [
    {
      "name": "linux-cross-windows-x64",
      "displayName": "Cross-compile Windows x64 (from Linux)",
      "description": "Cross-compile for Windows x64 using MinGW-w64 on Linux",
      "binaryDir": "${sourceDir}/build_windows_x64",
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Linux"
      },
      "generator": "Ninja",
      "toolchainFile": "${sourceDir}/cmake/mingw-w64-toolchain.cmake",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "RelWithDebInfo",
        "CROSS_COMPILE_WINDOWS": true
      }
    }
  ],
  "buildPresets": [
    {
      "name": "linux-cross-windows-x64",
      "configurePreset": "linux-cross-windows-x64"
    }
  ]
}

Step 4: Configure Headers-Only Linking

步骤4:配置仅头文件链接

In CMakeLists.txt:
cmake
option(CROSS_COMPILE_WINDOWS "Cross-compile for Windows from Linux" OFF)

if(CROSS_COMPILE_WINDOWS)
    # Headers only - OBS provides symbols at runtime
    add_library(obs-headers INTERFACE)
    target_include_directories(obs-headers INTERFACE
        "${OBS_SOURCE_DIR}/libobs"
        "${OBS_SOURCE_DIR}/frontend/api"
    )
    target_compile_definitions(obs-headers INTERFACE
        UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS WIN32 _WIN32
    )
    target_link_libraries(${PROJECT_NAME} PRIVATE obs-headers)

    # Windows system libraries
    target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 comctl32)

    # CRITICAL: Use .def file for exports
    set_target_properties(${PROJECT_NAME} PROPERTIES
        LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def -Wl,--unresolved-symbols=ignore-all"
    )
else()
    # Native build - full OBS libraries
    find_package(libobs REQUIRED)
    target_link_libraries(${PROJECT_NAME} PRIVATE OBS::libobs)
endif()
在CMakeLists.txt中:
cmake
option(CROSS_COMPILE_WINDOWS "Cross-compile for Windows from Linux" OFF)

if(CROSS_COMPILE_WINDOWS)
    # Headers only - OBS provides symbols at runtime
    add_library(obs-headers INTERFACE)
    target_include_directories(obs-headers INTERFACE
        "${OBS_SOURCE_DIR}/libobs"
        "${OBS_SOURCE_DIR}/frontend/api"
    )
    target_compile_definitions(obs-headers INTERFACE
        UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS WIN32 _WIN32
    )
    target_link_libraries(${PROJECT_NAME} PRIVATE obs-headers)

    # Windows system libraries
    target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 comctl32)

    # CRITICAL: Use .def file for exports
    set_target_properties(${PROJECT_NAME} PROPERTIES
        LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def -Wl,--unresolved-symbols=ignore-all"
    )
else()
    # Native build - full OBS libraries
    find_package(libobs REQUIRED)
    target_link_libraries(${PROJECT_NAME} PRIVATE OBS::libobs)
endif()

Step 5: Build

步骤5:构建

bash
undefined
bash
undefined

Fetch OBS SDK headers

Fetch OBS SDK headers

./ci/fetch-obs-sdk.sh windows
./ci/fetch-obs-sdk.sh windows

Configure

Configure

cmake --preset linux-cross-windows-x64
-DOBS_SOURCE_DIR="$PWD/.deps/windows-x64/obs-studio-32.0.4"
cmake --preset linux-cross-windows-x64
-DOBS_SOURCE_DIR="$PWD/.deps/windows-x64/obs-studio-32.0.4"

Build

Build

cmake --build --preset linux-cross-windows-x64
cmake --build --preset linux-cross-windows-x64

Verify

Verify

file build_windows_x64/my-plugin.dll | grep "PE32+"
undefined
file build_windows_x64/my-plugin.dll | grep "PE32+"
undefined

Headers-Only Linking Pattern

仅头文件链接模式

Why headers-only? OBS plugins are loaded at runtime by OBS Studio. The plugin doesn't link against libobs.dll - instead:
  1. OBS loads the plugin DLL
  2. Plugin exports
    obs_module_load()
    and other functions
  3. OBS provides all
    obs_*
    symbols at load time
Critical linker flags:
cmake
-Wl,--unresolved-symbols=ignore-all   # Don't fail on missing OBS symbols
-Wl,--warn-unresolved-symbols         # Downgrade to warnings
-Wl,--noinhibit-exec                  # Create output despite warnings
为什么使用仅头文件? OBS插件由OBS Studio在运行时加载。插件不会链接到libobs.dll,而是:
  1. OBS加载插件DLL
  2. 插件导出
    obs_module_load()
    及其他函数
  3. OBS在加载时提供所有
    obs_*
    符号
关键链接器标志:
cmake
-Wl,--unresolved-symbols=ignore-all   # Don't fail on missing OBS symbols
-Wl,--warn-unresolved-symbols         # Downgrade to warnings
-Wl,--noinhibit-exec                  # Create output despite warnings

Symbol Export with .def File

使用.def文件导出符号

MinGW sometimes exports functions by ordinal only. OBS requires named exports.
Create
src/plugin.def
:
def
LIBRARY my-plugin
EXPORTS
    ; Required OBS module entry points
    obs_module_load
    obs_module_unload
    obs_module_post_load
    obs_module_ver
    obs_module_set_pointer
    obs_current_module
    obs_module_description

    ; Locale functions (from OBS_MODULE_USE_DEFAULT_LOCALE)
    obs_module_set_locale
    obs_module_free_locale
    obs_module_get_string
    obs_module_text
Verify exports:
bash
x86_64-w64-mingw32-objdump -p my-plugin.dll | grep -A 100 "Export Table"
MinGW有时仅通过序号导出函数。OBS要求命名导出
创建
src/plugin.def
def
LIBRARY my-plugin
EXPORTS
    ; Required OBS module entry points
    obs_module_load
    obs_module_unload
    obs_module_post_load
    obs_module_ver
    obs_module_set_pointer
    obs_current_module
    obs_module_description

    ; Locale functions (from OBS_MODULE_USE_DEFAULT_LOCALE)
    obs_module_set_locale
    obs_module_free_locale
    obs_module_get_string
    obs_module_text
验证导出:
bash
x86_64-w64-mingw32-objdump -p my-plugin.dll | grep -A 100 "Export Table"

OBS SDK Fetching

OBS SDK获取

For cross-compilation, you need OBS headers (not full libraries).
Pattern from translate-live:
bash
#!/bin/bash
对于交叉编译,你需要OBS头文件(而非完整库)。
来自translate-live的模式:
bash
#!/bin/bash

fetch-obs-sdk.sh

fetch-obs-sdk.sh

PLATFORM="$1" # "windows" or "linux" OBS_VERSION="32.0.4" OBS_HASH="5e17f2e99..." # From buildspec.json
PLATFORM="$1" # "windows" or "linux" OBS_VERSION="32.0.4" OBS_HASH="5e17f2e99..." # From buildspec.json

Create deps directory

Create deps directory

mkdir -p .deps/${PLATFORM}-x64
mkdir -p .deps/${PLATFORM}-x64

Download OBS source (for headers)

Download OBS source (for headers)

Verify checksum

Verify checksum

echo "${OBS_HASH} obs-studio.tar.gz" | sha256sum -c
echo "${OBS_HASH} obs-studio.tar.gz" | sha256sum -c

Extract

Extract

tar -xzf obs-studio.tar.gz -C .deps/${PLATFORM}-x64
tar -xzf obs-studio.tar.gz -C .deps/${PLATFORM}-x64

Create stub obsconfig.h (normally generated by CMake)

Create stub obsconfig.h (normally generated by CMake)

cat > .deps/${PLATFORM}-x64/obs-studio-${OBS_VERSION}/libobs/obsconfig.h << 'EOF' #pragma once #define OBS_VERSION "32.0.4" #define OBS_DATA_PATH "" #define OBS_INSTALL_PREFIX "" #define OBS_PLUGIN_PATH "" EOF
undefined
cat > .deps/${PLATFORM}-x64/obs-studio-${OBS_VERSION}/libobs/obsconfig.h << 'EOF' #pragma once #define OBS_VERSION "32.0.4" #define OBS_DATA_PATH "" #define OBS_INSTALL_PREFIX "" #define OBS_PLUGIN_PATH "" EOF
undefined

CI/CD Workflow

CI/CD工作流

Gitea Actions / GitHub Actions

Gitea Actions / GitHub Actions

yaml
build-windows:
  name: Build Windows x64 (Cross-compile)
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4

    - name: Install dependencies
      run: |
        sudo apt-get update
        sudo apt-get install -y \
          cmake ninja-build jq curl unzip \
          mingw-w64 gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64

    - name: Fetch OBS SDK
      run: ./ci/fetch-obs-sdk.sh windows

    - name: Configure
      run: |
        OBS_VERSION=$(jq -r '.dependencies["obs-studio"].version' buildspec.json)
        cmake --preset linux-cross-windows-ci-x64 \
          -DOBS_SOURCE_DIR="${PWD}/.deps/windows-x64/obs-studio-${OBS_VERSION}"

    - name: Build
      run: cmake --build --preset linux-cross-windows-ci-x64

    - name: Verify DLL
      run: |
        file build_windows_x64/my-plugin.dll | grep "PE32+"
        x86_64-w64-mingw32-objdump -p build_windows_x64/my-plugin.dll | grep -A 100 "Export Table"

    - name: Package
      run: |
        VERSION=$(jq -r '.version' buildspec.json)
        COMMIT=$(git rev-parse --short=9 HEAD)
        ARTIFACT="my-plugin-${VERSION}-windows-x64-${COMMIT}"

        mkdir -p "release/${ARTIFACT}/bin/64bit"
        cp build_windows_x64/my-plugin.dll "release/${ARTIFACT}/bin/64bit/"
        cd release && zip -rq "${ARTIFACT}.zip" "${ARTIFACT}"
yaml
build-windows:
  name: Build Windows x64 (Cross-compile)
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4

    - name: Install dependencies
      run: |
        sudo apt-get update
        sudo apt-get install -y \
          cmake ninja-build jq curl unzip \
          mingw-w64 gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64

    - name: Fetch OBS SDK
      run: ./ci/fetch-obs-sdk.sh windows

    - name: Configure
      run: |
        OBS_VERSION=$(jq -r '.dependencies["obs-studio"].version' buildspec.json)
        cmake --preset linux-cross-windows-ci-x64 \
          -DOBS_SOURCE_DIR="${PWD}/.deps/windows-x64/obs-studio-${OBS_VERSION}"

    - name: Build
      run: cmake --build --preset linux-cross-windows-ci-x64

    - name: Verify DLL
      run: |
        file build_windows_x64/my-plugin.dll | grep "PE32+"
        x86_64-w64-mingw32-objdump -p build_windows_x64/my-plugin.dll | grep -A 100 "Export Table"

    - name: Package
      run: |
        VERSION=$(jq -r '.version' buildspec.json)
        COMMIT=$(git rev-parse --short=9 HEAD)
        ARTIFACT="my-plugin-${VERSION}-windows-x64-${COMMIT}"

        mkdir -p "release/${ARTIFACT}/bin/64bit"
        cp build_windows_x64/my-plugin.dll "release/${ARTIFACT}/bin/64bit/"
        cd release && zip -rq "${ARTIFACT}.zip" "${ARTIFACT}"

Artifact Naming Convention

制品命名规范

{plugin-name}-{version}-{platform}-{commit}.{ext}
Examples:
  • my-plugin-1.0.0-linux-x86_64-abc123def.tar.xz
  • my-plugin-1.0.0-windows-x64-abc123def.zip
Structure inside archive:
my-plugin-1.0.0-windows-x64-abc123def/
├── bin/
│   └── 64bit/
│       └── my-plugin.dll
└── data/
    └── locale/
        └── en-US.ini
{plugin-name}-{version}-{platform}-{commit}.{ext}
示例:
  • my-plugin-1.0.0-linux-x86_64-abc123def.tar.xz
  • my-plugin-1.0.0-windows-x64-abc123def.zip
归档内结构:
my-plugin-1.0.0-windows-x64-abc123def/
├── bin/
│   └── 64bit/
│       └── my-plugin.dll
└── data/
    └── locale/
        └── en-US.ini

buildspec.json Pattern

buildspec.json模式

Centralize dependencies and versions:
json
{
  "name": "my-plugin",
  "displayName": "My OBS Plugin",
  "version": "1.0.0",
  "author": "Your Name",
  "dependencies": {
    "obs-studio": {
      "version": "32.0.4",
      "hashes": {
        "windows-x64": "5e17f2e99213af77ee15c047755ee3e3e88b78e5eee17351c113d79671ffb98b"
      }
    }
  }
}
集中管理依赖和版本:
json
{
  "name": "my-plugin",
  "displayName": "My OBS Plugin",
  "version": "1.0.0",
  "author": "Your Name",
  "dependencies": {
    "obs-studio": {
      "version": "32.0.4",
      "hashes": {
        "windows-x64": "5e17f2e99213af77ee15c047755ee3e3e88b78e5eee17351c113d79671ffb98b"
      }
    }
  }
}

FORBIDDEN Patterns

禁用模式

PatternProblemSolution
Missing toolchain fileBuild uses host compilerAlways use
-DCMAKE_TOOLCHAIN_FILE
Linking libobs.a/dllImport library not availableHeaders-only + runtime resolution
Missing .def fileFunctions exported by ordinalCreate plugin.def with named exports
Missing
-static-libgcc
Requires MinGW runtime DLLsAdd to linker flags
Hardcoded OBS pathsBreaks on different systemsUse
OBS_SOURCE_DIR
variable
No checksum verificationSecurity riskVerify SHA256 of downloaded SDK
模式问题解决方案
缺失工具链文件构建使用宿主编译器始终使用
-DCMAKE_TOOLCHAIN_FILE
链接libobs.a/dll导入库不可用仅头文件+运行时解析
缺失.def文件函数仅通过序号导出创建包含命名导出的plugin.def
缺失
-static-libgcc
依赖MinGW运行时DLL添加至链接器标志
硬编码OBS路径在不同系统上失效使用
OBS_SOURCE_DIR
变量
无校验和验证安全风险验证下载的SDK的SHA256

Troubleshooting

故障排除

DLL has no exports

DLL无导出符号

Symptom: Plugin loads but OBS can't find
obs_module_load
Cause: Missing or incorrect .def file
Fix:
bash
undefined
症状: 插件已加载但OBS无法找到
obs_module_load
原因: .def文件缺失或不正确
修复:
bash
undefined

Check exports

Check exports

x86_64-w64-mingw32-objdump -p my-plugin.dll | grep -A 50 "Export Table"
x86_64-w64-mingw32-objdump -p my-plugin.dll | grep -A 50 "Export Table"

Should show named functions, not just ordinals

Should show named functions, not just ordinals

undefined
undefined

Undefined reference to OBS functions

OBS函数未定义引用

Symptom: Linker errors about
obs_register_source
, etc.
Cause: Missing unresolved-symbols flag
Fix: Add to CMakeLists.txt:
cmake
set_target_properties(${PROJECT_NAME} PROPERTIES
    LINK_FLAGS "-Wl,--unresolved-symbols=ignore-all"
)
症状: 链接器报错
obs_register_source
等未定义
原因: 缺失未解析符号标志
修复: 在CMakeLists.txt中添加:
cmake
set_target_properties(${PROJECT_NAME} PROPERTIES
    LINK_FLAGS "-Wl,--unresolved-symbols=ignore-all"
)

Wrong file format

文件格式错误

Symptom:
file
shows "ELF" instead of "PE32+"
Cause: Using host compiler instead of cross-compiler
Fix: Ensure toolchain file is loaded:
bash
cmake -DCMAKE_TOOLCHAIN_FILE=cmake/mingw-w64-toolchain.cmake ..
症状:
file
命令显示"ELF"而非"PE32+"
原因: 使用宿主编译器而非交叉编译器
修复: 确保加载了工具链文件:
bash
cmake -DCMAKE_TOOLCHAIN_FILE=cmake/mingw-w64-toolchain.cmake ..

External Documentation

外部文档

Context7 (Real-time docs)

Context7(实时文档)

mcp__context7__query-docs
libraryId: "/obsproject/obs-studio"
query: "CMake cross-compile Windows Linux plugin"
mcp__context7__query-docs
libraryId: "/obsproject/obs-studio"
query: "CMake cross-compile Windows Linux plugin"

Official References

官方参考

Related Skills

相关技能

  • obs-windows-building - Native Windows builds (MSVC, MinGW)
  • obs-cpp-qt-patterns - Qt frontend integration
  • obs-plugin-developing - Plugin architecture overview
  • obs-audio-plugin-writing - Audio plugin implementation
  • obs-windows-building - 原生Windows构建(MSVC、MinGW)
  • obs-cpp-qt-patterns - Qt前端集成
  • obs-plugin-developing - 插件架构概述
  • obs-audio-plugin-writing - 音频插件实现

Related Agent

相关Agent

Use obs-plugin-expert for coordinated guidance across all OBS plugin skills.
使用obs-plugin-expert获取所有OBS插件技能的协同指导。