Skip to content

Conversation

@Mosch0512
Copy link
Contributor

Summary of Changes

This pull request significantly enhances the project's build system by introducing robust cross-platform support for .NET components, particularly improving compatibility and performance within Windows Subsystem for Linux (WSL) environments. It streamlines the build process by intelligently handling path translations and NuGet caching, ensuring a more consistent and reliable development experience across different operating systems and IDEs. The changes also include crucial linker fixes for MinGW and comprehensive documentation to guide developers through various build configurations.

Highlights

  • Cross-Platform .NET Build Support: The build logic for the .NET ClientLibrary and ConstantsReplacer has been refactored to be platform-agnostic, moving it out of the MSVC-specific block. This enables successful builds with various compilers, including MinGW cross-builds from WSL.
  • WSL Interoperability for .NET: The build system now intelligently detects dotnet.exe (prioritizing the Windows binary for WSL interop) and converts Linux paths to Windows UNC paths using wslpath -w when invoking Windows dotnet.exe from WSL. This prevents MSBuild from misinterpreting Linux path separators as command-line switches. These wslpath calls are conditionally executed based on CMAKE_HOST_SYSTEM_NAME to avoid errors on native Windows.
  • Configurable NuGet Cache: A new CMake cache variable, MU_NUGET_CACHE_DIR, has been introduced, allowing users to specify the NuGet package cache directory. It defaults to <project>/.nuget, addressing potential issues with special characters in user profile paths and improving build reliability.
  • MinGW Linker Order Fix: The MinGW linker order has been corrected for the Main target. opengl32 and dwmapi are now explicitly linked after the imgui static library when ENABLE_EDITOR is active, resolving order-sensitive linking issues specific to MinGW.
  • Comprehensive Build Guide Documentation: A new docs/build-guide.md file has been added, providing detailed explanations of the build system's behavior across supported environments (WSL, CLion, Visual Studio), setup instructions, performance considerations, and directory layouts for various scenarios.
  • Updated Build Requirements and Git Ignore: The minimum CMake requirement has been updated to 3.25 in README.md. Additionally, _deps/ has been added to .gitignore to exclude locally-built external dependencies from version control.

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 <project>/.nuget)
- Fix MinGW linker order: opengl32/dwmapi must follow imgui static lib
- Add _deps/ to .gitignore for locally-built dependencies
- 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
- 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
… 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)
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @Mosch0512, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the project's build system by introducing robust cross-platform support for .NET components, particularly improving compatibility and performance within Windows Subsystem for Linux (WSL) environments. It streamlines the build process by intelligently handling path translations and NuGet caching, ensuring a more consistent and reliable development experience across different operating systems and IDEs. The changes also include crucial linker fixes for MinGW and comprehensive documentation to guide developers through various build configurations.

Highlights

  • Cross-Platform .NET Build Support: The build logic for the .NET ClientLibrary and ConstantsReplacer has been refactored to be platform-agnostic, enabling successful builds with various compilers, including MinGW cross-builds from WSL.
  • WSL Interoperability for .NET: The build system now intelligently detects 'dotnet.exe' (prioritizing the Windows binary for WSL interop) and converts Linux paths to Windows UNC paths using 'wslpath -w' when invoking Windows 'dotnet.exe' from WSL, preventing MSBuild path misinterpretations.
  • Configurable NuGet Cache: A new CMake cache variable, 'MU_NUGET_CACHE_DIR', has been introduced, allowing users to specify the NuGet package cache directory, defaulting to '/.nuget' to address potential issues with special characters in user profile paths.
  • MinGW Linker Order Fix: The MinGW linker order has been corrected for the 'Main' target, explicitly linking 'opengl32' and 'dwmapi' after the 'imgui' static library when 'ENABLE_EDITOR' is active, resolving order-sensitive linking issues.
  • Comprehensive Build Guide Documentation: A new 'docs/build-guide.md' file has been added, providing detailed explanations of the build system's behavior across supported environments (WSL, CLion, Visual Studio), setup instructions, performance considerations, and directory layouts.
  • Updated Build Requirements and Git Ignore: The minimum CMake requirement has been updated to 3.25 in 'README.md', and '_deps/' has been added to '.gitignore' to exclude locally-built external dependencies from version control.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • .gitignore
    • Added '_deps/' to exclude locally-built external dependencies from version control.
  • README.md
    • Updated the minimum CMake requirement from 3.16 to 3.25.
    • Clarified the working directory configuration for CLion, now pointing to the build output directory instead of 'src/bin'.
  • docs/build-guide.md
    • Added a new comprehensive build guide document.
    • Details supported environments (WSL, CLion, Visual Studio), setup instructions, performance considerations, and directory layouts.
    • Explains NuGet cache location, 'dotnet' discovery logic, and WSL path translation.
  • src/CMakeLists.txt
    • Moved the .NET ClientLibrary and ConstantsReplacer build logic out of the MSVC-specific conditional block to enable platform-agnostic compilation.
    • Implemented logic to find 'dotnet.exe' (Windows) first, then 'dotnet' (Linux), and added a warning/skip for cross-OS Native AOT compilation if a Linux 'dotnet' is found targeting Windows.
    • Introduced a 'mu_native_path' CMake function to convert Linux paths to Windows UNC paths using 'wslpath -w' when 'dotnet.exe' is invoked from WSL.
    • Made the NuGet package cache directory configurable via 'MU_NUGET_CACHE_DIR', defaulting to a project-local '.nuget' folder.
    • Applied the 'mu_native_path' conversion to all relevant paths used in 'dotnet publish' and 'dotnet build' commands.
    • Added a warning message if the .NET SDK is not found, indicating that the Client Library will not be built.
    • Corrected the MinGW linker order for the 'Main' target, ensuring 'opengl32' and 'dwmapi' are linked after 'imgui' when 'ENABLE_EDITOR' is active.
Activity
  • The pull request was opened by Mosch0512.
  • No additional human activity (comments, reviews, or status updates) has been recorded yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request significantly improves the project's build system by adding robust cross-platform .NET support, particularly for WSL environments. Key changes include platform-agnostic .NET build logic, intelligent path translation for dotnet.exe in WSL, a configurable NuGet cache directory, and a crucial linker order fix for MinGW. The addition of a comprehensive build-guide.md also greatly enhances developer onboarding and understanding of the build process. Overall, these changes contribute to a more consistent and reliable development experience across different operating systems and IDEs.

Comment on lines +478 to +479
if (NOT MSVC)
target_link_libraries(Main PRIVATE opengl32 dwmapi)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The conditional linking of opengl32 and dwmapi specifically for MinGW when ENABLE_EDITOR is active is a critical fix. MinGW's linker is known to be order-sensitive, and ensuring these libraries appear after imgui resolves potential linking issues, improving build reliability for MinGW users.

Comment on lines +296 to +312
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_path}"
OUTPUT_VARIABLE native_path
RESULT_VARIABLE rc
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (rc EQUAL 0)
set(${output_var} "${native_path}" PARENT_SCOPE)
else()
message(FATAL_ERROR "wslpath failed for '${input_path}'. Ensure wslpath is available.")
endif()
else()
set(${output_var} "${input_path}" PARENT_SCOPE)
endif()
endfunction()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The mu_native_path function is a critical component for enabling seamless WSL interoperability. By conditionally converting Linux paths to Windows UNC paths using wslpath -w, it correctly handles path differences when invoking Windows dotnet.exe from WSL, preventing MSBuild from misinterpreting path separators.

Comment on lines +329 to +333
# 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Applying mu_native_path to all relevant .NET project paths (DOTNET_PROJ, DOTNET_TEMP_OUTPUT, DOTNET_NUGET_DIR, DOTNET_TEMP_DIR) ensures that the path translation is consistently applied across the .NET build process, which is essential for correct operation in WSL.

Comment on lines +355 to +359
"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 $<CONFIG> -r ${DOTNET_RID} -p:PlatformTarget=${DOTNET_PLATFORM} -o "${DOTNET_TEMP_OUTPUT_NATIVE}" --nologo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The update to use the native paths (_NATIVE suffix) and the dynamically found DOTNET_EXECUTABLE in the dotnet publish command is crucial for the cross-platform build to function correctly. This ensures that the correct dotnet executable is used and paths are interpreted properly based on the environment.

src/Global Release/Main

# External dependencies (built locally)
_deps/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Adding _deps/ to .gitignore is a good practice to prevent locally built external dependencies from being committed to version control. This keeps the repository clean and focused on source code.

Comment on lines +1 to +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/<user>/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/<user>/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\<user>\` 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/<user>/MuMain'
git config --global --add safe.directory '%(prefix)///wsl.localhost/Ubuntu/home/<user>/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.

**Step 3 — Open the project in CLion:**

Open `Z:\home\<user>\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/<user>/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 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\<user>\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/<user>/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/<user>/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 `<project_root>/.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/<user>/MuMain/ClientLibrary/...csproj` | `\\wsl.localhost\Ubuntu\home\<user>\MuMain\ClientLibrary\...csproj` |
| `/home/<user>/MuMain/build-mingw/dotnet_out` | `\\wsl.localhost\Ubuntu\home\<user>\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).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The addition of docs/build-guide.md is an excellent improvement. This comprehensive guide provides much-needed clarity on the complex cross-platform build setup, covering various scenarios, performance considerations, and directory layouts. It will significantly reduce friction for new and existing developers working with different environments.

Comment on lines +276 to +289
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()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic to find dotnet.exe first and then fallback to dotnet is well-implemented, prioritizing the Windows binary for WSL interop. The warning message for cross-OS Native AOT limitations is also very helpful, guiding users on how to resolve potential build issues.

set(DOTNET_NUGET_DIR "${CMAKE_SOURCE_DIR}/.nuget")

# NuGet cache: defaults to <project>/.nuget, override with -DMU_NUGET_CACHE_DIR=...
set(MU_NUGET_CACHE_DIR "${CMAKE_SOURCE_DIR}/.nuget" CACHE PATH "NuGet package cache directory")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Introducing MU_NUGET_CACHE_DIR as a CMake cache variable with a sensible default and the ability to override it is a great enhancement. This addresses potential issues with special characters in user profile paths and improves build reliability, as noted in the build-guide.md.

Comment on lines +384 to +385
mu_native_path("${CONSTANTS_REPLACER_PROJ}" CONSTANTS_REPLACER_PROJ_NATIVE)
mu_native_path("${CMAKE_BINARY_DIR}/ConstantsReplacer" CONSTANTS_REPLACER_OUTDIR_NATIVE)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the Client Library, applying mu_native_path to the ConstantsReplacer project path and output directory ensures its build process also benefits from correct path translation in WSL environments.

Comment on lines +398 to 401
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()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Adding an else block to explicitly warn when the .NET SDK is not found is a good usability improvement. It provides clear feedback to the user about why the .NET components might not be building and the implications for the game's functionality.

@sven-n sven-n merged commit 64ac23b into sven-n:main Feb 7, 2026
1 check passed
@Mosch0512 Mosch0512 deleted the dotnet-build branch February 9, 2026 12:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants