From 1847f5df322b396c918aab6b6bdf00ad2b509786 Mon Sep 17 00:00:00 2001 From: Rix Date: Wed, 30 Sep 2026 13:22:59 -0700 Subject: [PATCH] Handle project paths with spaces when running make Fixes native and Lua compiler builds on Windows/macOS/Linux when the project lives under a path containing spaces, which GNU make and the psyqo makefiles cannot resolve correctly. On Windows the build now falls back to the 8.3 short path; elsewhere (and when 8.3 names are unavailable) the build aborts with a clear error before invoking make. --- Editor/Core/ShortPath.cs | 87 +++++++++++++++++++++++++++++++ Editor/Core/ShortPath.cs.meta | 2 + Editor/Core/SplashControlPanel.cs | 20 +++++-- 3 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 Editor/Core/ShortPath.cs create mode 100644 Editor/Core/ShortPath.cs.meta diff --git a/Editor/Core/ShortPath.cs b/Editor/Core/ShortPath.cs new file mode 100644 index 0000000..ef49b56 --- /dev/null +++ b/Editor/Core/ShortPath.cs @@ -0,0 +1,87 @@ +using System.Runtime.InteropServices; +using System.Text; +using UnityEngine; + +namespace SplashEdit.EditorCode +{ + /// + /// Resolves filesystem paths for safe use as a make working directory. + /// GNU make and the psyqo makefiles derive their own root via + /// $(abspath $(lastword $(MAKEFILE_LIST))) resolved against make's CWD, and neither + /// handles a space in that path correctly. On Windows we can usually dodge the + /// problem with the legacy 8.3 short path; everywhere else a space is fatal. + /// + public static class ShortPath + { + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern uint GetShortPathNameW(string lpszLongPath, StringBuilder lpszShortPath, uint cchBuffer); + + /// + /// Resolves into a path make can safely use as its working + /// directory. On Windows, a path containing spaces is converted to its 8.3 short + /// path. Returns false with a descriptive if the path + /// contains a space and cannot be made safe (non-Windows, or 8.3 names disabled). + /// + public static bool TryResolveForMake(string dir, out string resolvedDir, out string error) + { + if (Application.platform != RuntimePlatform.WindowsEditor) + { + if (dir.IndexOf(' ') >= 0) + { + resolvedDir = null; + error = SpacesInPathError(dir); + return false; + } + + resolvedDir = dir; + error = null; + return true; + } + + if (dir.IndexOf(' ') < 0) + { + resolvedDir = dir; + error = null; + return true; + } + + string shortPath = GetShortPath(dir); + if (string.IsNullOrEmpty(shortPath) || shortPath.IndexOf(' ') >= 0) + { + resolvedDir = null; + error = SpacesInPathError(dir) + + " On Windows this can usually be fixed by enabling 8.3 short names on the " + + "drive (run `fsutil 8dot3name set : 0` as Administrator - this only " + + "affects files created afterwards, so the project may need to be recreated " + + "at its current path once enabled)."; + return false; + } + + resolvedDir = shortPath; + error = null; + return true; + } + + private static string SpacesInPathError(string dir) => + $"The project path contains spaces (\"{dir}\"), which GNU make and the psyqo " + + "makefiles cannot handle. Move the project to a path without spaces."; + + private static string GetShortPath(string longPath) + { + var buffer = new StringBuilder(260); + uint length = GetShortPathNameW(longPath, buffer, (uint)buffer.Capacity); + if (length == 0) + return null; + + if (length > buffer.Capacity) + { + buffer = new StringBuilder((int)length); + length = GetShortPathNameW(longPath, buffer, (uint)buffer.Capacity); + if (length == 0) + return null; + } + + return buffer.ToString(); + } + } +} diff --git a/Editor/Core/ShortPath.cs.meta b/Editor/Core/ShortPath.cs.meta new file mode 100644 index 0000000..24fac87 --- /dev/null +++ b/Editor/Core/ShortPath.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 65e1672c263d4fdb8217a7a77b994e27 \ No newline at end of file diff --git a/Editor/Core/SplashControlPanel.cs b/Editor/Core/SplashControlPanel.cs index ca736c4..2825e8f 100644 --- a/Editor/Core/SplashControlPanel.cs +++ b/Editor/Core/SplashControlPanel.cs @@ -1907,14 +1907,20 @@ private async Task> CompileLuaAsync(Dictionary private async Task BuildLuacPsxAsync(string luacDir) { + if (!ShortPath.TryResolveForMake(luacDir, out string luacWorkDir, out string pathError)) + { + Log(pathError, LogType.Error); + return false; + } + int jobCount = Math.Max(1, SystemInfo.processorCount - 1); string makeCmd = $"make -j{jobCount}"; var psi = new ProcessStartInfo { FileName = Application.platform == RuntimePlatform.WindowsEditor ? "cmd.exe" : "/bin/bash", - Arguments = WrapCommandForMacOS(luacDir, makeCmd), - WorkingDirectory = luacDir, + Arguments = WrapCommandForMacOS(luacWorkDir, makeCmd), + WorkingDirectory = luacWorkDir, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, @@ -1993,6 +1999,12 @@ private async Task CompileNativeAsync() return false; } + if (!ShortPath.TryResolveForMake(nativeDir, out string nativeWorkDir, out string pathError)) + { + Log(pathError, LogType.Error); + return false; + } + string buildArg = SplashSettings.Mode == BuildMode.Debug ? "BUILD=Debug" : ""; if (SplashSettings.Target == BuildTarget.ISO) @@ -2029,8 +2041,8 @@ private async Task CompileNativeAsync() var psi = new ProcessStartInfo { FileName = Application.platform == RuntimePlatform.WindowsEditor ? "cmd.exe" : "/bin/bash", - Arguments = WrapCommandForMacOS(nativeDir, makeCmd), - WorkingDirectory = nativeDir, + Arguments = WrapCommandForMacOS(nativeWorkDir, makeCmd), + WorkingDirectory = nativeWorkDir, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false,