Files
source/cmake/toolchains/clang-cl.cmake
T
8b80466a7d rebuild the bink import library on every toolchain, not just cross ones
binkw32.lib as shipped is a long-format ordinal import library built in
2002, and link.exe is the only linker left that binds it. lld-link takes
it without complaint and writes an import descriptor with an empty thunk
table, so every Bink call reaches whatever the stale IAT slot holds. The
first one is BinkSoundUseDirectSound, reached from BinkInitialize during
EnterIntroScreen, which is unconditional -- Intro.cpp constructs its
VideoPlayer with VT_SMK|VT_BINK in every application, so a Smacker-only
gamedir still runs the Bink init path. The process dies before the splash
with an access violation executing an unmapped address.

clang-cl.cmake and mingw.cmake already rebuilt the library from
binkw32.def for exactly this reason, but they are toolchain files, so the
rebuild only happened when someone cross-compiled. Which linker is in use
is not a cross-compilation question: a preset that points
CMAKE_CXX_COMPILER at clang-cl -- how you use it from Visual Studio --
loads no toolchain file and linked the broken library instead. The test
was a proxy for "is this lld-link", correct until it wasn't.

So the rebuild moves to the top-level CMakeLists and runs unconditionally,
and clang-cl.cmake loses its copy: it already sets CMAKE_AR to llvm-lib,
which is the same binary the new code invokes with the same arguments.
mingw.cmake keeps its own, because GNU ar cannot build an import library
at all and dlltool takes different flags.

Only the name shape differs between archivers. lib.exe prepends the x86
leading underscore to every name in the .def; llvm-lib and llvm-dlltool
take the name as written. The checked-in file keeps the underscore for the
llvm tools and the MSVC path strips it back off.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 07:13:52 -03:00

79 lines
2.7 KiB
CMake

# Usage:
# MSVC_SDK=/path/to/msvc cmake --toolchain cmake/toolchains/clang-cl.cmake ...
#
# MSVC_SDK is where the cross headers and libraries live: the directory holding
# vc/ and kits/, which for msvc-wine is the root it was installed to. It comes
# from the environment.
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86)
set(MSVC_SDK "$ENV{MSVC_SDK}")
if(NOT IS_DIRECTORY "${MSVC_SDK}/vc/tools/msvc"
OR NOT IS_DIRECTORY "${MSVC_SDK}/kits/10/include")
message(FATAL_ERROR
"MSVC_SDK (${MSVC_SDK}) does not hold vc/tools/msvc and kits/10/include. "
"Point it at the MSVC installation, e.g. MSVC_SDK=/home/you/msvc")
endif()
# Both trees are versioned directories; take the newest of each rather than
# pinning a version that goes stale the next time the toolchain is updated.
function(_newest_subdirectory result dir)
file(GLOB versions "${dir}/*")
list(SORT versions)
list(POP_BACK versions newest)
set(${result} "${newest}" PARENT_SCOPE)
endfunction()
_newest_subdirectory(_msvc "${MSVC_SDK}/vc/tools/msvc")
_newest_subdirectory(_sdk "${MSVC_SDK}/kits/10/include")
get_filename_component(_sdk_version "${_sdk}" NAME)
set(_sdk_lib "${MSVC_SDK}/kits/10/lib/${_sdk_version}")
# Find every tool here rather than trusting PATH, so the choice of compiler,
# linker and rc is the toolchain file's alone.
foreach(tool clang-cl lld-link llvm-rc llvm-lib llvm-mt)
string(TOUPPER "${tool}" _variable)
string(REPLACE "-" "_" _variable "${_variable}")
# An absolute path: CMake resolves a bare name against the source directory.
find_program(${_variable} NAMES ${tool} REQUIRED)
endforeach()
set(CMAKE_C_COMPILER "${CLANG_CL}")
set(CMAKE_CXX_COMPILER "${CLANG_CL}")
set(CMAKE_LINKER "${LLD_LINK}")
set(CMAKE_RC_COMPILER "${LLVM_RC}")
set(CMAKE_AR "${LLVM_LIB}")
set(CMAKE_MT "${LLVM_MT}")
# clang-cl does not read INCLUDE and LIB the way cl does, so every directory
# has to be named. -imsvc rather than -I marks them as system headers, which
# keeps warnings about the SDK out of the build log.
set(_includes
"${_msvc}/atlmfc/include"
"${_msvc}/include"
"${_sdk}/shared"
"${_sdk}/ucrt"
"${_sdk}/um"
"${_sdk}/winrt"
"${_sdk}/km"
)
set(_flags "--target=i386-pc-windows-msvc")
foreach(directory ${_includes})
string(APPEND _flags " -imsvc ${directory}")
endforeach()
set(CMAKE_C_FLAGS_INIT "${_flags}")
set(CMAKE_CXX_FLAGS_INIT "${_flags}")
# The resource compiler is preprocessed by clang-cl, which needs the same
# headers again: ja2.rc includes windows.h. It takes -I, not -imsvc.
set(_rc_flags "")
foreach(directory ${_includes})
string(APPEND _rc_flags " -I ${directory}")
endforeach()
set(CMAKE_RC_FLAGS_INIT "${_rc_flags}")
set(CMAKE_EXE_LINKER_FLAGS_INIT
"/libpath:${_msvc}/lib/x86 /libpath:${_sdk_lib}/ucrt/x86 /libpath:${_sdk_lib}/um/x86")