Fix Windows configure: point find_package at OBS's exported w32-pthreads
Build / macOS (macos-latest) (push) Successful in 28s
Build / Linux (ubuntu-24.04) (push) Successful in 46s
Build / Windows (windows-latest) (push) Successful in 13m44s

The libobs_DIR fix in 79de5e8f worked -- libobsConfig.cmake now loads on the
Windows runner -- and immediately exposed the next link in the same chain.
obs-studio's libobsConfig.cmake.in carries, under if(MSVC), a hard

    find_dependency(w32-pthreads REQUIRED)

because libobs/cmake/os-windows.cmake links PUBLIC OBS::w32-pthreads. That
lookup failed and aborted the whole configure.

The cause is not a missing export, which was the first hypothesis:
deps/w32-pthreads/CMakeLists.txt ends in target_export(w32-pthreads), the
same helper libobs itself uses, so the install(TARGETS ... EXPORT),
install(EXPORT ... NAMESPACE OBS::) and generated w32-pthreadsConfig.cmake
all exist and all run -- CMake would have hard-errored at generate time if
w32-pthreads were in no export set, and our own patch adds it under the
libobs subtree, which installs before the tolerated obs-frontend-api install
error stops the rest.

It is the same search-path mismatch libobs itself had: target_export installs
to <prefix>/${OBS_CMAKE_DESTINATION}/<target>/, which on Windows is
<prefix>/cmake/w32-pthreads/ -- a shape find_package's Config-mode suffixes
never search. So apply the same remedy CMake's own error message suggests,
and apply it before the find_package(libobs) call that transitively triggers
the find_dependency.

Also adds a fallback Findw32-pthreads.cmake, reached only when that export is
genuinely absent, which reconstructs OBS::w32-pthreads from the bootstrap's
artifacts, and a repair for a locationless imported target mirroring the
existing OBS::libobs one. The fallback deliberately lives in
cmake/windows/find-fallback/ rather than cmake/windows/, which osconfig.cmake
already puts on CMAKE_MODULE_PATH: a find module there would shadow OBS's
real exported package on every build, since MODULE mode is tried first.

Verified on Linux (this is a Linux sandbox) by reconstructing the exact
failure -- a stub libobsConfig.cmake with the same find_dependency, reached
through libobs_DIR -- and confirming it fails without this block and passes
with it, and separately that deleting the package routes find_package through
the fallback module instead. A full Linux configure of the repo is unchanged;
both new blocks are inside if(OS_WINDOWS) and the upstream find_dependency is
inside if(MSVC), so macOS and Linux are no-ops.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
This commit is contained in:
2026-09-07 05:40:38 -07:00
co-authored by Claude Sonnet 5
parent 1a8255230f
commit f27b1c0b45
3 changed files with 312 additions and 0 deletions
+111
View File
@@ -184,8 +184,119 @@ if(OS_WINDOWS AND NOT libobs_DIR)
endif() endif()
endif() endif()
# ...and the exact same problem, one level down, for w32-pthreads.
#
# libobs/cmake/os-windows.cmake links `PUBLIC OBS::w32-pthreads`, so
# obs-studio's libobsConfig.cmake.in carries, verbatim:
#
# if(MSVC)
# find_dependency(w32-pthreads REQUIRED)
# endif()
#
# That call is REQUIRED, it runs from inside libobsConfig.cmake, and until
# this block existed it aborted the whole configure the moment the libobs_DIR
# fix above finally succeeded in loading that config file:
#
# By not providing "Findw32-pthreads.cmake" in CMAKE_MODULE_PATH this
# project has asked CMake to find a package configuration file provided by
# "w32-pthreads", but CMake did not find one.
# .deps/cmake/libobs/libobsConfig.cmake:30 (find_dependency)
#
# This is NOT a missing export. deps/w32-pthreads/CMakeLists.txt ends with
# `target_export(w32-pthreads)`, which is the same helper libobs itself uses
# (cmake/common/helpers_common.cmake): it emits install(TARGETS ... EXPORT
# w32-pthreadsTargets), install(EXPORT ... NAMESPACE OBS::), a generated
# w32-pthreadsConfig.cmake and its version file, all COMPONENT Development.
# Those rules *must* exist and *must* have run, for two independent reasons:
#
# 1. CMake hard-errors at generate time if a target in one export set links
# to a target that is in no export set at all ("install(EXPORT
# "libobsTargets") includes target "libobs" which requires target
# "w32-pthreads" that is not in any export set"). obs-studio's generate
# step succeeded, so w32-pthreads was exported.
# 2. The install rules land under the libobs *directory* (this repo's
# _patch_obs_studio_w32_pthreads adds deps/w32-pthreads from
# libobs/CMakeLists.txt), and libobs is the first subdirectory the modern
# top-level CMakeLists.txt adds -- so its whole subtree installs before
# the tolerated UI/obs-frontend-api install error aborts the rest.
#
# The failure is purely the search path, identical to libobs's: target_export
# installs the package to "${OBS_CMAKE_DESTINATION}/${target}", which on
# Windows is <prefix>/cmake/w32-pthreads/ -- a shape find_package never
# searches. So apply the same remedy CMake's own error message suggests, and
# do it BEFORE find_package(libobs) below, because that is the call that
# transitively triggers find_dependency(w32-pthreads).
#
# macOS and Linux never reach this: the find_dependency is inside `if(MSVC)`,
# and OS_WINDOWS gates the block regardless -- a pure no-op off Windows.
if(OS_WINDOWS AND NOT w32-pthreads_DIR)
set(_stplugin_win_pthreads_dir "${CMAKE_CURRENT_SOURCE_DIR}/.deps/cmake/w32-pthreads")
if(EXISTS "${_stplugin_win_pthreads_dir}/w32-pthreadsConfig.cmake")
set(w32-pthreads_DIR "${_stplugin_win_pthreads_dir}" CACHE PATH
"Directory containing w32-pthreadsConfig.cmake" FORCE)
message(STATUS
"w32-pthreads_DIR not set; libobsConfig.cmake's "
"find_dependency(w32-pthreads REQUIRED) hits the same "
"OBS_CMAKE_DESTINATION=cmake search-suffix problem as libobs "
"itself, so pointing it directly at the from-source install: "
"${_stplugin_win_pthreads_dir}")
else()
# Fall back to a hand-written find module rather than letting the
# REQUIRED find_dependency kill the configure. cmake/windows is
# already on CMAKE_MODULE_PATH (see cmake/common/osconfig.cmake), so
# the fallback module deliberately lives in a subdirectory that is
# NOT -- a Findw32-pthreads.cmake sitting on the default module path
# would shadow OBS's own exported package on every build, and its
# real export is the better answer whenever it is present.
#
# Reaching here means the bootstrap install did not produce the
# export, so say exactly what IS in .deps/cmake/ -- the next CI log
# then answers the question directly instead of costing another run.
file(GLOB _stplugin_deps_cmake_dirs "${CMAKE_CURRENT_SOURCE_DIR}/.deps/cmake/*")
message(STATUS
"No w32-pthreadsConfig.cmake at ${_stplugin_win_pthreads_dir}; "
"OBS CMake packages actually installed under .deps/cmake: "
"'${_stplugin_deps_cmake_dirs}'. Falling back to this repo's own "
"Findw32-pthreads.cmake, which builds OBS::w32-pthreads straight "
"from the bootstrap's build artifacts.")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows/find-fallback")
endif()
endif()
find_package(libobs QUIET) find_package(libobs QUIET)
# OBS::w32-pthreads can come back locationless for exactly the same reason
# OBS::libobs can (see the block below this one): the package config loads,
# but the per-configuration w32-pthreadsTargets-release.cmake that carries
# IMPORTED_IMPLIB/IMPORTED_LOCATION may not have been installed. libobs links
# it PUBLIC, so it is on this plugin's own link line and an empty location is
# a generate-time error, not a warning. Repair it from the known install
# destinations (obs-studio/cmake/windows/defaults.cmake:
# OBS_EXECUTABLE_DESTINATION=bin/64bit for the DLL, OBS_LIBRARY_DESTINATION=lib
# for the import library) -- the same repair, and the same reasoning, as the
# OBS::libobs one.
if(OS_WINDOWS AND TARGET OBS::w32-pthreads)
get_target_property(_stplugin_pthreads_implib OBS::w32-pthreads IMPORTED_IMPLIB)
get_target_property(_stplugin_pthreads_implib_release OBS::w32-pthreads IMPORTED_IMPLIB_RELEASE)
if(NOT _stplugin_pthreads_implib AND NOT _stplugin_pthreads_implib_release)
find_file(_stplugin_pthreads_implib_found w32-pthreads.lib
PATHS "${CMAKE_CURRENT_SOURCE_DIR}/.deps/lib" NO_DEFAULT_PATH)
find_file(_stplugin_pthreads_dll_found w32-pthreads.dll
PATHS "${CMAKE_CURRENT_SOURCE_DIR}/.deps/bin/64bit" NO_DEFAULT_PATH)
if(_stplugin_pthreads_implib_found)
set_target_properties(OBS::w32-pthreads PROPERTIES
IMPORTED_IMPLIB "${_stplugin_pthreads_implib_found}")
if(_stplugin_pthreads_dll_found)
set_target_properties(OBS::w32-pthreads PROPERTIES
IMPORTED_LOCATION "${_stplugin_pthreads_dll_found}")
endif()
message(STATUS
"OBS::w32-pthreads had no imported location; pointed it at "
"${_stplugin_pthreads_implib_found}")
endif()
endif()
endif()
# The imported OBS::libobs target can come back without a location. OBS 30.0.2 # The imported OBS::libobs target can come back without a location. OBS 30.0.2
# installs libobsTargets.cmake but not the per-configuration # installs libobsTargets.cmake but not the per-configuration
# libobsTargets-<config>.cmake alongside it when libobs is built on its own, # libobsTargets-<config>.cmake alongside it when libobs is built on its own,
+83
View File
@@ -458,3 +458,86 @@ pass", which earlier (failing-job) runs did show before failing later in the
job. The `w32-pthreads` blocker above is the next thing to solve, and it is job. The `w32-pthreads` blocker above is the next thing to solve, and it is
upstream's problem to work around rather than a defect in this repo's upstream's problem to work around rather than a defect in this repo's
bootstrap. bootstrap.
### After the w32-pthreads target: the w32-pthreads *package*
The `add_subdirectory(deps/w32-pthreads)` patch above did its job — the
`edb0c02`-era generate error is gone, obs-studio 30.0.2 configures, builds
`w32-pthreads.dll` and `obs.dll`, and installs. Two further Windows-only
blockers then surfaced behind it, both the same underlying upstream mismatch
and neither one a defect in this repo:
1. **`find_package(libobs)` could not locate the package it had just
installed.** obs-studio's `cmake/windows/defaults.cmake` sets
`OBS_CMAKE_DESTINATION=cmake`, and `target_export()` installs each
package to `<prefix>/${OBS_CMAKE_DESTINATION}/<target>/` — i.e.
`.deps/cmake/libobs/`. That is not one of CMake's Config-mode search
suffixes (`<prefix>/cmake/` is, but only for a config file sitting
*directly* in it; `<prefix>/<name>*/cmake/` is, but the `<name>`
directory has to come first). Fixed in `79de5e8f` by setting
`libobs_DIR` explicitly; the long comment above that block in
`CMakeLists.txt` has the full reasoning.
2. **…and then `libobsConfig.cmake` could not locate `w32-pthreads` for
exactly the same reason.** `libobs/cmake/os-windows.cmake` links
`PUBLIC OBS::w32-pthreads`, so upstream's `libobsConfig.cmake.in` carries
a hard `find_dependency(w32-pthreads REQUIRED)` under `if(MSVC)`. Once
fix 1 finally got that config file loaded, the dependency lookup inside
it failed and killed the configure:
```
By not providing "Findw32-pthreads.cmake" in CMAKE_MODULE_PATH this project
has asked CMake to find a package configuration file provided by
"w32-pthreads", but CMake did not find one.
.deps/cmake/libobs/libobsConfig.cmake:30 (find_dependency)
```
**This is not a missing export**, which was the first hypothesis and is
worth recording as wrong: `deps/w32-pthreads/CMakeLists.txt` ends with
`target_export(w32-pthreads)`, the same helper `libobs` itself uses, so
it does emit `install(TARGETS … EXPORT w32-pthreadsTargets)`,
`install(EXPORT … NAMESPACE OBS::)` and a generated
`w32-pthreadsConfig.cmake`, all `COMPONENT Development`. Two independent
arguments say those rules ran: CMake hard-errors at generate time if an
exported target links a target that is in no export set at all (and OBS's
generate step succeeded), and this repo's patch adds `deps/w32-pthreads`
from `libobs/CMakeLists.txt`, making it part of the `libobs` subtree —
which installs *before* the tolerated `UI/obs-frontend-api` install error
aborts the rest. The package really is at `.deps/cmake/w32-pthreads/`;
`find_package` was simply never going to look there.
So the fix is the same one-liner as for `libobs`, and it is literally
what CMake's own error message suggests: set `w32-pthreads_DIR` before
the `find_package(libobs)` call that transitively triggers the
`find_dependency`. Both `_DIR` blocks now sit next to each other in
`CMakeLists.txt`.
Behind that sits `cmake/windows/find-fallback/Findw32-pthreads.cmake`,
used only if that export is genuinely absent from `.deps/`. It rebuilds
`OBS::w32-pthreads` by hand from the bootstrap's own artifacts. It
deliberately does *not* live in `cmake/windows/`, which
`cmake/common/osconfig.cmake` already puts on `CMAKE_MODULE_PATH` for
every Windows configure — a find module there would shadow OBS's real
exported package on every build, since `find_package` tries MODULE mode
before CONFIG mode. `CMakeLists.txt` appends the `find-fallback/`
directory to `CMAKE_MODULE_PATH` only after it has established the real
export is missing, and logs what *is* under `.deps/cmake/` when it does,
so a future failure of this shape is answered by the CI log rather than
by another run.
Note this package is load-bearing for more than the dependency check:
`libobs/util/threading.h` does `#include <pthread.h>`, and on Windows
that header only exists because `target_export(w32-pthreads)` installs
`pthread.h`/`sched.h` as `PUBLIC_HEADER` into `.deps/include/`.
Verified before pushing, on Linux, since this is a Linux sandbox: a
reconstruction of the exact failure — a stub `libobsConfig.cmake` containing
`find_dependency(w32-pthreads REQUIRED)`, reached through `libobs_DIR`, with
the package installed at `.deps/cmake/w32-pthreads/` — reproduces the CI
error without the `w32-pthreads_DIR` block and passes with it; and the
fallback find module was exercised separately by deleting that package, with
`find_package` resolving through MODULE mode to it instead. A full Linux
configure of this repo is unchanged (both blocks are inside `if(OS_WINDOWS)`,
and the upstream `find_dependency` is inside `if(MSVC)`, so macOS and Linux
are pure no-ops). Whether the real Windows runner now gets to a
`streamer-tools-camera.dll` is what the CI run on this commit has to show.
@@ -0,0 +1,118 @@
# Findw32-pthreads.cmake -- last-resort fallback, Windows only.
#
# WHY THIS EXISTS
#
# obs-studio's libobs links `PUBLIC OBS::w32-pthreads` on Windows
# (libobs/cmake/os-windows.cmake), so the libobsConfig.cmake it installs
# carries an unconditional, REQUIRED dependency on a findable `w32-pthreads`
# CMake package:
#
# if(MSVC)
# find_dependency(w32-pthreads REQUIRED)
# endif()
#
# obs-studio *does* export that package -- deps/w32-pthreads/CMakeLists.txt
# ends in `target_export(w32-pthreads)` -- but it exports it to
# <prefix>/cmake/w32-pthreads/, the same OBS_CMAKE_DESTINATION shape that
# find_package's Config-mode search suffixes never look at. The top-level
# CMakeLists.txt therefore points `w32-pthreads_DIR` straight at it, exactly
# as it already does for `libobs_DIR`, and that is the path this build is
# expected to take.
#
# This module is only reached when that export is genuinely absent from
# .deps/ -- for instance if a future obs-studio changes where or whether
# deps/w32-pthreads installs its package, or if the tolerated
# UI/obs-frontend-api install error in
# cmake/common/buildspec_common.cmake::_setup_obs_studio ever starts aborting
# the install *before* libobs's own subtree instead of after it. In that case
# the alternative is a hard configure failure inside libobsConfig.cmake with
# no plugin module built at all, so reconstructing the imported target by
# hand from artifacts the bootstrap definitely produced is strictly better.
#
# It deliberately lives in cmake/windows/find-fallback/ and NOT in
# cmake/windows/, which cmake/common/osconfig.cmake puts on CMAKE_MODULE_PATH
# for every Windows configure. A Findw32-pthreads.cmake on the default module
# path would win over OBS's own exported package on every single build
# (find_package tries MODULE mode before CONFIG mode), permanently replacing
# upstream's real export metadata with this approximation. The top-level
# CMakeLists.txt appends this directory to CMAKE_MODULE_PATH only when it has
# already established that the real export is missing.
#
# Nothing outside Windows ever loads this: the find_dependency above is
# inside `if(MSVC)`, and the CMAKE_MODULE_PATH append that exposes this file
# is inside `if(OS_WINDOWS ...)`.
if(TARGET OBS::w32-pthreads)
set(w32-pthreads_FOUND TRUE)
return()
endif()
# Resolve paths from this file's own location rather than
# CMAKE_CURRENT_SOURCE_DIR: a find module runs in whatever scope called
# find_package, and here that call comes from inside libobsConfig.cmake.
# <repo>/cmake/windows/find-fallback/ -> <repo>
get_filename_component(_w32pt_repo_root "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE)
set(_w32pt_deps "${_w32pt_repo_root}/.deps")
# Search order, both from obs-studio's own Windows layout:
# 1. the bootstrap's install prefix -- obs-studio/cmake/windows/defaults.cmake
# sets OBS_LIBRARY_DESTINATION=lib (ARCHIVE, i.e. the import library),
# OBS_EXECUTABLE_DESTINATION=bin/64bit (RUNTIME, i.e. the DLL) and
# OBS_INCLUDE_DESTINATION=include (where target_export installs
# w32-pthreads' PUBLIC_HEADER pthread.h/sched.h);
# 2. the obs-studio build tree the bootstrap just built in, in case the
# install step is what failed rather than the export.
file(GLOB _w32pt_build_trees "${_w32pt_deps}/obs-studio-*/build_*/deps/w32-pthreads/Release")
file(GLOB _w32pt_source_trees "${_w32pt_deps}/obs-studio-*/deps/w32-pthreads")
find_library(
w32-pthreads_IMPLIB
NAMES w32-pthreads
PATHS "${_w32pt_deps}/lib" ${_w32pt_build_trees}
NO_DEFAULT_PATH
)
find_file(
w32-pthreads_RUNTIME_LIBRARY
NAMES w32-pthreads.dll
PATHS "${_w32pt_deps}/bin/64bit" ${_w32pt_build_trees}
NO_DEFAULT_PATH
)
find_path(
w32-pthreads_INCLUDE_DIR
NAMES pthread.h
PATHS "${_w32pt_deps}/include" ${_w32pt_source_trees}
NO_DEFAULT_PATH
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
w32-pthreads
REQUIRED_VARS w32-pthreads_IMPLIB w32-pthreads_INCLUDE_DIR
REASON_FAILURE_MESSAGE
"The OBS SDK bootstrap neither exported a w32-pthreads CMake package under ${_w32pt_deps}/cmake/ nor left a w32-pthreads import library anywhere under ${_w32pt_deps}."
)
if(w32-pthreads_FOUND)
# SHARED, matching deps/w32-pthreads/CMakeLists.txt's own
# `add_library(w32-pthreads SHARED ...)`. IMPORTED_LOCATION is the DLL and
# IMPORTED_IMPLIB the .lib, which is what an imported SHARED library means
# on Windows; if only the .lib was found, declare it UNKNOWN instead so
# CMake does not demand a DLL it will never be handed.
if(w32-pthreads_RUNTIME_LIBRARY)
add_library(OBS::w32-pthreads SHARED IMPORTED)
set_target_properties(
OBS::w32-pthreads
PROPERTIES IMPORTED_LOCATION "${w32-pthreads_RUNTIME_LIBRARY}" IMPORTED_IMPLIB "${w32-pthreads_IMPLIB}"
)
else()
add_library(OBS::w32-pthreads UNKNOWN IMPORTED)
set_target_properties(OBS::w32-pthreads PROPERTIES IMPORTED_LOCATION "${w32-pthreads_IMPLIB}")
endif()
set_target_properties(
OBS::w32-pthreads
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${w32-pthreads_INCLUDE_DIR}"
)
message(STATUS "Findw32-pthreads (fallback): OBS::w32-pthreads -> ${w32-pthreads_IMPLIB}")
endif()
mark_as_advanced(w32-pthreads_IMPLIB w32-pthreads_RUNTIME_LIBRARY w32-pthreads_INCLUDE_DIR)