ci: patch obs-studio's Windows CMake to define OBS::w32-pthreads
Build / macOS (macos-latest) (push) Successful in 32s
Build / Linux (ubuntu-24.04) (push) Successful in 1m2s
Build / Windows (windows-latest) (push) Failing after 11m20s

libobs/cmake/os-windows.cmake unconditionally links OBS::w32-pthreads, but
in the OBS_CMAKE_VERSION>=3.0.0 ("modern") top-level CMakeLists.txt branch
this bootstrap selects, nothing ever adds deps/w32-pthreads (confirmed at
every checked tag, 30.0.2 through 31.1.1) -- only the legacy branch's
add_subdirectory(deps) does, and libobs/CMakeLists.txt itself only adds
deps/libcaption and deps/uthash.

Upstream's own CI never hits this because it leaves ENABLE_UI on, and
UI/cmake/os-windows.cmake happens to add deps/w32-pthreads as a side effect
of building the Qt UI. Building obs-frontend-api instead of libobs (as
upstream's CI does) does not help: UI/obs-frontend-api/CMakeLists.txt only
links OBS::libobs, and UI/CMakeLists.txt returns before reaching the file
that adds w32-pthreads whenever ENABLE_UI is off -- which this bootstrap
deliberately keeps off to avoid a ~100 MB Qt6 download this plugin's plain
obs_properties_* UI does not need.

Add _patch_obs_studio_w32_pthreads() to buildspec_common.cmake: after the
obs-studio archive is extracted and before the OBS sub-configure runs, patch
its libobs/CMakeLists.txt to add deps/w32-pthreads itself, guarded by the
same if(NOT TARGET OBS::w32-pthreads) check UI/cmake/os-windows.cmake already
uses upstream. Idempotent (skips if already patched) and fails loudly if the
expected anchor text is missing, rather than silently no-opping against a
future OBS version with a different libobs/CMakeLists.txt shape.

Verified locally: the CMake string(FIND)/string(REPLACE) patch logic was run
against the real libobs/CMakeLists.txt fetched from the obs-studio 30.0.2
tag, confirmed to produce the intended block, and confirmed idempotent on a
second run. The actual Windows CMake configure/build this unblocks cannot be
verified from this Linux sandbox -- that's what the next CI run is for.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
This commit is contained in:
2026-09-06 23:12:41 -07:00
co-authored by Claude Sonnet 5
parent c5fedd176f
commit 2bbd94775a
2 changed files with 121 additions and 14 deletions
+52 -14
View File
@@ -33,10 +33,11 @@ under CI). Windows CI has **failed on every completed run so far**. The
`-A x64` argument fix is now confirmed working — the run carrying it got as
far as building libobs — but it exposed a deeper blocker: OBS 30.0.2's
opt-in modern CMake path never defines the `OBS::w32-pthreads` target its own
Windows libobs links against. The PowerShell rewrite of the Windows steps is
still queued and unproven. See "Where the Windows bootstrap got to" under CI
below for the trace and the options, and check current CI status rather than
trusting this paragraph's age.
Windows libobs links against. A targeted bootstrap patch for that gap has been
pushed but not yet confirmed by a completed green run. The PowerShell rewrite
of the Windows steps is also still unproven. See "Where the Windows bootstrap
got to" under CI below for the trace and the options, and check current CI
status rather than trusting this paragraph's age.
See "What is verified, and how" below for exactly what has and has not been
checked, and "Testing this by hand" for what a human still needs to do.
@@ -229,7 +230,7 @@ runners available to this repo under the `CyberCoveLLC` org.
|---|---|---|---|
| `linux` | `ubuntu-24.04` | `localhost.localdomain` | **Green.** Builds the real adapter against Ubuntu's libobs-dev 30.0.2, runs all six test suites, uploads `build/package` as an artifact |
| `macos` | `macos-latest` | `home-mac` (Global) | **Green.** Builds libobs 30.0.2 from source, then the real adapter; 6/6 tests; artifact uploaded. But see the macOS packaging gap below |
| `windows` | `windows-latest` | `winvm-builder` (org-scoped) | **Failing** — every completed run on this branch has failed. The latest gets as far as building libobs and stops on an OBS-side `OBS::w32-pthreads` target that its own modern CMake path never defines; see below |
| `windows` | `windows-latest` | `winvm-builder` (org-scoped) | **Failing, fix pushed and awaiting a completed run.** Every completed run so far has failed; the latest got as far as building libobs and stopped on an OBS-side `OBS::w32-pthreads` target that its own modern CMake path never defines. A bootstrap patch for that gap has been pushed but not yet confirmed by a green run; see below |
The Linux job is pinned to `ubuntu-24.04` rather than `ubuntu-latest`: this
instance's two Linux runners answer `ubuntu-latest` with different releases,
@@ -350,16 +351,53 @@ Deliberately **not** "fixed" by bumping the pin: 30.0.2, 30.1.2, 30.2.3,
`OBS::w32-pthreads` from `libobs/cmake/os-windows.cmake` while none of them
add `deps/w32-pthreads` from `libobs/CMakeLists.txt`. A version bump is
therefore not obviously the answer and needs checking rather than assuming.
Options, roughly in order of preference:
1. Work out how obs-plugintemplate's own Windows CI satisfies this target at
its 31.1.1 pin — it builds `obs-frontend-api` rather than `libobs`, which
may pull in a different subdirectory set. If so, building that target (and
accepting the Qt dependency on Windows only) is the smallest change.
2. Have the bootstrap add `add_subdirectory(deps/w32-pthreads)` to the
extracted OBS tree before configuring. Effective, but a patch against a
third-party tree that must be carried across pin bumps.
3. Drop the from-source libobs on Windows and find a prebuilt OBS SDK.
Option 1 (build `obs-frontend-api`, matching obs-plugintemplate's own CI, and
accept the Qt dependency on Windows only) was investigated and **rejected**:
`UI/obs-frontend-api/CMakeLists.txt` only links `OBS::libobs`, nothing else —
it does not itself pull in `deps/w32-pthreads`. What actually satisfies the
target upstream is that `UI/CMakeLists.txt` returns early when
`ENABLE_UI=OFF`, *before* reaching `include(cmake/os-windows.cmake)` — the
file that (via its own `if(NOT TARGET OBS::w32-pthreads)` guard) adds
`deps/w32-pthreads`. Upstream's CI never sets `ENABLE_UI=OFF`, so that
add-as-a-side-effect-of-Qt always happens for them. Building
`obs-frontend-api` instead of `libobs` would not change any of that; the only
way to get the same side effect is to stop passing `-DENABLE_UI:BOOL=OFF`,
which is exactly the ~100 MB Qt6 download this bootstrap was trimmed to avoid
(see the Windows `buildspec.cmake` comment) and buys this plugin nothing,
since its properties UI is plain `obs_properties_*`.
Went with Option 2 instead: `cmake/common/buildspec_common.cmake` now carries
`_patch_obs_studio_w32_pthreads()`, called for `OS_WINDOWS` right before
`_setup_obs_studio()`. It patches the freshly-extracted
`libobs/CMakeLists.txt` to add the one missing subdirectory itself, using the
exact same `if(NOT TARGET OBS::w32-pthreads)` guard
`UI/cmake/os-windows.cmake` already relies on upstream:
```cmake
if(OS_WINDOWS)
if(NOT TARGET OBS::w32-pthreads)
add_subdirectory("${CMAKE_SOURCE_DIR}/deps/w32-pthreads" "${CMAKE_BINARY_DIR}/deps/w32-pthreads")
endif()
include(cmake/os-windows.cmake)
...
```
It is idempotent (checks for `deps/w32-pthreads` already present in the file
before patching, so re-running against a previously-patched extraction is a
no-op) and fails loudly with `FATAL_ERROR` if the anchor text it expects to
find is not there, rather than silently doing nothing on a future OBS version
whose `libobs/CMakeLists.txt` has changed shape. Verified locally (this is a
Linux sandbox, so only the CMake string-patching logic itself could be
checked, not a real Windows configure/build): ran the same `string(FIND)`
/`string(REPLACE)` sequence against the real `libobs/CMakeLists.txt` fetched
from the obs-studio 30.0.2 tag, confirmed it produces the intended
`if(OS_WINDOWS) / if(NOT TARGET ...) / add_subdirectory(...) / endif() /
include(...)` block, and confirmed a second run against the already-patched
file is a no-op. Whether this actually gets libobs through CMake generate and
building on a real Windows runner is the thing the next CI run needs to
prove — option 3 (dropping the from-source libobs on Windows for a prebuilt
SDK) remains the fallback if it does not.
Two bugs of its own were found; the first is now proven fixed by `edb0c02`
getting past it, the second is still unproven:
+69
View File
@@ -24,6 +24,7 @@
# build tree, so it does not trip over the install rules of targets that
# were deliberately never built.
# 7. _resolve_versioned_macos_sdk exists at all -- see its own comment.
# 8. _patch_obs_studio_w32_pthreads exists at all -- see its own comment.
#
include_guard(GLOBAL)
@@ -147,6 +148,70 @@ function(_resolve_versioned_macos_sdk out_path)
endif()
endfunction()
# _patch_obs_studio_w32_pthreads: Windows-only. Confirmed at every obs-studio
# tag from 30.0.2 through 31.1.1 (checked directly against
# libobs/cmake/os-windows.cmake and the top-level CMakeLists.txt at each tag):
# libobs/cmake/os-windows.cmake unconditionally links `OBS::w32-pthreads`, but
# that target is defined only by deps/w32-pthreads/CMakeLists.txt, and nothing
# in the OBS_CMAKE_VERSION>=3.0.0 ("modern") top-level CMakeLists.txt branch --
# the one -DOBS_CMAKE_VERSION=3.0.0 selects -- ever adds deps/w32-pthreads.
# libobs/CMakeLists.txt itself only adds deps/libcaption and deps/uthash.
#
# Upstream obs-studio's own CI never hits this because it builds with
# ENABLE_UI left ON: UI/cmake/os-windows.cmake happens to add
# deps/w32-pthreads too (guarded by `if(NOT TARGET OBS::w32-pthreads)`), which
# satisfies libobs's link by the time CMake generates -- purely as a side
# effect of Qt still being in the build, not because anything wires
# w32-pthreads to libobs on purpose. This bootstrap deliberately builds with
# ENABLE_UI:BOOL=OFF (see the file header) specifically to avoid pulling in
# Qt6, so that side effect never happens here, and the gap is exposed.
#
# Rather than re-enable ENABLE_UI (and pay for a ~100 MB Qt6 download this
# plugin's plain obs_properties_* UI does not need) or vendor a full copy of
# deps/CMakeLists.txt, patch libobs/CMakeLists.txt to add the one missing
# subdirectory itself, using the exact same existence guard
# UI/cmake/os-windows.cmake already relies on. Idempotent: running this again
# against an already-patched tree is a no-op (the search text no longer
# matches), so it is safe to call on every configure regardless of whether
# .deps/ was freshly extracted or reused from a previous run.
function(_patch_obs_studio_w32_pthreads)
set(_cmakelists "${dependencies_dir}/${_obs_destination}/libobs/CMakeLists.txt")
if(NOT EXISTS "${_cmakelists}")
message(FATAL_ERROR "Cannot apply the w32-pthreads workaround: ${_cmakelists} does not exist.")
endif()
file(READ "${_cmakelists}" _contents)
string(FIND "${_contents}" "deps/w32-pthreads" _already_patched)
if(NOT _already_patched EQUAL -1)
message(STATUS "libobs/CMakeLists.txt already carries the w32-pthreads workaround - skipping")
return()
endif()
set(_needle "if(OS_WINDOWS)\n include(cmake/os-windows.cmake)")
set(_replacement
"if(OS_WINDOWS)\n if(NOT TARGET OBS::w32-pthreads)\n add_subdirectory(\"\${CMAKE_SOURCE_DIR}/deps/w32-pthreads\" \"\${CMAKE_BINARY_DIR}/deps/w32-pthreads\")\n endif()\n include(cmake/os-windows.cmake)"
)
string(FIND "${_contents}" "${_needle}" _pos)
if(_pos EQUAL -1)
message(
FATAL_ERROR
"Could not find the expected 'if(OS_WINDOWS) / include(cmake/os-windows.cmake)' block in "
"${_cmakelists} to apply the w32-pthreads workaround. obs-studio's libobs/CMakeLists.txt "
"layout may have changed since this was written against 30.0.2."
)
endif()
string(REPLACE "${_needle}" "${_replacement}" _patched "${_contents}")
file(WRITE "${_cmakelists}" "${_patched}")
message(
STATUS
"Patched ${_cmakelists}: added deps/w32-pthreads so OBS::w32-pthreads exists "
"(obs-studio's modern Windows CMake path never defines it with ENABLE_UI=OFF)."
)
endfunction()
# _setup_obs_studio: Create obs-studio build project, then build libobs and obs-frontend-api
function(_setup_obs_studio)
if(NOT libobs_DIR)
@@ -366,5 +431,9 @@ function(_check_dependencies)
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} CACHE PATH "CMake prefix search path" FORCE)
if(OS_WINDOWS)
_patch_obs_studio_w32_pthreads()
endif()
_setup_obs_studio()
endfunction()