From b9002ae29782c953b67351effc9cbc7f97d84ffa Mon Sep 17 00:00:00 2001 From: Belonit <54427022+Belonit@users.noreply.github.com> Date: Sun, 30 Aug 2026 01:01:23 +0300 Subject: [PATCH 1/8] Fix clang-cl source compatibility --- code/_wsproto.cpp | 2 +- code/init.cpp | 6 +++--- code/int.cpp | 8 ++++---- code/int.h | 2 +- code/list.h | 1 + code/lzo1x_c.cpp | 12 ++++++------ code/lzo1x_d.cpp | 8 ++++---- code/scenario.cpp | 2 +- code/tag.cpp | 2 +- code/tag.h | 2 +- code/vqalib/unvq.cpp | 6 +++--- code/vqalib/vqapalette.h | 8 ++++---- code/wsproto.h | 2 +- 13 files changed, 31 insertions(+), 30 deletions(-) diff --git a/code/_wsproto.cpp b/code/_wsproto.cpp index 2514d980..3762adf9 100644 --- a/code/_wsproto.cpp +++ b/code/_wsproto.cpp @@ -31,7 +31,7 @@ #include "always.h" -#include "_WSProto.h" +#include "_wsproto.h" WinsockInterfaceClass *PacketTransport = 0; //The object for interfacing with Winsock diff --git a/code/init.cpp b/code/init.cpp index c4543ac6..b876c495 100644 --- a/code/init.cpp +++ b/code/init.cpp @@ -204,7 +204,7 @@ struct ChooseCampaignStruct { ** Enable the set of limited cheat key options. */ #ifdef _DEBUG -#define PARM_PLAYTEST 0xF7DDC227 // "PLAYTEST" +#define PARM_PLAYTEST static_cast(0xF7DDC227u) // "PLAYTEST" #endif /* @@ -212,11 +212,11 @@ struct ChooseCampaignStruct { */ #ifdef _DEBUG #ifndef PARM_PLAYTEST -#define PARM_PLAYTEST 0xF7DDC227 // "PLAYTEST" +#define PARM_PLAYTEST static_cast(0xF7DDC227u) // "PLAYTEST" #endif #endif -#define PARM_INSTALL 0xD95C68A2 // "FROMINSTALL" +#define PARM_INSTALL static_cast(0xD95C68A2u) // "FROMINSTALL" /**************************************** diff --git a/code/int.cpp b/code/int.cpp index 04b0a083..de173442 100644 --- a/code/int.cpp +++ b/code/int.cpp @@ -35,7 +35,7 @@ #include "mpmath.h" -int bignum::Error = 0; -bool bignum::Carry = false; -bool bignum::Borrow = false; -bignum bignum::Remainder; +template<> int Int::Error = 0; +template<> bool Int::Carry = false; +template<> bool Int::Borrow = false; +template<> Int Int::Remainder{}; diff --git a/code/int.h b/code/int.h index b258e61c..1a22d621 100644 --- a/code/int.h +++ b/code/int.h @@ -173,7 +173,7 @@ class Int { // Friend helper functions. template - friend T Generate_Prime(Straw & rng, int pbits, T const * = 0); + friend T Generate_Prime(Straw & rng, int pbits, T const *); template friend T Gcd(const Int & a, const T & b); // friend bool NextPrime(Int & p, const Int & max, bool blumInt=false); diff --git a/code/list.h b/code/list.h index e2b6dfbd..2897e7cf 100644 --- a/code/list.h +++ b/code/list.h @@ -34,6 +34,7 @@ #include "control.h" #include "dialog.h" +#include "font.h" #include "shapebtn.h" #include "slider.h" #include "vector.h" diff --git a/code/lzo1x_c.cpp b/code/lzo1x_c.cpp index ebcf7dd7..d612da89 100644 --- a/code/lzo1x_c.cpp +++ b/code/lzo1x_c.cpp @@ -121,7 +121,7 @@ static int do_compress(const lzo_byte * in, lzo_uint in_len, lzo_voidp wrkmem ) { - register const lzo_byte *ip; + const lzo_byte *ip; lzo_uint dv; lzo_byte *op; const lzo_byte * const in_end = in + in_len; @@ -139,7 +139,7 @@ static int do_compress(const lzo_byte * in, lzo_uint in_len, DVAL_NEXT(dv,ip); UPDATE_D(dict,cycle,dv,ip); ip++; for (;;) { - register const lzo_byte *m_pos; + const lzo_byte *m_pos; lzo_uint m_len; lzo_ptrdiff_t m_off; lzo_uint lit; @@ -197,7 +197,7 @@ static int do_compress(const lzo_byte * in, lzo_uint in_len, /* store current literal run */ if (lit > 0) { - register lzo_uint t = lit; + lzo_uint t = lit; if (t <= 3) { assert(op - 2 > out); @@ -206,7 +206,7 @@ static int do_compress(const lzo_byte * in, lzo_uint in_len, if (t <= 18) { *op++ = LZO_BYTE(t - 3); } else { - register lzo_uint tt = t - 18; + lzo_uint tt = t - 18; *op++ = 0; while (tt > 255) { @@ -304,7 +304,7 @@ static int do_compress(const lzo_byte * in, lzo_uint in_len, /* store final literal run */ if (in_end - ii > 0) { - register lzo_uint t = in_end - ii; + lzo_uint t = in_end - ii; if (op == out && t <= 238) { *op++ = LZO_BYTE(17 + t); @@ -315,7 +315,7 @@ static int do_compress(const lzo_byte * in, lzo_uint in_len, if (t <= 18) { *op++ = LZO_BYTE(t - 3); } else { - register lzo_uint tt = t - 18; + lzo_uint tt = t - 18; *op++ = 0; while (tt > 255) { diff --git a/code/lzo1x_d.cpp b/code/lzo1x_d.cpp index 502f2a37..d25d3965 100644 --- a/code/lzo1x_d.cpp +++ b/code/lzo1x_d.cpp @@ -95,10 +95,10 @@ int lzo1x_decompress ( const lzo_byte * in, lzo_uint in_len, lzo_byte * out, lzo_uint * out_len, lzo_voidp ) { - register lzo_byte *op; - register const lzo_byte *ip; - register lzo_uint t; - register const lzo_byte *m_pos; + lzo_byte *op; + const lzo_byte *ip; + lzo_uint t; + const lzo_byte *m_pos; const lzo_byte * const ip_end = in + in_len; *out_len = 0; diff --git a/code/scenario.cpp b/code/scenario.cpp index f2b91b73..b26021e4 100644 --- a/code/scenario.cpp +++ b/code/scenario.cpp @@ -926,7 +926,7 @@ void Clear_Scenario(void) Map.ZoneConnections.Clear(); - TagClass::Init(); + TagClass::Init_Heap(); for (index = 0; index < ARRAY_SIZE(Scen->GlobalFlags); index++) { Scen->Set_Global_To(index, false); diff --git a/code/tag.cpp b/code/tag.cpp index 2183dcd7..09fa81b7 100644 --- a/code/tag.cpp +++ b/code/tag.cpp @@ -333,7 +333,7 @@ void TagClass::Set_Position(Cell cell) /// This routine is called when a scenario is torn down so that no tag from the previous /// mission survives into the next one. /// -void TagClass::Init(void) +void TagClass::Init_Heap(void) { while (Tags.Count() > 0) { delete Tags[0]; diff --git a/code/tag.h b/code/tag.h index 9567f1ab..f978fa4f 100644 --- a/code/tag.h +++ b/code/tag.h @@ -59,7 +59,7 @@ class TagClass : public AbstractClass static void All_Timer_Global_Reset(int global); static void All_Timer_Local_Reset(int local); - static void Init(void); + static void Init_Heap(void); void Link(TriggerClass *trigger); bool Unlink(TriggerClass *trigger); diff --git a/code/vqalib/unvq.cpp b/code/vqalib/unvq.cpp index 4eb83ef9..f218874e 100644 --- a/code/vqalib/unvq.cpp +++ b/code/vqalib/unvq.cpp @@ -956,7 +956,7 @@ void __cdecl UnVQ2_C0_4x4_TRANS(unsigned char * codebook, unsigned char * pointe { uint8_t * dst = (uint8_t *)buffer; uint8_t * row_base = (uint8_t *)buffer; - register uint16_t * src = (uint16_t *)pointers; + uint16_t * src = (uint16_t *)pointers; uint32_t blocks = 0; uint32_t total = blocksperrow * numrows; @@ -1222,7 +1222,7 @@ void __cdecl UnVQ2_C0_4x4_KEY(unsigned char * codebook, unsigned char * pointers { uint8_t * dst = (uint8_t *)buffer; uint8_t * row_base = (uint8_t *)buffer; - register uint16_t * src = (uint16_t *)pointers; + uint16_t * src = (uint16_t *)pointers; uint32_t blocks = 0; uint32_t total = numrows * blocksperrow; @@ -2010,7 +2010,7 @@ void __cdecl UnVQ2_C0_4x2_KEY(unsigned char * codebook, unsigned char * pointers { uint8_t * dst = (uint8_t *)buffer; uint8_t * row_base = (uint8_t *)buffer; - register uint16_t * src = (uint16_t *)pointers; + uint16_t * src = (uint16_t *)pointers; uint32_t blocks = 0; uint32_t total = numrows * blocksperrow; diff --git a/code/vqalib/vqapalette.h b/code/vqalib/vqapalette.h index 856c58f1..136e2eb0 100644 --- a/code/vqalib/vqapalette.h +++ b/code/vqalib/vqapalette.h @@ -39,10 +39,10 @@ extern "C" { #endif -void cdecl SetPalette(unsigned char *palette,long numbytes,unsigned long slowpal); -void cdecl ReadPalette(void *palette); -void cdecl SetDAC(long color, long red, long green, long blue); -void cdecl TranslatePalette(void *pal24, void *pal15, long numbytes); +void __cdecl SetPalette(unsigned char *palette,long numbytes,unsigned long slowpal); +void __cdecl ReadPalette(void *palette); +void __cdecl SetDAC(long color, long red, long green, long blue); +void __cdecl TranslatePalette(void *pal24, void *pal15, long numbytes); #ifdef __cplusplus } diff --git a/code/wsproto.h b/code/wsproto.h index ce2e02e7..cfcd4336 100644 --- a/code/wsproto.h +++ b/code/wsproto.h @@ -31,7 +31,7 @@ #pragma once -#include "_WSProto.h" +#include "_wsproto.h" #include "ipxaddr.h" #include "vector.h" From 86b3cf29fcafdb3e604218f8f9859e4f0a42abce Mon Sep 17 00:00:00 2001 From: Belonit <54427022+Belonit@users.noreply.github.com> Date: Sun, 30 Aug 2026 01:01:23 +0300 Subject: [PATCH 2/8] Fix inline assembly for clang-cl Keep labels inside their inline assembly blocks and make byte-sized memory operands explicit where clang-cl requires their size. --- code/blitblit.h | 23 ++++++------ code/lcw.cpp | 91 +++++++++++++++++++---------------------------- code/xsurface.cpp | 4 +-- 3 files changed, 49 insertions(+), 69 deletions(-) diff --git a/code/blitblit.h b/code/blitblit.h index 6a3165a0..4fdd1ea9 100644 --- a/code/blitblit.h +++ b/code/blitblit.h @@ -2328,9 +2328,8 @@ inline void BlitTrans::BlitForward(void * dest, void const * sour mov ecx,[len] dec edi inc ecx - } -again: - __asm { + + again: dec ecx jz fini mov al,[esi] @@ -2340,8 +2339,9 @@ inline void BlitTrans::BlitForward(void * dest, void const * sour jz again mov [edi],al jmp again + + fini: } -fini:; } @@ -2358,9 +2358,8 @@ inline void BlitTransXlat::BlitForward(void * dest, void const * sub edi,2 mov esi,[source] xor eax,eax - } -again: - __asm { + + again: dec ecx jz over add edi,2 @@ -2371,8 +2370,9 @@ inline void BlitTransXlat::BlitForward(void * dest, void const * mov dx,[ebx+eax*2] mov [edi],dx jmp again + + over: } -over:; } @@ -2390,14 +2390,12 @@ inline void BlitTransRemapXlat::BlitForward(void * dest, void co mov ebx,[remapper] mov edx,[translator] xor eax,eax - } + again: /* ** This block is 11 cycles per pixel, if not transparent, and 5 ** cycles per pixel, if transparent. */ -again: - __asm { dec ecx jz over add edi,2 @@ -2409,8 +2407,9 @@ inline void BlitTransRemapXlat::BlitForward(void * dest, void co mov ax,[edx+eax*2] // Second remap step (8 bit to 16 bit). mov [edi],ax jmp again + + over: } -over:; } diff --git a/code/lcw.cpp b/code/lcw.cpp index 777a5afa..85e10710 100644 --- a/code/lcw.cpp +++ b/code/lcw.cpp @@ -241,16 +241,13 @@ int LCW_Comp(void const * source, void * dest, int datasize) stosb //; write out a len of 1 lodsb //; get the byte stosb //; save it - } -loopstart: - __asm { + loopstart: mov [ndest],edi //; save offset of compressed data mov edi,[a1stsrc] //; get the offset to the first byte of data mov [count],1 //; set the count of run to 0 - } -searchloop: - __asm { + + searchloop: sub eax,eax mov al,[esi] //; get the current byte of data cmp al,[esi+64] @@ -284,14 +281,12 @@ int LCW_Comp(void const * source, void * dest, int datasize) mov [ndest],edi //; save offset of compressed data mov edi,ebx jmp searchloop - } -notlongenough: - __asm { + + notlongenough: mov edi,ebx - } -notrunlength: -oploop: - __asm { + + notrunlength: + oploop: mov ecx,esi //; get the address of the last byte +1 sub ecx,edi //; get the total number of bytes left to comp jz short searchdone @@ -316,9 +311,8 @@ int LCW_Comp(void const * source, void * dest, int datasize) jne short notend //; if found mismatch then di - bx = match count inc edi //; else cx = 0 and di + 1 - bx = match count - } -notend: - __asm { + + notend: mov esi,edx //; restore si mov eax,edi //; get the dest sub eax,ebx //; sub the start for total bytes that match @@ -330,9 +324,8 @@ int LCW_Comp(void const * source, void * dest, int datasize) dec ebx //; back it up for the actual match offset mov [matchoff],ebx //; save the offset for later jmp searchloop //; loop until we searched it all - } -searchdone: - __asm { + + searchdone: mov ecx,[count] //; get the count of the longest run mov edi,[ndest] //; get the offset of our compressed data cmp ecx,2 //; see if its not enough run to matter @@ -345,9 +338,8 @@ int LCW_Comp(void const * source, void * dest, int datasize) sub eax,[matchoff] //; sub the offset of the match cmp eax,0FFFh //; if its less than 12 bits its a short ja short medrun //; if its not, its a medium - } -//shortrun: - __asm { + + //shortrun: sub ebx,ebx mov bl,cl //; get the length (3-10) sub bl,3 //; sub 3 for a 3 bit number 0-7 @@ -355,9 +347,8 @@ int LCW_Comp(void const * source, void * dest, int datasize) add ah,bl //; add in the length for the high nibble xchg ah,al //; reverse the bytes for a word store jmp short srunnxt //; do the run fixup code - } -medrun: - __asm { + + medrun: cmp ecx,64 //; see if its a short run ja short longrun //; if not, oh well at least its long @@ -366,66 +357,57 @@ int LCW_Comp(void const * source, void * dest, int datasize) mov al,cl //; put it in al for the stosb stosb //; store it jmp short medrunnxt //; do the run fixup code - } -lenin: - __asm { + + lenin: cmp [inlen],0 //; is it doing a length? // cmp [DWORD PTR inlen],0 //; is it doing a length? jnz short len //; if so, skip code - } -lenin1: - __asm { + + lenin1: mov [lenoff],edi //; save the length code offset mov al,80h //; set the length to 0 stosb //; save it - } -len: - __asm { + + len: mov ebx,[lenoff] //; get the offset of the length code - cmp [ebx],0BFh //; see if its maxed out + cmp byte ptr [ebx],0BFh //; see if its maxed out // cmp [BYTE PTR ebx],0BFh //; see if its maxed out je lenin1 //; if so put out a new len code - } -//stolen: - __asm { - inc [ebx] //; inc the count code + + //stolen: + inc byte ptr [ebx] //; inc the count code // inc [BYTE PTR ebx] //; inc the count code lodsb //; get the byte stosb //; store it mov [inlen],1 //; we are now in a length so save it // mov [DWORD PTR inlen],1 //; we are now in a length so save it jmp short nxt //; do the next code - } -longrun: - __asm { + + longrun: mov al,0ffh //; its a long so set a code of FF stosb //; store it mov eax,[count] //; send out the count stosw //; store it - } -medrunnxt: - __asm { + + medrunnxt: mov eax,[matchoff] //; get the offset sub eax,[a1stsrc] //; make it relative tot he start of data - } -srunnxt: - __asm { + + srunnxt: stosw //; store it //; this code common to all runs add esi,[count] //; add in the length of the run to the source mov [inlen],0 //; set the in leght flag to false // mov [DWORD PTR inlen],0 //; set the in leght flag to false - } -nxt: - __asm { + + nxt: cmp esi,[end_of_data] //; see if we did the whole pic jae short outofhere //; if so, cool! were done jmp loopstart - } -outofhere: - __asm { + + outofhere: mov ax,080h //; remember to send an end of data code stosb //; store it mov eax,edi //; get the last compressed address @@ -436,4 +418,3 @@ int LCW_Comp(void const * source, void * dest, int datasize) return(retval); } #endif - diff --git a/code/xsurface.cpp b/code/xsurface.cpp index 1d299669..9c834b81 100644 --- a/code/xsurface.cpp +++ b/code/xsurface.cpp @@ -811,12 +811,12 @@ static void *surface_quick_fill(void *buf, int count, int color) mov edi, [buf] cmp ecx, 0 - jle short $end + jle short fill_end mov eax, [color] rep stosd - $end: + fill_end: mov eax, edi pop edi /// Bug fixed in TS but not in ShapeSet } From 4ccbf851bebe0f6be6e1ed55ea6657d843920818 Mon Sep 17 00:00:00 2001 From: Belonit <54427022+Belonit@users.noreply.github.com> Date: Sun, 30 Aug 2026 01:01:23 +0300 Subject: [PATCH 3/8] Add experimental clang-cl cross-build Configure a Linux-hosted Ninja build with clang-cl, LLD, and the installed MSVC headers and libraries. Apply the compatibility settings required by bx. --- CMakeLists.txt | 24 +++++++- cmake/clang-cl-bx-compat.h | 23 ++++++++ cmake/toolchains/clang-cl-msvc-wine.cmake | 72 +++++++++++++++++++++++ code/CMakeLists.txt | 38 ++++++++++-- code/language/CMakeLists.txt | 8 ++- docs/BUILDING.md | 21 +++++++ thirdparty/CMakeLists.txt | 17 ++++++ 7 files changed, 195 insertions(+), 8 deletions(-) create mode 100644 cmake/clang-cl-bx-compat.h create mode 100644 cmake/toolchains/clang-cl-msvc-wine.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 33878dba..2763905a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.23) project(OpenTS VERSION 0.2.0 LANGUAGES C CXX ASM_MASM) +enable_language(RC) # A SemVer prerelease label, which project() cannot carry because it takes numbers only. Set it # to "beta1" and the version reads 0.1.0-beta1; leave it empty outside a prerelease series. The @@ -11,8 +12,27 @@ set(OPENTS_VERSION_PRERELEASE "") # alone. Every other build names the commit it came from as well. option(OPENTS_OFFICIAL_BUILD "Build as an official release of the declared version" OFF) -if(NOT MSVC OR MSVC_VERSION LESS 1930) - message(FATAL_ERROR "OpenTS requires the Visual Studio 2022 MSVC toolchain.") +option(OPENTS_EXPERIMENTAL_CLANG_CL "Build with clang-cl using the MSVC ABI" OFF) + +set(OPENTS_MSVC_ABI_COMPILER OFF) +if(MSVC) + if(MSVC_VERSION LESS 1930) + message(FATAL_ERROR "OpenTS requires MSVC 19.30 or newer.") + endif() + set(OPENTS_MSVC_ABI_COMPILER ON) +elseif(OPENTS_EXPERIMENTAL_CLANG_CL + AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang" + AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") + set(OPENTS_MSVC_ABI_COMPILER ON) + set(CMAKE_DEPFILE_FLAGS_RC "" CACHE STRING "" FORCE) + set(CMAKE_RC_COMPILE_OBJECT + " /C 1252 /fo " + CACHE STRING "" FORCE) +else() + message(FATAL_ERROR + "OpenTS requires the Visual Studio 2022 MSVC toolchain. " + "The unsupported clang-cl experiment must be configured with " + "-DOPENTS_EXPERIMENTAL_CLANG_CL=ON.") endif() set(CMAKE_CXX_STANDARD 20) diff --git a/cmake/clang-cl-bx-compat.h b/cmake/clang-cl-bx-compat.h new file mode 100644 index 00000000..3aa448b5 --- /dev/null +++ b/cmake/clang-cl-bx-compat.h @@ -0,0 +1,23 @@ +/******************************************************************************* + * O P E N T S + ****************************************************************************** + * SPDX-License-Identifier: GPL-3.0-or-later + * Copyright 2026 OpenTS contributors + ******************************************************************************/ + +#pragma once + +#ifndef BX_CONFIG_DEBUG +#ifdef _DEBUG +#define BX_CONFIG_DEBUG 1 +#else +#define BX_CONFIG_DEBUG 0 +#endif +#endif + +#include + +#if defined(__clang__) && defined(_M_IX86) +#undef __stdcall +#define __stdcall __attribute__((stdcall)) +#endif diff --git a/cmake/toolchains/clang-cl-msvc-wine.cmake b/cmake/toolchains/clang-cl-msvc-wine.cmake new file mode 100644 index 00000000..4fc29f87 --- /dev/null +++ b/cmake/toolchains/clang-cl-msvc-wine.cmake @@ -0,0 +1,72 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86) + +set(OPENTS_EXPERIMENTAL_CLANG_CL ON CACHE BOOL "" FORCE) +set(OPENTS_MSVC_ROOT "" CACHE PATH "Path to an msvc-wine installation") +list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES OPENTS_MSVC_ROOT) + +if(NOT OPENTS_MSVC_ROOT AND DEFINED ENV{OPENTS_MSVC_ROOT}) + set(OPENTS_MSVC_ROOT "$ENV{OPENTS_MSVC_ROOT}" CACHE PATH "" FORCE) +endif() + +if(NOT OPENTS_MSVC_ROOT) + message(FATAL_ERROR + "Set OPENTS_MSVC_ROOT to the msvc-wine installation directory.") +endif() + +set(_opents_msvc_version "14.44.35207") +set(_opents_sdk_version "10.0.26100.0") +set(_opents_msvc_dir "${OPENTS_MSVC_ROOT}/VC/Tools/MSVC/${_opents_msvc_version}") +set(_opents_sdk_dir "${OPENTS_MSVC_ROOT}/Windows Kits/10") + +foreach(_required_path + "${_opents_msvc_dir}/include" + "${_opents_sdk_dir}/Include/${_opents_sdk_version}/um" + "${OPENTS_MSVC_ROOT}/bin/x86/ml") + if(NOT EXISTS "${_required_path}") + message(FATAL_ERROR "Required MSVC component not found: ${_required_path}") + endif() +endforeach() + +find_program(_opents_clang_cl clang-cl REQUIRED) +find_program(_opents_lld_link lld-link REQUIRED) +find_program(_opents_llvm_lib llvm-lib REQUIRED) +find_program(_opents_llvm_mt llvm-mt REQUIRED) +find_program(_opents_llvm_rc llvm-rc REQUIRED) + +set(CMAKE_C_COMPILER "${_opents_clang_cl}") +set(CMAKE_CXX_COMPILER "${_opents_clang_cl}") +set(CMAKE_C_COMPILER_TARGET i686-pc-windows-msvc) +set(CMAKE_CXX_COMPILER_TARGET i686-pc-windows-msvc) +set(CMAKE_C_FLAGS_INIT "/clang:-fms-compatibility-version=19.44") +set(CMAKE_CXX_FLAGS_INIT "/clang:-fms-compatibility-version=19.44") +set(CMAKE_LINKER "${_opents_lld_link}") +set(CMAKE_AR "${_opents_llvm_lib}") +set(CMAKE_RC_COMPILER "${_opents_llvm_rc}" CACHE FILEPATH "" FORCE) +set(CMAKE_MT "${_opents_llvm_mt}") +set(CMAKE_ASM_MASM_COMPILER "${OPENTS_MSVC_ROOT}/bin/x86/ml") + +set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES + "${_opents_msvc_dir}/atlmfc/include" + "${_opents_msvc_dir}/include" + "${_opents_sdk_dir}/Include/${_opents_sdk_version}/shared" + "${_opents_sdk_dir}/Include/${_opents_sdk_version}/ucrt" + "${_opents_sdk_dir}/Include/${_opents_sdk_version}/um" + "${_opents_sdk_dir}/Include/${_opents_sdk_version}/winrt") +set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_C_STANDARD_INCLUDE_DIRECTORIES}) + +set(_opents_rc_flags "") +foreach(_include_dir IN LISTS CMAKE_C_STANDARD_INCLUDE_DIRECTORIES) + string(APPEND _opents_rc_flags " /I\"${_include_dir}\"") +endforeach() +set(CMAKE_RC_FLAGS_INIT "${_opents_rc_flags}") + +set(_opents_linker_paths + "/libpath:\"${_opents_msvc_dir}/atlmfc/lib/x86\"" + "/libpath:\"${_opents_msvc_dir}/lib/x86\"" + "/libpath:\"${_opents_sdk_dir}/Lib/${_opents_sdk_version}/ucrt/x86\"" + "/libpath:\"${_opents_sdk_dir}/Lib/${_opents_sdk_version}/um/x86\"") +string(JOIN " " _opents_linker_flags ${_opents_linker_paths}) +set(CMAKE_EXE_LINKER_FLAGS_INIT "${_opents_linker_flags}") +set(CMAKE_SHARED_LINKER_FLAGS_INIT "${_opents_linker_flags}") +set(CMAKE_MODULE_LINKER_FLAGS_INIT "${_opents_linker_flags}") diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index d7c705fb..3adda54a 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -57,6 +57,12 @@ endforeach() # message(STATUS "${PROJECT_NAME}: Creating '${PROJECT_NAME}' executable...") +if(OPENTS_EXPERIMENTAL_CLANG_CL) + set(CMAKE_DEPFILE_FLAGS_RC "") + set(CMAKE_RC_COMPILE_OBJECT + " /C 1252 /fo ") +endif() + add_executable(OpenTS WIN32 ${OPENTS_SRC}) target_compile_features(OpenTS PRIVATE cxx_std_20) @@ -92,6 +98,11 @@ set_target_properties(OpenTS PROPERTIES # message(STATUS "${PROJECT_NAME}: Applying compiler flags...") +if(OPENTS_EXPERIMENTAL_CLANG_CL) + set(OPENTS_PARALLEL_COMPILE_OPTION "") +else() + set(OPENTS_PARALLEL_COMPILE_OPTION /MP) +endif() set(OPENTS_COMPILE_OPTIONS # ================= DEBUG ================= @@ -101,12 +112,12 @@ set(OPENTS_COMPILE_OPTIONS # /arch:SSE2 -- IEEE-754 single precision, no x87 excess precision. # /fp:precise -- no reassociation of the engine's accumulations. $<$: - /Zi /Od /RTC1 /GR /MP /EHsc /Oy- /MTd /Zc:__cplusplus /arch:SSE2 /fp:precise + /Zi /Od /RTC1 /GR ${OPENTS_PARALLEL_COMPILE_OPTION} /EHsc /Oy- /MTd /Zc:__cplusplus /arch:SSE2 /fp:precise > # ---------- C ---------- $<$: - /Zi /Od /RTC1 /MP /Oy- /arch:SSE2 /fp:precise + /Zi /Od /RTC1 ${OPENTS_PARALLEL_COMPILE_OPTION} /Oy- /arch:SSE2 /fp:precise > # ---------- MASM ---------- @@ -122,12 +133,12 @@ set(OPENTS_COMPILE_OPTIONS # /arch:SSE2 -- IEEE-754 single precision, no x87 excess precision. # /fp:precise -- no reassociation of the engine's accumulations. $<$: - /Zi /O2 /GF /GR /MP /EHsc /MT /Zc:__cplusplus /arch:SSE2 /fp:precise + /Zi /O2 /GF /GR ${OPENTS_PARALLEL_COMPILE_OPTION} /EHsc /MT /Zc:__cplusplus /arch:SSE2 /fp:precise > # ---------- C ---------- $<$: - /Zi /O2 /GF /MP /arch:SSE2 /fp:precise + /Zi /O2 /GF ${OPENTS_PARALLEL_COMPILE_OPTION} /arch:SSE2 /fp:precise > # ---------- MASM ---------- @@ -139,6 +150,12 @@ set(OPENTS_COMPILE_OPTIONS target_compile_options(OpenTS PRIVATE ${OPENTS_COMPILE_OPTIONS}) +if(OPENTS_EXPERIMENTAL_CLANG_CL) + target_compile_options(OpenTS PRIVATE + /clang:-Wno-c++11-narrowing + ) +endif() + # # --------------------------------------------------------- # Subprojects @@ -163,9 +180,20 @@ set(BGFX_ROOT "${CMAKE_SOURCE_DIR}/thirdparty/bgfx.cmake/bgfx") set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/bgfxbackend.cpp" PROPERTIES INCLUDE_DIRECTORIES "${BGFX_ROOT}/include;${CMAKE_SOURCE_DIR}/thirdparty/bgfx.cmake/bx/include;${BGFX_ROOT}/examples/common/imgui" + COMPILE_DEFINITIONS + "BX_CONFIG_DEBUG=$,1,$>" COMPILE_OPTIONS "/Zc:preprocessor" ) +# bx rewrites __stdcall while its headers are being parsed by clang-cl. Force the +# compatibility header into the renderer translation unit as well as bx/bgfx so the +# MSVC standard-library headers that follow still see the Win32 calling convention. +if(OPENTS_EXPERIMENTAL_CLANG_CL AND CMAKE_SIZEOF_VOID_P EQUAL 4) + set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/bgfxbackend.cpp" APPEND PROPERTY + COMPILE_OPTIONS "/FI${CMAKE_SOURCE_DIR}/cmake/clang-cl-bx-compat.h" + ) +endif() + message(STATUS "${PROJECT_NAME}: Adding compilier definitions...") target_compile_definitions(OpenTS PRIVATE WIN32 @@ -218,7 +246,7 @@ target_link_libraries(OpenTS PRIVATE ole32 oleaut32 uuid odbc32 odbccp32 ) -if (MSVC) +if (OPENTS_MSVC_ABI_COMPILER) target_link_options(OpenTS PRIVATE /SUBSYSTEM:WINDOWS /DEBUG diff --git a/code/language/CMakeLists.txt b/code/language/CMakeLists.txt index 4d1feabe..2c6fcceb 100644 --- a/code/language/CMakeLists.txt +++ b/code/language/CMakeLists.txt @@ -3,6 +3,12 @@ file(GLOB_RECURSE LANG_SRC CONFIGURE_DEPENDS "*.h" "*.hpp" "*.hm" ) +if(OPENTS_EXPERIMENTAL_CLANG_CL) + set(CMAKE_DEPFILE_FLAGS_RC "") + set(CMAKE_RC_COMPILE_OBJECT + " /C 1252 /fo ") +endif() + add_library(Language SHARED ${LANG_SRC}) target_compile_features(Language PRIVATE cxx_std_20) target_compile_definitions(Language PRIVATE NOMINMAX) @@ -12,7 +18,7 @@ target_compile_definitions(Language PRIVATE NOMINMAX) target_include_directories(Language PRIVATE "${OPENTS_GENERATED_DIR}") add_dependencies(Language OpenTSBuildStamp) -if (MSVC) +if (OPENTS_MSVC_ABI_COMPILER) target_link_options(Language PRIVATE "/NOENTRY" "/NODEFAULTLIB") endif() diff --git a/docs/BUILDING.md b/docs/BUILDING.md index f9078a61..0423eb9f 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -20,6 +20,27 @@ Other generators, compilers, architectures, and configurations are not supported by the current tree. +### Experimental clang-cl cross-build + +An unsupported Linux cross-build is available for compiler-portability work. It +uses native `clang-cl`, LLD, and LLVM library and resource tools with the MSVC +headers and libraries, while MASM runs through an `msvc-wine` x86 wrapper. It +does not expand the supported build matrix or establish runtime behavior. + +Provide an `msvc-wine` installation containing MSVC 14.44.35207 and Windows SDK +10.0.26100.0, then configure a single-configuration Ninja build: + +```bash +cmake -S . -B build/clang-cl -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/clang-cl-msvc-wine.cmake \ + -DOPENTS_MSVC_ROOT=/path/to/msvc +cmake --build build/clang-cl +``` + +The toolchain requires `clang-cl`, `lld-link`, `llvm-lib`, `llvm-mt`, and +`llvm-rc` on `PATH`. Wine must be installed so the wrapper can run `ml.exe`. + Install Visual Studio 2022 with the **Desktop development with C++** workload, a Windows SDK, CMake 3.23 or newer, and Git for Windows. diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 603217a7..7e9a0e70 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -19,3 +19,20 @@ set(BGFX_CONFIG_RENDERER_WEBGPU OFF CACHE BOOL "" FORCE) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") add_subdirectory(bgfx.cmake) + +if(OPENTS_EXPERIMENTAL_CLANG_CL AND CMAKE_SIZEOF_VOID_P EQUAL 4) + # bx treats Clang with the MSVC CRT like a non-x86 compiler and erases + # __stdcall. Restore it before Windows declarations are parsed. + foreach(target bx bimg bgfx) + target_compile_options(${target} PRIVATE + "$<$:/FI${PROJECT_SOURCE_DIR}/cmake/clang-cl-bx-compat.h>" + ) + endforeach() + + # The ASTC encoder selects a 64-bit popcount intrinsic when SSE4.2 is enabled, + # but that intrinsic is unavailable for the Win32 target. Its SSE2 path is portable. + target_compile_definitions(bimg PRIVATE ASTCENC_POPCNT=0 ASTCENC_SSE=20) + + # These libraries support the disabled texture tools and are not linked into OpenTS. + set_target_properties(bimg_decode bimg_encode PROPERTIES EXCLUDE_FROM_ALL TRUE) +endif() From 2144b873b3b4a8ce100d5dcb7f1043f5ae05e273 Mon Sep 17 00:00:00 2001 From: Belonit <54427022+Belonit@users.noreply.github.com> Date: Sun, 30 Aug 2026 01:01:23 +0300 Subject: [PATCH 4/8] Align bgfx allocations for clang-cl Use aligned CRT allocation for bgfx render records so clang-cl-generated aligned SSE accesses cannot receive under-aligned storage. --- code/bgfxbackend.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/code/bgfxbackend.cpp b/code/bgfxbackend.cpp index 2645ede6..3dc92567 100644 --- a/code/bgfxbackend.cpp +++ b/code/bgfxbackend.cpp @@ -15,15 +15,18 @@ #include "dbgprint.h" #include "except.h" +#include #include #include #include #include +#include #include #include #include +#include static const bgfx::EmbeddedShader _EmbeddedShaders[] = { @@ -119,6 +122,30 @@ class BackendCallback : public bgfx::CallbackI static BackendCallback _Callback; +// bgfx contains cache-line-aligned render records but requests their backing arrays with +// the allocator's default alignment. The Win32 CRT only guarantees eight-byte alignment, +// which is insufficient when clang-cl copies those records with aligned SSE instructions. +class BackendAllocator : public bx::AllocatorI +{ + public: + virtual ~BackendAllocator(void) override {} + + virtual void * realloc(void * ptr, size_t size, size_t alignment, const char *, uint32_t) override + { + if (size == 0) { + _aligned_free(ptr); + return(NULL); + } + + const size_t cachelinealignment = BX_CACHE_LINE_SIZE; + alignment = std::max(alignment, cachelinealignment); + return(_aligned_realloc(ptr, size, alignment)); + } +}; + +static BackendAllocator _Allocator; + + /// /// Builds the table that widens a 565 pixel to the 32 bit color the fallback path uploads. /// @@ -273,6 +300,7 @@ bool Backend_Init(HWND window, int windowwidth, int windowheight, BackendRendere init.resolution.height = (uint32_t)windowheight; init.resolution.reset = _ResetFlags; init.callback = &_Callback; + init.allocator = &_Allocator; switch (renderer) { case BACKEND_RENDERER_D3D11: From e19066451554e9ea94f14f1e2272d9a4561a9566 Mon Sep 17 00:00:00 2001 From: Belonit <54427022+Belonit@users.noreply.github.com> Date: Sun, 30 Aug 2026 01:01:24 +0300 Subject: [PATCH 5/8] Use UASM for clang-cl assembly Assemble the legacy MASM sources with native UASM instead of invoking ml.exe through Wine. --- cmake/toolchains/clang-cl-msvc-wine.cmake | 6 ++-- code/CMakeLists.txt | 17 +++++++--- code/winasm.asm | 38 +++++++++++++---------- docs/BUILDING.md | 6 ++-- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/cmake/toolchains/clang-cl-msvc-wine.cmake b/cmake/toolchains/clang-cl-msvc-wine.cmake index 4fc29f87..039d9336 100644 --- a/cmake/toolchains/clang-cl-msvc-wine.cmake +++ b/cmake/toolchains/clang-cl-msvc-wine.cmake @@ -21,8 +21,7 @@ set(_opents_sdk_dir "${OPENTS_MSVC_ROOT}/Windows Kits/10") foreach(_required_path "${_opents_msvc_dir}/include" - "${_opents_sdk_dir}/Include/${_opents_sdk_version}/um" - "${OPENTS_MSVC_ROOT}/bin/x86/ml") + "${_opents_sdk_dir}/Include/${_opents_sdk_version}/um") if(NOT EXISTS "${_required_path}") message(FATAL_ERROR "Required MSVC component not found: ${_required_path}") endif() @@ -33,6 +32,7 @@ find_program(_opents_lld_link lld-link REQUIRED) find_program(_opents_llvm_lib llvm-lib REQUIRED) find_program(_opents_llvm_mt llvm-mt REQUIRED) find_program(_opents_llvm_rc llvm-rc REQUIRED) +find_program(_opents_uasm uasm REQUIRED) set(CMAKE_C_COMPILER "${_opents_clang_cl}") set(CMAKE_CXX_COMPILER "${_opents_clang_cl}") @@ -44,7 +44,7 @@ set(CMAKE_LINKER "${_opents_lld_link}") set(CMAKE_AR "${_opents_llvm_lib}") set(CMAKE_RC_COMPILER "${_opents_llvm_rc}" CACHE FILEPATH "" FORCE) set(CMAKE_MT "${_opents_llvm_mt}") -set(CMAKE_ASM_MASM_COMPILER "${OPENTS_MSVC_ROOT}/bin/x86/ml") +set(CMAKE_ASM_MASM_COMPILER "${_opents_uasm}" CACHE FILEPATH "" FORCE) set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES "${_opents_msvc_dir}/atlmfc/include" diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 3adda54a..389be0c7 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -99,10 +99,15 @@ set_target_properties(OpenTS PROPERTIES message(STATUS "${PROJECT_NAME}: Applying compiler flags...") if(OPENTS_EXPERIMENTAL_CLANG_CL) + set(OPENTS_ASM_MASM_OPTIONS -Zi -c -coff -Cx -safeseh) + set(OPENTS_ASM_MASM_SOURCE_OPTIONS "-Zi -c -coff -Cx -safeseh") set(OPENTS_PARALLEL_COMPILE_OPTION "") else() + set(OPENTS_ASM_MASM_OPTIONS /Zi /c /coff /Cx /safeseh) + set(OPENTS_ASM_MASM_SOURCE_OPTIONS "/Zi /c /coff /Cx /safeseh") set(OPENTS_PARALLEL_COMPILE_OPTION /MP) endif() + set(OPENTS_COMPILE_OPTIONS # ================= DEBUG ================= @@ -122,7 +127,7 @@ set(OPENTS_COMPILE_OPTIONS # ---------- MASM ---------- $<$: - /Zi /c /coff /Cx /safeseh + ${OPENTS_ASM_MASM_OPTIONS} > > @@ -143,7 +148,7 @@ set(OPENTS_COMPILE_OPTIONS # ---------- MASM ---------- $<$: - /Zi /c /coff /Cx /safeseh + ${OPENTS_ASM_MASM_OPTIONS} > > ) @@ -152,7 +157,9 @@ target_compile_options(OpenTS PRIVATE ${OPENTS_COMPILE_OPTIONS}) if(OPENTS_EXPERIMENTAL_CLANG_CL) target_compile_options(OpenTS PRIVATE - /clang:-Wno-c++11-narrowing + $<$: + /clang:-Wno-c++11-narrowing + > ) endif() @@ -271,12 +278,12 @@ message(STATUS "${PROJECT_NAME}: Adding MASM support...") enable_language(ASM_MASM) -# All .asm files compile automatically using ML.EXE with appropriate flags. +# The experimental clang-cl toolchain uses native UASM; Visual Studio uses ML.EXE. foreach(f ${OPENTS_SRC}) if(f MATCHES "\\.asm$") set_source_files_properties(${f} PROPERTIES LANGUAGE ASM_MASM - COMPILE_FLAGS "-Zi -c -coff -Cx" + COMPILE_FLAGS "${OPENTS_ASM_MASM_SOURCE_OPTIONS}" ) endif() endforeach() diff --git a/code/winasm.asm b/code/winasm.asm index 281bb787..f02ccaed 100644 --- a/code/winasm.asm +++ b/code/winasm.asm @@ -983,8 +983,8 @@ Draw_Voxel_Regular_Normals_ASM proc C uses esi edi ebx ecx edx \ mov esi, arg1 push ebp - movsx ebp, [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, [esi + TRANSFORM_COMPONENT(3,J)] + movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] + movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] xor ecx, ecx mov cl, [esi].ZSize mov edi, offset VoxelPixelDeltaTable @@ -1112,8 +1112,8 @@ Draw_Voxel_Reverse_Normals_ASM proc C uses esi edi ebx ecx edx \ mov esi, arg1 push ebp - movsx ebp, [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, [esi + TRANSFORM_COMPONENT(3,J)] + movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] + movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] xor ecx, ecx mov cl, [esi].ZSize mov edi, offset VoxelPixelDeltaTable @@ -1242,8 +1242,8 @@ Draw_Voxel_Regular_Lighting_Normals_ASM proc C uses esi edi ebx ecx edx \ mov esi, arg1 push ebp - movsx ebp, [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, [esi + TRANSFORM_COMPONENT(3,J)] + movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] + movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] xor ecx, ecx mov cl, [esi].ZSize mov edi, offset VoxelPixelDeltaTable @@ -1375,8 +1375,8 @@ Draw_Voxel_Reverse_Lighting_Normals_ASM proc C uses esi edi ebx ecx edx \ mov esi, arg1 push ebp - movsx ebp, [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, [esi + TRANSFORM_COMPONENT(3,J)] + movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] + movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] xor ecx, ecx mov cl, [esi].ZSize mov edi, offset VoxelPixelDeltaTable @@ -1508,8 +1508,8 @@ Draw_Voxel_Regular_ASM proc C uses esi edi ebx ecx edx \ mov esi, arg1 push ebp - movsx ebp, [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, [esi + TRANSFORM_COMPONENT(3,J)] + movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] + movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] mov ecx, 0FFh sub cl, [esi].ZSize mov edi, offset VoxelPixelDeltaTable @@ -1636,8 +1636,8 @@ Draw_Voxel_Reverse_ASM proc C uses esi edi ebx ecx edx \ mov esi, arg1 push ebp - movsx ebp, [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, [esi + TRANSFORM_COMPONENT(3,J)] + movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] + movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] mov ecx, 0FFh sub cl, [esi].ZSize mov edi, offset VoxelPixelDeltaTable @@ -1764,8 +1764,8 @@ Draw_Voxel_Regular_UNUSED_ASM proc C uses esi edi ebx ecx edx \ mov esi, arg1 push ebp - movsx ebp, [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, [esi + TRANSFORM_COMPONENT(3,J)] + movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] + movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] mov ecx, 0FFh sub cl, [esi].ZSize mov edi, offset VoxelPixelDeltaTable @@ -1893,8 +1893,8 @@ Draw_Voxel_Reverse_UNUSED_ASM proc C uses esi edi ebx ecx edx \ mov esi, arg1 push ebp - movsx ebp, [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, [esi + TRANSFORM_COMPONENT(3,J)] + movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] + movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] mov ecx, 0FFh sub cl, [esi].ZSize mov edi, offset VoxelPixelDeltaTable @@ -2024,6 +2024,7 @@ _Int3 endp ;endp + _TEXT$mmx ends _TEXT$mycode segment page public use32 'CODE' ; segment mycode page public use32 'code' ; Need stricter segment alignment public C Asm_Interpolate @@ -2250,13 +2251,14 @@ Asm_Interpolate_Line_Double endp ;ends + _TEXT$mycode ends .data;dataseg TopLine dd 640 dup (?) BottomLine dd 640 dup (?) LineBuffer dd 640 dup (?) - .code _TEXT$mycode ; segment mycode page public use32 'code' ; Need stricter segment alignment + _TEXT$mycode segment page public use32 'CODE' ; segment mycode page public use32 'code' ; Need stricter segment alignment Interpolate_Single_Line proc near \ @@ -2531,4 +2533,6 @@ Asm_Create_Palette_Interpolation_Table proc near Asm_Create_Palette_Interpolation_Table endp + _TEXT$mycode ends + end diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 0423eb9f..01548a8a 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -24,8 +24,8 @@ supported by the current tree. An unsupported Linux cross-build is available for compiler-portability work. It uses native `clang-cl`, LLD, and LLVM library and resource tools with the MSVC -headers and libraries, while MASM runs through an `msvc-wine` x86 wrapper. It -does not expand the supported build matrix or establish runtime behavior. +headers and libraries, and UASM. It does not expand the supported build matrix +or establish runtime behavior. Provide an `msvc-wine` installation containing MSVC 14.44.35207 and Windows SDK 10.0.26100.0, then configure a single-configuration Ninja build: @@ -39,7 +39,7 @@ cmake --build build/clang-cl ``` The toolchain requires `clang-cl`, `lld-link`, `llvm-lib`, `llvm-mt`, and -`llvm-rc` on `PATH`. Wine must be installed so the wrapper can run `ml.exe`. +`llvm-rc` and `uasm` on `PATH`. Install Visual Studio 2022 with the **Desktop development with C++** workload, a Windows SDK, CMake 3.23 or newer, and Git for Windows. From 6b3fa036863e1b2a1fd445855297d08ae3891cde Mon Sep 17 00:00:00 2001 From: Belonit <54427022+Belonit@users.noreply.github.com> Date: Sun, 30 Aug 2026 01:01:24 +0300 Subject: [PATCH 6/8] Rename Wine-free clang-cl toolchain The build pipeline no longer invokes Wine after native UASM and LLVM RC replaced the remaining wrapper tools. --- ...lang-cl-msvc-wine.cmake => clang-cl-msvc.cmake} | 4 ++-- docs/BUILDING.md | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) rename cmake/toolchains/{clang-cl-msvc-wine.cmake => clang-cl-msvc.cmake} (94%) diff --git a/cmake/toolchains/clang-cl-msvc-wine.cmake b/cmake/toolchains/clang-cl-msvc.cmake similarity index 94% rename from cmake/toolchains/clang-cl-msvc-wine.cmake rename to cmake/toolchains/clang-cl-msvc.cmake index 039d9336..e3b366e7 100644 --- a/cmake/toolchains/clang-cl-msvc-wine.cmake +++ b/cmake/toolchains/clang-cl-msvc.cmake @@ -2,7 +2,7 @@ set(CMAKE_SYSTEM_NAME Windows) set(CMAKE_SYSTEM_PROCESSOR x86) set(OPENTS_EXPERIMENTAL_CLANG_CL ON CACHE BOOL "" FORCE) -set(OPENTS_MSVC_ROOT "" CACHE PATH "Path to an msvc-wine installation") +set(OPENTS_MSVC_ROOT "" CACHE PATH "Path to the MSVC and Windows SDK files") list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES OPENTS_MSVC_ROOT) if(NOT OPENTS_MSVC_ROOT AND DEFINED ENV{OPENTS_MSVC_ROOT}) @@ -11,7 +11,7 @@ endif() if(NOT OPENTS_MSVC_ROOT) message(FATAL_ERROR - "Set OPENTS_MSVC_ROOT to the msvc-wine installation directory.") + "Set OPENTS_MSVC_ROOT to the directory containing MSVC and the Windows SDK.") endif() set(_opents_msvc_version "14.44.35207") diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 01548a8a..65d6fd19 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -23,23 +23,23 @@ supported by the current tree. ### Experimental clang-cl cross-build An unsupported Linux cross-build is available for compiler-portability work. It -uses native `clang-cl`, LLD, and LLVM library and resource tools with the MSVC -headers and libraries, and UASM. It does not expand the supported build matrix +uses native `clang-cl`, LLD, LLVM library and resource tools, and UASM with +the MSVC headers and libraries. It does not expand the supported build matrix or establish runtime behavior. -Provide an `msvc-wine` installation containing MSVC 14.44.35207 and Windows SDK -10.0.26100.0, then configure a single-configuration Ninja build: +Provide a directory containing MSVC 14.44.35207 and Windows SDK 10.0.26100.0, +then configure a single-configuration Ninja build: ```bash cmake -S . -B build/clang-cl -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/clang-cl-msvc-wine.cmake \ + -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/clang-cl-msvc.cmake \ -DOPENTS_MSVC_ROOT=/path/to/msvc cmake --build build/clang-cl ``` -The toolchain requires `clang-cl`, `lld-link`, `llvm-lib`, `llvm-mt`, and -`llvm-rc` and `uasm` on `PATH`. +The toolchain requires `clang-cl`, `lld-link`, `llvm-lib`, `llvm-mt`, +`llvm-rc`, and `uasm` on `PATH`. Install Visual Studio 2022 with the **Desktop development with C++** workload, a Windows SDK, CMake 3.23 or newer, and Git for Windows. From 47252276254e53fd4875646e02fb89607e8e9f16 Mon Sep 17 00:00:00 2001 From: Belonit <54427022+Belonit@users.noreply.github.com> Date: Sun, 30 Aug 2026 01:01:24 +0300 Subject: [PATCH 7/8] Create c_cpp_properties.clang.example.json --- .vscode/c_cpp_properties.clang.example.json | 50 +++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .vscode/c_cpp_properties.clang.example.json diff --git a/.vscode/c_cpp_properties.clang.example.json b/.vscode/c_cpp_properties.clang.example.json new file mode 100644 index 00000000..9aa88568 --- /dev/null +++ b/.vscode/c_cpp_properties.clang.example.json @@ -0,0 +1,50 @@ +{ + // Copy this file to c_cpp_properties.json and adjust these paths if needed. + "env": { + // LLVM installed with its default Windows installer location. + "CLANG_CL_PATH": "${env:ProgramFiles}/LLVM/bin/clang-cl.exe", + // Visual Studio 2022 Community. Change the edition or installation path as needed. + "MSVC_ROOT": "${env:ProgramFiles}/Microsoft Visual Studio/2022/Community", + "MSVC_VERSION": "14.44.35207", + // The Windows SDK is normally installed under Program Files (x86). + "WINDOWS_SDK_ROOT": "${env:ProgramFiles(x86)}/Windows Kits/10", + "WINDOWS_SDK_VERSION": "10.0.26100.0", + // Set this to the CMake binary directory used for the clang-cl build. + "CLANG_BUILD_DIR": "${workspaceFolder}/build/clang-cl" + }, + "configurations": [ + { + "name": "Win32 clang-cl with MSVC headers", + "compilerPath": "${CLANG_CL_PATH}", + "compilerArgs": [ + "--target=i686-pc-windows-msvc", + "/clang:-fms-compatibility-version=19.44" + ], + "intelliSenseMode": "windows-clang-x86", + "cStandard": "c17", + "cppStandard": "c++20", + "includePath": [ + "${workspaceFolder}/code", + "${workspaceFolder}/code/vqalib", + "${workspaceFolder}/thirdparty/**", + "${CLANG_BUILD_DIR}/generated", + "${MSVC_ROOT}/VC/Tools/MSVC/${MSVC_VERSION}/include", + "${MSVC_ROOT}/VC/Tools/MSVC/${MSVC_VERSION}/atlmfc/include", + "${WINDOWS_SDK_ROOT}/Include/${WINDOWS_SDK_VERSION}/ucrt", + "${WINDOWS_SDK_ROOT}/Include/${WINDOWS_SDK_VERSION}/shared", + "${WINDOWS_SDK_ROOT}/Include/${WINDOWS_SDK_VERSION}/um", + "${WINDOWS_SDK_ROOT}/Include/${WINDOWS_SDK_VERSION}/winrt", + "${WINDOWS_SDK_ROOT}/Include/${WINDOWS_SDK_VERSION}/cppwinrt" + ], + "defines": [ + "WIN32", + "_WIN32", + "_WINDOWS", + "_MBCS", + "NOMINMAX", + "NO_BLOWFISH_DLL" + ] + } + ], + "version": 4 +} From d9107062a25b7d2923793de43ca6900ec4b50e3d Mon Sep 17 00:00:00 2001 From: Belonit <54427022+Belonit@users.noreply.github.com> Date: Sun, 30 Aug 2026 01:01:24 +0300 Subject: [PATCH 8/8] Document clang-cl runtime limitations --- docs/BUILDING.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 65d6fd19..c8d54a50 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -27,6 +27,10 @@ uses native `clang-cl`, LLD, LLVM library and resource tools, and UASM with the MSVC headers and libraries. It does not expand the supported build matrix or establish runtime behavior. +The reconstructed codebase may still contain undefined behavior that the +supported MSVC build happens not to expose. A successful clang-cl build may +therefore run incorrectly or fail at runtime; validate any result separately. + Provide a directory containing MSVC 14.44.35207 and Windows SDK 10.0.26100.0, then configure a single-configuration Ninja build: