obs-windows-building
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOBS Windows Building
OBS Windows平台插件构建
Purpose
用途
Build OBS Studio plugins for Windows using MSVC (Visual Studio) or MinGW. Covers symbol exports, Windows-specific linking, platform source files, and DLL verification.
使用MSVC(Visual Studio)或MinGW在Windows平台构建OBS Studio插件。内容涵盖符号导出、Windows专属链接、平台源码文件以及DLL验证。
When NOT to Use
不适用于以下场景
- Cross-compiling from Linux → Use obs-cross-compiling
- Qt/C++ frontend development → Use obs-cpp-qt-patterns
- Audio plugin implementation → Use obs-audio-plugin-writing
- Code review → Use obs-plugin-reviewing
- 从Linux交叉编译 → 使用obs-cross-compiling
- Qt/C++前端开发 → 使用obs-cpp-qt-patterns
- 音频插件实现 → 使用obs-audio-plugin-writing
- 代码审查 → 使用obs-plugin-reviewing
Quick Start: Windows Build in 4 Steps
快速入门:Windows平台构建四步走
Step 1: Install Prerequisites
步骤1:安装前置依赖
Visual Studio 2022:
- Workload: "Desktop development with C++"
- Individual components: CMake, Windows SDK
Or MinGW (via MSYS2):
bash
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-cmakeVisual Studio 2022:
- 工作负载:"使用C++的桌面开发"
- 单独组件:CMake、Windows SDK
或MinGW(通过MSYS2安装):
bash
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-cmakeStep 2: Create Windows CMake Preset
步骤2:创建Windows CMake预设
json
{
"name": "windows-x64",
"displayName": "Windows x64",
"description": "Build for Windows x64 with Visual Studio",
"binaryDir": "${sourceDir}/build_x64",
"generator": "Visual Studio 17 2022",
"architecture": "x64",
"cacheVariables": {
"OBS_SOURCE_DIR": "${sourceDir}/.deps/windows-x64/obs-studio-32.0.4"
}
}json
{
"name": "windows-x64",
"displayName": "Windows x64",
"description": "Build for Windows x64 with Visual Studio",
"binaryDir": "${sourceDir}/build_x64",
"generator": "Visual Studio 17 2022",
"architecture": "x64",
"cacheVariables": {
"OBS_SOURCE_DIR": "${sourceDir}/.deps/windows-x64/obs-studio-32.0.4"
}
}Step 3: Create .def Export File
步骤3:创建.def导出文件
Create :
src/plugin.defdef
LIBRARY my-plugin
EXPORTS
obs_module_load
obs_module_unload
obs_module_post_load
obs_module_ver
obs_module_set_pointer
obs_current_module
obs_module_description
obs_module_set_locale
obs_module_free_locale
obs_module_get_string
obs_module_text创建:
src/plugin.defdef
LIBRARY my-plugin
EXPORTS
obs_module_load
obs_module_unload
obs_module_post_load
obs_module_ver
obs_module_set_pointer
obs_current_module
obs_module_description
obs_module_set_locale
obs_module_free_locale
obs_module_get_string
obs_module_textStep 4: Configure CMakeLists.txt
步骤4:配置CMakeLists.txt
cmake
if(WIN32)
# Windows system libraries
target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 comctl32)
# Export module functions via .def file
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
# MinGW
set_target_properties(${PROJECT_NAME} PROPERTIES
LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def -Wl,--unresolved-symbols=ignore-all"
)
else()
# MSVC
set_target_properties(${PROJECT_NAME} PROPERTIES
LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def"
)
endif()
endif()cmake
if(WIN32)
# Windows system libraries
target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 comctl32)
# Export module functions via .def file
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
# MinGW
set_target_properties(${PROJECT_NAME} PROPERTIES
LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def -Wl,--unresolved-symbols=ignore-all"
)
else()
# MSVC
set_target_properties(${PROJECT_NAME} PROPERTIES
LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def"
)
endif()
endif()MSVC vs MinGW Comparison
MSVC与MinGW对比
| Aspect | MSVC | MinGW |
|---|---|---|
| IDE | Visual Studio | VS Code, CLion |
| Debugging | Full VS debugger | GDB |
| Build speed | Slower | Faster |
| ABI | Native Windows | GCC-based |
| Qt compat | Requires MSVC Qt | Works with MinGW Qt |
| CI/CD | Windows runner | Linux cross-compile |
Recommendation: Use MSVC for native Windows development, MinGW for CI cross-compilation.
| 对比维度 | MSVC | MinGW |
|---|---|---|
| 集成开发环境 | Visual Studio | VS Code、CLion |
| 调试工具 | 完整VS调试器 | GDB |
| 构建速度 | 较慢 | 较快 |
| 应用二进制接口(ABI) | 原生Windows标准 | 基于GCC |
| Qt兼容性 | 需要MSVC版本的Qt | 兼容MinGW版本的Qt |
| CI/CD支持 | Windows运行器 | Linux交叉编译 |
推荐方案: 原生Windows开发使用MSVC,CI交叉编译使用MinGW。
Symbol Export with .def Files
使用.def文件导出符号
Why .def Files?
为什么需要.def文件?
OBS loads plugins at runtime and looks up functions by name. Without explicit exports:
- MSVC may not export functions without
__declspec(dllexport) - MinGW may export by ordinal only (numbers, not names)
OBS在运行时加载插件,并通过函数名称查找函数。如果没有显式导出:
- MSVC可能不会导出未标记的函数
__declspec(dllexport) - MinGW可能仅通过序号(数字而非名称)导出函数
.def File Format
.def文件格式
def
; Comments start with semicolon
LIBRARY my-plugin ; DLL name
EXPORTS
obs_module_load ; Function to export
obs_module_unload
; Add all OBS_DECLARE_MODULE() and OBS_MODULE_USE_DEFAULT_LOCALE() functionsdef
; 注释以分号开头
LIBRARY my-plugin ; DLL名称
EXPORTS
obs_module_load ; 要导出的函数
obs_module_unload
; 添加所有OBS_DECLARE_MODULE()和OBS_MODULE_USE_DEFAULT_LOCALE()相关函数MSVC Linker Flag
MSVC链接器参数
cmake
set_target_properties(${PROJECT_NAME} PROPERTIES
LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def"
)cmake
set_target_properties(${PROJECT_NAME} PROPERTIES
LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def"
)MinGW Linker Flag
MinGW链接器参数
cmake
set_target_properties(${PROJECT_NAME} PROPERTIES
LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def -Wl,--unresolved-symbols=ignore-all"
)cmake
set_target_properties(${PROJECT_NAME} PROPERTIES
LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/src/plugin.def -Wl,--unresolved-symbols=ignore-all"
)Windows System Libraries
Windows系统库
Common Libraries
常用库
| Library | Purpose | Header |
|---|---|---|
| Windows Sockets 2 (networking) | |
| Common controls (UI widgets) | |
| Windows API (windows, messages) | |
| Core Windows API | |
| COM support | |
| GUID/UUID support | |
| 库名称 | 用途 | 头文件 |
|---|---|---|
| Windows Sockets 2(网络功能) | |
| 通用控件(UI组件) | |
| Windows API(窗口、消息) | |
| 核心Windows API | |
| COM支持 | |
| GUID/UUID支持 | |
CMake Linking
CMake链接配置
cmake
if(WIN32)
target_link_libraries(${PROJECT_NAME} PRIVATE
ws2_32 # Sockets
comctl32 # UI controls
)
endif()cmake
if(WIN32)
target_link_libraries(${PROJECT_NAME} PRIVATE
ws2_32 # 套接字
comctl32 # UI控件
)
endif()Include Order (CRITICAL)
头文件包含顺序(至关重要)
c
/* WRONG - will cause compile errors */
#include <windows.h>
#include <winsock2.h>
/* CORRECT - winsock2.h must come first */
#include <winsock2.h>
#include <windows.h>c
/* 错误写法 - 会导致编译错误 */
#include <windows.h>
#include <winsock2.h>
/* 正确写法 - winsock2.h必须放在前面 */
#include <winsock2.h>
#include <windows.h>Platform-Specific Source Files
平台专属源码文件
Directory Structure
目录结构
src/
├── plugin-main.c # Cross-platform
├── my-source.c # Cross-platform
└── platform/
├── socket-posix.c # Linux/macOS
└── socket-win32.c # Windowssrc/
├── plugin-main.c # 跨平台代码
├── my-source.c # 跨平台代码
└── platform/
├── socket-posix.c # Linux/macOS平台
└── socket-win32.c # Windows平台CMakeLists.txt Pattern
CMakeLists.txt编写模式
cmake
undefinedcmake
undefinedCommon sources
通用源码
target_sources(${PROJECT_NAME} PRIVATE
src/plugin-main.c
src/my-source.c
)
target_sources(${PROJECT_NAME} PRIVATE
src/plugin-main.c
src/my-source.c
)
Platform-specific sources
平台专属源码
if(WIN32)
target_sources(${PROJECT_NAME} PRIVATE
src/platform/socket-win32.c
)
else()
target_sources(${PROJECT_NAME} PRIVATE
src/platform/socket-posix.c
)
endif()
undefinedif(WIN32)
target_sources(${PROJECT_NAME} PRIVATE
src/platform/socket-win32.c
)
else()
target_sources(${PROJECT_NAME} PRIVATE
src/platform/socket-posix.c
)
endif()
undefinedPlatform Header Pattern
平台头文件编写模式
c
/* platform.h - Platform abstraction */
#pragma once
#ifdef _WIN32
#include "platform/socket-win32.h"
#else
#include "platform/socket-posix.h"
#endif
/* Common interface */
int platform_socket_init(void);
void platform_socket_cleanup(void);
int platform_socket_send(const char *host, int port, const void *data, size_t len);c
/* platform.h - 平台抽象层 */
#pragma once
#ifdef _WIN32
#include "platform/socket-win32.h"
#else
#include "platform/socket-posix.h"
#endif
/* 通用接口 */
int platform_socket_init(void);
void platform_socket_cleanup(void);
int platform_socket_send(const char *host, int port, const void *data, size_t len);Windows-Specific Code Patterns
Windows专属代码模式
Winsock Initialization
Winsock初始化
c
/* socket-win32.c */
#include <winsock2.h>
#include <ws2tcpip.h>
static bool winsock_initialized = false;
int platform_socket_init(void)
{
WSADATA wsa_data;
int result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (result != 0) {
return -1;
}
winsock_initialized = true;
return 0;
}
void platform_socket_cleanup(void)
{
if (winsock_initialized) {
WSACleanup();
winsock_initialized = false;
}
}c
/* socket-win32.c */
#include <winsock2.h>
#include <ws2tcpip.h>
static bool winsock_initialized = false;
int platform_socket_init(void)
{
WSADATA wsa_data;
int result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (result != 0) {
return -1;
}
winsock_initialized = true;
return 0;
}
void platform_socket_cleanup(void)
{
if (winsock_initialized) {
WSACleanup();
winsock_initialized = false;
}
}Windows API Loader Pattern
Windows API加载模式
For optional Windows APIs (not always available):
c
/* api-loader.c */
#include <windows.h>
typedef BOOL (WINAPI *SetProcessDpiAwarenessContext_t)(DPI_AWARENESS_CONTEXT);
static SetProcessDpiAwarenessContext_t pSetProcessDpiAwarenessContext = NULL;
void load_optional_apis(void)
{
HMODULE user32 = GetModuleHandleW(L"user32.dll");
if (user32) {
pSetProcessDpiAwarenessContext = (SetProcessDpiAwarenessContext_t)
GetProcAddress(user32, "SetProcessDpiAwarenessContext");
}
}
void set_dpi_awareness(void)
{
if (pSetProcessDpiAwarenessContext) {
pSetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
}针对可选Windows API(并非所有系统都支持):
c
/* api-loader.c */
#include <windows.h>
typedef BOOL (WINAPI *SetProcessDpiAwarenessContext_t)(DPI_AWARENESS_CONTEXT);
static SetProcessDpiAwarenessContext_t pSetProcessDpiAwarenessContext = NULL;
void load_optional_apis(void)
{
HMODULE user32 = GetModuleHandleW(L"user32.dll");
if (user32) {
pSetProcessDpiAwarenessContext = (SetProcessDpiAwarenessContext_t)
GetProcAddress(user32, "SetProcessDpiAwarenessContext");
}
}
void set_dpi_awareness(void)
{
if (pSetProcessDpiAwarenessContext) {
pSetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
}OBS Plugin Installation Paths
OBS插件安装路径
User Installation (Recommended)
用户级安装(推荐)
%APPDATA%\obs-studio\plugins\my-plugin\
├── bin\
│ └── 64bit\
│ └── my-plugin.dll
└── data\
└── locale\
└── en-US.ini%APPDATA%\obs-studio\plugins\my-plugin\
├── bin\
│ └── 64bit\
│ └── my-plugin.dll
└── data\
└── locale\
└── en-US.iniSystem Installation
系统级安装
C:\ProgramData\obs-studio\plugins\my-plugin\
├── bin\
│ └── 64bit\
│ └── my-plugin.dll
└── data\
└── locale\
└── en-US.iniC:\ProgramData\obs-studio\plugins\my-plugin\
├── bin\
│ └── 64bit\
│ └── my-plugin.dll
└── data\
└── locale\
└── en-US.iniCMake Install Target
CMake安装目标配置
cmake
if(WIN32)
set(OBS_PLUGIN_DIR "$ENV{APPDATA}/obs-studio/plugins/${PROJECT_NAME}")
endif()
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION ${OBS_PLUGIN_DIR}/bin/64bit
)
install(DIRECTORY data/locale
DESTINATION ${OBS_PLUGIN_DIR}/data
)cmake
if(WIN32)
set(OBS_PLUGIN_DIR "$ENV{APPDATA}/obs-studio/plugins/${PROJECT_NAME}")
endif()
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION ${OBS_PLUGIN_DIR}/bin/64bit
)
install(DIRECTORY data/locale
DESTINATION ${OBS_PLUGIN_DIR}/data
)DLL Verification
DLL验证
Check File Type
检查文件类型
cmd
:: PowerShell
Get-Item my-plugin.dll | Select-Object Name, Lengthcmd
:: PowerShell
Get-Item my-plugin.dll | Select-Object Name, LengthCheck Exports with dumpbin (MSVC)
使用dumpbin检查导出(MSVC)
cmd
dumpbin /exports my-plugin.dllExpected output:
ordinal hint RVA name
1 0 00001000 obs_current_module
2 1 00001010 obs_module_description
3 2 00001020 obs_module_load
...cmd
dumpbin /exports my-plugin.dll预期输出:
ordinal hint RVA name
1 0 00001000 obs_current_module
2 1 00001010 obs_module_description
3 2 00001020 obs_module_load
...Check Exports with objdump (MinGW)
使用objdump检查导出(MinGW)
bash
x86_64-w64-mingw32-objdump -p my-plugin.dll | grep -A 50 "Export Table"bash
x86_64-w64-mingw32-objdump -p my-plugin.dll | grep -A 50 "Export Table"FORBIDDEN Patterns
禁用模式
| Pattern | Problem | Solution |
|---|---|---|
| Missing .def file | Functions not exported by name | Create plugin.def |
| Wrong include order | winsock2 errors | Include winsock2.h before windows.h |
| Missing WSAStartup | Socket functions fail | Call platform_socket_init() |
| Hardcoded paths | Breaks on other machines | Use %APPDATA% or relative paths |
| ANSI APIs | Unicode issues | Use wide (W) APIs or UTF-8 |
| Missing /DEF linker flag | No exports in DLL | Add LINK_FLAGS in CMake |
| 模式 | 问题 | 解决方案 |
|---|---|---|
| 缺失.def文件 | 函数未按名称导出 | 创建plugin.def文件 |
| 头文件包含顺序错误 | winsock2编译错误 | 将winsock2.h放在windows.h之前包含 |
| 未调用WSAStartup | 套接字函数执行失败 | 调用platform_socket_init() |
| 硬编码路径 | 在其他机器上无法正常运行 | 使用%APPDATA%或相对路径 |
| 使用ANSI API | 存在Unicode兼容问题 | 使用宽字符(W)API或UTF-8编码 |
| 缺失/DEF链接参数 | DLL中无导出内容 | 在CMake中添加LINK_FLAGS配置 |
Troubleshooting
故障排查
Plugin Not Visible in OBS
OBS中无法看到插件
Check:
- DLL is in subdirectory
bin/64bit/ - Path is correct:
%APPDATA%\obs-studio\plugins\{name}\bin\64bit\ - DLL exports are present:
dumpbin /exports my-plugin.dll
检查项:
- DLL是否位于子目录下
bin/64bit/ - 路径是否正确:
%APPDATA%\obs-studio\plugins\{name}\bin\64bit\ - DLL是否包含导出内容:执行检查
dumpbin /exports my-plugin.dll
"Entry Point Not Found" Error
「找不到入口点」错误
Cause: Missing export
obs_module_loadFix: Ensure .def file includes and linker flag is set.
obs_module_load原因: 缺失导出项
obs_module_load修复方案: 确保.def文件包含,且已设置链接器参数。
obs_module_loadWinsock Errors
Winsock错误
Symptom: Socket functions return -1 or WSANOTINITIALISED
Fix: Call before any socket operations.
WSAStartup()症状: 套接字函数返回-1或WSANOTINITIALISED
修复方案: 在任何套接字操作前调用。
WSAStartup()Unicode/ANSI Mismatch
Unicode/ANSI不匹配
Symptom: String corruption, "???" characters
Fix:
c
/* Use wide APIs or define UNICODE */
#define UNICODE
#define _UNICODE
#include <windows.h>症状: 字符串损坏、出现「???」字符
修复方案:
c
/* 使用宽字符API或定义UNICODE宏 */
#define UNICODE
#define _UNICODE
#include <windows.h>Build Commands
构建命令
Visual Studio
Visual Studio
cmd
:: Configure
cmake --preset windows-x64
:: Build
cmake --build --preset windows-x64 --config RelWithDebInfo
:: Install
cmake --install build_x64 --config RelWithDebInfocmd
:: 配置
cmake --preset windows-x64
:: 构建
cmake --build --preset windows-x64 --config RelWithDebInfo
:: 安装
cmake --install build_x64 --config RelWithDebInfoMinGW (MSYS2)
MinGW(MSYS2)
bash
undefinedbash
undefinedConfigure
配置
cmake -G "Ninja" -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake -G "Ninja" -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
Build
构建
cmake --build build
cmake --build build
Install
安装
cmake --install build
undefinedcmake --install build
undefinedExternal Documentation
外部文档
Context7
Context7
mcp__context7__query-docs
libraryId: "/obsproject/obs-studio"
query: "Windows plugin build Visual Studio MSVC"mcp__context7__query-docs
libraryId: "/obsproject/obs-studio"
query: "Windows plugin build Visual Studio MSVC"Official References
官方参考资料
- OBS Windows Build: https://obsproject.com/wiki/Building-OBS-Studio
- Visual Studio Docs: https://docs.microsoft.com/en-us/visualstudio/
- Windows SDK: https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/
- OBS Windows构建文档:https://obsproject.com/wiki/Building-OBS-Studio
- Visual Studio官方文档:https://docs.microsoft.com/en-us/visualstudio/
- Windows SDK官方下载:https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/
Related Skills
相关技能
- obs-cross-compiling - Cross-compile from Linux to Windows
- obs-cpp-qt-patterns - Qt frontend integration
- obs-plugin-developing - Plugin architecture overview
- obs-audio-plugin-writing - Audio plugin implementation
- obs-cross-compiling - 从Linux交叉编译到Windows
- 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插件技能的协同指导。