From 1a0eeecddc5f49de8fe5fdc2e52a84e8c36e295b Mon Sep 17 00:00:00 2001 From: Mosch0512 Date: Thu, 5 Feb 2026 22:30:42 +0100 Subject: [PATCH 1/5] Add cross-platform .NET build support and NuGet cache configuration Move .NET ClientLibrary and ConstantsReplacer builds out of the MSVC-only block so they work with any compiler (including MinGW cross-builds from WSL). Key changes: - Detect dotnet.exe first (for WSL interop), fallback to dotnet - Convert Linux paths to Windows UNC paths (wslpath -w) when calling Windows dotnet.exe from WSL, since MSBuild treats '/' as a switch prefix - Guard wslpath calls with CMAKE_HOST_SYSTEM_NAME to avoid errors on native Windows - Add MU_NUGET_CACHE_DIR cache variable (defaults to /.nuget) - Fix MinGW linker order: opengl32/dwmapi must follow imgui static lib - Add _deps/ to .gitignore for locally-built dependencies --- .gitignore | 3 ++ src/CMakeLists.txt | 71 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index d0bec29cb..2b1df646a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,9 @@ src/source/Global Release/ src/Global Release/ src/Global Release/Main +# External dependencies (built locally) +_deps/ + # CMake build directories build/ build-mingw/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a8924fd46..cd27a3e0f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -267,19 +267,53 @@ if (MSVC) $ COMMENT "Copying required DLLs to build directory" ) +endif() + +# .NET Client Library and tools (platform-agnostic, requires dotnet SDK) +# Native AOT can only target the OS it runs on, so when cross-compiling from +# WSL we need the Windows dotnet.exe (available via WSL interop) rather than +# a Linux dotnet. +find_program(DOTNET_EXECUTABLE dotnet.exe) +if (NOT DOTNET_EXECUTABLE) + find_program(DOTNET_EXECUTABLE dotnet) +endif() +if (DOTNET_EXECUTABLE) + message(STATUS "Found .NET SDK: ${DOTNET_EXECUTABLE}") # 1. Define the output path using a variable CMake can understand early set(DOTNET_DLL_PATH "${CMAKE_CURRENT_BINARY_DIR}/MUnique.Client.Library.dll") set(DOTNET_PROJ "${CMAKE_CURRENT_SOURCE_DIR}/../ClientLibrary/MUnique.Client.Library.csproj") - # Create temp directories for Native AOT build (avoiding paths with umlauts) + # Create temp directories for Native AOT build. set(DOTNET_TEMP_OUTPUT "${CMAKE_BINARY_DIR}/dotnet_out") set(DOTNET_TEMP_DIR "${CMAKE_BINARY_DIR}/.dotnet_temp") - set(DOTNET_NUGET_DIR "${CMAKE_SOURCE_DIR}/.nuget") + + # NuGet cache: defaults to /.nuget, override with -DMU_NUGET_CACHE_DIR=... + set(MU_NUGET_CACHE_DIR "${CMAKE_SOURCE_DIR}/.nuget" CACHE PATH "NuGet package cache directory") + set(DOTNET_NUGET_DIR "${MU_NUGET_CACHE_DIR}") file(MAKE_DIRECTORY "${DOTNET_TEMP_OUTPUT}") file(MAKE_DIRECTORY "${DOTNET_TEMP_DIR}") file(MAKE_DIRECTORY "${DOTNET_NUGET_DIR}") + # When using Windows dotnet.exe from WSL, paths passed to MSBuild must be + # Windows-style. Linux paths starting with '/' are misinterpreted as + # MSBuild switch prefixes. We use wslpath -w for backslash UNC paths + # (\\wsl.localhost\...) which MSBuild handles correctly. + if (DOTNET_EXECUTABLE MATCHES "\\.exe$" AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + foreach(_var DOTNET_PROJ DOTNET_TEMP_OUTPUT DOTNET_NUGET_DIR DOTNET_TEMP_DIR) + execute_process( + COMMAND wslpath -w "${${_var}}" + OUTPUT_VARIABLE ${_var}_NATIVE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endforeach() + else() + set(DOTNET_PROJ_NATIVE "${DOTNET_PROJ}") + set(DOTNET_TEMP_OUTPUT_NATIVE "${DOTNET_TEMP_OUTPUT}") + set(DOTNET_NUGET_DIR_NATIVE "${DOTNET_NUGET_DIR}") + set(DOTNET_TEMP_DIR_NATIVE "${DOTNET_TEMP_DIR}") + endif() + # 2. Tell CMake to watch ALL .cs files in the ClientLibrary folder file(GLOB_RECURSE DOTNET_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../ClientLibrary/*.cs") @@ -300,11 +334,11 @@ if (MSVC) OUTPUT "${DOTNET_DLL_PATH}" COMMAND ${CMAKE_COMMAND} -E echo "--- C# Changes Detected: Rebuilding Client Library ---" COMMAND ${CMAKE_COMMAND} -E env - "NUGET_PACKAGES=${DOTNET_NUGET_DIR}" - "DOTNET_CLI_HOME=${DOTNET_TEMP_DIR}" - "TEMP=${DOTNET_TEMP_DIR}" - "TMP=${DOTNET_TEMP_DIR}" - dotnet publish "${DOTNET_PROJ}" -c $ -r ${DOTNET_RID} -p:PlatformTarget=${DOTNET_PLATFORM} -o "${DOTNET_TEMP_OUTPUT}" --nologo + "NUGET_PACKAGES=${DOTNET_NUGET_DIR_NATIVE}" + "DOTNET_CLI_HOME=${DOTNET_TEMP_DIR_NATIVE}" + "TEMP=${DOTNET_TEMP_DIR_NATIVE}" + "TMP=${DOTNET_TEMP_DIR_NATIVE}" + "${DOTNET_EXECUTABLE}" publish "${DOTNET_PROJ_NATIVE}" -c $ -r ${DOTNET_RID} -p:PlatformTarget=${DOTNET_PLATFORM} -o "${DOTNET_TEMP_OUTPUT_NATIVE}" --nologo COMMAND ${CMAKE_COMMAND} -E copy_if_different "${DOTNET_TEMP_OUTPUT}/MUnique.Client.Library.dll" "${DOTNET_DLL_PATH}" DEPENDS "${DOTNET_PROJ}" ${DOTNET_SOURCES} COMMENT "Checking for .NET Client Library updates..." @@ -329,18 +363,36 @@ if (MSVC) # ConstantsReplacer build target set(CONSTANTS_REPLACER_PROJ "${CMAKE_CURRENT_SOURCE_DIR}/../ConstantsReplacer/ConstantsReplacer.csproj") + if (DOTNET_EXECUTABLE MATCHES "\\.exe$" AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + execute_process( + COMMAND wslpath -w "${CONSTANTS_REPLACER_PROJ}" + OUTPUT_VARIABLE CONSTANTS_REPLACER_PROJ_NATIVE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process( + COMMAND wslpath -w "${CMAKE_BINARY_DIR}/ConstantsReplacer" + OUTPUT_VARIABLE CONSTANTS_REPLACER_OUTDIR_NATIVE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + else() + set(CONSTANTS_REPLACER_PROJ_NATIVE "${CONSTANTS_REPLACER_PROJ}") + set(CONSTANTS_REPLACER_OUTDIR_NATIVE "${CMAKE_BINARY_DIR}/ConstantsReplacer") + endif() file(GLOB_RECURSE CONSTANTS_REPLACER_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../ConstantsReplacer/*.cs") set(CONSTANTS_REPLACER_OUTPUT "${CMAKE_BINARY_DIR}/ConstantsReplacer/ConstantsReplacer.exe") add_custom_command( OUTPUT "${CONSTANTS_REPLACER_OUTPUT}" - COMMAND dotnet build "${CONSTANTS_REPLACER_PROJ}" -c $ -o "${CMAKE_BINARY_DIR}/ConstantsReplacer" --nologo + COMMAND "${DOTNET_EXECUTABLE}" build "${CONSTANTS_REPLACER_PROJ_NATIVE}" -c $ -o "${CONSTANTS_REPLACER_OUTDIR_NATIVE}" --nologo DEPENDS "${CONSTANTS_REPLACER_PROJ}" ${CONSTANTS_REPLACER_SOURCES} COMMENT "Building ConstantsReplacer tool..." VERBATIM ) add_custom_target(ConstantsReplacer DEPENDS "${CONSTANTS_REPLACER_OUTPUT}") +else() + message(WARNING ".NET SDK not found. MUnique.Client.Library.dll will NOT be built. " + "The game will run but cannot connect to the server. Install .NET SDK 10.0+ to enable.") endif() # MinGW (32-bit or 64-bit) cross-toolchains: link against the Windows/OpenGL @@ -415,4 +467,7 @@ endif() # Link ImGui for all platforms when editor is enabled if(ENABLE_EDITOR) target_link_libraries(Main PRIVATE imgui) + # ImGui backends need opengl32 and dwmapi; with MinGW's order-sensitive + # linker these must come after the imgui static library. + target_link_libraries(Main PRIVATE opengl32 dwmapi) endif() From 6ab29ab3cb9d76bfcefc49be1925da43ccbdc2ad Mon Sep 17 00:00:00 2001 From: Mosch0512 Date: Thu, 5 Feb 2026 23:01:15 +0100 Subject: [PATCH 2/5] Add build platform guide and update README for cross-platform builds - Add docs/build-guide.md: comprehensive guide covering all build scenarios (WSL+MinGW, CLion via Z: drive, CLion native Windows, VS presets) with step-by-step setup instructions and directory layouts - Update README.md: fix CMake minimum version (3.25), fix CLion working directory to use build output instead of src/bin --- README.md | 5 +- docs/build-guide.md | 315 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 318 insertions(+), 2 deletions(-) create mode 100644 docs/build-guide.md diff --git a/README.md b/README.md index b7d2aa794..b4ad985e3 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ What needs to be done for Season 6: ## How to build & run ### Requirements -* **CMake** 3.16 or newer (bundled with Visual Studio and CLion) +* **CMake** 3.25 or newer (bundled with Visual Studio and CLion) * **.NET SDK 10.0** or newer (for building the Client Library) * **Visual Studio 2022+** with C++ and C# workloads, **CLion**, or **Rider** (see IDE-specific instructions below) * A compatible server: [OpenMU](https://github.com/MUnique/OpenMU) @@ -162,7 +162,8 @@ The project uses **CMake** as its build system. The `.NET Client Library` is aut 3. **Configure working directory:** - Run → Edit Configurations - Select `Main` - - Set "Working directory" to: `$ProjectFileDir$/src/bin` + - Set "Working directory" to the build output directory (e.g. `cmake-build-debug/src/Debug`) + - The post-build step copies all game assets there automatically 4. **Build and Run:** - Click the hammer icon to build diff --git a/docs/build-guide.md b/docs/build-guide.md new file mode 100644 index 000000000..1850efc02 --- /dev/null +++ b/docs/build-guide.md @@ -0,0 +1,315 @@ +# CMake Build System — Platform Guide + +This document explains how the build system works across all supported environments, what directories are created and why, and how to set up each environment correctly. + +--- + +## Quick Reference + +| Environment | Best for | Build speed | Setup effort | +|-------------|----------|-------------|--------------| +| WSL terminal + MinGW | Daily development, Claude Code | Fast | Medium (one-time) | +| CLion via Z: drive + MSVC | Quick MSVC testing (no file copy) | Slow (cross-filesystem I/O) | Easy | +| CLion with native Windows path + MSVC | Debugging, full-speed MSVC builds | Fast | Easy (manual file sync) | +| Windows native + MSVC (VS presets) | Full-speed MSVC builds | Fast | Easy (manual file sync) | + +**Recommended workflow:** Use WSL + MinGW for daily development and Claude Code. Use CLion/MSVC only when you need the debugger or MSVC-specific testing. + +--- + +## Supported Build Scenarios + +| Scenario | Compiler | CMake runs on | dotnet used | Status | +|----------|----------|---------------|-------------|--------| +| Windows (VS presets) | MSVC x86 | Windows | `dotnet.exe` (Windows) | Supported | +| CLion via Z: drive | MSVC x86 | Windows | `dotnet.exe` (Windows) | Supported (slow I/O) | +| CLion with native Windows path | MSVC x86 | Windows | `dotnet.exe` (Windows) | Supported (fast) | +| WSL terminal (MinGW) | MinGW i686 | Linux (WSL) | `dotnet.exe` (Windows, via WSL interop) | Supported | +| Pure Linux (no WSL) | MinGW i686 | Linux | `dotnet` (Linux) | Partial — no DLL | +| CLion on Linux | MinGW i686 | Linux | `dotnet` (Linux) | Untested — no DLL | + +--- + +## Setup Guide + +### WSL Terminal — MinGW (Recommended for Development) + +**Where to keep the repo:** On the WSL filesystem (`/home//MuMain`). This is the fast path — all file I/O stays on native Linux ext4. + +**Do NOT** put the repo on `/mnt/c/...` (Windows filesystem from WSL). That path goes through a slow translation layer and is significantly slower than native WSL filesystem. + +**Prerequisites (one-time):** + +```bash +sudo apt-get update && sudo apt-get install -y mingw-w64 g++-mingw-w64-i686 cmake ninja-build +``` + +**Configure and build:** + +```bash +cmake -S . -B build-mingw -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/mingw-w64-i686.cmake \ + -DCMAKE_BUILD_TYPE=Debug \ + -DENABLE_EDITOR=ON \ + -DMU_TURBOJPEG_STATIC_LIB=_deps/mingw-i686/lib/libturbojpeg.a + +cmake --build build-mingw -j$(nproc) +``` + +**Running the game:** The post-build step copies all assets from `src/bin/` into `build-mingw/src/`. Run from the build output directory: + +```bash +cd build-mingw/src && ./Main.exe +``` + +### CLion on Windows — Which Approach? + +CLion on Windows uses the MSVC compiler. There are two ways to point CLion at the source code: + +| Approach | How it works | Tradeoff | +|----------|-------------|----------| +| **Z: drive** (mapped WSL filesystem) | CLion reads source files directly from your WSL repo via a mapped network drive. No file copying needed. | Slower builds — every file read crosses the WSL↔Windows boundary. | +| **Native Windows path** | You copy/clone the repo onto a Windows drive (e.g. `D:\repos\MuMain`). CLion reads files from fast local NTFS. | Faster builds, but you maintain a separate copy of the repo. | + +Pick **Z: drive** if you want a single repo checkout and don't mind slower builds. +Pick **native Windows path** if you want fast MSVC builds and are okay syncing/copying files manually. + +Both approaches produce identical output. The only difference is build speed. + +--- + +### CLion on Windows via Z: Drive + +This approach maps your WSL filesystem as a Windows drive letter so CLion can open the repo directly — no file copying needed. + +**Prerequisites:** + +1. The repo must already exist on the WSL filesystem (e.g. `/home//MuMain`). +2. WSL must be running. +3. CLion must be installed on Windows. + +**Step 1 — Map the WSL filesystem as Z: drive (one-time, persistent across reboots):** + +Open PowerShell and run: + +```powershell +net use Z: \\wsl.localhost\Ubuntu /persistent:yes +``` + +This makes your entire WSL home directory accessible as `Z:\home\\` from Windows. The `/persistent:yes` flag means the mapping survives reboots (as long as WSL is running). + +**Step 2 — Fix git "dubious ownership" warning (one-time):** + +Windows git flags WSL-owned repos as untrusted. Without this fix, CLion's git integration won't work. Run in PowerShell: + +```powershell +git config --global --add safe.directory '%(prefix)///wsl.localhost/Ubuntu/home//MuMain' +git config --global --add safe.directory '%(prefix)///wsl.localhost/Ubuntu/home//MuMain/src/dependencies/imgui' +``` + +Note: You must use the UNC format above (`///wsl.localhost/...`), not `Z:/...` — git internally resolves the Z: drive back to the UNC path. + +**Step 3 — Open the project in CLion:** + +Open `Z:\home\\MuMain` in CLion (File > Open). + +**Step 4 — Configure CMake in CLion** (Settings > Build, Execution, Deployment > CMake): + +- **CMake options:** + ``` + -G Ninja -DCMAKE_TOOLCHAIN_FILE=Z:/home//MuMain/toolchain-x86.cmake -DENABLE_EDITOR=ON + ``` +- **Build directory:** Set to a **Windows-native path** for faster builds: + ``` + C:\build\MuMain-x86debug-mueditor + ``` + This is important: even though source files are on Z:, putting build output on a local Windows drive (C: or D:) avoids slow cross-filesystem writes. + +**Step 5 — Set up the Run Configuration:** + +Set the **Working directory** to the build output directory: +``` +C:\build\MuMain-x86debug-mueditor\src\Debug +``` + +Do NOT set it to `Z:\...\src\bin`. The post-build step automatically copies all game assets (data files, textures, etc.) into the build output directory, and using the Windows-native path avoids slow cross-filesystem reads at runtime. + +--- + +### CLion on Windows with Native Windows Path + +This approach uses a repo cloned directly on a Windows drive. Everything is on fast local NTFS — no cross-filesystem penalty. + +**Prerequisites:** + +1. Clone or copy the repo onto a Windows drive (e.g. `D:\repos\MuMain`). +2. CLion must be installed on Windows. + +**Step 1 — Open the project in CLion:** + +Open `D:\repos\MuMain` in CLion (File > Open). + +**Step 2 — Configure CMake in CLion** (Settings > Build, Execution, Deployment > CMake): + +- **CMake options:** + ``` + -G Ninja -DCMAKE_TOOLCHAIN_FILE=D:/repos/MuMain/toolchain-x86.cmake -DENABLE_EDITOR=ON + ``` +- **Build directory:** Can use CLion's default (inside the project) or a custom path. Both are fast since everything is on native NTFS. + +**Step 3 — Set up the Run Configuration:** + +Set the **Working directory** to the build output directory: +``` +D:\repos\MuMain\cmake-build-x86debug-mueditor\src\Debug +``` + +The post-build step copies all game assets there automatically. + +**Note:** Visual Studio 2026 cannot open projects from the Z: drive (WSL filesystem), but works fine with native Windows paths like `D:\repos\MuMain`. + +### Windows — Visual Studio Presets + +```powershell +cmake --preset windows-x86 # standard x86 +cmake --preset windows-x86-mueditor # x86 with ImGui editor + +cmake --build --preset windows-x86-debug +cmake --build --preset windows-x86-mueditor-debug +``` + +**Working directory for running:** `out/build/windows-x86/src/Debug/` (assets are copied there by the post-build step). + +--- + +## Performance Notes + +| Operation | WSL filesystem | Z: drive from Windows | Native Windows (C:\) | +|-----------|---------------|----------------------|---------------------| +| File reads (compilation) | Fast | Slow | Fast | +| File writes (build output) | Fast | Slow | Fast | +| Git operations | Fast | Slow | Fast | +| Claude Code file operations | Fast | N/A | N/A | +| Game runtime (data file reads) | Fast (WSL interop) | Slow | Fast | + +**Key takeaway:** Keep the repo on WSL for Claude Code. For CLion/MSVC, put the build output on a Windows drive. Accept that source file reads from Z: will be slower — this is a tradeoff for having a single repo checkout. + +--- + +## Directory Layout Per Scenario + +### 1. Windows — Visual Studio Presets + +``` +MuMain/ <-- on Windows filesystem (C:\...) + .nuget/ <-- NuGet package cache (default, configurable) + out/build/windows-x86/ <-- build output (CMAKE_BINARY_DIR) + src/ + Debug/ + Main.exe <-- game executable + copied assets + MUnique.Client.Library.dll + dotnet_out/ <-- intermediate .NET publish output + .dotnet_temp/ <-- .NET CLI temp (avoids umlaut paths) +``` + +### 2. CLion on Windows via Z: Drive + +``` +Z:\home\\MuMain\ <-- source (mapped WSL filesystem) + .nuget\ <-- NuGet cache (in project root) + +C:\build\MuMain-x86debug-mueditor\ <-- build directory (Windows-native, fast) + src/ + Debug/ + Main.exe <-- game executable + copied assets + MUnique.Client.Library.dll + dotnet_out/ + .dotnet_temp/ +``` + +**Note:** If `ilc.exe` from the NuGet cache fails to execute on the WSL filesystem, override with a Windows-native path: `cmake -DMU_NUGET_CACHE_DIR=C:/.mu-nuget ...` + +### 3. CLion on Windows with Native Windows Path + +``` +D:\repos\MuMain\ <-- source (on Windows drive) + .nuget\ <-- NuGet cache (in project root) + cmake-build-x86debug-mueditor\ <-- build directory (CLion default or custom) + src/ + Debug/ + Main.exe <-- game executable + copied assets + MUnique.Client.Library.dll + dotnet_out/ + .dotnet_temp/ +``` + +### 4. WSL Terminal — MinGW Cross-Compile + +``` +/home//MuMain/ <-- source + build (all on WSL filesystem) + .nuget/ <-- NuGet cache (in project root) + build-mingw/ <-- build output (CMAKE_BINARY_DIR) + src/ + Main.exe <-- PE32 Windows executable + copied assets + MUnique.Client.Library.dll + dotnet_out/ + .dotnet_temp/ +``` + +### 5. Pure Linux (No WSL, No Windows dotnet) + +``` +/home//MuMain/ + build-mingw/ + src/ + Main.exe <-- built, but no DLL +``` + +The Linux `dotnet` SDK cannot produce a Windows `.dll` via Native AOT (cross-OS AOT is not supported). CMake prints a warning and skips the .NET build. The game runs but cannot connect to a server. + +--- + +## NuGet Cache Location + +The NuGet cache defaults to `/.nuget` on all platforms. This keeps it inside the repo (already in `.gitignore`) and avoids issues with special characters in user profile paths. + +Override with: + +```bash +cmake -DMU_NUGET_CACHE_DIR=D:/my-nuget-cache ... +``` + +**Why not the default NuGet cache?** The system default is `%USERPROFILE%\.nuget\packages`. If the Windows username contains special characters (e.g. umlauts), the Native AOT IL compiler (`ilc.exe`) can fail. Using a project-local path avoids this. + +**Edge case — CLion via Z: drive:** The NuGet cache contains native executables like `ilc.exe`. Windows may fail to execute `.exe` files stored on the WSL ext4 filesystem via `\\wsl.localhost\`. If this happens, override to a Windows-native path: `cmake -DMU_NUGET_CACHE_DIR=C:/.mu-nuget ...` + +--- + +## How dotnet Is Found + +```cmake +find_program(DOTNET_EXECUTABLE dotnet.exe) # prefer Windows binary +if (NOT DOTNET_EXECUTABLE) + find_program(DOTNET_EXECUTABLE dotnet) # fallback to Linux binary +endif() +``` + +- **WSL:** Finds `dotnet.exe` at `/mnt/c/Program Files/dotnet/dotnet.exe` via WSL interop. Produces correct Windows DLLs with Native AOT. +- **Native Windows:** Finds `dotnet.exe` directly. +- **Pure Linux:** Falls back to `dotnet`. Cannot produce Windows DLLs. +- **No SDK installed:** CMake warns and skips the .NET build. + +--- + +## Path Translation (WSL Only) + +When CMake detects it's running on Linux (`CMAKE_HOST_SYSTEM_NAME == "Linux"`) and found a Windows `dotnet.exe`, it converts all paths passed to `dotnet.exe` using `wslpath -w`: + +| Linux path | Converted Windows path | +|------------|----------------------| +| `/home//MuMain/ClientLibrary/...csproj` | `\\wsl.localhost\Ubuntu\home\\MuMain\ClientLibrary\...csproj` | +| `/home//MuMain/build-mingw/dotnet_out` | `\\wsl.localhost\Ubuntu\home\\MuMain\build-mingw\dotnet_out` | + +Paths used by CMake-native commands (`copy_if_different`, `DEPENDS`) stay as Linux paths. + +The guard `CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux"` ensures `wslpath` is never called on native Windows (where it doesn't exist). From 267b13883e85e0269a49ed9b755207d7f13df01a Mon Sep 17 00:00:00 2001 From: Mosch0512 Date: Fri, 6 Feb 2026 01:12:12 +0100 Subject: [PATCH 3/5] Address PR review: add mu_native_path macro and fix CI build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add mu_native_path() macro to deduplicate WSL path conversion logic (used by both ClientLibrary and ConstantsReplacer targets) - Skip .NET build when Linux dotnet targets Windows (cross-OS Native AOT is not supported) — fixes CI workflow failure on GitHub Actions - Only link opengl32/dwmapi after imgui for non-MSVC compilers (MinGW needs correct link order, MSVC doesn't) - Fix "Visual Studio 2026" typo in build guide --- docs/build-guide.md | 2 +- src/CMakeLists.txt | 73 +++++++++++++++++++++++---------------------- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/docs/build-guide.md b/docs/build-guide.md index 1850efc02..1b2b515e4 100644 --- a/docs/build-guide.md +++ b/docs/build-guide.md @@ -166,7 +166,7 @@ D:\repos\MuMain\cmake-build-x86debug-mueditor\src\Debug The post-build step copies all game assets there automatically. -**Note:** Visual Studio 2026 cannot open projects from the Z: drive (WSL filesystem), but works fine with native Windows paths like `D:\repos\MuMain`. +**Note:** Visual Studio cannot open projects from the Z: drive (WSL filesystem), but works fine with native Windows paths like `D:\repos\MuMain`. ### Windows — Visual Studio Presets diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd27a3e0f..b2b891f7d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -277,9 +277,33 @@ find_program(DOTNET_EXECUTABLE dotnet.exe) if (NOT DOTNET_EXECUTABLE) find_program(DOTNET_EXECUTABLE dotnet) endif() +if (DOTNET_EXECUTABLE) + # Native AOT cannot cross-compile across OS boundaries. A Linux dotnet + # targeting win-x86/win-x64 will fail. Only proceed when we have a Windows + # dotnet.exe (native or via WSL interop). + if (NOT DOTNET_EXECUTABLE MATCHES "\\.exe$" AND CMAKE_SYSTEM_NAME STREQUAL "Windows") + message(WARNING "Found Linux dotnet but target is Windows. " + "Cross-OS Native AOT is not supported. MUnique.Client.Library.dll will NOT be built. " + "Install the Windows .NET SDK or use WSL interop (dotnet.exe) to enable.") + set(DOTNET_EXECUTABLE "") + endif() +endif() if (DOTNET_EXECUTABLE) message(STATUS "Found .NET SDK: ${DOTNET_EXECUTABLE}") + # Helper macro: convert a path to Windows-native format when using + # Windows dotnet.exe from WSL. On all other platforms this is a no-op. + macro(mu_native_path _input _output) + set(${_output} "${_input}") + if (DOTNET_EXECUTABLE MATCHES "\\.exe$" AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + execute_process( + COMMAND wslpath -w "${_input}" + OUTPUT_VARIABLE ${_output} + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endif() + endmacro() + # 1. Define the output path using a variable CMake can understand early set(DOTNET_DLL_PATH "${CMAKE_CURRENT_BINARY_DIR}/MUnique.Client.Library.dll") set(DOTNET_PROJ "${CMAKE_CURRENT_SOURCE_DIR}/../ClientLibrary/MUnique.Client.Library.csproj") @@ -295,24 +319,11 @@ if (DOTNET_EXECUTABLE) file(MAKE_DIRECTORY "${DOTNET_TEMP_DIR}") file(MAKE_DIRECTORY "${DOTNET_NUGET_DIR}") - # When using Windows dotnet.exe from WSL, paths passed to MSBuild must be - # Windows-style. Linux paths starting with '/' are misinterpreted as - # MSBuild switch prefixes. We use wslpath -w for backslash UNC paths - # (\\wsl.localhost\...) which MSBuild handles correctly. - if (DOTNET_EXECUTABLE MATCHES "\\.exe$" AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") - foreach(_var DOTNET_PROJ DOTNET_TEMP_OUTPUT DOTNET_NUGET_DIR DOTNET_TEMP_DIR) - execute_process( - COMMAND wslpath -w "${${_var}}" - OUTPUT_VARIABLE ${_var}_NATIVE - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - endforeach() - else() - set(DOTNET_PROJ_NATIVE "${DOTNET_PROJ}") - set(DOTNET_TEMP_OUTPUT_NATIVE "${DOTNET_TEMP_OUTPUT}") - set(DOTNET_NUGET_DIR_NATIVE "${DOTNET_NUGET_DIR}") - set(DOTNET_TEMP_DIR_NATIVE "${DOTNET_TEMP_DIR}") - endif() + # Convert paths to Windows-native format for MSBuild (no-op outside WSL). + mu_native_path("${DOTNET_PROJ}" DOTNET_PROJ_NATIVE) + mu_native_path("${DOTNET_TEMP_OUTPUT}" DOTNET_TEMP_OUTPUT_NATIVE) + mu_native_path("${DOTNET_NUGET_DIR}" DOTNET_NUGET_DIR_NATIVE) + mu_native_path("${DOTNET_TEMP_DIR}" DOTNET_TEMP_DIR_NATIVE) # 2. Tell CMake to watch ALL .cs files in the ClientLibrary folder file(GLOB_RECURSE DOTNET_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../ClientLibrary/*.cs") @@ -363,21 +374,8 @@ if (DOTNET_EXECUTABLE) # ConstantsReplacer build target set(CONSTANTS_REPLACER_PROJ "${CMAKE_CURRENT_SOURCE_DIR}/../ConstantsReplacer/ConstantsReplacer.csproj") - if (DOTNET_EXECUTABLE MATCHES "\\.exe$" AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") - execute_process( - COMMAND wslpath -w "${CONSTANTS_REPLACER_PROJ}" - OUTPUT_VARIABLE CONSTANTS_REPLACER_PROJ_NATIVE - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - execute_process( - COMMAND wslpath -w "${CMAKE_BINARY_DIR}/ConstantsReplacer" - OUTPUT_VARIABLE CONSTANTS_REPLACER_OUTDIR_NATIVE - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - else() - set(CONSTANTS_REPLACER_PROJ_NATIVE "${CONSTANTS_REPLACER_PROJ}") - set(CONSTANTS_REPLACER_OUTDIR_NATIVE "${CMAKE_BINARY_DIR}/ConstantsReplacer") - endif() + mu_native_path("${CONSTANTS_REPLACER_PROJ}" CONSTANTS_REPLACER_PROJ_NATIVE) + mu_native_path("${CMAKE_BINARY_DIR}/ConstantsReplacer" CONSTANTS_REPLACER_OUTDIR_NATIVE) file(GLOB_RECURSE CONSTANTS_REPLACER_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../ConstantsReplacer/*.cs") set(CONSTANTS_REPLACER_OUTPUT "${CMAKE_BINARY_DIR}/ConstantsReplacer/ConstantsReplacer.exe") @@ -467,7 +465,10 @@ endif() # Link ImGui for all platforms when editor is enabled if(ENABLE_EDITOR) target_link_libraries(Main PRIVATE imgui) - # ImGui backends need opengl32 and dwmapi; with MinGW's order-sensitive - # linker these must come after the imgui static library. - target_link_libraries(Main PRIVATE opengl32 dwmapi) + # MinGW's linker is order-sensitive: opengl32 and dwmapi (needed by ImGui + # backends) must appear after the imgui static library. MSVC already links + # these earlier and doesn't care about order. + if (NOT MSVC) + target_link_libraries(Main PRIVATE opengl32 dwmapi) + endif() endif() From 2d965b4240ccecd9f5a7041bd27eab52a55a2fe4 Mon Sep 17 00:00:00 2001 From: Mosch0512 Date: Fri, 6 Feb 2026 01:20:18 +0100 Subject: [PATCH 4/5] Address PR review: add wslpath error handling and fix imgui submodule path - Add RESULT_VARIABLE check to mu_native_path macro so wslpath failures produce a clear FATAL_ERROR instead of silently passing Linux paths - Fix imgui submodule path in build guide (src/ThirdParty/imgui, not src/dependencies/imgui) --- docs/build-guide.md | 2 +- src/CMakeLists.txt | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/build-guide.md b/docs/build-guide.md index 1b2b515e4..ddf900811 100644 --- a/docs/build-guide.md +++ b/docs/build-guide.md @@ -104,7 +104,7 @@ Windows git flags WSL-owned repos as untrusted. Without this fix, CLion's git in ```powershell git config --global --add safe.directory '%(prefix)///wsl.localhost/Ubuntu/home//MuMain' -git config --global --add safe.directory '%(prefix)///wsl.localhost/Ubuntu/home//MuMain/src/dependencies/imgui' +git config --global --add safe.directory '%(prefix)///wsl.localhost/Ubuntu/home//MuMain/src/ThirdParty/imgui' ``` Note: You must use the UNC format above (`///wsl.localhost/...`), not `Z:/...` — git internally resolves the Z: drive back to the UNC path. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b2b891f7d..93368723c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -298,9 +298,15 @@ if (DOTNET_EXECUTABLE) if (DOTNET_EXECUTABLE MATCHES "\\.exe$" AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") execute_process( COMMAND wslpath -w "${_input}" - OUTPUT_VARIABLE ${_output} + OUTPUT_VARIABLE _mu_native_result + RESULT_VARIABLE _mu_native_rc OUTPUT_STRIP_TRAILING_WHITESPACE ) + if (_mu_native_rc EQUAL 0) + set(${_output} "${_mu_native_result}") + else() + message(FATAL_ERROR "wslpath failed for '${_input}'. Ensure wslpath is available.") + endif() endif() endmacro() From ab179e9e77ae8fae94cab85b4de73486a58f5fe0 Mon Sep 17 00:00:00 2001 From: Mosch0512 Date: Fri, 6 Feb 2026 01:27:18 +0100 Subject: [PATCH 5/5] Refactor mu_native_path from macro to function for proper variable scoping --- src/CMakeLists.txt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 93368723c..2c1154134 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -293,22 +293,23 @@ if (DOTNET_EXECUTABLE) # Helper macro: convert a path to Windows-native format when using # Windows dotnet.exe from WSL. On all other platforms this is a no-op. - macro(mu_native_path _input _output) - set(${_output} "${_input}") + function(mu_native_path input_path output_var) if (DOTNET_EXECUTABLE MATCHES "\\.exe$" AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") execute_process( - COMMAND wslpath -w "${_input}" - OUTPUT_VARIABLE _mu_native_result - RESULT_VARIABLE _mu_native_rc + COMMAND wslpath -w "${input_path}" + OUTPUT_VARIABLE native_path + RESULT_VARIABLE rc OUTPUT_STRIP_TRAILING_WHITESPACE ) - if (_mu_native_rc EQUAL 0) - set(${_output} "${_mu_native_result}") + if (rc EQUAL 0) + set(${output_var} "${native_path}" PARENT_SCOPE) else() - message(FATAL_ERROR "wslpath failed for '${_input}'. Ensure wslpath is available.") + message(FATAL_ERROR "wslpath failed for '${input_path}'. Ensure wslpath is available.") endif() + else() + set(${output_var} "${input_path}" PARENT_SCOPE) endif() - endmacro() + endfunction() # 1. Define the output path using a variable CMake can understand early set(DOTNET_DLL_PATH "${CMAKE_CURRENT_BINARY_DIR}/MUnique.Client.Library.dll")