From 328e14d06cc0dd040214ed43301e9ef568b97e23 Mon Sep 17 00:00:00 2001 From: Christopher Homberger Date: Thu, 16 Jul 2026 20:40:14 +0200 Subject: [PATCH] rfc: build via wine sdk and clang --- .cargo/config.toml | 14 +++++ .cargo/lld-link-winegcc | 92 +++++++++++++++++++++++++++++ .cargo/wine-msvc-libs/dbghelp.lib | 1 + .cargo/wine-msvc-libs/kernel32.lib | 1 + .cargo/wine-msvc-libs/msvcrt.lib | 1 + .cargo/wine-msvc-libs/ntdll.lib | 1 + .cargo/wine-msvc-libs/userenv.lib | 1 + .cargo/wine-msvc-libs/winecrt0.lib | 1 + .cargo/wine-msvc-libs/ws2_32.lib | 1 + .cargo/wine-shims/.gitignore | 1 + .cargo/wine-shims/tls_shim.c | 25 ++++++++ .cargo/wine-shims/typeinfo_shim.cpp | 43 ++++++++++++++ 12 files changed, 182 insertions(+) create mode 100644 .cargo/config.toml create mode 100755 .cargo/lld-link-winegcc create mode 120000 .cargo/wine-msvc-libs/dbghelp.lib create mode 120000 .cargo/wine-msvc-libs/kernel32.lib create mode 120000 .cargo/wine-msvc-libs/msvcrt.lib create mode 120000 .cargo/wine-msvc-libs/ntdll.lib create mode 120000 .cargo/wine-msvc-libs/userenv.lib create mode 120000 .cargo/wine-msvc-libs/winecrt0.lib create mode 120000 .cargo/wine-msvc-libs/ws2_32.lib create mode 100644 .cargo/wine-shims/.gitignore create mode 100644 .cargo/wine-shims/tls_shim.c create mode 100644 .cargo/wine-shims/typeinfo_shim.cpp diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..3a5fa93 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,14 @@ +[build] +target = "x86_64-pc-windows-msvc" + +[target.x86_64-pc-windows-msvc] +linker = "./.cargo/lld-link-winegcc" +rustflags = [ + "-Lnative=./.cargo/wine-msvc-libs", +] + +[env] +CC_x86_64_pc_windows_msvc = "/usr/local/bin/winegcc --target=x86_64-windows-msvc" +CXX_x86_64_pc_windows_msvc = "/usr/local/bin/wineg++ --target=x86_64-windows-msvc" +AR_x86_64_pc_windows_msvc = "/usr/local/bin/llvm-lib" +CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_AR = "/usr/local/bin/llvm-lib" diff --git a/.cargo/lld-link-winegcc b/.cargo/lld-link-winegcc new file mode 100755 index 0000000..b7f9264 --- /dev/null +++ b/.cargo/lld-link-winegcc @@ -0,0 +1,92 @@ +#!/bin/zsh +set -euo pipefail + +script_dir=${0:A:h} +repo_root=${script_dir:h} +shim_dir="$script_dir/wine-shims" + +mkdir -p "$shim_dir" + +source "$repo_root/.env" || : + +clang --target=x86_64-windows-msvc -c "$shim_dir/tls_shim.c" -o "$shim_dir/tls_shim.obj" +clang++ --target=x86_64-windows-msvc -fno-exceptions -fno-rtti -nostdinc++ -nostdlib++ \ + -c "$shim_dir/typeinfo_shim.cpp" -o "$shim_dir/typeinfo_shim.obj" + +typeset -a out_args +typeset -A skipped_defaultlibs + +for arg in "$@"; do + case "$arg" in + -flavor|link) + ;; + /OUT:*) + out_args+=("-o" "${arg#/OUT:}") + ;; + /LIBPATH:*|/libpath:*) + out_args+=("-L${arg#*:}") + ;; + /defaultlib:msvcrt) + if [[ -z ${skipped_defaultlibs[msvcrt]-} ]]; then + out_args+=("-lmsvcrt") + fi + ;; + /NODEFAULTLIB:*|/nodefaultlib:*) + lib_name=${arg#*:} + lib_name=${lib_name:l} + skipped_defaultlibs[$lib_name]=1 + if [[ "$lib_name" == "msvcrt" ]]; then + filtered_args=() + for existing in "${out_args[@]}"; do + if [[ "$existing" != "-lmsvcrt" ]]; then + filtered_args+=("$existing") + fi + done + out_args=("${filtered_args[@]}") + out_args+=("-nostartfiles" "-nostdlib") + fi + out_args+=("-Xlinker" "$arg") + ;; + /defaultlib:*.lib|/DEFAULTLIB:*.lib) + lib_name=${arg#*:} + lib_name=${lib_name:t} + lib_name=${lib_name%.lib} + out_args+=("-l${lib_name}") + ;; + /defaultlib:*) + lib_name=${arg#*:} + out_args+=("-l${lib_name}") + ;; + winecrt0.lib) + out_args+=("-lwinecrt0") + ;; + /DLL) + out_args+=("-shared") + ;; + /DEF:*|/IMPLIB:*|/ENTRY:*|/SUBSYSTEM:*|/FIXED:*|/DYNAMICBASE|/NOLOGO|/NXCOMPAT|/OPT:*|/DEBUG|/PDBALTPATH:*|/NATVIS:*|/linkrepro:*) + # These are real lld-link options. Keep them as linker args instead of + # translating them ourselves. + out_args+=("-Xlinker" "$arg") + ;; + [A-Za-z0-9_]*.lib) + lib_name=${arg%.lib} + out_args+=("-l${lib_name}") + ;; + *.lib|*.o|*.obj|*.rlib) + out_args+=("$arg") + ;; + *) + out_args+=("$arg") + ;; + esac +done + +if [[ -z ${skipped_defaultlibs[msvcrt]-} ]]; then + out_args=("$shim_dir/tls_shim.obj" "$shim_dir/typeinfo_shim.obj" "${out_args[@]}") +fi + +if [[ -n ${skipped_defaultlibs[msvcrt]-} ]]; then + exec clang --target=x86_64-windows-msvc -fuse-ld=lld-link "${out_args[@]}" +fi + +exec winegcc --target=x86_64-windows-msvc "${out_args[@]}" diff --git a/.cargo/wine-msvc-libs/dbghelp.lib b/.cargo/wine-msvc-libs/dbghelp.lib new file mode 120000 index 0000000..ddd9d73 --- /dev/null +++ b/.cargo/wine-msvc-libs/dbghelp.lib @@ -0,0 +1 @@ +/usr/local/lib/wine/x86_64-windows/libdbghelp.a \ No newline at end of file diff --git a/.cargo/wine-msvc-libs/kernel32.lib b/.cargo/wine-msvc-libs/kernel32.lib new file mode 120000 index 0000000..7692f70 --- /dev/null +++ b/.cargo/wine-msvc-libs/kernel32.lib @@ -0,0 +1 @@ +/usr/local/lib/wine/x86_64-windows/libkernel32.a \ No newline at end of file diff --git a/.cargo/wine-msvc-libs/msvcrt.lib b/.cargo/wine-msvc-libs/msvcrt.lib new file mode 120000 index 0000000..3c41852 --- /dev/null +++ b/.cargo/wine-msvc-libs/msvcrt.lib @@ -0,0 +1 @@ +/usr/local/lib/wine/x86_64-windows/libmsvcrt.a \ No newline at end of file diff --git a/.cargo/wine-msvc-libs/ntdll.lib b/.cargo/wine-msvc-libs/ntdll.lib new file mode 120000 index 0000000..d58555e --- /dev/null +++ b/.cargo/wine-msvc-libs/ntdll.lib @@ -0,0 +1 @@ +/usr/local/lib/wine/x86_64-windows/libntdll.a \ No newline at end of file diff --git a/.cargo/wine-msvc-libs/userenv.lib b/.cargo/wine-msvc-libs/userenv.lib new file mode 120000 index 0000000..8de040d --- /dev/null +++ b/.cargo/wine-msvc-libs/userenv.lib @@ -0,0 +1 @@ +/usr/local/lib/wine/x86_64-windows/libuserenv.a \ No newline at end of file diff --git a/.cargo/wine-msvc-libs/winecrt0.lib b/.cargo/wine-msvc-libs/winecrt0.lib new file mode 120000 index 0000000..4e34b29 --- /dev/null +++ b/.cargo/wine-msvc-libs/winecrt0.lib @@ -0,0 +1 @@ +/usr/local/lib/wine/x86_64-windows/libwinecrt0.a \ No newline at end of file diff --git a/.cargo/wine-msvc-libs/ws2_32.lib b/.cargo/wine-msvc-libs/ws2_32.lib new file mode 120000 index 0000000..7852b45 --- /dev/null +++ b/.cargo/wine-msvc-libs/ws2_32.lib @@ -0,0 +1 @@ +/usr/local/lib/wine/x86_64-windows/libws2_32.a \ No newline at end of file diff --git a/.cargo/wine-shims/.gitignore b/.cargo/wine-shims/.gitignore new file mode 100644 index 0000000..281748d --- /dev/null +++ b/.cargo/wine-shims/.gitignore @@ -0,0 +1 @@ +*.obj \ No newline at end of file diff --git a/.cargo/wine-shims/tls_shim.c b/.cargo/wine-shims/tls_shim.c new file mode 100644 index 0000000..48f4383 --- /dev/null +++ b/.cargo/wine-shims/tls_shim.c @@ -0,0 +1,25 @@ +#ifdef _WIN64 +typedef unsigned long ULONG; + +int _tls_index = 0; + +__attribute__((section(".tls"))) char _tls_start = 0; +__attribute__((section(".tls$ZZZ"))) char _tls_end = 0; + +__attribute__((section(".CRT$XLA"))) void *__xl_a = 0; +__attribute__((section(".CRT$XLZ"))) void *__xl_z = 0; + +const struct { + void *StartAddressOfRawData; + void *EndAddressOfRawData; + void *AddressOfIndex; + void *AddressOfCallBacks; + ULONG SizeOfZeroFill; + ULONG Characteristics; +} _tls_used = { + &_tls_start, + &_tls_end, + &_tls_index, + &__xl_a + 1, +}; +#endif diff --git a/.cargo/wine-shims/typeinfo_shim.cpp b/.cargo/wine-shims/typeinfo_shim.cpp new file mode 100644 index 0000000..8c06e3a --- /dev/null +++ b/.cargo/wine-shims/typeinfo_shim.cpp @@ -0,0 +1,43 @@ +extern "C" int strcmp(const char*, const char*); +extern "C" void free(void*); + +class type_info { + type_info& operator=(const type_info&); + type_info(const type_info&); + + mutable struct { + const char* undecorated_name; + const char decorated_name[1]; + } data; + + int compare(const type_info& rhs) const noexcept; + +public: + virtual ~type_info(); + + const char* name() const noexcept; + unsigned long long hash_code() const noexcept; +}; + +type_info::type_info(const type_info&) = default; + +int type_info::compare(const type_info& rhs) const noexcept { + if (&data == &rhs.data) { + return 0; + } + return strcmp(&data.decorated_name[1], &rhs.data.decorated_name[1]); +} + +const char* type_info::name() const noexcept { + return &data.decorated_name[1]; +} + +unsigned long long type_info::hash_code() const noexcept { + return 0; +} + +type_info::~type_info() {} + +void operator delete(void* p, unsigned long long) noexcept { + free(p); +}