summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2026-02-07 11:02:38 +0800
committerGitHub <[email protected]>2026-02-07 11:02:38 +0800
commit15d8fed683b17f3bff4abb3d36f79fa291ac577c (patch)
tree044a4a9b8b824cdb7aba3a513b28ae701e69cd16
parent4780a467c144f27a4c2f9923d030750d0f25f5a5 (diff)
parent08f5b8a7bdac97cab8f5055a5ae9b066d2b18664 (diff)
Merge pull request #7302 from xmake-io/missdll
Improve run process errors
-rw-r--r--core/src/xmake/engine.c2
-rw-r--r--core/src/xmake/winos/set_error_mode.c41
-rw-r--r--tests/projects/windows/windows_links/src/foo.c9
-rw-r--r--tests/projects/windows/windows_links/src/main.c21
-rw-r--r--tests/projects/windows/windows_links/xmake.lua20
-rw-r--r--xmake/actions/run/main.lua12
-rw-r--r--xmake/core/base/os.lua5
-rw-r--r--xmake/core/base/process.lua52
-rw-r--r--xmake/core/project/policy.lua2
-rw-r--r--xmake/core/sandbox/modules/os.lua8
-rw-r--r--xmake/core/sandbox/modules/winos.lua1
11 files changed, 168 insertions, 5 deletions
diff --git a/core/src/xmake/engine.c b/core/src/xmake/engine.c
index 9c02d8487..1a542bc7c 100644
--- a/core/src/xmake/engine.c
+++ b/core/src/xmake/engine.c
@@ -279,6 +279,7 @@ tb_int_t xm_winos_registry_keys(lua_State *lua);
tb_int_t xm_winos_registry_values(lua_State *lua);
tb_int_t xm_winos_short_path(lua_State *lua);
tb_int_t xm_winos_processes(lua_State* lua);
+tb_int_t xm_winos_set_error_mode(lua_State *lua);
#endif
// the utf8 functions
@@ -485,6 +486,7 @@ static luaL_Reg const g_winos_functions[] = {
{ "registry_values", xm_winos_registry_values },
{ "short_path", xm_winos_short_path },
{ "processes", xm_winos_processes },
+ { "set_error_mode", xm_winos_set_error_mode },
{ tb_null, tb_null },
};
#endif
diff --git a/core/src/xmake/winos/set_error_mode.c b/core/src/xmake/winos/set_error_mode.c
new file mode 100644
index 000000000..ceff4684b
--- /dev/null
+++ b/core/src/xmake/winos/set_error_mode.c
@@ -0,0 +1,41 @@
+/*!A cross-platform build utility based on Lua
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015-present, Xmake Open Source Community.
+ *
+ * @author ruki
+ * @file set_error_mode.c
+ *
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "set_error_mode"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+
+tb_int_t xm_winos_set_error_mode(lua_State *lua) {
+ tb_size_t mode = (tb_size_t)luaL_checkinteger(lua, 1);
+ lua_pushinteger(lua, (tb_int_t)SetErrorMode((UINT)mode));
+ return 1;
+}
diff --git a/tests/projects/windows/windows_links/src/foo.c b/tests/projects/windows/windows_links/src/foo.c
new file mode 100644
index 000000000..29b5a4334
--- /dev/null
+++ b/tests/projects/windows/windows_links/src/foo.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void foo() {
+ printf("foo called\n");
+}
+
diff --git a/tests/projects/windows/windows_links/src/main.c b/tests/projects/windows/windows_links/src/main.c
new file mode 100644
index 000000000..bc94c3f13
--- /dev/null
+++ b/tests/projects/windows/windows_links/src/main.c
@@ -0,0 +1,21 @@
+#include <windows.h>
+#include <psapi.h>
+#include <stdio.h>
+
+__declspec(dllimport) void foo();
+
+int main() {
+ PROCESS_MEMORY_COUNTERS pmc;
+ printf("Calling GetProcessMemoryInfo...\n");
+ if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
+ printf("PageFaultCount: %lu\n", pmc.PageFaultCount);
+ printf("WorkingSetSize: %lu\n", pmc.WorkingSetSize);
+ } else {
+ printf("GetProcessMemoryInfo failed (%lu)\n", GetLastError());
+ }
+ printf("Calling foo...\n");
+ foo();
+ printf("Done.\n");
+ return 0;
+}
+
diff --git a/tests/projects/windows/windows_links/xmake.lua b/tests/projects/windows/windows_links/xmake.lua
new file mode 100644
index 000000000..57ae03712
--- /dev/null
+++ b/tests/projects/windows/windows_links/xmake.lua
@@ -0,0 +1,20 @@
+add_rules("mode.debug", "mode.release")
+
+set_policy("run.windows_error_dialog", true)
+
+target("foo")
+ set_kind("shared")
+ add_files("src/foo.c")
+
+target("test_foo_dll_presence")
+ set_kind("binary")
+ add_files("src/main.c")
+ add_deps("foo")
+ add_syslinks("psapi")
+ after_build(function (target)
+ local foo = target:dep("foo")
+ if foo then
+ os.tryrm(foo:targetfile())
+ end
+ end)
+
diff --git a/xmake/actions/run/main.lua b/xmake/actions/run/main.lua
index 39cbd4d6a..6ed59f3f1 100644
--- a/xmake/actions/run/main.lua
+++ b/xmake/actions/run/main.lua
@@ -88,12 +88,24 @@ function _do_run_target(target)
targetfile = wine.program
end
+ -- enable GUI error dialogs (Windows only)
+ -- @see https://github.com/xmake-io/xmake/issues/7176
+ local old_errormode
+ if target:policy("run.windows_error_dialog") and winos.set_error_mode then
+ old_errormode = winos.set_error_mode(0)
+ end
+
-- debugging?
if option.get("debug") then
debugger.run(targetfile, args, {curdir = rundir, addenvs = addenvs, setenvs = setenvs})
else
os.execv(targetfile, args, {curdir = rundir, detach = option.get("detach"), addenvs = addenvs, setenvs = setenvs})
end
+
+ -- restore error mode
+ if old_errormode then
+ winos.set_error_mode(old_errormode)
+ end
end
-- run target
diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua
index ae730738e..d20cd671a 100644
--- a/xmake/core/base/os.lua
+++ b/xmake/core/base/os.lua
@@ -1020,6 +1020,9 @@ function os.execv(program, argv, opt)
local waitok, status = proc:wait(opt.timeout or -1)
if waitok > 0 then
ok = status
+ if ok and ok ~= 0 then
+ errors = process.get_exit_errors(filename, ok)
+ end
elseif waitok == 0 and opt.timeout then
proc:kill()
waitok, status = proc:wait(-1)
@@ -1093,7 +1096,7 @@ function os.iorunv(program, argv, opt)
if argv then
cmd = cmd .. " " .. os.args(argv)
end
- errors = string.format("cannot runv(%s), %s", cmd, errors and errors or "unknown reason")
+ errors = string.format("cannot runv(%s), %s", cmd, errors or "unknown reason")
end
-- get output and error data
diff --git a/xmake/core/base/process.lua b/xmake/core/base/process.lua
index 5436115ed..692a6360f 100644
--- a/xmake/core/base/process.lua
+++ b/xmake/core/base/process.lua
@@ -271,5 +271,57 @@ function process.openv(program, argv, opt)
end
end
+-- get missing dlls
+function process._get_missing_dlls(program)
+ local missing = {}
+ if not os.isexec(program) then
+ return missing
+ end
+
+ -- get paths
+ local pathenv = os.getenv("PATH") or ""
+ local paths = path.splitenv(pathenv)
+ table.insert(paths, 1, path.directory(program))
+
+ -- find missing dlls
+ local sandbox_module = require("sandbox/modules/import/core/sandbox/module")
+ local get_depend_libraries = sandbox_module.import("utils.binary.deplibs", {anonymous = true})
+ local imports = get_depend_libraries(program, {recursive = true}) or {}
+ for i, dll in ipairs(imports) do
+ imports[i] = path.filename(dll)
+ end
+ for _, dll in ipairs(imports) do
+ local found = false
+ for _, p in ipairs(paths) do
+ if os.isfile(path.join(p, dll)) then
+ found = true
+ break
+ end
+ end
+ if not found then
+ table.insert(missing, dll)
+ end
+ end
+ return missing
+end
+
+-- get process exit errors
+function process.get_exit_errors(program, exitcode)
+ local errors
+ if os.is_host("windows") then
+ -- DLL is missing, 0xC0000135
+ if exitcode == -1073741515 then
+ local missing_dlls = process._get_missing_dlls(program)
+ if #missing_dlls > 0 then
+ errors = string.format("system error 0xC0000135 (STATUS_DLL_NOT_FOUND).\nThe application failed to start because the following DLLs were not found:\n - %s\nPlease check your PATH environment variable or copy the missing DLLs to the executable directory.", table.concat(missing_dlls, "\n - "))
+ else
+ errors = string.format("system error 0xC0000135 (STATUS_DLL_NOT_FOUND).\nThe application failed to start because a dependent DLL was not found.\nPlease check your PATH environment variable or copy the missing DLL to the executable directory.")
+ end
+ end
+ end
+ return errors
+end
+
+
-- return module: process
return process
diff --git a/xmake/core/project/policy.lua b/xmake/core/project/policy.lua
index 5123f0a5c..0fdd70831 100644
--- a/xmake/core/project/policy.lua
+++ b/xmake/core/project/policy.lua
@@ -127,6 +127,8 @@ function policy.policies()
["windows.manifest.uac.ui"] = {description = "Enable ui access for windows UAC.", type = "boolean"},
-- Automatically build before running
["run.autobuild"] = {description = "Automatically build before running.", type = "boolean"},
+ -- Enable/Disable Windows Error Reporting Dialogs
+ ["run.windows_error_dialog"] = {description = "Enable Windows Error Reporting Dialogs during execution.", default = false, type = "boolean"},
-- Enable install rpath
["install.rpath"] = {description = "Enable install rpath.", default = true, type = "boolean"},
-- Strip package libraries for installation
diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua
index aebb3cfb0..8fe76987e 100644
--- a/xmake/core/sandbox/modules/os.lua
+++ b/xmake/core/sandbox/modules/os.lua
@@ -330,9 +330,9 @@ function sandbox_os.exec(cmd, ...)
local ok, errors = os.exec(cmd)
if ok ~= 0 then
if ok ~= nil then
- errors = string.format("exec(%s) failed(%d)", cmd, ok)
+ errors = string.format("exec(%s) failed(%d), %s", cmd, ok, errors or "unknown reason")
else
- errors = string.format("cannot exec(%s), %s", cmd, errors and errors or "unknown reason")
+ errors = string.format("cannot exec(%s), %s", cmd, errors or "unknown reason")
end
os.raise(errors)
end
@@ -371,9 +371,9 @@ function sandbox_os.execv(program, argv, opt)
-- get errors
if ok ~= nil then
- errors = string.format("execv(%s) failed(%d)", cmd, ok)
+ errors = string.format("execv(%s) failed(%d), %s", cmd, ok, errors or "unknown reason")
else
- errors = string.format("cannot execv(%s), %s", cmd, errors and errors or "unknown reason")
+ errors = string.format("cannot execv(%s), %s", cmd, errors or "unknown reason")
end
os.raise(errors)
end
diff --git a/xmake/core/sandbox/modules/winos.lua b/xmake/core/sandbox/modules/winos.lua
index eddcf91d4..2ed01245d 100644
--- a/xmake/core/sandbox/modules/winos.lua
+++ b/xmake/core/sandbox/modules/winos.lua
@@ -35,6 +35,7 @@ sandbox_winos.logical_drives = winos.logical_drives
sandbox_winos.cmdargv = winos.cmdargv
sandbox_winos.processes = winos.processes
sandbox_winos.inherit_handles_safely = winos.inherit_handles_safely
+sandbox_winos.set_error_mode = winos.set_error_mode
-- get windows system version
function sandbox_winos.version()