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
@@ -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)