From 377a3e21381b4db9f05c81478189337e7713a18e Mon Sep 17 00:00:00 2001 From: Saikari Date: Thu, 5 Feb 2026 21:11:29 +0300 Subject: add initial implementation of foo and main for Windows DLL example --- projects/test_windows_links/src/foo.c | 8 + projects/test_windows_links/src/main.c | 24 + projects/test_windows_links/xmake.lua | 17 + xmake/core/sandbox/modules/os.lua | 1155 ++++++++++++++++++-------------- 4 files changed, 698 insertions(+), 506 deletions(-) create mode 100644 projects/test_windows_links/src/foo.c create mode 100644 projects/test_windows_links/src/main.c create mode 100644 projects/test_windows_links/xmake.lua diff --git a/projects/test_windows_links/src/foo.c b/projects/test_windows_links/src/foo.c new file mode 100644 index 000000000..b399bc175 --- /dev/null +++ b/projects/test_windows_links/src/foo.c @@ -0,0 +1,8 @@ +#include + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void foo() { + printf("foo called\n"); +} diff --git a/projects/test_windows_links/src/main.c b/projects/test_windows_links/src/main.c new file mode 100644 index 000000000..8f9578202 --- /dev/null +++ b/projects/test_windows_links/src/main.c @@ -0,0 +1,24 @@ +#include +#include +#include + +#ifdef _WIN32 +__declspec(dllimport) void foo(); +#else +void foo(); +#endif + +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/projects/test_windows_links/xmake.lua b/projects/test_windows_links/xmake.lua new file mode 100644 index 000000000..5d8c0d984 --- /dev/null +++ b/projects/test_windows_links/xmake.lua @@ -0,0 +1,17 @@ +add_rules("mode.debug", "mode.release") + +target("foo") + set_kind("shared") + add_files("src/foo.c") + +target("test_mingw_dll") + 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/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua index aebb3cfb0..58b1ed836 100644 --- a/xmake/core/sandbox/modules/os.lua +++ b/xmake/core/sandbox/modules/os.lua @@ -1,506 +1,649 @@ ---!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 os.lua --- - --- load modules -local io = require("base/io") -local os = require("base/os") -local utils = require("base/utils") -local xmake = require("base/xmake") -local option = require("base/option") -local semver = require("base/semver") -local scheduler = require("base/scheduler") -local sandbox = require("sandbox/sandbox") -local vformat = require("sandbox/modules/vformat") - --- define module -local sandbox_os = sandbox_os or {} - --- inherit some builtin interfaces -sandbox_os.shell = os.shell -sandbox_os.term = os.term -sandbox_os.host = os.host -sandbox_os.arch = os.arch -sandbox_os.subhost = os.subhost -sandbox_os.subarch = os.subarch -sandbox_os.is_host = os.is_host -sandbox_os.is_arch = os.is_arch -sandbox_os.is_subhost = os.is_subhost -sandbox_os.is_subarch = os.is_subarch -sandbox_os.syserror = os.syserror -sandbox_os.strerror = os.strerror -sandbox_os.exit = os.exit -sandbox_os.atexit = os.atexit -sandbox_os.date = os.date -sandbox_os.time = os.time -sandbox_os.args = os.args -sandbox_os.args = os.args -sandbox_os.argv = os.argv -sandbox_os.mtime = os.mtime -sandbox_os.raise = os.raise -sandbox_os.fscase = os.fscase -sandbox_os.isroot = os.isroot -sandbox_os.mclock = os.mclock -sandbox_os.nuldev = os.nuldev -sandbox_os.getenv = os.getenv -sandbox_os.setenv = os.setenv -sandbox_os.addenv = os.addenv -sandbox_os.setenvp = os.setenvp -sandbox_os.addenvp = os.addenvp -sandbox_os.getenvs = os.getenvs -sandbox_os.setenvs = os.setenvs -sandbox_os.addenvs = os.addenvs -sandbox_os.joinenvs = os.joinenvs -sandbox_os.pbpaste = os.pbpaste -sandbox_os.pbcopy = os.pbcopy -sandbox_os.cpuinfo = os.cpuinfo -sandbox_os.meminfo = os.meminfo -sandbox_os.default_njob = os.default_njob -sandbox_os.emptydir = os.emptydir -sandbox_os.filesize = os.filesize -sandbox_os.features = os.features -sandbox_os.workingdir = os.workingdir -sandbox_os.programdir = os.programdir -sandbox_os.programfile = os.programfile -sandbox_os.projectdir = os.projectdir -sandbox_os.projectfile = os.projectfile -sandbox_os.getwinsize = os.getwinsize -sandbox_os.getpid = os.getpid - --- syserror code -sandbox_os.SYSERR_UNKNOWN = os.SYSERR_UNKNOWN -sandbox_os.SYSERR_NONE = os.SYSERR_NONE -sandbox_os.SYSERR_NOT_PERM = os.SYSERR_NOT_PERM -sandbox_os.SYSERR_NOT_FILEDIR = os.SYSERR_NOT_FILEDIR -sandbox_os.SYSERR_NOT_ACCESS = os.SYSERR_NOT_ACCESS - --- copy file or directory -function sandbox_os.cp(srcpath, dstpath, opt) - assert(srcpath and dstpath) - srcpath = tostring(srcpath) - dstpath = tostring(dstpath) - local ok, errors = os.cp(vformat(srcpath), vformat(dstpath), opt) - if not ok then - os.raise(errors) - end -end - --- move file or directory -function sandbox_os.mv(srcpath, dstpath, opt) - assert(srcpath and dstpath) - srcpath = tostring(srcpath) - dstpath = tostring(dstpath) - local ok, errors = os.mv(vformat(srcpath), vformat(dstpath), opt) - if not ok then - os.raise(errors) - end -end - --- remove files or directories -function sandbox_os.rm(filepath, opt) - assert(filepath) - filepath = tostring(filepath) - local ok, errors = os.rm(vformat(filepath), opt) - if not ok then - os.raise(errors) - end -end - --- link file or directory to the new symfile -function sandbox_os.ln(srcpath, dstpath, opt) - assert(srcpath and dstpath) - srcpath = tostring(srcpath) - dstpath = tostring(dstpath) - local ok, errors = os.ln(vformat(srcpath), vformat(dstpath), opt) - if not ok then - os.raise(errors) - end -end - --- copy file or directory with the verbose info -function sandbox_os.vcp(srcpath, dstpath, opt) - assert(srcpath and dstpath) - if option.get("verbose") then - utils.cprint("${dim}> copy %s to %s", srcpath, dstpath) - end - return sandbox_os.cp(srcpath, dstpath, opt) -end - --- move file or directory with the verbose info -function sandbox_os.vmv(srcpath, dstpath, opt) - assert(srcpath and dstpath) - if option.get("verbose") then - utils.cprint("${dim}> move %s to %s", srcpath, dstpath) - end - return sandbox_os.mv(srcpath, dstpath, opt) -end - --- remove file or directory with the verbose info -function sandbox_os.vrm(filepath, opt) - assert(filepath) - if option.get("verbose") then - utils.cprint("${dim}> remove %s", filepath) - end - return sandbox_os.rm(filepath, opt) -end - --- link file or directory with the verbose info -function sandbox_os.vln(srcpath, dstpath, opt) - assert(srcpath and dstpath) - if option.get("verbose") then - utils.cprint("${dim}> link %s to %s", srcpath, dstpath) - end - return sandbox_os.ln(srcpath, dstpath, opt) -end - --- try to copy file or directory -function sandbox_os.trycp(srcpath, dstpath, opt) - assert(srcpath and dstpath) - return os.cp(vformat(srcpath), vformat(dstpath), opt) -end - --- try to move file or directory -function sandbox_os.trymv(srcpath, dstpath, opt) - assert(srcpath and dstpath) - return os.mv(vformat(srcpath), vformat(dstpath), opt) -end - --- try to remove files or directories -function sandbox_os.tryrm(filepath, opt) - assert(filepath) - return os.rm(vformat(filepath), opt) -end - --- change to directory -function sandbox_os.cd(dir) - - -- check - assert(dir) - - -- format it first - dir = vformat(dir) - - -- enter this directory - local oldir, errors = os.cd(dir) - if not oldir then - os.raise(errors) - end - - -- ok - return oldir -end - --- touch file or directory -function sandbox_os.touch(filepath, opt) - assert(filepath) - local ok, errors = os.touch(vformat(filepath), opt) - if not ok then - os.raise(errors) - end -end - --- create directories -function sandbox_os.mkdir(dir) - assert(dir) - local ok, errors = os.mkdir(vformat(dir)) - if not ok then - os.raise(errors) - end -end - --- remove directories -function sandbox_os.rmdir(dir, opt) - assert(dir) - local ok, errors = os.rmdir(vformat(dir), opt) - if not ok then - os.raise(errors) - end -end - --- get the current directory -function sandbox_os.curdir() - return assert(os.curdir()) -end - --- get the temporary directory -function sandbox_os.tmpdir(opt) - return assert(os.tmpdir(opt)) -end - --- get the temporary file -function sandbox_os.tmpfile(key, opt) - return assert(os.tmpfile(key, opt)) -end - --- get the script directory -function sandbox_os.scriptdir() - local instance = sandbox.instance() - local rootdir = instance:rootdir() - assert(rootdir) - return rootdir -end - --- quietly run command -function sandbox_os.run(cmd, ...) - cmd = vformat(cmd, ...) - local ok, errors = os.run(cmd) - if not ok then - os.raise(errors) - end -end - --- quietly run command with arguments list -function sandbox_os.runv(program, argv, opt) - program = vformat(program) - local ok, errors = os.runv(program, argv, opt) - if not ok then - os.raise(errors) - end -end - --- quietly run command and echo verbose info if [-v|--verbose] option is enabled -function sandbox_os.vrun(cmd, ...) - if option.get("verbose") then - print(vformat(cmd, ...)) - end - (option.get("verbose") and sandbox_os.exec or sandbox_os.run)(cmd, ...) -end - --- quietly run command with arguments list and echo verbose info if [-v|--verbose] option is enabled -function sandbox_os.vrunv(program, argv, opt) - if option.get("verbose") then - print(vformat(program) .. " " .. sandbox_os.args(argv or {})) - end - if not (opt and opt.dryrun) then - (option.get("verbose") and sandbox_os.execv or sandbox_os.runv)(program, argv, opt) - end -end - --- run command and return output and error data -function sandbox_os.iorun(cmd, ...) - cmd = vformat(cmd, ...) - local ok, outdata, errdata, errors = os.iorun(cmd) - if not ok then - if not errors then - errors = errdata or "" - if #errors:trim() == 0 then - errors = outdata or "" - end - end - os.raise({errors = errors, stderr = errdata, stdout = outdata}) - end - return outdata, errdata -end - --- run command and return output and error data -function sandbox_os.iorunv(program, argv, opt) - program = vformat(program) - local ok, outdata, errdata, errors = os.iorunv(program, argv, opt) - if not ok then - if not errors then - errors = errdata or "" - if #errors:trim() == 0 then - errors = outdata or "" - end - end - os.raise({errors = errors, stderr = errdata, stdout = outdata}) - end - return outdata, errdata -end - --- execute command -function sandbox_os.exec(cmd, ...) - cmd = vformat(cmd, ...) - local ok, errors = os.exec(cmd) - if ok ~= 0 then - if ok ~= nil then - errors = string.format("exec(%s) failed(%d)", cmd, ok) - else - errors = string.format("cannot exec(%s), %s", cmd, errors and errors or "unknown reason") - end - os.raise(errors) - end -end - --- execute command with arguments list -function sandbox_os.execv(program, argv, opt) - - -- make program - program = vformat(program) - - -- flush io buffer first for fixing redirect io output order - -- - -- e.g. - -- - -- xmake run > /tmp/a - -- print("xxx1") - -- os.exec("echo xxx2") - -- - -- cat /tmp/a - -- xxx2 - -- xxx1 - -- - io.flush() - - -- run it - opt = opt or {} - local ok, errors = os.execv(program, argv, opt) - if ok ~= 0 and not opt.try then - - -- get command - local cmd = program - if argv then - cmd = cmd .. " " .. os.args(argv) - end - - -- get errors - if ok ~= nil then - errors = string.format("execv(%s) failed(%d)", cmd, ok) - else - errors = string.format("cannot execv(%s), %s", cmd, errors and errors or "unknown reason") - end - os.raise(errors) - end - - -- we need return results if opt.try is enabled - return ok, errors -end - --- execute command and echo verbose info if [-v|--verbose] option is enabled -function sandbox_os.vexec(cmd, ...) - - -- echo command - if option.get("verbose") then - utils.cprint("${color.dump.string}" .. vformat(cmd, ...)) - end - - -- run it - sandbox_os.exec(cmd, ...) -end - --- execute command with arguments list and echo verbose info if [-v|--verbose] option is enabled -function sandbox_os.vexecv(program, argv, opt) - - -- echo command - if option.get("verbose") then - utils.cprint("${color.dump.string}" .. vformat(program) .. " " .. sandbox_os.args(argv)) - end - - -- run it - if not (opt and opt.dryrun) then - return sandbox_os.execv(program, argv, opt) - else - return 0 - end -end - --- match files or directories -function sandbox_os.match(pattern, mode, opt) - return os.match(vformat(tostring(pattern)), mode, opt) -end - --- match directories -function sandbox_os.dirs(pattern, opt) - return os.dirs(vformat(tostring(pattern)), opt) -end - --- match files -function sandbox_os.files(pattern, opt) - return os.files(vformat(tostring(pattern)), opt) -end - --- match files and directories -function sandbox_os.filedirs(pattern, opt) - return os.filedirs(vformat(tostring(pattern)), opt) -end - --- is directory? -function sandbox_os.isdir(dirpath) - assert(dirpath) - dirpath = tostring(dirpath) - return os.isdir(vformat(dirpath)) -end - --- is file? -function sandbox_os.isfile(filepath) - assert(filepath) - filepath = tostring(filepath) - return os.isfile(vformat(filepath)) -end - --- is symlink? -function sandbox_os.islink(filepath) - assert(filepath) - filepath = tostring(filepath) - return os.islink(vformat(filepath)) -end - --- is execute program? -function sandbox_os.isexec(filepath) - assert(filepath) - filepath = tostring(filepath) - return os.isexec(vformat(filepath)) -end - --- exists file or directory? -function sandbox_os.exists(filedir) - assert(filedir) - filedir = tostring(filedir) - return os.exists(vformat(filedir)) -end - --- read the content of symlink -function sandbox_os.readlink(symlink) - local result = os.readlink(tostring(symlink)) - if not result then - os.raise("cannot read link(%s)", symlink) - end - return result -end - --- sleep (support in coroutine) -function sandbox_os.sleep(ms) - if scheduler:co_running() then - local ok, errors = scheduler:co_sleep(ms) - if not ok then - raise(errors) - end - else - os.sleep(ms) - end -end - --- get xmake version -function sandbox_os.xmakever() - - -- fill cache - if sandbox_os._XMAKEVER == nil then - -- get xmakever - local xmakever = semver.new(xmake._VERSION_SHORT) - -- save to cache - sandbox_os._XMAKEVER = xmakever or false - end - - -- done - return sandbox_os._XMAKEVER or nil -end - --- return module -return sandbox_os - +--!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 os.lua +-- + +-- load modules +local io = require("base/io") +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local xmake = require("base/xmake") +local option = require("base/option") +local semver = require("base/semver") +local scheduler = require("base/scheduler") +local sandbox = require("sandbox/sandbox") +local vformat = require("sandbox/modules/vformat") + +-- define module +local sandbox_os = sandbox_os or {} + +-- inherit some builtin interfaces +sandbox_os.shell = os.shell +sandbox_os.term = os.term +sandbox_os.host = os.host +sandbox_os.arch = os.arch +sandbox_os.subhost = os.subhost +sandbox_os.subarch = os.subarch +sandbox_os.is_host = os.is_host +sandbox_os.is_arch = os.is_arch +sandbox_os.is_subhost = os.is_subhost +sandbox_os.is_subarch = os.is_subarch +sandbox_os.syserror = os.syserror +sandbox_os.strerror = os.strerror +sandbox_os.exit = os.exit +sandbox_os.atexit = os.atexit +sandbox_os.date = os.date +sandbox_os.time = os.time +sandbox_os.args = os.args +sandbox_os.args = os.args +sandbox_os.argv = os.argv +sandbox_os.mtime = os.mtime +sandbox_os.raise = os.raise +sandbox_os.fscase = os.fscase +sandbox_os.isroot = os.isroot +sandbox_os.mclock = os.mclock +sandbox_os.nuldev = os.nuldev +sandbox_os.getenv = os.getenv +sandbox_os.setenv = os.setenv +sandbox_os.addenv = os.addenv +sandbox_os.setenvp = os.setenvp +sandbox_os.addenvp = os.addenvp +sandbox_os.getenvs = os.getenvs +sandbox_os.setenvs = os.setenvs +sandbox_os.addenvs = os.addenvs +sandbox_os.joinenvs = os.joinenvs +sandbox_os.pbpaste = os.pbpaste +sandbox_os.pbcopy = os.pbcopy +sandbox_os.cpuinfo = os.cpuinfo +sandbox_os.meminfo = os.meminfo +sandbox_os.default_njob = os.default_njob +sandbox_os.emptydir = os.emptydir +sandbox_os.filesize = os.filesize +sandbox_os.features = os.features +sandbox_os.workingdir = os.workingdir +sandbox_os.programdir = os.programdir +sandbox_os.programfile = os.programfile +sandbox_os.projectdir = os.projectdir +sandbox_os.projectfile = os.projectfile +sandbox_os.getwinsize = os.getwinsize +sandbox_os.getpid = os.getpid + +-- syserror code +sandbox_os.SYSERR_UNKNOWN = os.SYSERR_UNKNOWN +sandbox_os.SYSERR_NONE = os.SYSERR_NONE +sandbox_os.SYSERR_NOT_PERM = os.SYSERR_NOT_PERM +sandbox_os.SYSERR_NOT_FILEDIR = os.SYSERR_NOT_FILEDIR +sandbox_os.SYSERR_NOT_ACCESS = os.SYSERR_NOT_ACCESS + +-- copy file or directory +function sandbox_os.cp(srcpath, dstpath, opt) + assert(srcpath and dstpath) + srcpath = tostring(srcpath) + dstpath = tostring(dstpath) + local ok, errors = os.cp(vformat(srcpath), vformat(dstpath), opt) + if not ok then + os.raise(errors) + end +end + +-- move file or directory +function sandbox_os.mv(srcpath, dstpath, opt) + assert(srcpath and dstpath) + srcpath = tostring(srcpath) + dstpath = tostring(dstpath) + local ok, errors = os.mv(vformat(srcpath), vformat(dstpath), opt) + if not ok then + os.raise(errors) + end +end + +-- remove files or directories +function sandbox_os.rm(filepath, opt) + assert(filepath) + filepath = tostring(filepath) + local ok, errors = os.rm(vformat(filepath), opt) + if not ok then + os.raise(errors) + end +end + +-- link file or directory to the new symfile +function sandbox_os.ln(srcpath, dstpath, opt) + assert(srcpath and dstpath) + srcpath = tostring(srcpath) + dstpath = tostring(dstpath) + local ok, errors = os.ln(vformat(srcpath), vformat(dstpath), opt) + if not ok then + os.raise(errors) + end +end + +-- copy file or directory with the verbose info +function sandbox_os.vcp(srcpath, dstpath, opt) + assert(srcpath and dstpath) + if option.get("verbose") then + utils.cprint("${dim}> copy %s to %s", srcpath, dstpath) + end + return sandbox_os.cp(srcpath, dstpath, opt) +end + +-- move file or directory with the verbose info +function sandbox_os.vmv(srcpath, dstpath, opt) + assert(srcpath and dstpath) + if option.get("verbose") then + utils.cprint("${dim}> move %s to %s", srcpath, dstpath) + end + return sandbox_os.mv(srcpath, dstpath, opt) +end + +-- remove file or directory with the verbose info +function sandbox_os.vrm(filepath, opt) + assert(filepath) + if option.get("verbose") then + utils.cprint("${dim}> remove %s", filepath) + end + return sandbox_os.rm(filepath, opt) +end + +-- link file or directory with the verbose info +function sandbox_os.vln(srcpath, dstpath, opt) + assert(srcpath and dstpath) + if option.get("verbose") then + utils.cprint("${dim}> link %s to %s", srcpath, dstpath) + end + return sandbox_os.ln(srcpath, dstpath, opt) +end + +-- try to copy file or directory +function sandbox_os.trycp(srcpath, dstpath, opt) + assert(srcpath and dstpath) + return os.cp(vformat(srcpath), vformat(dstpath), opt) +end + +-- try to move file or directory +function sandbox_os.trymv(srcpath, dstpath, opt) + assert(srcpath and dstpath) + return os.mv(vformat(srcpath), vformat(dstpath), opt) +end + +-- try to remove files or directories +function sandbox_os.tryrm(filepath, opt) + assert(filepath) + return os.rm(vformat(filepath), opt) +end + +-- change to directory +function sandbox_os.cd(dir) + + -- check + assert(dir) + + -- format it first + dir = vformat(dir) + + -- enter this directory + local oldir, errors = os.cd(dir) + if not oldir then + os.raise(errors) + end + + -- ok + return oldir +end + +-- touch file or directory +function sandbox_os.touch(filepath, opt) + assert(filepath) + local ok, errors = os.touch(vformat(filepath), opt) + if not ok then + os.raise(errors) + end +end + +-- create directories +function sandbox_os.mkdir(dir) + assert(dir) + local ok, errors = os.mkdir(vformat(dir)) + if not ok then + os.raise(errors) + end +end + +-- remove directories +function sandbox_os.rmdir(dir, opt) + assert(dir) + local ok, errors = os.rmdir(vformat(dir), opt) + if not ok then + os.raise(errors) + end +end + +-- get the current directory +function sandbox_os.curdir() + return assert(os.curdir()) +end + +-- get the temporary directory +function sandbox_os.tmpdir(opt) + return assert(os.tmpdir(opt)) +end + +-- get the temporary file +function sandbox_os.tmpfile(key, opt) + return assert(os.tmpfile(key, opt)) +end + +-- get the script directory +function sandbox_os.scriptdir() + local instance = sandbox.instance() + local rootdir = instance:rootdir() + assert(rootdir) + return rootdir +end + +-- quietly run command +function sandbox_os.run(cmd, ...) + cmd = vformat(cmd, ...) + local ok, errors = os.run(cmd) + if not ok then + os.raise(errors) + end +end + +-- quietly run command with arguments list +function sandbox_os.runv(program, argv, opt) + program = vformat(program) + local ok, errors = os.runv(program, argv, opt) + if not ok then + os.raise(errors) + end +end + +-- quietly run command and echo verbose info if [-v|--verbose] option is enabled +function sandbox_os.vrun(cmd, ...) + if option.get("verbose") then + print(vformat(cmd, ...)) + end + (option.get("verbose") and sandbox_os.exec or sandbox_os.run)(cmd, ...) +end + +-- quietly run command with arguments list and echo verbose info if [-v|--verbose] option is enabled +function sandbox_os.vrunv(program, argv, opt) + if option.get("verbose") then + print(vformat(program) .. " " .. sandbox_os.args(argv or {})) + end + if not (opt and opt.dryrun) then + (option.get("verbose") and sandbox_os.execv or sandbox_os.runv)(program, argv, opt) + end +end + +-- run command and return output and error data +function sandbox_os.iorun(cmd, ...) + cmd = vformat(cmd, ...) + local ok, outdata, errdata, errors = os.iorun(cmd) + if not ok then + if not errors then + errors = errdata or "" + if #errors:trim() == 0 then + errors = outdata or "" + end + end + os.raise({errors = errors, stderr = errdata, stdout = outdata}) + end + return outdata, errdata +end + +-- run command and return output and error data +function sandbox_os.iorunv(program, argv, opt) + program = vformat(program) + local ok, outdata, errdata, errors = os.iorunv(program, argv, opt) + if not ok then + if not errors then + errors = errdata or "" + if #errors:trim() == 0 then + errors = outdata or "" + end + end + os.raise({errors = errors, stderr = errdata, stdout = outdata}) + end + return outdata, errdata +end + +-- execute command +function sandbox_os.exec(cmd, ...) + cmd = vformat(cmd, ...) + local ok, errors = os.exec(cmd) + if ok ~= 0 then + if ok ~= nil then + errors = string.format("exec(%s) failed(%d)", cmd, ok) + else + errors = string.format("cannot exec(%s), %s", cmd, errors and errors or "unknown reason") + end + os.raise(errors) + end +end + +-- execute command with arguments list +-- get missing dlls +local function _get_missing_dlls(program) + local missing = {} + local program_dir = path.directory(program) + local pathenv = os.getenv("PATH") or "" + local paths = path.splitenv(pathenv) + table.insert(paths, 1, program_dir) + + local function _find_dll(name) + for _, p in ipairs(paths) do + if os.isfile(path.join(p, name)) then + return true + end + end + return false + end + + local imports = {} + local file = io.open(program, "rb") + if file then + local function read_uint16() + local str = file:read(2) + if not str then return 0 end + local b1, b2 = string.byte(str, 1, 2) + return b1 + b2 * 256 + end + local function read_uint32() + local str = file:read(4) + if not str then return 0 end + local b1, b2, b3, b4 = string.byte(str, 1, 4) + return b1 + b2 * 256 + b3 * 65536 + b4 * 16777216 + end + + local mz = file:read(2) + if mz == "MZ" then + file:seek("set", 0x3C) + local e_lfanew = read_uint32() + file:seek("set", e_lfanew) + if file:read(4) == "PE\0\0" then + -- file header + file:seek("cur", 2) -- Machine (2) + local number_of_sections = read_uint16() + file:seek("cur", 12) -- TimeDateStamp(4) + PointerToSymbolTable(4) + NumberOfSymbols(4) + local size_of_optional_header = read_uint16() + file:seek("cur", 2) -- Characteristics (2) + + -- optional header + local magic = read_uint16() + local is_pe64 = (magic == 0x20b) + + -- skip standard fields and some windows fields to reach DataDirectories + -- Standard(24/22) + Windows(68/88) + -- PE32: 24 + 68 = 92 bytes from magic to DataDirectories + -- PE32+: 24 + 88 = 112 bytes from magic to DataDirectories + -- Minus magic(2) that we just read + local skip = (is_pe64 and (24 + 88 - 2) or (24 + 68 - 2)) + file:seek("cur", skip) + + -- Data Directories + -- Export Table (8) + file:seek("cur", 8) + + -- Import Table + local import_rva = read_uint32() + local import_size = read_uint32() + + if import_rva > 0 then + -- Section Headers + file:seek("set", e_lfanew + 4 + 20 + size_of_optional_header) + local sections = {} + for i = 1, number_of_sections do + local s = {} + file:seek("cur", 8) -- name + s.vsize = read_uint32() + s.vaddr = read_uint32() + s.rawsize = read_uint32() + s.rawaddr = read_uint32() + file:seek("cur", 16) + table.insert(sections, s) + end + + local function rva_to_offset(rva) + for _, s in ipairs(sections) do + if rva >= s.vaddr and rva < s.vaddr + s.vsize then + return s.rawaddr + (rva - s.vaddr) + end + end + return nil + end + + local import_offset = rva_to_offset(import_rva) + if import_offset then + file:seek("set", import_offset) + while true do + local original_ft = read_uint32() -- OriginalFirstThunk + local time_date = read_uint32() + local forwarder = read_uint32() + local name_rva = read_uint32() + local first_thunk = read_uint32() + + if original_ft == 0 and name_rva == 0 then break end + + if name_rva > 0 then + local name_offset = rva_to_offset(name_rva) + if name_offset then + local save_pos = file:seek() + file:seek("set", name_offset) + local chars = {} + while true do + local b = string.byte(file:read(1)) + if b == 0 then break end + table.insert(chars, string.char(b)) + end + table.insert(imports, table.concat(chars)) + file:seek("set", save_pos) + end + end + end + end + end + end + end + file:close() + end + + for _, dll in ipairs(imports) do + if not _find_dll(dll) then + table.insert(missing, dll) + end + end + return missing +end + +function sandbox_os.execv(program, argv, opt) + + -- make program + program = vformat(program) + + -- flush io buffer first for fixing redirect io output order + -- + -- e.g. + -- + -- xmake run > /tmp/a + -- print("xxx1") + -- os.exec("echo xxx2") + -- + -- cat /tmp/a + -- xxx2 + -- xxx1 + -- + io.flush() + + -- run it + opt = opt or {} + local ok, errors = os.execv(program, argv, opt) + if ok ~= 0 and not opt.try then + + -- get command + local cmd = program + if argv then + cmd = cmd .. " " .. os.args(argv) + end + + -- get errors + if ok ~= nil then + if ok == -1073741515 then -- 0xC0000135 + local missing_dlls = _get_missing_dlls(program) + if #missing_dlls > 0 then + errors = string.format("execv(%s) failed(%d): 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.", cmd, ok, table.concat(missing_dlls, "\n - ")) + else + errors = string.format("execv(%s) failed(%d): 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.", cmd, ok) + end + else + errors = string.format("execv(%s) failed(%d)", cmd, ok) + end + else + errors = string.format("cannot execv(%s), %s", cmd, errors and errors or "unknown reason") + end + os.raise(errors) + end + + -- we need return results if opt.try is enabled + return ok, errors +end + +-- execute command and echo verbose info if [-v|--verbose] option is enabled +function sandbox_os.vexec(cmd, ...) + + -- echo command + if option.get("verbose") then + utils.cprint("${color.dump.string}" .. vformat(cmd, ...)) + end + + -- run it + sandbox_os.exec(cmd, ...) +end + +-- execute command with arguments list and echo verbose info if [-v|--verbose] option is enabled +function sandbox_os.vexecv(program, argv, opt) + + -- echo command + if option.get("verbose") then + utils.cprint("${color.dump.string}" .. vformat(program) .. " " .. sandbox_os.args(argv)) + end + + -- run it + if not (opt and opt.dryrun) then + return sandbox_os.execv(program, argv, opt) + else + return 0 + end +end + +-- match files or directories +function sandbox_os.match(pattern, mode, opt) + return os.match(vformat(tostring(pattern)), mode, opt) +end + +-- match directories +function sandbox_os.dirs(pattern, opt) + return os.dirs(vformat(tostring(pattern)), opt) +end + +-- match files +function sandbox_os.files(pattern, opt) + return os.files(vformat(tostring(pattern)), opt) +end + +-- match files and directories +function sandbox_os.filedirs(pattern, opt) + return os.filedirs(vformat(tostring(pattern)), opt) +end + +-- is directory? +function sandbox_os.isdir(dirpath) + assert(dirpath) + dirpath = tostring(dirpath) + return os.isdir(vformat(dirpath)) +end + +-- is file? +function sandbox_os.isfile(filepath) + assert(filepath) + filepath = tostring(filepath) + return os.isfile(vformat(filepath)) +end + +-- is symlink? +function sandbox_os.islink(filepath) + assert(filepath) + filepath = tostring(filepath) + return os.islink(vformat(filepath)) +end + +-- is execute program? +function sandbox_os.isexec(filepath) + assert(filepath) + filepath = tostring(filepath) + return os.isexec(vformat(filepath)) +end + +-- exists file or directory? +function sandbox_os.exists(filedir) + assert(filedir) + filedir = tostring(filedir) + return os.exists(vformat(filedir)) +end + +-- read the content of symlink +function sandbox_os.readlink(symlink) + local result = os.readlink(tostring(symlink)) + if not result then + os.raise("cannot read link(%s)", symlink) + end + return result +end + +-- sleep (support in coroutine) +function sandbox_os.sleep(ms) + if scheduler:co_running() then + local ok, errors = scheduler:co_sleep(ms) + if not ok then + raise(errors) + end + else + os.sleep(ms) + end +end + +-- get xmake version +function sandbox_os.xmakever() + + -- fill cache + if sandbox_os._XMAKEVER == nil then + -- get xmakever + local xmakever = semver.new(xmake._VERSION_SHORT) + -- save to cache + sandbox_os._XMAKEVER = xmakever or false + end + + -- done + return sandbox_os._XMAKEVER or nil +end + +-- return module +return sandbox_os + -- cgit v1.3.1 From 34a21b3d628b695491815da3f0c465a96e98fd30 Mon Sep 17 00:00:00 2001 From: Saikari Date: Thu, 5 Feb 2026 21:35:26 +0300 Subject: swap CRLF to LF? --- xmake/core/sandbox/modules/os.lua | 1298 ++++++++++++++++++------------------- 1 file changed, 649 insertions(+), 649 deletions(-) diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua index 58b1ed836..77c591451 100644 --- a/xmake/core/sandbox/modules/os.lua +++ b/xmake/core/sandbox/modules/os.lua @@ -1,649 +1,649 @@ ---!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 os.lua --- - --- load modules -local io = require("base/io") -local os = require("base/os") -local path = require("base/path") -local utils = require("base/utils") -local xmake = require("base/xmake") -local option = require("base/option") -local semver = require("base/semver") -local scheduler = require("base/scheduler") -local sandbox = require("sandbox/sandbox") -local vformat = require("sandbox/modules/vformat") - --- define module -local sandbox_os = sandbox_os or {} - --- inherit some builtin interfaces -sandbox_os.shell = os.shell -sandbox_os.term = os.term -sandbox_os.host = os.host -sandbox_os.arch = os.arch -sandbox_os.subhost = os.subhost -sandbox_os.subarch = os.subarch -sandbox_os.is_host = os.is_host -sandbox_os.is_arch = os.is_arch -sandbox_os.is_subhost = os.is_subhost -sandbox_os.is_subarch = os.is_subarch -sandbox_os.syserror = os.syserror -sandbox_os.strerror = os.strerror -sandbox_os.exit = os.exit -sandbox_os.atexit = os.atexit -sandbox_os.date = os.date -sandbox_os.time = os.time -sandbox_os.args = os.args -sandbox_os.args = os.args -sandbox_os.argv = os.argv -sandbox_os.mtime = os.mtime -sandbox_os.raise = os.raise -sandbox_os.fscase = os.fscase -sandbox_os.isroot = os.isroot -sandbox_os.mclock = os.mclock -sandbox_os.nuldev = os.nuldev -sandbox_os.getenv = os.getenv -sandbox_os.setenv = os.setenv -sandbox_os.addenv = os.addenv -sandbox_os.setenvp = os.setenvp -sandbox_os.addenvp = os.addenvp -sandbox_os.getenvs = os.getenvs -sandbox_os.setenvs = os.setenvs -sandbox_os.addenvs = os.addenvs -sandbox_os.joinenvs = os.joinenvs -sandbox_os.pbpaste = os.pbpaste -sandbox_os.pbcopy = os.pbcopy -sandbox_os.cpuinfo = os.cpuinfo -sandbox_os.meminfo = os.meminfo -sandbox_os.default_njob = os.default_njob -sandbox_os.emptydir = os.emptydir -sandbox_os.filesize = os.filesize -sandbox_os.features = os.features -sandbox_os.workingdir = os.workingdir -sandbox_os.programdir = os.programdir -sandbox_os.programfile = os.programfile -sandbox_os.projectdir = os.projectdir -sandbox_os.projectfile = os.projectfile -sandbox_os.getwinsize = os.getwinsize -sandbox_os.getpid = os.getpid - --- syserror code -sandbox_os.SYSERR_UNKNOWN = os.SYSERR_UNKNOWN -sandbox_os.SYSERR_NONE = os.SYSERR_NONE -sandbox_os.SYSERR_NOT_PERM = os.SYSERR_NOT_PERM -sandbox_os.SYSERR_NOT_FILEDIR = os.SYSERR_NOT_FILEDIR -sandbox_os.SYSERR_NOT_ACCESS = os.SYSERR_NOT_ACCESS - --- copy file or directory -function sandbox_os.cp(srcpath, dstpath, opt) - assert(srcpath and dstpath) - srcpath = tostring(srcpath) - dstpath = tostring(dstpath) - local ok, errors = os.cp(vformat(srcpath), vformat(dstpath), opt) - if not ok then - os.raise(errors) - end -end - --- move file or directory -function sandbox_os.mv(srcpath, dstpath, opt) - assert(srcpath and dstpath) - srcpath = tostring(srcpath) - dstpath = tostring(dstpath) - local ok, errors = os.mv(vformat(srcpath), vformat(dstpath), opt) - if not ok then - os.raise(errors) - end -end - --- remove files or directories -function sandbox_os.rm(filepath, opt) - assert(filepath) - filepath = tostring(filepath) - local ok, errors = os.rm(vformat(filepath), opt) - if not ok then - os.raise(errors) - end -end - --- link file or directory to the new symfile -function sandbox_os.ln(srcpath, dstpath, opt) - assert(srcpath and dstpath) - srcpath = tostring(srcpath) - dstpath = tostring(dstpath) - local ok, errors = os.ln(vformat(srcpath), vformat(dstpath), opt) - if not ok then - os.raise(errors) - end -end - --- copy file or directory with the verbose info -function sandbox_os.vcp(srcpath, dstpath, opt) - assert(srcpath and dstpath) - if option.get("verbose") then - utils.cprint("${dim}> copy %s to %s", srcpath, dstpath) - end - return sandbox_os.cp(srcpath, dstpath, opt) -end - --- move file or directory with the verbose info -function sandbox_os.vmv(srcpath, dstpath, opt) - assert(srcpath and dstpath) - if option.get("verbose") then - utils.cprint("${dim}> move %s to %s", srcpath, dstpath) - end - return sandbox_os.mv(srcpath, dstpath, opt) -end - --- remove file or directory with the verbose info -function sandbox_os.vrm(filepath, opt) - assert(filepath) - if option.get("verbose") then - utils.cprint("${dim}> remove %s", filepath) - end - return sandbox_os.rm(filepath, opt) -end - --- link file or directory with the verbose info -function sandbox_os.vln(srcpath, dstpath, opt) - assert(srcpath and dstpath) - if option.get("verbose") then - utils.cprint("${dim}> link %s to %s", srcpath, dstpath) - end - return sandbox_os.ln(srcpath, dstpath, opt) -end - --- try to copy file or directory -function sandbox_os.trycp(srcpath, dstpath, opt) - assert(srcpath and dstpath) - return os.cp(vformat(srcpath), vformat(dstpath), opt) -end - --- try to move file or directory -function sandbox_os.trymv(srcpath, dstpath, opt) - assert(srcpath and dstpath) - return os.mv(vformat(srcpath), vformat(dstpath), opt) -end - --- try to remove files or directories -function sandbox_os.tryrm(filepath, opt) - assert(filepath) - return os.rm(vformat(filepath), opt) -end - --- change to directory -function sandbox_os.cd(dir) - - -- check - assert(dir) - - -- format it first - dir = vformat(dir) - - -- enter this directory - local oldir, errors = os.cd(dir) - if not oldir then - os.raise(errors) - end - - -- ok - return oldir -end - --- touch file or directory -function sandbox_os.touch(filepath, opt) - assert(filepath) - local ok, errors = os.touch(vformat(filepath), opt) - if not ok then - os.raise(errors) - end -end - --- create directories -function sandbox_os.mkdir(dir) - assert(dir) - local ok, errors = os.mkdir(vformat(dir)) - if not ok then - os.raise(errors) - end -end - --- remove directories -function sandbox_os.rmdir(dir, opt) - assert(dir) - local ok, errors = os.rmdir(vformat(dir), opt) - if not ok then - os.raise(errors) - end -end - --- get the current directory -function sandbox_os.curdir() - return assert(os.curdir()) -end - --- get the temporary directory -function sandbox_os.tmpdir(opt) - return assert(os.tmpdir(opt)) -end - --- get the temporary file -function sandbox_os.tmpfile(key, opt) - return assert(os.tmpfile(key, opt)) -end - --- get the script directory -function sandbox_os.scriptdir() - local instance = sandbox.instance() - local rootdir = instance:rootdir() - assert(rootdir) - return rootdir -end - --- quietly run command -function sandbox_os.run(cmd, ...) - cmd = vformat(cmd, ...) - local ok, errors = os.run(cmd) - if not ok then - os.raise(errors) - end -end - --- quietly run command with arguments list -function sandbox_os.runv(program, argv, opt) - program = vformat(program) - local ok, errors = os.runv(program, argv, opt) - if not ok then - os.raise(errors) - end -end - --- quietly run command and echo verbose info if [-v|--verbose] option is enabled -function sandbox_os.vrun(cmd, ...) - if option.get("verbose") then - print(vformat(cmd, ...)) - end - (option.get("verbose") and sandbox_os.exec or sandbox_os.run)(cmd, ...) -end - --- quietly run command with arguments list and echo verbose info if [-v|--verbose] option is enabled -function sandbox_os.vrunv(program, argv, opt) - if option.get("verbose") then - print(vformat(program) .. " " .. sandbox_os.args(argv or {})) - end - if not (opt and opt.dryrun) then - (option.get("verbose") and sandbox_os.execv or sandbox_os.runv)(program, argv, opt) - end -end - --- run command and return output and error data -function sandbox_os.iorun(cmd, ...) - cmd = vformat(cmd, ...) - local ok, outdata, errdata, errors = os.iorun(cmd) - if not ok then - if not errors then - errors = errdata or "" - if #errors:trim() == 0 then - errors = outdata or "" - end - end - os.raise({errors = errors, stderr = errdata, stdout = outdata}) - end - return outdata, errdata -end - --- run command and return output and error data -function sandbox_os.iorunv(program, argv, opt) - program = vformat(program) - local ok, outdata, errdata, errors = os.iorunv(program, argv, opt) - if not ok then - if not errors then - errors = errdata or "" - if #errors:trim() == 0 then - errors = outdata or "" - end - end - os.raise({errors = errors, stderr = errdata, stdout = outdata}) - end - return outdata, errdata -end - --- execute command -function sandbox_os.exec(cmd, ...) - cmd = vformat(cmd, ...) - local ok, errors = os.exec(cmd) - if ok ~= 0 then - if ok ~= nil then - errors = string.format("exec(%s) failed(%d)", cmd, ok) - else - errors = string.format("cannot exec(%s), %s", cmd, errors and errors or "unknown reason") - end - os.raise(errors) - end -end - --- execute command with arguments list --- get missing dlls -local function _get_missing_dlls(program) - local missing = {} - local program_dir = path.directory(program) - local pathenv = os.getenv("PATH") or "" - local paths = path.splitenv(pathenv) - table.insert(paths, 1, program_dir) - - local function _find_dll(name) - for _, p in ipairs(paths) do - if os.isfile(path.join(p, name)) then - return true - end - end - return false - end - - local imports = {} - local file = io.open(program, "rb") - if file then - local function read_uint16() - local str = file:read(2) - if not str then return 0 end - local b1, b2 = string.byte(str, 1, 2) - return b1 + b2 * 256 - end - local function read_uint32() - local str = file:read(4) - if not str then return 0 end - local b1, b2, b3, b4 = string.byte(str, 1, 4) - return b1 + b2 * 256 + b3 * 65536 + b4 * 16777216 - end - - local mz = file:read(2) - if mz == "MZ" then - file:seek("set", 0x3C) - local e_lfanew = read_uint32() - file:seek("set", e_lfanew) - if file:read(4) == "PE\0\0" then - -- file header - file:seek("cur", 2) -- Machine (2) - local number_of_sections = read_uint16() - file:seek("cur", 12) -- TimeDateStamp(4) + PointerToSymbolTable(4) + NumberOfSymbols(4) - local size_of_optional_header = read_uint16() - file:seek("cur", 2) -- Characteristics (2) - - -- optional header - local magic = read_uint16() - local is_pe64 = (magic == 0x20b) - - -- skip standard fields and some windows fields to reach DataDirectories - -- Standard(24/22) + Windows(68/88) - -- PE32: 24 + 68 = 92 bytes from magic to DataDirectories - -- PE32+: 24 + 88 = 112 bytes from magic to DataDirectories - -- Minus magic(2) that we just read - local skip = (is_pe64 and (24 + 88 - 2) or (24 + 68 - 2)) - file:seek("cur", skip) - - -- Data Directories - -- Export Table (8) - file:seek("cur", 8) - - -- Import Table - local import_rva = read_uint32() - local import_size = read_uint32() - - if import_rva > 0 then - -- Section Headers - file:seek("set", e_lfanew + 4 + 20 + size_of_optional_header) - local sections = {} - for i = 1, number_of_sections do - local s = {} - file:seek("cur", 8) -- name - s.vsize = read_uint32() - s.vaddr = read_uint32() - s.rawsize = read_uint32() - s.rawaddr = read_uint32() - file:seek("cur", 16) - table.insert(sections, s) - end - - local function rva_to_offset(rva) - for _, s in ipairs(sections) do - if rva >= s.vaddr and rva < s.vaddr + s.vsize then - return s.rawaddr + (rva - s.vaddr) - end - end - return nil - end - - local import_offset = rva_to_offset(import_rva) - if import_offset then - file:seek("set", import_offset) - while true do - local original_ft = read_uint32() -- OriginalFirstThunk - local time_date = read_uint32() - local forwarder = read_uint32() - local name_rva = read_uint32() - local first_thunk = read_uint32() - - if original_ft == 0 and name_rva == 0 then break end - - if name_rva > 0 then - local name_offset = rva_to_offset(name_rva) - if name_offset then - local save_pos = file:seek() - file:seek("set", name_offset) - local chars = {} - while true do - local b = string.byte(file:read(1)) - if b == 0 then break end - table.insert(chars, string.char(b)) - end - table.insert(imports, table.concat(chars)) - file:seek("set", save_pos) - end - end - end - end - end - end - end - file:close() - end - - for _, dll in ipairs(imports) do - if not _find_dll(dll) then - table.insert(missing, dll) - end - end - return missing -end - -function sandbox_os.execv(program, argv, opt) - - -- make program - program = vformat(program) - - -- flush io buffer first for fixing redirect io output order - -- - -- e.g. - -- - -- xmake run > /tmp/a - -- print("xxx1") - -- os.exec("echo xxx2") - -- - -- cat /tmp/a - -- xxx2 - -- xxx1 - -- - io.flush() - - -- run it - opt = opt or {} - local ok, errors = os.execv(program, argv, opt) - if ok ~= 0 and not opt.try then - - -- get command - local cmd = program - if argv then - cmd = cmd .. " " .. os.args(argv) - end - - -- get errors - if ok ~= nil then - if ok == -1073741515 then -- 0xC0000135 - local missing_dlls = _get_missing_dlls(program) - if #missing_dlls > 0 then - errors = string.format("execv(%s) failed(%d): 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.", cmd, ok, table.concat(missing_dlls, "\n - ")) - else - errors = string.format("execv(%s) failed(%d): 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.", cmd, ok) - end - else - errors = string.format("execv(%s) failed(%d)", cmd, ok) - end - else - errors = string.format("cannot execv(%s), %s", cmd, errors and errors or "unknown reason") - end - os.raise(errors) - end - - -- we need return results if opt.try is enabled - return ok, errors -end - --- execute command and echo verbose info if [-v|--verbose] option is enabled -function sandbox_os.vexec(cmd, ...) - - -- echo command - if option.get("verbose") then - utils.cprint("${color.dump.string}" .. vformat(cmd, ...)) - end - - -- run it - sandbox_os.exec(cmd, ...) -end - --- execute command with arguments list and echo verbose info if [-v|--verbose] option is enabled -function sandbox_os.vexecv(program, argv, opt) - - -- echo command - if option.get("verbose") then - utils.cprint("${color.dump.string}" .. vformat(program) .. " " .. sandbox_os.args(argv)) - end - - -- run it - if not (opt and opt.dryrun) then - return sandbox_os.execv(program, argv, opt) - else - return 0 - end -end - --- match files or directories -function sandbox_os.match(pattern, mode, opt) - return os.match(vformat(tostring(pattern)), mode, opt) -end - --- match directories -function sandbox_os.dirs(pattern, opt) - return os.dirs(vformat(tostring(pattern)), opt) -end - --- match files -function sandbox_os.files(pattern, opt) - return os.files(vformat(tostring(pattern)), opt) -end - --- match files and directories -function sandbox_os.filedirs(pattern, opt) - return os.filedirs(vformat(tostring(pattern)), opt) -end - --- is directory? -function sandbox_os.isdir(dirpath) - assert(dirpath) - dirpath = tostring(dirpath) - return os.isdir(vformat(dirpath)) -end - --- is file? -function sandbox_os.isfile(filepath) - assert(filepath) - filepath = tostring(filepath) - return os.isfile(vformat(filepath)) -end - --- is symlink? -function sandbox_os.islink(filepath) - assert(filepath) - filepath = tostring(filepath) - return os.islink(vformat(filepath)) -end - --- is execute program? -function sandbox_os.isexec(filepath) - assert(filepath) - filepath = tostring(filepath) - return os.isexec(vformat(filepath)) -end - --- exists file or directory? -function sandbox_os.exists(filedir) - assert(filedir) - filedir = tostring(filedir) - return os.exists(vformat(filedir)) -end - --- read the content of symlink -function sandbox_os.readlink(symlink) - local result = os.readlink(tostring(symlink)) - if not result then - os.raise("cannot read link(%s)", symlink) - end - return result -end - --- sleep (support in coroutine) -function sandbox_os.sleep(ms) - if scheduler:co_running() then - local ok, errors = scheduler:co_sleep(ms) - if not ok then - raise(errors) - end - else - os.sleep(ms) - end -end - --- get xmake version -function sandbox_os.xmakever() - - -- fill cache - if sandbox_os._XMAKEVER == nil then - -- get xmakever - local xmakever = semver.new(xmake._VERSION_SHORT) - -- save to cache - sandbox_os._XMAKEVER = xmakever or false - end - - -- done - return sandbox_os._XMAKEVER or nil -end - --- return module -return sandbox_os - +--!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 os.lua +-- + +-- load modules +local io = require("base/io") +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local xmake = require("base/xmake") +local option = require("base/option") +local semver = require("base/semver") +local scheduler = require("base/scheduler") +local sandbox = require("sandbox/sandbox") +local vformat = require("sandbox/modules/vformat") + +-- define module +local sandbox_os = sandbox_os or {} + +-- inherit some builtin interfaces +sandbox_os.shell = os.shell +sandbox_os.term = os.term +sandbox_os.host = os.host +sandbox_os.arch = os.arch +sandbox_os.subhost = os.subhost +sandbox_os.subarch = os.subarch +sandbox_os.is_host = os.is_host +sandbox_os.is_arch = os.is_arch +sandbox_os.is_subhost = os.is_subhost +sandbox_os.is_subarch = os.is_subarch +sandbox_os.syserror = os.syserror +sandbox_os.strerror = os.strerror +sandbox_os.exit = os.exit +sandbox_os.atexit = os.atexit +sandbox_os.date = os.date +sandbox_os.time = os.time +sandbox_os.args = os.args +sandbox_os.args = os.args +sandbox_os.argv = os.argv +sandbox_os.mtime = os.mtime +sandbox_os.raise = os.raise +sandbox_os.fscase = os.fscase +sandbox_os.isroot = os.isroot +sandbox_os.mclock = os.mclock +sandbox_os.nuldev = os.nuldev +sandbox_os.getenv = os.getenv +sandbox_os.setenv = os.setenv +sandbox_os.addenv = os.addenv +sandbox_os.setenvp = os.setenvp +sandbox_os.addenvp = os.addenvp +sandbox_os.getenvs = os.getenvs +sandbox_os.setenvs = os.setenvs +sandbox_os.addenvs = os.addenvs +sandbox_os.joinenvs = os.joinenvs +sandbox_os.pbpaste = os.pbpaste +sandbox_os.pbcopy = os.pbcopy +sandbox_os.cpuinfo = os.cpuinfo +sandbox_os.meminfo = os.meminfo +sandbox_os.default_njob = os.default_njob +sandbox_os.emptydir = os.emptydir +sandbox_os.filesize = os.filesize +sandbox_os.features = os.features +sandbox_os.workingdir = os.workingdir +sandbox_os.programdir = os.programdir +sandbox_os.programfile = os.programfile +sandbox_os.projectdir = os.projectdir +sandbox_os.projectfile = os.projectfile +sandbox_os.getwinsize = os.getwinsize +sandbox_os.getpid = os.getpid + +-- syserror code +sandbox_os.SYSERR_UNKNOWN = os.SYSERR_UNKNOWN +sandbox_os.SYSERR_NONE = os.SYSERR_NONE +sandbox_os.SYSERR_NOT_PERM = os.SYSERR_NOT_PERM +sandbox_os.SYSERR_NOT_FILEDIR = os.SYSERR_NOT_FILEDIR +sandbox_os.SYSERR_NOT_ACCESS = os.SYSERR_NOT_ACCESS + +-- copy file or directory +function sandbox_os.cp(srcpath, dstpath, opt) + assert(srcpath and dstpath) + srcpath = tostring(srcpath) + dstpath = tostring(dstpath) + local ok, errors = os.cp(vformat(srcpath), vformat(dstpath), opt) + if not ok then + os.raise(errors) + end +end + +-- move file or directory +function sandbox_os.mv(srcpath, dstpath, opt) + assert(srcpath and dstpath) + srcpath = tostring(srcpath) + dstpath = tostring(dstpath) + local ok, errors = os.mv(vformat(srcpath), vformat(dstpath), opt) + if not ok then + os.raise(errors) + end +end + +-- remove files or directories +function sandbox_os.rm(filepath, opt) + assert(filepath) + filepath = tostring(filepath) + local ok, errors = os.rm(vformat(filepath), opt) + if not ok then + os.raise(errors) + end +end + +-- link file or directory to the new symfile +function sandbox_os.ln(srcpath, dstpath, opt) + assert(srcpath and dstpath) + srcpath = tostring(srcpath) + dstpath = tostring(dstpath) + local ok, errors = os.ln(vformat(srcpath), vformat(dstpath), opt) + if not ok then + os.raise(errors) + end +end + +-- copy file or directory with the verbose info +function sandbox_os.vcp(srcpath, dstpath, opt) + assert(srcpath and dstpath) + if option.get("verbose") then + utils.cprint("${dim}> copy %s to %s", srcpath, dstpath) + end + return sandbox_os.cp(srcpath, dstpath, opt) +end + +-- move file or directory with the verbose info +function sandbox_os.vmv(srcpath, dstpath, opt) + assert(srcpath and dstpath) + if option.get("verbose") then + utils.cprint("${dim}> move %s to %s", srcpath, dstpath) + end + return sandbox_os.mv(srcpath, dstpath, opt) +end + +-- remove file or directory with the verbose info +function sandbox_os.vrm(filepath, opt) + assert(filepath) + if option.get("verbose") then + utils.cprint("${dim}> remove %s", filepath) + end + return sandbox_os.rm(filepath, opt) +end + +-- link file or directory with the verbose info +function sandbox_os.vln(srcpath, dstpath, opt) + assert(srcpath and dstpath) + if option.get("verbose") then + utils.cprint("${dim}> link %s to %s", srcpath, dstpath) + end + return sandbox_os.ln(srcpath, dstpath, opt) +end + +-- try to copy file or directory +function sandbox_os.trycp(srcpath, dstpath, opt) + assert(srcpath and dstpath) + return os.cp(vformat(srcpath), vformat(dstpath), opt) +end + +-- try to move file or directory +function sandbox_os.trymv(srcpath, dstpath, opt) + assert(srcpath and dstpath) + return os.mv(vformat(srcpath), vformat(dstpath), opt) +end + +-- try to remove files or directories +function sandbox_os.tryrm(filepath, opt) + assert(filepath) + return os.rm(vformat(filepath), opt) +end + +-- change to directory +function sandbox_os.cd(dir) + + -- check + assert(dir) + + -- format it first + dir = vformat(dir) + + -- enter this directory + local oldir, errors = os.cd(dir) + if not oldir then + os.raise(errors) + end + + -- ok + return oldir +end + +-- touch file or directory +function sandbox_os.touch(filepath, opt) + assert(filepath) + local ok, errors = os.touch(vformat(filepath), opt) + if not ok then + os.raise(errors) + end +end + +-- create directories +function sandbox_os.mkdir(dir) + assert(dir) + local ok, errors = os.mkdir(vformat(dir)) + if not ok then + os.raise(errors) + end +end + +-- remove directories +function sandbox_os.rmdir(dir, opt) + assert(dir) + local ok, errors = os.rmdir(vformat(dir), opt) + if not ok then + os.raise(errors) + end +end + +-- get the current directory +function sandbox_os.curdir() + return assert(os.curdir()) +end + +-- get the temporary directory +function sandbox_os.tmpdir(opt) + return assert(os.tmpdir(opt)) +end + +-- get the temporary file +function sandbox_os.tmpfile(key, opt) + return assert(os.tmpfile(key, opt)) +end + +-- get the script directory +function sandbox_os.scriptdir() + local instance = sandbox.instance() + local rootdir = instance:rootdir() + assert(rootdir) + return rootdir +end + +-- quietly run command +function sandbox_os.run(cmd, ...) + cmd = vformat(cmd, ...) + local ok, errors = os.run(cmd) + if not ok then + os.raise(errors) + end +end + +-- quietly run command with arguments list +function sandbox_os.runv(program, argv, opt) + program = vformat(program) + local ok, errors = os.runv(program, argv, opt) + if not ok then + os.raise(errors) + end +end + +-- quietly run command and echo verbose info if [-v|--verbose] option is enabled +function sandbox_os.vrun(cmd, ...) + if option.get("verbose") then + print(vformat(cmd, ...)) + end + (option.get("verbose") and sandbox_os.exec or sandbox_os.run)(cmd, ...) +end + +-- quietly run command with arguments list and echo verbose info if [-v|--verbose] option is enabled +function sandbox_os.vrunv(program, argv, opt) + if option.get("verbose") then + print(vformat(program) .. " " .. sandbox_os.args(argv or {})) + end + if not (opt and opt.dryrun) then + (option.get("verbose") and sandbox_os.execv or sandbox_os.runv)(program, argv, opt) + end +end + +-- run command and return output and error data +function sandbox_os.iorun(cmd, ...) + cmd = vformat(cmd, ...) + local ok, outdata, errdata, errors = os.iorun(cmd) + if not ok then + if not errors then + errors = errdata or "" + if #errors:trim() == 0 then + errors = outdata or "" + end + end + os.raise({errors = errors, stderr = errdata, stdout = outdata}) + end + return outdata, errdata +end + +-- run command and return output and error data +function sandbox_os.iorunv(program, argv, opt) + program = vformat(program) + local ok, outdata, errdata, errors = os.iorunv(program, argv, opt) + if not ok then + if not errors then + errors = errdata or "" + if #errors:trim() == 0 then + errors = outdata or "" + end + end + os.raise({errors = errors, stderr = errdata, stdout = outdata}) + end + return outdata, errdata +end + +-- execute command +function sandbox_os.exec(cmd, ...) + cmd = vformat(cmd, ...) + local ok, errors = os.exec(cmd) + if ok ~= 0 then + if ok ~= nil then + errors = string.format("exec(%s) failed(%d)", cmd, ok) + else + errors = string.format("cannot exec(%s), %s", cmd, errors and errors or "unknown reason") + end + os.raise(errors) + end +end + +-- execute command with arguments list +-- get missing dlls +local function _get_missing_dlls(program) + local missing = {} + local program_dir = path.directory(program) + local pathenv = os.getenv("PATH") or "" + local paths = path.splitenv(pathenv) + table.insert(paths, 1, program_dir) + + local function _find_dll(name) + for _, p in ipairs(paths) do + if os.isfile(path.join(p, name)) then + return true + end + end + return false + end + + local imports = {} + local file = io.open(program, "rb") + if file then + local function read_uint16() + local str = file:read(2) + if not str then return 0 end + local b1, b2 = string.byte(str, 1, 2) + return b1 + b2 * 256 + end + local function read_uint32() + local str = file:read(4) + if not str then return 0 end + local b1, b2, b3, b4 = string.byte(str, 1, 4) + return b1 + b2 * 256 + b3 * 65536 + b4 * 16777216 + end + + local mz = file:read(2) + if mz == "MZ" then + file:seek("set", 0x3C) + local e_lfanew = read_uint32() + file:seek("set", e_lfanew) + if file:read(4) == "PE\0\0" then + -- file header + file:seek("cur", 2) -- Machine (2) + local number_of_sections = read_uint16() + file:seek("cur", 12) -- TimeDateStamp(4) + PointerToSymbolTable(4) + NumberOfSymbols(4) + local size_of_optional_header = read_uint16() + file:seek("cur", 2) -- Characteristics (2) + + -- optional header + local magic = read_uint16() + local is_pe64 = (magic == 0x20b) + + -- skip standard fields and some windows fields to reach DataDirectories + -- Standard(24/22) + Windows(68/88) + -- PE32: 24 + 68 = 92 bytes from magic to DataDirectories + -- PE32+: 24 + 88 = 112 bytes from magic to DataDirectories + -- Minus magic(2) that we just read + local skip = (is_pe64 and (24 + 88 - 2) or (24 + 68 - 2)) + file:seek("cur", skip) + + -- Data Directories + -- Export Table (8) + file:seek("cur", 8) + + -- Import Table + local import_rva = read_uint32() + local import_size = read_uint32() + + if import_rva > 0 then + -- Section Headers + file:seek("set", e_lfanew + 4 + 20 + size_of_optional_header) + local sections = {} + for i = 1, number_of_sections do + local s = {} + file:seek("cur", 8) -- name + s.vsize = read_uint32() + s.vaddr = read_uint32() + s.rawsize = read_uint32() + s.rawaddr = read_uint32() + file:seek("cur", 16) + table.insert(sections, s) + end + + local function rva_to_offset(rva) + for _, s in ipairs(sections) do + if rva >= s.vaddr and rva < s.vaddr + s.vsize then + return s.rawaddr + (rva - s.vaddr) + end + end + return nil + end + + local import_offset = rva_to_offset(import_rva) + if import_offset then + file:seek("set", import_offset) + while true do + local original_ft = read_uint32() -- OriginalFirstThunk + local time_date = read_uint32() + local forwarder = read_uint32() + local name_rva = read_uint32() + local first_thunk = read_uint32() + + if original_ft == 0 and name_rva == 0 then break end + + if name_rva > 0 then + local name_offset = rva_to_offset(name_rva) + if name_offset then + local save_pos = file:seek() + file:seek("set", name_offset) + local chars = {} + while true do + local b = string.byte(file:read(1)) + if b == 0 then break end + table.insert(chars, string.char(b)) + end + table.insert(imports, table.concat(chars)) + file:seek("set", save_pos) + end + end + end + end + end + end + end + file:close() + end + + for _, dll in ipairs(imports) do + if not _find_dll(dll) then + table.insert(missing, dll) + end + end + return missing +end + +function sandbox_os.execv(program, argv, opt) + + -- make program + program = vformat(program) + + -- flush io buffer first for fixing redirect io output order + -- + -- e.g. + -- + -- xmake run > /tmp/a + -- print("xxx1") + -- os.exec("echo xxx2") + -- + -- cat /tmp/a + -- xxx2 + -- xxx1 + -- + io.flush() + + -- run it + opt = opt or {} + local ok, errors = os.execv(program, argv, opt) + if ok ~= 0 and not opt.try then + + -- get command + local cmd = program + if argv then + cmd = cmd .. " " .. os.args(argv) + end + + -- get errors + if ok ~= nil then + if ok == -1073741515 then -- 0xC0000135 + local missing_dlls = _get_missing_dlls(program) + if #missing_dlls > 0 then + errors = string.format("execv(%s) failed(%d): 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.", cmd, ok, table.concat(missing_dlls, "\n - ")) + else + errors = string.format("execv(%s) failed(%d): 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.", cmd, ok) + end + else + errors = string.format("execv(%s) failed(%d)", cmd, ok) + end + else + errors = string.format("cannot execv(%s), %s", cmd, errors and errors or "unknown reason") + end + os.raise(errors) + end + + -- we need return results if opt.try is enabled + return ok, errors +end + +-- execute command and echo verbose info if [-v|--verbose] option is enabled +function sandbox_os.vexec(cmd, ...) + + -- echo command + if option.get("verbose") then + utils.cprint("${color.dump.string}" .. vformat(cmd, ...)) + end + + -- run it + sandbox_os.exec(cmd, ...) +end + +-- execute command with arguments list and echo verbose info if [-v|--verbose] option is enabled +function sandbox_os.vexecv(program, argv, opt) + + -- echo command + if option.get("verbose") then + utils.cprint("${color.dump.string}" .. vformat(program) .. " " .. sandbox_os.args(argv)) + end + + -- run it + if not (opt and opt.dryrun) then + return sandbox_os.execv(program, argv, opt) + else + return 0 + end +end + +-- match files or directories +function sandbox_os.match(pattern, mode, opt) + return os.match(vformat(tostring(pattern)), mode, opt) +end + +-- match directories +function sandbox_os.dirs(pattern, opt) + return os.dirs(vformat(tostring(pattern)), opt) +end + +-- match files +function sandbox_os.files(pattern, opt) + return os.files(vformat(tostring(pattern)), opt) +end + +-- match files and directories +function sandbox_os.filedirs(pattern, opt) + return os.filedirs(vformat(tostring(pattern)), opt) +end + +-- is directory? +function sandbox_os.isdir(dirpath) + assert(dirpath) + dirpath = tostring(dirpath) + return os.isdir(vformat(dirpath)) +end + +-- is file? +function sandbox_os.isfile(filepath) + assert(filepath) + filepath = tostring(filepath) + return os.isfile(vformat(filepath)) +end + +-- is symlink? +function sandbox_os.islink(filepath) + assert(filepath) + filepath = tostring(filepath) + return os.islink(vformat(filepath)) +end + +-- is execute program? +function sandbox_os.isexec(filepath) + assert(filepath) + filepath = tostring(filepath) + return os.isexec(vformat(filepath)) +end + +-- exists file or directory? +function sandbox_os.exists(filedir) + assert(filedir) + filedir = tostring(filedir) + return os.exists(vformat(filedir)) +end + +-- read the content of symlink +function sandbox_os.readlink(symlink) + local result = os.readlink(tostring(symlink)) + if not result then + os.raise("cannot read link(%s)", symlink) + end + return result +end + +-- sleep (support in coroutine) +function sandbox_os.sleep(ms) + if scheduler:co_running() then + local ok, errors = scheduler:co_sleep(ms) + if not ok then + raise(errors) + end + else + os.sleep(ms) + end +end + +-- get xmake version +function sandbox_os.xmakever() + + -- fill cache + if sandbox_os._XMAKEVER == nil then + -- get xmakever + local xmakever = semver.new(xmake._VERSION_SHORT) + -- save to cache + sandbox_os._XMAKEVER = xmakever or false + end + + -- done + return sandbox_os._XMAKEVER or nil +end + +-- return module +return sandbox_os + -- cgit v1.3.1 From 728ead07ff58cd9d8330075414cfe21b1034b757 Mon Sep 17 00:00:00 2001 From: Saikari Date: Thu, 5 Feb 2026 21:37:51 +0300 Subject: cls --- xmake/core/sandbox/modules/os.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua index 77c591451..197356ffa 100644 --- a/xmake/core/sandbox/modules/os.lua +++ b/xmake/core/sandbox/modules/os.lua @@ -509,8 +509,6 @@ function sandbox_os.execv(program, argv, opt) local missing_dlls = _get_missing_dlls(program) if #missing_dlls > 0 then errors = string.format("execv(%s) failed(%d): 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.", cmd, ok, table.concat(missing_dlls, "\n - ")) - else - errors = string.format("execv(%s) failed(%d): 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.", cmd, ok) end else errors = string.format("execv(%s) failed(%d)", cmd, ok) -- cgit v1.3.1 From bb7879934dca1ef7b26584f4dfadc29462d5a059 Mon Sep 17 00:00:00 2001 From: Saikari Date: Thu, 5 Feb 2026 22:48:58 +0300 Subject: create policy besides pe parser --- core/src/xmake/engine.c | 2 ++ core/src/xmake/winos/set_error_mode.c | 7 +++++++ projects/test_windows_links/xmake.lua | 2 ++ xmake/actions/run/main.lua | 2 +- xmake/core/project/policy.lua | 2 ++ xmake/core/sandbox/modules/os.lua | 19 +++++++++++++++++++ xmake/core/sandbox/modules/winos.lua | 1 + 7 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 core/src/xmake/winos/set_error_mode.c diff --git a/core/src/xmake/engine.c b/core/src/xmake/engine.c index 9c02d8487..ccd77e7e5 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 }, + { "seterrormode", 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..43131d2e2 --- /dev/null +++ b/core/src/xmake/winos/set_error_mode.c @@ -0,0 +1,7 @@ +#include "prefix.h" + +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/projects/test_windows_links/xmake.lua b/projects/test_windows_links/xmake.lua index 5d8c0d984..e856892d3 100644 --- a/projects/test_windows_links/xmake.lua +++ b/projects/test_windows_links/xmake.lua @@ -1,5 +1,7 @@ add_rules("mode.debug", "mode.release") +set_policy("run.gui_error_dialogs", true) + target("foo") set_kind("shared") add_files("src/foo.c") diff --git a/xmake/actions/run/main.lua b/xmake/actions/run/main.lua index 6cfe09d3a..899df8d61 100644 --- a/xmake/actions/run/main.lua +++ b/xmake/actions/run/main.lua @@ -63,7 +63,7 @@ function _do_run_target(target) 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}) + os.execv(targetfile, args, {curdir = rundir, detach = option.get("detach"), addenvs = addenvs, setenvs = setenvs, winos_error_mode_gui = target:policy("run.gui_error_dialogs")}) end end diff --git a/xmake/core/project/policy.lua b/xmake/core/project/policy.lua index 5123f0a5c..3f24d9a0f 100644 --- a/xmake/core/project/policy.lua +++ b/xmake/core/project/policy.lua @@ -34,6 +34,8 @@ function policy.policies() local policies = policy._POLICIES if not policies then policies = { + -- Enable/Disable Windows Error Reporting Dialogs + ["run.gui_error_dialogs"] = {description = "Enable Windows Error Reporting Dialogs during execution.", default = false, type = "boolean"}, -- We will check and ignore all unsupported flags by default, but we can also pass `{force = true}` to force to set flags, e.g. add_ldflags("-static", {force = true}) ["check.auto_ignore_flags"] = {description = "Enable check and ignore unsupported flags automatically.", default = true, type = "boolean"}, -- We will map gcc flags to the current compiler and linker by default. diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua index 197356ffa..5718f8dec 100644 --- a/xmake/core/sandbox/modules/os.lua +++ b/xmake/core/sandbox/modules/os.lua @@ -494,7 +494,24 @@ function sandbox_os.execv(program, argv, opt) -- run it opt = opt or {} + + -- check policy for GUI error dialogs (Windows only) + local old_mode + local winos + if os.is_host("windows") and opt.winos_error_mode_gui then + winos = require("sandbox/modules/winos") + if winos.seterrormode then + old_mode = winos.seterrormode(0) + end + end + local ok, errors = os.execv(program, argv, opt) + + -- restore error mode + if old_mode then + winos.seterrormode(old_mode) + end + if ok ~= 0 and not opt.try then -- get command @@ -509,6 +526,8 @@ function sandbox_os.execv(program, argv, opt) local missing_dlls = _get_missing_dlls(program) if #missing_dlls > 0 then errors = string.format("execv(%s) failed(%d): 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.", cmd, ok, table.concat(missing_dlls, "\n - ")) + else + errors = string.format("execv(%s) failed(%d): 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.", cmd, ok) end else errors = string.format("execv(%s) failed(%d)", cmd, ok) diff --git a/xmake/core/sandbox/modules/winos.lua b/xmake/core/sandbox/modules/winos.lua index eddcf91d4..862ed9a8b 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.seterrormode = winos.seterrormode -- get windows system version function sandbox_winos.version() -- cgit v1.3.1 From b51f3b5f386c18504be698ea9c14953c8b289605 Mon Sep 17 00:00:00 2001 From: Saikari Date: Thu, 5 Feb 2026 23:36:25 +0300 Subject: fix logic --- core/src/xmake/process/openv.c | 27 +++++++++++++++++++++++++++ xmake/core/base/os.lua | 3 ++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/core/src/xmake/process/openv.c b/core/src/xmake/process/openv.c index 223d2d774..b9020cb2c 100644 --- a/core/src/xmake/process/openv.c +++ b/core/src/xmake/process/openv.c @@ -34,6 +34,9 @@ defined(TB_CONFIG_OS_HAIKU) || defined(TB_COMPILER_IS_MINGW) #include #endif +#ifdef TB_CONFIG_OS_WINDOWS +#include +#endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation @@ -100,6 +103,12 @@ tb_int_t xm_process_openv(lua_State *lua) { // init attributes tb_process_attr_t attr = { 0 }; +#ifdef TB_CONFIG_OS_WINDOWS + // the error mode + UINT old_error_mode = 0; + tb_bool_t set_error_mode = tb_false; +#endif + // get option arguments tb_bool_t exclusive = tb_false; tb_size_t envn = 0; @@ -130,6 +139,17 @@ tb_int_t xm_process_openv(lua_State *lua) { } lua_pop(lua, 1); +#ifdef TB_CONFIG_OS_WINDOWS + // save winos error mode? + lua_pushstring(lua, "winos_error_mode_gui"); + lua_gettable(lua, 3); + if (lua_toboolean(lua, -1)) { + old_error_mode = SetErrorMode(0); + set_error_mode = tb_true; + } + lua_pop(lua, 1); +#endif + // get curdir lua_pushstring(lua, "curdir"); lua_gettable(lua, 3); @@ -323,6 +343,13 @@ tb_int_t xm_process_openv(lua_State *lua) { lua_pushnil(lua); } +#ifdef TB_CONFIG_OS_WINDOWS + // restore error mode + if (set_error_mode) { + SetErrorMode(old_error_mode); + } +#endif + // exit argv if (argv) { tb_free(argv); diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua index ae730738e..0607bb209 100644 --- a/xmake/core/base/os.lua +++ b/xmake/core/base/os.lua @@ -994,7 +994,8 @@ function os.execv(program, argv, opt) stderr = opt.stderr, curdir = opt.curdir, detach = opt.detach, - exclusive = opt.exclusive} + exclusive = opt.exclusive, + winos_error_mode_gui = opt.winos_error_mode_gui} -- profile process performance local runtime -- cgit v1.3.1 From 912af4ea2bebda7b6d930aaec92fe73d183b6971 Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 6 Feb 2026 10:17:33 +0300 Subject: Move project to `tests/projects/windows/` --- projects/test_windows_links/src/foo.c | 8 -------- projects/test_windows_links/src/main.c | 24 ---------------------- projects/test_windows_links/xmake.lua | 19 ----------------- .../projects/windows/test_windows_links/src/foo.c | 8 ++++++++ .../projects/windows/test_windows_links/src/main.c | 24 ++++++++++++++++++++++ .../projects/windows/test_windows_links/xmake.lua | 19 +++++++++++++++++ 6 files changed, 51 insertions(+), 51 deletions(-) delete mode 100644 projects/test_windows_links/src/foo.c delete mode 100644 projects/test_windows_links/src/main.c delete mode 100644 projects/test_windows_links/xmake.lua create mode 100644 tests/projects/windows/test_windows_links/src/foo.c create mode 100644 tests/projects/windows/test_windows_links/src/main.c create mode 100644 tests/projects/windows/test_windows_links/xmake.lua diff --git a/projects/test_windows_links/src/foo.c b/projects/test_windows_links/src/foo.c deleted file mode 100644 index b399bc175..000000000 --- a/projects/test_windows_links/src/foo.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -#ifdef _WIN32 -__declspec(dllexport) -#endif -void foo() { - printf("foo called\n"); -} diff --git a/projects/test_windows_links/src/main.c b/projects/test_windows_links/src/main.c deleted file mode 100644 index 8f9578202..000000000 --- a/projects/test_windows_links/src/main.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include - -#ifdef _WIN32 -__declspec(dllimport) void foo(); -#else -void foo(); -#endif - -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/projects/test_windows_links/xmake.lua b/projects/test_windows_links/xmake.lua deleted file mode 100644 index e856892d3..000000000 --- a/projects/test_windows_links/xmake.lua +++ /dev/null @@ -1,19 +0,0 @@ -add_rules("mode.debug", "mode.release") - -set_policy("run.gui_error_dialogs", true) - -target("foo") - set_kind("shared") - add_files("src/foo.c") - -target("test_mingw_dll") - 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/tests/projects/windows/test_windows_links/src/foo.c b/tests/projects/windows/test_windows_links/src/foo.c new file mode 100644 index 000000000..b399bc175 --- /dev/null +++ b/tests/projects/windows/test_windows_links/src/foo.c @@ -0,0 +1,8 @@ +#include + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void foo() { + printf("foo called\n"); +} diff --git a/tests/projects/windows/test_windows_links/src/main.c b/tests/projects/windows/test_windows_links/src/main.c new file mode 100644 index 000000000..8f9578202 --- /dev/null +++ b/tests/projects/windows/test_windows_links/src/main.c @@ -0,0 +1,24 @@ +#include +#include +#include + +#ifdef _WIN32 +__declspec(dllimport) void foo(); +#else +void foo(); +#endif + +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/test_windows_links/xmake.lua b/tests/projects/windows/test_windows_links/xmake.lua new file mode 100644 index 000000000..2f01a3c88 --- /dev/null +++ b/tests/projects/windows/test_windows_links/xmake.lua @@ -0,0 +1,19 @@ +add_rules("mode.debug", "mode.release") + +set_policy("run.gui_error_dialogs", false) + +target("foo") + set_kind("shared") + add_files("src/foo.c") + +target("test_mingw_dll") + 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) -- cgit v1.3.1 From da9078511fa52c95cf7e5aad21deb55b27e64488 Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 6 Feb 2026 10:20:07 +0300 Subject: try add license header --- core/src/xmake/winos/set_error_mode.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/core/src/xmake/winos/set_error_mode.c b/core/src/xmake/winos/set_error_mode.c index 43131d2e2..ceff4684b 100644 --- a/core/src/xmake/winos/set_error_mode.c +++ b/core/src/xmake/winos/set_error_mode.c @@ -1,5 +1,39 @@ +/*!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)); -- cgit v1.3.1 From d49ea464353c5e63c95c77cc97d1827dd3df53ad Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 6 Feb 2026 11:11:15 +0300 Subject: Resolve comments --- core/src/xmake/process/openv.c | 27 ----- .../projects/windows/test_windows_links/xmake.lua | 2 +- xmake/core/base/os.lua | 3 +- xmake/core/sandbox/modules/os.lua | 109 +-------------------- 4 files changed, 4 insertions(+), 137 deletions(-) diff --git a/core/src/xmake/process/openv.c b/core/src/xmake/process/openv.c index b9020cb2c..223d2d774 100644 --- a/core/src/xmake/process/openv.c +++ b/core/src/xmake/process/openv.c @@ -34,9 +34,6 @@ defined(TB_CONFIG_OS_HAIKU) || defined(TB_COMPILER_IS_MINGW) #include #endif -#ifdef TB_CONFIG_OS_WINDOWS -#include -#endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation @@ -103,12 +100,6 @@ tb_int_t xm_process_openv(lua_State *lua) { // init attributes tb_process_attr_t attr = { 0 }; -#ifdef TB_CONFIG_OS_WINDOWS - // the error mode - UINT old_error_mode = 0; - tb_bool_t set_error_mode = tb_false; -#endif - // get option arguments tb_bool_t exclusive = tb_false; tb_size_t envn = 0; @@ -139,17 +130,6 @@ tb_int_t xm_process_openv(lua_State *lua) { } lua_pop(lua, 1); -#ifdef TB_CONFIG_OS_WINDOWS - // save winos error mode? - lua_pushstring(lua, "winos_error_mode_gui"); - lua_gettable(lua, 3); - if (lua_toboolean(lua, -1)) { - old_error_mode = SetErrorMode(0); - set_error_mode = tb_true; - } - lua_pop(lua, 1); -#endif - // get curdir lua_pushstring(lua, "curdir"); lua_gettable(lua, 3); @@ -343,13 +323,6 @@ tb_int_t xm_process_openv(lua_State *lua) { lua_pushnil(lua); } -#ifdef TB_CONFIG_OS_WINDOWS - // restore error mode - if (set_error_mode) { - SetErrorMode(old_error_mode); - } -#endif - // exit argv if (argv) { tb_free(argv); diff --git a/tests/projects/windows/test_windows_links/xmake.lua b/tests/projects/windows/test_windows_links/xmake.lua index 2f01a3c88..e856892d3 100644 --- a/tests/projects/windows/test_windows_links/xmake.lua +++ b/tests/projects/windows/test_windows_links/xmake.lua @@ -1,6 +1,6 @@ add_rules("mode.debug", "mode.release") -set_policy("run.gui_error_dialogs", false) +set_policy("run.gui_error_dialogs", true) target("foo") set_kind("shared") diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua index 0607bb209..ae730738e 100644 --- a/xmake/core/base/os.lua +++ b/xmake/core/base/os.lua @@ -994,8 +994,7 @@ function os.execv(program, argv, opt) stderr = opt.stderr, curdir = opt.curdir, detach = opt.detach, - exclusive = opt.exclusive, - winos_error_mode_gui = opt.winos_error_mode_gui} + exclusive = opt.exclusive} -- profile process performance local runtime diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua index 5718f8dec..25242f3f4 100644 --- a/xmake/core/sandbox/modules/os.lua +++ b/xmake/core/sandbox/modules/os.lua @@ -26,6 +26,7 @@ local utils = require("base/utils") local xmake = require("base/xmake") local option = require("base/option") local semver = require("base/semver") +local binutils = require("base/binutils") local scheduler = require("base/scheduler") local sandbox = require("sandbox/sandbox") local vformat = require("sandbox/modules/vformat") @@ -357,113 +358,7 @@ local function _get_missing_dlls(program) return false end - local imports = {} - local file = io.open(program, "rb") - if file then - local function read_uint16() - local str = file:read(2) - if not str then return 0 end - local b1, b2 = string.byte(str, 1, 2) - return b1 + b2 * 256 - end - local function read_uint32() - local str = file:read(4) - if not str then return 0 end - local b1, b2, b3, b4 = string.byte(str, 1, 4) - return b1 + b2 * 256 + b3 * 65536 + b4 * 16777216 - end - - local mz = file:read(2) - if mz == "MZ" then - file:seek("set", 0x3C) - local e_lfanew = read_uint32() - file:seek("set", e_lfanew) - if file:read(4) == "PE\0\0" then - -- file header - file:seek("cur", 2) -- Machine (2) - local number_of_sections = read_uint16() - file:seek("cur", 12) -- TimeDateStamp(4) + PointerToSymbolTable(4) + NumberOfSymbols(4) - local size_of_optional_header = read_uint16() - file:seek("cur", 2) -- Characteristics (2) - - -- optional header - local magic = read_uint16() - local is_pe64 = (magic == 0x20b) - - -- skip standard fields and some windows fields to reach DataDirectories - -- Standard(24/22) + Windows(68/88) - -- PE32: 24 + 68 = 92 bytes from magic to DataDirectories - -- PE32+: 24 + 88 = 112 bytes from magic to DataDirectories - -- Minus magic(2) that we just read - local skip = (is_pe64 and (24 + 88 - 2) or (24 + 68 - 2)) - file:seek("cur", skip) - - -- Data Directories - -- Export Table (8) - file:seek("cur", 8) - - -- Import Table - local import_rva = read_uint32() - local import_size = read_uint32() - - if import_rva > 0 then - -- Section Headers - file:seek("set", e_lfanew + 4 + 20 + size_of_optional_header) - local sections = {} - for i = 1, number_of_sections do - local s = {} - file:seek("cur", 8) -- name - s.vsize = read_uint32() - s.vaddr = read_uint32() - s.rawsize = read_uint32() - s.rawaddr = read_uint32() - file:seek("cur", 16) - table.insert(sections, s) - end - - local function rva_to_offset(rva) - for _, s in ipairs(sections) do - if rva >= s.vaddr and rva < s.vaddr + s.vsize then - return s.rawaddr + (rva - s.vaddr) - end - end - return nil - end - - local import_offset = rva_to_offset(import_rva) - if import_offset then - file:seek("set", import_offset) - while true do - local original_ft = read_uint32() -- OriginalFirstThunk - local time_date = read_uint32() - local forwarder = read_uint32() - local name_rva = read_uint32() - local first_thunk = read_uint32() - - if original_ft == 0 and name_rva == 0 then break end - - if name_rva > 0 then - local name_offset = rva_to_offset(name_rva) - if name_offset then - local save_pos = file:seek() - file:seek("set", name_offset) - local chars = {} - while true do - local b = string.byte(file:read(1)) - if b == 0 then break end - table.insert(chars, string.char(b)) - end - table.insert(imports, table.concat(chars)) - file:seek("set", save_pos) - end - end - end - end - end - end - end - file:close() - end + local imports = binutils.deplibs(program) or {} for _, dll in ipairs(imports) do if not _find_dll(dll) then -- cgit v1.3.1 From 5794b2207a8e1cb93ee8c180bb3994b1a3d40ad6 Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 6 Feb 2026 13:05:45 +0300 Subject: test_windows_links -> windows_links --- tests/projects/windows/test_windows_links/xmake.lua | 19 ------------------- tests/projects/windows/windows_links/xmake.lua | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 19 deletions(-) delete mode 100644 tests/projects/windows/test_windows_links/xmake.lua create mode 100644 tests/projects/windows/windows_links/xmake.lua diff --git a/tests/projects/windows/test_windows_links/xmake.lua b/tests/projects/windows/test_windows_links/xmake.lua deleted file mode 100644 index e856892d3..000000000 --- a/tests/projects/windows/test_windows_links/xmake.lua +++ /dev/null @@ -1,19 +0,0 @@ -add_rules("mode.debug", "mode.release") - -set_policy("run.gui_error_dialogs", true) - -target("foo") - set_kind("shared") - add_files("src/foo.c") - -target("test_mingw_dll") - 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/tests/projects/windows/windows_links/xmake.lua b/tests/projects/windows/windows_links/xmake.lua new file mode 100644 index 000000000..a38616132 --- /dev/null +++ b/tests/projects/windows/windows_links/xmake.lua @@ -0,0 +1,20 @@ +add_rules("mode.debug", "mode.release") + +set_policy("run.gui_error_dialogs", true) + +target("foo") + set_kind("shared") + add_files("src/foo.c") + +target("test_mingw_dll") + 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) + -- cgit v1.3.1 From efd77f2c7a750c1ab73694745d8e3babfe662fb9 Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 6 Feb 2026 13:07:01 +0300 Subject: Add foo.c to windows_links project --- tests/projects/windows/test_windows_links/src/foo.c | 8 -------- tests/projects/windows/windows_links/src/foo.c | 9 +++++++++ 2 files changed, 9 insertions(+), 8 deletions(-) delete mode 100644 tests/projects/windows/test_windows_links/src/foo.c create mode 100644 tests/projects/windows/windows_links/src/foo.c diff --git a/tests/projects/windows/test_windows_links/src/foo.c b/tests/projects/windows/test_windows_links/src/foo.c deleted file mode 100644 index b399bc175..000000000 --- a/tests/projects/windows/test_windows_links/src/foo.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -#ifdef _WIN32 -__declspec(dllexport) -#endif -void foo() { - printf("foo called\n"); -} 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 + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void foo() { + printf("foo called\n"); +} + -- cgit v1.3.1 From 1fe6d3c21b1d861ab5d80c617869b80ac363f451 Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 6 Feb 2026 13:07:39 +0300 Subject: Update and rename main.c to main.c --- .../projects/windows/test_windows_links/src/main.c | 24 ---------------------- tests/projects/windows/windows_links/src/main.c | 24 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 24 deletions(-) delete mode 100644 tests/projects/windows/test_windows_links/src/main.c create mode 100644 tests/projects/windows/windows_links/src/main.c diff --git a/tests/projects/windows/test_windows_links/src/main.c b/tests/projects/windows/test_windows_links/src/main.c deleted file mode 100644 index 8f9578202..000000000 --- a/tests/projects/windows/test_windows_links/src/main.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include - -#ifdef _WIN32 -__declspec(dllimport) void foo(); -#else -void foo(); -#endif - -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/src/main.c b/tests/projects/windows/windows_links/src/main.c new file mode 100644 index 000000000..8f9578202 --- /dev/null +++ b/tests/projects/windows/windows_links/src/main.c @@ -0,0 +1,24 @@ +#include +#include +#include + +#ifdef _WIN32 +__declspec(dllimport) void foo(); +#else +void foo(); +#endif + +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; +} -- cgit v1.3.1 From 12d3bbcb05dd4393da1ec472c9e1ad135afa3e20 Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 6 Feb 2026 14:51:24 +0300 Subject: Refactor main.c to remove preprocessor conditionals --- tests/projects/windows/windows_links/src/main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/projects/windows/windows_links/src/main.c b/tests/projects/windows/windows_links/src/main.c index 8f9578202..bc94c3f13 100644 --- a/tests/projects/windows/windows_links/src/main.c +++ b/tests/projects/windows/windows_links/src/main.c @@ -2,11 +2,7 @@ #include #include -#ifdef _WIN32 __declspec(dllimport) void foo(); -#else -void foo(); -#endif int main() { PROCESS_MEMORY_COUNTERS pmc; @@ -22,3 +18,4 @@ int main() { printf("Done.\n"); return 0; } + -- cgit v1.3.1 From 6007059c47a51d5847772fb68e357e4869ba85b3 Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 6 Feb 2026 15:37:26 +0300 Subject: cleanup --- tests/projects/windows/windows_links/xmake.lua | 2 +- xmake/core/sandbox/modules/os.lua | 34 ++++++++++++++------------ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/tests/projects/windows/windows_links/xmake.lua b/tests/projects/windows/windows_links/xmake.lua index a38616132..dcb7e4e2c 100644 --- a/tests/projects/windows/windows_links/xmake.lua +++ b/tests/projects/windows/windows_links/xmake.lua @@ -6,7 +6,7 @@ target("foo") set_kind("shared") add_files("src/foo.c") -target("test_mingw_dll") +target("test_foo_dll_presence") set_kind("binary") add_files("src/main.c") add_deps("foo") diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua index 25242f3f4..ce2cf6504 100644 --- a/xmake/core/sandbox/modules/os.lua +++ b/xmake/core/sandbox/modules/os.lua @@ -340,34 +340,36 @@ function sandbox_os.exec(cmd, ...) end end --- execute command with arguments list -- get missing dlls -local function _get_missing_dlls(program) - local missing = {} - local program_dir = path.directory(program) +function sandbox_os._get_missing_dlls(program) + + -- check + assert(program) + + -- get paths local pathenv = os.getenv("PATH") or "" local paths = path.splitenv(pathenv) - table.insert(paths, 1, program_dir) + table.insert(paths, 1, path.directory(program)) - local function _find_dll(name) + -- find missing dlls + local missing = {} + local imports = binutils.deplibs(program) or {} + for _, dll in ipairs(imports) do + local found = false for _, p in ipairs(paths) do - if os.isfile(path.join(p, name)) then - return true + if os.isfile(path.join(p, dll)) then + found = true + break end end - return false - end - - local imports = binutils.deplibs(program) or {} - - for _, dll in ipairs(imports) do - if not _find_dll(dll) then + if not found then table.insert(missing, dll) end end return missing end +-- execute command with arguments list function sandbox_os.execv(program, argv, opt) -- make program @@ -418,7 +420,7 @@ function sandbox_os.execv(program, argv, opt) -- get errors if ok ~= nil then if ok == -1073741515 then -- 0xC0000135 - local missing_dlls = _get_missing_dlls(program) + local missing_dlls = sandbox_os._get_missing_dlls(program) if #missing_dlls > 0 then errors = string.format("execv(%s) failed(%d): 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.", cmd, ok, table.concat(missing_dlls, "\n - ")) else -- cgit v1.3.1 From 791292f2ee65a4ca8566c3e7a38cbcbf965ddd08 Mon Sep 17 00:00:00 2001 From: ruki Date: Sat, 7 Feb 2026 00:52:20 +0800 Subject: improve run policy and missing dll --- core/src/xmake/engine.c | 2 +- tests/projects/windows/windows_links/xmake.lua | 2 +- xmake/actions/run/main.lua | 14 +++++- xmake/core/base/os.lua | 5 +- xmake/core/base/process.lua | 43 +++++++++++++++++ xmake/core/project/policy.lua | 4 +- xmake/core/sandbox/modules/os.lua | 65 ++------------------------ xmake/core/sandbox/modules/winos.lua | 2 +- 8 files changed, 69 insertions(+), 68 deletions(-) diff --git a/core/src/xmake/engine.c b/core/src/xmake/engine.c index ccd77e7e5..1a542bc7c 100644 --- a/core/src/xmake/engine.c +++ b/core/src/xmake/engine.c @@ -486,7 +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 }, - { "seterrormode", xm_winos_set_error_mode }, + { "set_error_mode", xm_winos_set_error_mode }, { tb_null, tb_null }, }; #endif diff --git a/tests/projects/windows/windows_links/xmake.lua b/tests/projects/windows/windows_links/xmake.lua index dcb7e4e2c..57ae03712 100644 --- a/tests/projects/windows/windows_links/xmake.lua +++ b/tests/projects/windows/windows_links/xmake.lua @@ -1,6 +1,6 @@ add_rules("mode.debug", "mode.release") -set_policy("run.gui_error_dialogs", true) +set_policy("run.windows_error_dialog", true) target("foo") set_kind("shared") diff --git a/xmake/actions/run/main.lua b/xmake/actions/run/main.lua index 899df8d61..87ba5f098 100644 --- a/xmake/actions/run/main.lua +++ b/xmake/actions/run/main.lua @@ -59,11 +59,23 @@ 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, winos_error_mode_gui = target:policy("run.gui_error_dialogs")}) + 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 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..bea469346 100644 --- a/xmake/core/base/process.lua +++ b/xmake/core/base/process.lua @@ -271,5 +271,48 @@ function process.openv(program, argv, opt) end end +-- get missing dlls +function process._get_missing_dlls(program) + + -- get paths + local pathenv = os.getenv("PATH") or "" + local paths = path.splitenv(pathenv) + table.insert(paths, 1, path.directory(program)) + + -- find missing dlls + local missing = {} + local binutils = require("base/binutils") + local imports = binutils.deplibs(program) or {} + 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) + if is_host("windows") then + -- DLL is missing, 0xC0000135 + if exitcode == -1073741515 and os.isexec(program) 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 +end + + -- return module: process return process diff --git a/xmake/core/project/policy.lua b/xmake/core/project/policy.lua index 3f24d9a0f..0fdd70831 100644 --- a/xmake/core/project/policy.lua +++ b/xmake/core/project/policy.lua @@ -34,8 +34,6 @@ function policy.policies() local policies = policy._POLICIES if not policies then policies = { - -- Enable/Disable Windows Error Reporting Dialogs - ["run.gui_error_dialogs"] = {description = "Enable Windows Error Reporting Dialogs during execution.", default = false, type = "boolean"}, -- We will check and ignore all unsupported flags by default, but we can also pass `{force = true}` to force to set flags, e.g. add_ldflags("-static", {force = true}) ["check.auto_ignore_flags"] = {description = "Enable check and ignore unsupported flags automatically.", default = true, type = "boolean"}, -- We will map gcc flags to the current compiler and linker by default. @@ -129,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 ce2cf6504..8fe76987e 100644 --- a/xmake/core/sandbox/modules/os.lua +++ b/xmake/core/sandbox/modules/os.lua @@ -21,12 +21,10 @@ -- load modules local io = require("base/io") local os = require("base/os") -local path = require("base/path") local utils = require("base/utils") local xmake = require("base/xmake") local option = require("base/option") local semver = require("base/semver") -local binutils = require("base/binutils") local scheduler = require("base/scheduler") local sandbox = require("sandbox/sandbox") local vformat = require("sandbox/modules/vformat") @@ -332,43 +330,14 @@ 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 end --- get missing dlls -function sandbox_os._get_missing_dlls(program) - - -- check - assert(program) - - -- get paths - local pathenv = os.getenv("PATH") or "" - local paths = path.splitenv(pathenv) - table.insert(paths, 1, path.directory(program)) - - -- find missing dlls - local missing = {} - local imports = binutils.deplibs(program) or {} - 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 - -- execute command with arguments list function sandbox_os.execv(program, argv, opt) @@ -391,24 +360,7 @@ function sandbox_os.execv(program, argv, opt) -- run it opt = opt or {} - - -- check policy for GUI error dialogs (Windows only) - local old_mode - local winos - if os.is_host("windows") and opt.winos_error_mode_gui then - winos = require("sandbox/modules/winos") - if winos.seterrormode then - old_mode = winos.seterrormode(0) - end - end - local ok, errors = os.execv(program, argv, opt) - - -- restore error mode - if old_mode then - winos.seterrormode(old_mode) - end - if ok ~= 0 and not opt.try then -- get command @@ -419,18 +371,9 @@ function sandbox_os.execv(program, argv, opt) -- get errors if ok ~= nil then - if ok == -1073741515 then -- 0xC0000135 - local missing_dlls = sandbox_os._get_missing_dlls(program) - if #missing_dlls > 0 then - errors = string.format("execv(%s) failed(%d): 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.", cmd, ok, table.concat(missing_dlls, "\n - ")) - else - errors = string.format("execv(%s) failed(%d): 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.", cmd, ok) - end - else - errors = string.format("execv(%s) failed(%d)", cmd, ok) - end + 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 862ed9a8b..2ed01245d 100644 --- a/xmake/core/sandbox/modules/winos.lua +++ b/xmake/core/sandbox/modules/winos.lua @@ -35,7 +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.seterrormode = winos.seterrormode +sandbox_winos.set_error_mode = winos.set_error_mode -- get windows system version function sandbox_winos.version() -- cgit v1.3.1 From 7cce7d28b459173ca174d7a5e4391d9194291a69 Mon Sep 17 00:00:00 2001 From: ruki Date: Sat, 7 Feb 2026 00:56:28 +0800 Subject: improve missing dlls --- xmake/core/base/process.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/xmake/core/base/process.lua b/xmake/core/base/process.lua index bea469346..031f02bb4 100644 --- a/xmake/core/base/process.lua +++ b/xmake/core/base/process.lua @@ -281,8 +281,12 @@ function process._get_missing_dlls(program) -- find missing dlls local missing = {} - local binutils = require("base/binutils") - local imports = binutils.deplibs(program) or {} + 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 @@ -292,7 +296,7 @@ function process._get_missing_dlls(program) end end if not found then - table.insert(missing, dll) + table.insert(missing, dll) end end return missing -- cgit v1.3.1 From ba898b75c5de008424bea5380977f05d364597b3 Mon Sep 17 00:00:00 2001 From: ruki Date: Sat, 7 Feb 2026 00:57:32 +0800 Subject: fix missdll --- xmake/core/base/process.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/xmake/core/base/process.lua b/xmake/core/base/process.lua index 031f02bb4..3466b9575 100644 --- a/xmake/core/base/process.lua +++ b/xmake/core/base/process.lua @@ -273,6 +273,10 @@ 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 "" @@ -280,7 +284,6 @@ function process._get_missing_dlls(program) table.insert(paths, 1, path.directory(program)) -- find missing dlls - local missing = {} 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 {} @@ -304,9 +307,9 @@ end -- get process exit errors function process.get_exit_errors(program, exitcode) - if is_host("windows") then + if os.is_host("windows") then -- DLL is missing, 0xC0000135 - if exitcode == -1073741515 and os.isexec(program) then + 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 - ")) -- cgit v1.3.1 From 08f5b8a7bdac97cab8f5055a5ae9b066d2b18664 Mon Sep 17 00:00:00 2001 From: ruki Date: Sat, 7 Feb 2026 00:58:04 +0800 Subject: fix missdll errors --- xmake/core/base/process.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xmake/core/base/process.lua b/xmake/core/base/process.lua index 3466b9575..692a6360f 100644 --- a/xmake/core/base/process.lua +++ b/xmake/core/base/process.lua @@ -307,6 +307,7 @@ 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 @@ -318,6 +319,7 @@ function process.get_exit_errors(program, exitcode) end end end + return errors end -- cgit v1.3.1