diff options
56 files changed, 835 insertions, 102 deletions
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 2bb1b81ea..5bbc0f047 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -62,12 +62,11 @@ jobs: sudo apt install -y dh-make rng-tools devscripts lintian echo "$PPA_GPG_PRIKEY_2C0C68C9" > ppa_gpg.key gpg --import ppa_gpg.key - scripts/makeppa questing # 25.10 - scripts/makeppa plucky # 25.04 + # @note only the series which are not obsolete on launchpad can be uploaded, + # @see https://api.launchpad.net/1.0/ubuntu/series + scripts/makeppa stonking # 26.10 + scripts/makeppa resolute # 26.04 scripts/makeppa noble # 24.04 - scripts/makeppa mantic # 23.10 - scripts/makeppa lunar # 23.04 - scripts/makeppa kinetic # 22.10 scripts/makeppa jammy # 22.04 scripts/makeppa focal # 20.04 scripts/makeppa bionic # 18.04 diff --git a/CHANGELOG.md b/CHANGELOG.md index 648679063..52dc9bdc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,40 @@ ## master (unreleased) +## v3.1.1 + +### New features + +* [#7696](https://github.com/xmake-io/xmake/pull/7696): Add addons support, to extend xmake with plugins, rules, toolchains, templates, modules and includes files +* [#7702](https://github.com/xmake-io/xmake/pull/7702): Auto-install the addons declared by a project and lock them in `xmake-addons.lock` +* [#7714](https://github.com/xmake-io/xmake/pull/7714): Support `add_addons(...)` in `xmake.lua` +* [#7706](https://github.com/xmake-io/xmake/pull/7706): Add tests for addons +* [#7707](https://github.com/xmake-io/xmake/pull/7707): Add tests for the package definitions shipped by addons +* [#7717](https://github.com/xmake-io/xmake/pull/7717): Move the `format` / `doxygen` / `macro` plugins to addons +* [#7723](https://github.com/xmake-io/xmake/pull/7723): Add new cross-compilation architectures, e.g. SPARC64 +* [#7721](https://github.com/xmake-io/xmake/pull/7721): Add the `package.host.install_locally` policy +* [#7699](https://github.com/xmake-io/xmake/pull/7699): Rework the templates directory and template distribution +* Add the `pkg` package manager for BSD + +### Changes + +* [#7719](https://github.com/xmake-io/xmake/pull/7719): Propagate the vector extensions of a package to its consumers +* [#7713](https://github.com/xmake-io/xmake/pull/7713): Run `hlsl2spv` / `glsl2spv` before the C++ module scan +* [#7722](https://github.com/xmake-io/xmake/pull/7722): Improve the interpreter, project loading, search cache and semver +* [#7733](https://github.com/xmake-io/xmake/pull/7733): Check the name conflicts of the global modules of addons +* [#7726](https://github.com/xmake-io/xmake/pull/7726): Improve the mingw toolchain for clang and libc++ + +### Bugs fixed + +* [#7737](https://github.com/xmake-io/xmake/pull/7737): Fix the duplicated packages of the nested builds when installing them locally +* [#7738](https://github.com/xmake-io/xmake/issues/7738): Fix the platform menu of the remote build, e.g. `xmake f -p windows --wdk=xxx` +* [#7710](https://github.com/xmake-io/xmake/pull/7710): Fix the link name of libraries ending with `.lib` +* [#7709](https://github.com/xmake-io/xmake/pull/7709): Fix the runtime flags of clang +* [#7703](https://github.com/xmake-io/xmake/pull/7703): Fix wix to recognize `x86_64` when passing `-arch` +* [#7701](https://github.com/xmake-io/xmake/pull/7701): Fix the dependency check to detect appended nested values +* [#7698](https://github.com/xmake-io/xmake/pull/7698): Fix the semver version selection and build metadata sorting +* Fix `scheduler.co_resume` to raise the errors of the resumed coroutine + ## v3.1.0 ### New features @@ -2490,6 +2524,40 @@ ## master (开发中) +## v3.1.1 + +### 新特性 + +* [#7696](https://github.com/xmake-io/xmake/pull/7696): 添加 addons 支持,可以用插件、规则、工具链、模板、模块和 includes 文件扩展 xmake +* [#7702](https://github.com/xmake-io/xmake/pull/7702): 自动安装工程声明的 addon,并用 `xmake-addons.lock` 锁定版本 +* [#7714](https://github.com/xmake-io/xmake/pull/7714): 支持在 `xmake.lua` 中使用 `add_addons(...)` +* [#7706](https://github.com/xmake-io/xmake/pull/7706): 添加 addon 测试 +* [#7707](https://github.com/xmake-io/xmake/pull/7707): 添加 addon 分发 package 定义的测试 +* [#7717](https://github.com/xmake-io/xmake/pull/7717): 将 `format` / `doxygen` / `macro` 插件迁移为 addon +* [#7723](https://github.com/xmake-io/xmake/pull/7723): 添加新的交叉编译架构,例如 SPARC64 +* [#7721](https://github.com/xmake-io/xmake/pull/7721): 添加 `package.host.install_locally` 策略 +* [#7699](https://github.com/xmake-io/xmake/pull/7699): 重构模板目录和模板分发 +* 添加 BSD 的 `pkg` 包管理器支持 + +### 改进 + +* [#7719](https://github.com/xmake-io/xmake/pull/7719): 将包的向量扩展配置传递给使用它的目标 +* [#7713](https://github.com/xmake-io/xmake/pull/7713): 让 `hlsl2spv` / `glsl2spv` 在 C++ 模块扫描之前执行 +* [#7722](https://github.com/xmake-io/xmake/pull/7722): 改进 interpreter、工程加载、搜索缓存和 semver +* [#7733](https://github.com/xmake-io/xmake/pull/7733): 检查 addon 全局模块的命名冲突 +* [#7726](https://github.com/xmake-io/xmake/pull/7726): 改进 mingw 工具链对 clang 和 libc++ 的支持 + +### Bug 修复 + +* [#7737](https://github.com/xmake-io/xmake/pull/7737): 修复本地安装包时,嵌套构建重复安装包的问题 +* [#7738](https://github.com/xmake-io/xmake/issues/7738): 修复远程编译下的平台菜单,例如 `xmake f -p windows --wdk=xxx` +* [#7710](https://github.com/xmake-io/xmake/pull/7710): 修复 `.lib` 结尾的库名被错误裁剪的问题 +* [#7709](https://github.com/xmake-io/xmake/pull/7709): 修复 clang 的 runtime flags 检测 +* [#7703](https://github.com/xmake-io/xmake/pull/7703): 修复 wix 传递 `-arch` 时无法识别 `x86_64` 的问题 +* [#7701](https://github.com/xmake-io/xmake/pull/7701): 修复依赖检测无法发现嵌套值追加的问题 +* [#7698](https://github.com/xmake-io/xmake/pull/7698): 修复 semver 的版本选择和 build metadata 排序 +* 修复 `scheduler.co_resume`,让被恢复协程的错误能够正常抛出 + ## v3.1.0 ### 新特性 diff --git a/core/src/tbox/tbox b/core/src/tbox/tbox -Subproject 14f9089e1e4a9b8b01f5789f4c5d6a04e6652b3 +Subproject 3330978dce512b5c7104683383a40ab2b14be73 diff --git a/core/src/xmake/utf8/width.c b/core/src/xmake/utf8/width.c index 615572462..fb79ee198 100644 --- a/core/src/xmake/utf8/width.c +++ b/core/src/xmake/utf8/width.c @@ -33,7 +33,11 @@ * utf8.width(codepoint) */ tb_int_t xm_utf8_width(lua_State* lua) { - if (lua_isnumber(lua, 1)) { + /* we must not use lua_isnumber() here: it also accepts a numeric string, + * so utf8.width("9") would return the width of the code point 9 (a tab) + * instead of the width of the string "9" + */ + if (lua_type(lua, 1) == LUA_TNUMBER) { xm_utf8_int_t val = (xm_utf8_int_t)lua_tointeger(lua, 1); lua_pushinteger(lua, xm_utf8_charwidth(val)); } else { diff --git a/core/xmake.lua b/core/xmake.lua index 5eb42cc1c..5536cbf98 100644 --- a/core/xmake.lua +++ b/core/xmake.lua @@ -1,7 +1,7 @@ set_project("xmake") set_xmakever("3.0.5") set_policy("build.progress_style", "multirow") -set_version("3.1.0", {build = "%Y%m%d"}) +set_version("3.1.1", {build = "%Y%m%d"}) -- set all warnings as errors set_warnings("all", "error") diff --git a/core/xmake.sh b/core/xmake.sh index 085a3f82b..935a7158b 100755 --- a/core/xmake.sh +++ b/core/xmake.sh @@ -1,7 +1,7 @@ #!/bin/sh set_project "xmake" -set_version "3.1.0" "%Y%m%d" +set_version "3.1.1" "%Y%m%d" # set warning all set_warnings "all" diff --git a/scripts/get.ps1 b/scripts/get.ps1 index 3f0869c78..487675c21 100755 --- a/scripts/get.ps1 +++ b/scripts/get.ps1 @@ -11,7 +11,7 @@ param ( ) & { - $LastRelease = "v3.1.0" + $LastRelease = "v3.1.1" $ErrorActionPreference = 'Stop' function writeErrorTip($msg) { diff --git a/scripts/rpmbuild/xmake.spec b/scripts/rpmbuild/xmake.spec index 7fe43780c..fd4695904 100644 --- a/scripts/rpmbuild/xmake.spec +++ b/scripts/rpmbuild/xmake.spec @@ -3,7 +3,7 @@ %undefine __brp_mangle_shebangs Name: xmake -Version: 3.1.0 +Version: 3.1.1 Release: 1%{?dist} Summary: A cross-platform build utility based on Lua diff --git a/tests/actions/addon/custom-override/addon.lua b/tests/actions/addon/custom-override/addon.lua new file mode 100644 index 000000000..3540b51f5 --- /dev/null +++ b/tests/actions/addon/custom-override/addon.lua @@ -0,0 +1,2 @@ +addon("custom-override") + set_description("the addon which takes over a builtin plugin") diff --git a/tests/actions/addon/custom-override/plugins/format/main.lua b/tests/actions/addon/custom-override/plugins/format/main.lua new file mode 100644 index 000000000..92f9b73b8 --- /dev/null +++ b/tests/actions/addon/custom-override/plugins/format/main.lua @@ -0,0 +1,3 @@ +function main() + print("hello from custom-override") +end diff --git a/tests/actions/addon/custom-override/plugins/format/xmake.lua b/tests/actions/addon/custom-override/plugins/format/xmake.lua new file mode 100644 index 000000000..446e24db1 --- /dev/null +++ b/tests/actions/addon/custom-override/plugins/format/xmake.lua @@ -0,0 +1,6 @@ +-- @note `format` is a builtin plugin of xmake, we use it to test that an addon +-- is able to take over a builtin plugin +task("format") + set_category("plugin") + set_menu {usage = "xmake format", description = "Say hello instead of formatting.", options = {}} + on_run("main") diff --git a/tests/actions/addon/test.lua b/tests/actions/addon/test.lua index 05818a054..fcc5c2efc 100644 --- a/tests/actions/addon/test.lua +++ b/tests/actions/addon/test.lua @@ -467,6 +467,26 @@ function test_install_conflicts(t) end) end +-- an addon is able to take over a builtin plugin, so we can move a deprecated builtin +-- plugin to an addon, e.g. `xmake format` +function test_install_override(t) + + -- the builtin plugin is used if we do not install the addon + t:require_not(os.iorunv("xmake", {"format", "--help"}):find("Say hello instead of formatting", 1, true)) + + _with_addons({"custom-override"}, function () + local out = os.iorunv("xmake", {"format"}) + t:require(out:find("hello from custom-override", 1, true)) + + -- and it should not be reported as a conflict + t:require_not(out:find("conflicts", 1, true)) + t:require(os.iorunv("xmake", {"format", "--help"}):find("Say hello instead of formatting", 1, true)) + end) + + -- the builtin plugin is used again after removing the addon + t:require_not(os.iorunv("xmake", {"format", "--help"}):find("Say hello instead of formatting", 1, true)) +end + -- the invalid installs should fail, and the `addon` name is reserved for the addon references function test_invalid(t) t:require_not(try { function () os.runv("xmake", {"addon", "--install", "-y", "addon-test-missing"}); return true end }) diff --git a/tests/projects/c++/modules/precompile_reduced_bmi/src/base.mpp b/tests/projects/c++/modules/precompile_reduced_bmi/src/base.mpp new file mode 100644 index 000000000..e3e6224f2 --- /dev/null +++ b/tests/projects/c++/modules/precompile_reduced_bmi/src/base.mpp @@ -0,0 +1,5 @@ +export module base; + +export int base_value() { + return 40; +} diff --git a/tests/projects/c++/modules/precompile_reduced_bmi/src/hello.mpp b/tests/projects/c++/modules/precompile_reduced_bmi/src/hello.mpp new file mode 100644 index 000000000..9de491171 --- /dev/null +++ b/tests/projects/c++/modules/precompile_reduced_bmi/src/hello.mpp @@ -0,0 +1,7 @@ +export module hello; + +import base; + +export int answer() { + return base_value() + 2; +} diff --git a/tests/projects/c++/modules/precompile_reduced_bmi/src/main.cpp b/tests/projects/c++/modules/precompile_reduced_bmi/src/main.cpp new file mode 100644 index 000000000..75adbd883 --- /dev/null +++ b/tests/projects/c++/modules/precompile_reduced_bmi/src/main.cpp @@ -0,0 +1,5 @@ +import hello; + +int main() { + return answer() == 42 ? 0 : 1; +} diff --git a/tests/projects/c++/modules/precompile_reduced_bmi/test.lua b/tests/projects/c++/modules/precompile_reduced_bmi/test.lua new file mode 100644 index 000000000..765290f7b --- /dev/null +++ b/tests/projects/c++/modules/precompile_reduced_bmi/test.lua @@ -0,0 +1,107 @@ +inherit(".test_base") +import("core.base.json") + +local _CLANG_MIN_VER = "23" + +function clang_min_ver() + return _CLANG_MIN_VER +end + +function _check_commands(config, outdata) + local has_precompile_reduced_bmi = outdata:find("--precompile-reduced-bmi", 1, true) ~= nil + local expect_precompile_reduced_bmi = config.precompile_reduced_bmi and config.two_phases + assert(has_precompile_reduced_bmi == expect_precompile_reduced_bmi, + "unexpected --precompile-reduced-bmi usage\n%s", outdata) + + if config.two_phases then + local object_command + for _, line in ipairs(outdata:split("\n", {plain = true})) do + if line:find("hello.mpp", 1, true) and + (line:find("hello.mpp.o", 1, true) or line:find("hello.mpp.obj", 1, true)) and + line:find(" -c ", 1, true) and + not line:find("clang-scan-deps", 1, true) and + not line:find("--precompile", 1, true) then + object_command = line + break + end + end + assert(object_command, "module object command missing\n%s", outdata) + local consumes_bmi = object_command:find("hello.pcm", 1, true) ~= nil + assert(consumes_bmi ~= expect_precompile_reduced_bmi, "unexpected module object input\n%s", outdata) + end +end + +function _check_incremental() + local outdata = os.iorun("xmake -v") + if outdata:find("compiling", 1, true) or + outdata:find("linking", 1, true) or + outdata:find("generating", 1, true) then + raise("Modules incremental compilation does not work\n%s", outdata) + end +end + +function _check_compile_commands(config) + os.run("xmake project -k compile_commands") + local bmi_command + local object_command + for _, command in ipairs(assert(json.loadfile("compile_commands.json"))) do + if command.file:endswith("hello.mpp") then + local commandline = command.command or table.concat(command.arguments or {}, " ") + if commandline:find("--precompile", 1, true) then + bmi_command = commandline + elseif commandline:find("hello.mpp.o", 1, true) or commandline:find("hello.mpp.obj", 1, true) then + object_command = commandline + end + end + end + assert(bmi_command, "module BMI command missing from compile_commands.json") + assert(object_command, "module object command missing from compile_commands.json") + local expect_precompile_reduced_bmi = config.precompile_reduced_bmi and config.two_phases + assert((bmi_command:find("--precompile-reduced-bmi", 1, true) ~= nil) == expect_precompile_reduced_bmi, + "unexpected module BMI command\n%s", bmi_command) + assert(object_command:find("hello.mpp", 1, true) and not object_command:find("hello.pcm", 1, true), + "unexpected module object command\n%s", object_command) +end + +function _configure(config) + local argv = {"f", "--yes", "--toolchain=" .. config.toolchain} + if config.platform then + table.join2(argv, {"-p", config.platform}) + end + if config.runtimes then + table.insert(argv, "--runtimes=" .. config.runtimes) + end + local policies = "--policies=build.c++.modules.std:" .. (config.stdmodule and "y" or "n") + policies = policies .. ",build.c++.modules.fallbackscanner:" .. (config.fallbackscanner and "y" or "n") + policies = policies .. ",build.c++.modules.two_phases:" .. (config.two_phases and "y" or "n") + policies = policies .. ",build.c++.modules.clang.precompile_reduced_bmi:" .. (config.precompile_reduced_bmi and "y" or "n") + table.insert(argv, policies) + table.join2(argv, config.flags or {}) + os.execv("xmake", argv) +end + +function _check_build(config) + local outdata = os.iorun("xmake -rv") + _check_commands(config, outdata) + + os.run("xmake run") + _check_incremental() + if config.two_phases then + _check_compile_commands(config) + end + + if config.two_phases then + local toggled_config = table.clone(config) + toggled_config.precompile_reduced_bmi = not config.precompile_reduced_bmi + _configure(toggled_config) + local toggled_outdata = os.iorun("xmake -v") + _check_commands(toggled_config, toggled_outdata) + os.run("xmake run") + _check_incremental() + _check_compile_commands(toggled_config) + end +end + +function main(_) + run_tests({compiler = "clang", version = clang_min_ver(), precompile_reduced_bmi = true, build = _check_build}) +end diff --git a/tests/projects/c++/modules/precompile_reduced_bmi/xmake.lua b/tests/projects/c++/modules/precompile_reduced_bmi/xmake.lua new file mode 100644 index 000000000..0aa2dc516 --- /dev/null +++ b/tests/projects/c++/modules/precompile_reduced_bmi/xmake.lua @@ -0,0 +1,6 @@ +add_rules("mode.release", "mode.debug") +set_languages("c++20") + +target("precompile_reduced_bmi") + set_kind("binary") + add_files("src/*.cpp", "src/*.mpp") diff --git a/tests/projects/c++/modules/stdmodules_deps/src/bar.mpp b/tests/projects/c++/modules/stdmodules_deps/src/bar.mpp index 001cd7c2d..ab104076c 100644 --- a/tests/projects/c++/modules/stdmodules_deps/src/bar.mpp +++ b/tests/projects/c++/modules/stdmodules_deps/src/bar.mpp @@ -4,11 +4,9 @@ import std; export auto my_sum2(std::size_t a, std::size_t b) -> std::size_t; -#if defined(__GNUC__) && !defined(__clang__) -inline -#else -module :private; -#endif - auto my_sum2(std::size_t a, std::size_t b) -> std::size_t { +// Clang 23 implements P1857R3, which rejects module directives controlled by +// preprocessing conditionals. This test therefore uses an inline definition. +// See https://wg21.link/P1857R3 +inline auto my_sum2(std::size_t a, std::size_t b) -> std::size_t { return a + a + b + b; } diff --git a/tests/projects/c++/modules/test_base.lua b/tests/projects/c++/modules/test_base.lua index 372229695..2d0fa3f57 100644 --- a/tests/projects/c++/modules/test_base.lua +++ b/tests/projects/c++/modules/test_base.lua @@ -103,6 +103,9 @@ function build_tests(toolchain_name, opt) local policies = "--policies=build.c++.modules.std:" .. (opt.stdmodule and "y" or "n") policies = policies .. ",build.c++.modules.fallbackscanner:" .. (opt.fallbackscanner and "y" or "n") policies = policies .. ",build.c++.modules.two_phases:" .. (two_phases and "y" or "n") + if opt.precompile_reduced_bmi ~= nil then + policies = policies .. ",build.c++.modules.clang.precompile_reduced_bmi:" .. (opt.precompile_reduced_bmi and "y" or "n") + end local platform = " " if opt.platform then @@ -127,7 +130,7 @@ function build_tests(toolchain_name, opt) os.exec("xmake clean -a") os.exec("xmake f" .. platform .. "--toolchain=" .. toolchain_name .. runtimes .. "-c --yes " .. policies .. flags) if opt.build then - opt.build() + opt.build(table.join(opt, {toolchain = toolchain_name, two_phases = two_phases})) else _build(opt.check_outdata) end @@ -150,9 +153,12 @@ function run_tests(clang_options, gcc_options, msvc_options) if not clang_options.disable_clang_cl then local clang_cl_options = table.clone(clang_options) clang_cl_options.compiler = "clang-cl" - clang_cl_options.version = clang_cl_min_ver() + local clang_cl_minver = clang_cl_min_ver() + if semver.compare(clang_cl_options.version, clang_cl_minver) < 0 then + clang_cl_options.version = clang_cl_minver + end build_tests("clang-cl", clang_cl_options) - build_tests("clang-cl", table.join(clang_options, {two_phases = false})) + build_tests("clang-cl", table.join(clang_cl_options, {two_phases = false})) end if clang_options.stdmodule then wprint("std modules tests skipped for Windows clang libc++ as it's not currently supported officially") diff --git a/xmake/core/base/poller.lua b/xmake/core/base/poller.lua index bb18dfda4..43c3bea1a 100644 --- a/xmake/core/base/poller.lua +++ b/xmake/core/base/poller.lua @@ -124,7 +124,7 @@ function poller:remove(obj) end -- remove poller object data - self:_pollerdata_set(obj, nil) + self:_pollerdata_set(obj:cdata(), nil) return true end @@ -153,13 +153,15 @@ function poller:wait(timeout) local otype = v[1] local cdata = v[2] local events = v[3] - local pollerdata = self:_pollerdata(cdata) - if not pollerdata then - return -1, string.format("no object data for cdata(%s)!", cdata) + -- this object may have been removed from the poller while its event + -- was already collected, e.g. a pending overlapped io on windows, + -- we just drop it, it has no owner any more, @see poller:remove() + local pollerdata = self:_pollerdata(cdata) + if pollerdata then + local obj = pollerdata[1] + assert(obj and obj:otype() == otype and obj:cdata() == cdata) + table.insert(results, {obj, events, pollerdata[2]}) end - local obj = pollerdata[1] - assert(obj and obj:otype() == otype and obj:cdata() == cdata) - table.insert(results, {obj, events, pollerdata[2]}) end end return count, results diff --git a/xmake/core/base/scheduler.lua b/xmake/core/base/scheduler.lua index a59c38207..4ae8d74e0 100644 --- a/xmake/core/base/scheduler.lua +++ b/xmake/core/base/scheduler.lua @@ -304,9 +304,17 @@ end function scheduler:_poller_events_cb(obj, events) -- get poller object data + -- + -- the object may have been cancelled while its event was already queued, + -- e.g. a process which exits right after we stopped waiting for it, + -- @see scheduler:poller_cancel() + -- + -- such an event has no owner any more, we just drop it: it is not an + -- error of the scheduler and it must not abort the whole loop local pollerdata = self:_poller_data(obj) if not pollerdata then - return false, string.format("%s: cannot get poller data!", obj) + utils.dprint("%s: drop the event(%d), it has been cancelled!", obj, events) + return true end -- is process/fwatcher object? @@ -1068,6 +1076,10 @@ function scheduler:poller_waitproc(obj, timeout) running:waitobj_set(obj) -- wait + -- + -- @note we keep this process in the poller if it is timeout, so its exit status + -- is still saved as a pending status when it exits later, and the next wait + -- returns it immediately, @see scheduler:_poller_events_cb() local ok = self:co_suspend() return ok, pollerdata.object_event end diff --git a/xmake/core/base/task.lua b/xmake/core/base/task.lua index 2cd1fa58a..2b3788603 100644 --- a/xmake/core/base/task.lua +++ b/xmake/core/base/task.lua @@ -24,6 +24,7 @@ local task = task or {} -- load modules local os = require("base/os") local table = require("base/table") +local utils = require("base/utils") local string = require("base/string") local global = require("base/global") local hashset = require("base/hashset") @@ -84,17 +85,18 @@ end function task._directories() local dirs = task._DIRECTORIES if dirs == nil then - dirs = { - path.join(global.directory(), "plugins"), - path.join(os.programdir(), "plugins"), - path.join(os.programdir(), "actions")} - - -- add the plugins of the installed addons, e.g. ~/.xmake/addons/<name>/<version>/plugins + -- add the plugins of the installed addons first, e.g. ~/.xmake/addons/<name>/<version>/plugins -- -- we get them from the addons registry file directly, -- so we do not need to scan the whole addons directory on startup -- - table.join2(dirs, addon.payloads("plugins")) + -- @note the first one wins, so an addon is able to take over a deprecated + -- builtin plugin, e.g. `xmake format` + -- + dirs = addon.payloads("plugins") + table.insert(dirs, path.join(global.directory(), "plugins")) + table.insert(dirs, path.join(os.programdir(), "plugins")) + table.insert(dirs, path.join(os.programdir(), "actions")) task._DIRECTORIES = dirs end return dirs @@ -401,8 +403,9 @@ end -- is the given plugin conflicting with the loaded one? -- --- the plugins are not namespaced, so we need to report the conflicts of the addons, --- otherwise we do not know which plugin will be run +-- the plugins are not namespaced, so the first one always wins, @see task._directories(), +-- but we need to report the conflicts of the addons, otherwise we do not know which +-- plugin will be run -- -- @param taskname the task name -- @param taskfile the task file of the loaded plugin, it will be nil if it's the first one @@ -413,16 +416,15 @@ function task._is_conflicting(taskname, taskfile, filepath) return false end - -- we only report it if one of them comes from an addon, the builtin plugins - -- and the plugins in the global directory are always overridable - local addondir = path.absolute(addon.installdir()) - if not path.absolute(taskfile):startswith(addondir) and not path.absolute(filepath):startswith(addondir) then - return false - end - + -- we only report it if both of them come from the addons, taking over a builtin + -- plugin is expected, e.g. `xmake format` has been moved to an addon + -- -- @note we cannot raise errors here, otherwise all the commands will be broken, -- and the user cannot even remove the conflicting addons - utils.warning("plugin(%s) conflicts, we will use the first one!\n -> %s\n -> %s", taskname, taskfile, filepath) + local addondir = path.absolute(addon.installdir()) + if path.absolute(taskfile):startswith(addondir) and path.absolute(filepath):startswith(addondir) then + utils.warning("plugin(%s) conflicts, we will use the first one!\n -> %s\n -> %s", taskname, taskfile, filepath) + end return true end diff --git a/xmake/core/package/addon.lua b/xmake/core/package/addon.lua index e35a58317..d6798f56f 100644 --- a/xmake/core/package/addon.lua +++ b/xmake/core/package/addon.lua @@ -168,12 +168,19 @@ function addon._check_conflicts(dirname, addoninfo) end -- the global modules can also conflict with the builtin and the user modules + -- + -- @note the `core.*` modules are in the core directory of the sandbox, + -- they are not in `<programdir>/modules`, + -- @see core/sandbox/modules/import/core/sandbox/module.lua + local moduledirs = {path.join(os.programdir(), "modules"), + path.join(os.programdir(), "core", "sandbox", "modules", "import"), + path.join(global.directory(), "modules")} for _, name in ipairs(addoninfo.globalmodules or {}) do local modulepath = (name:gsub("%.", "/")) .. ".lua" - for _, moduledir in ipairs({os.programdir(), global.directory()}) do - if os.isfile(path.join(moduledir, "modules", modulepath)) then + for _, moduledir in ipairs(moduledirs) do + if os.isfile(path.join(moduledir, modulepath)) then return string.format("global module(%s) conflicts, it has been provided by %s!\nplease rename it in the addon manifest.", - name, moduledir == os.programdir() and "xmake" or path.join(moduledir, "modules")) + name, moduledir:startswith(os.programdir()) and "xmake" or moduledir) end end end diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua index 2d2720fba..3d98a3743 100644 --- a/xmake/core/package/package.lua +++ b/xmake/core/package/package.lua @@ -2117,11 +2117,17 @@ function _instance:fetch(opt) -- always install to the local project directory? -- @see https://github.com/xmake-io/xmake/pull/4376 + -- + -- @note the host packages are the tools which build the other packages, e.g. the toolchains, + -- they do not depend on the project configuration and they are shared between the projects, + -- so they are only installed locally with their own policy + -- @see https://github.com/xmake-io/xmake/issues/7716 + local policyname = self:is_host() and "package.host.install_locally" or "package.install_locally" local install_locally - if project and project.policy("package.install_locally") then + if project and project.policy(policyname) then install_locally = true end - if install_locally == nil and self:policy("package.install_locally") then + if install_locally == nil and self:policy(policyname) then install_locally = true end if not self:is_local() and install_locally and system ~= true then @@ -3110,12 +3116,20 @@ end -- -- @param opt the options, e.g. {localdir = true} -- - localdir: return the local project packages directory (build/.packages) --- instead of the global directory (~/.xmake/packages) +-- instead of the global directory (~/.xmake/packages), +-- it can be overridden with `XMAKE_PKG_LOCALDIR` -- -- @return the install directory path -- function package.installdir(opt) if opt and opt.localdir then + -- the parent process passes its local directory to the sub-process which builds + -- a package, so the packages it installs locally land in the same place and are + -- not installed twice, @see https://github.com/xmake-io/xmake/issues/7716 + local localdir = os.getenv("XMAKE_PKG_LOCALDIR") + if localdir then + return path.normalize(path.absolute(localdir)) + end return path.join(config.builddir({absolute = true}), ".packages") end local installdir = package._INSTALLDIR diff --git a/xmake/core/platform/menu.lua b/xmake/core/platform/menu.lua index cec901ee8..77a57381d 100644 --- a/xmake/core/platform/menu.lua +++ b/xmake/core/platform/menu.lua @@ -42,7 +42,7 @@ function _remote_build_is_connected() local projectdir = os.projectdir() local projectfile = os.projectfile() if projectfile and os.isfile(projectfile) and projectdir then - local workdir = path.join(config.directory(), "remote_build") + local workdir = path.join(config.directory(), "service", "remote_build") local statusfile = path.join(workdir, "status.txt") if os.isfile(statusfile) then local status = io.load(statusfile) diff --git a/xmake/core/project/policy.lua b/xmake/core/project/policy.lua index 617a792d6..bcda37858 100644 --- a/xmake/core/project/policy.lua +++ b/xmake/core/project/policy.lua @@ -83,6 +83,8 @@ function policy.policies() ["build.c++.modules.hide_dependencies"] = {description = "Hide dependencies from the commandline when build C++ modules.", default = false, type = "boolean"}, -- Enable two phase compilation for C++ modules if supported by the compiler ["build.c++.modules.two_phases"] = {description = "Enable two phase compilation if supported.", default = true, type = "boolean"}, + -- Use --precompile-reduced-bmi for Clang two-phase module compilation if supported + ["build.c++.modules.clang.precompile_reduced_bmi"] = {description = "Use --precompile-reduced-bmi for Clang two-phase module compilation if supported.", default = false, type = "boolean"}, -- Enable std module ["build.c++.modules.std"] = {description = "Enable std modules.", default = true, type = "boolean"}, -- Enable unreferenced and non-public named module culling @@ -158,6 +160,12 @@ function policy.policies() ["package.install_always"] = {description = "Always install packages every time.", type = "boolean"}, -- Install packages in the local project folder ["package.install_locally"] = {description = "Install packages in the local project folder.", default = false, type = "boolean"}, + -- Install the host packages in the local project folder + -- + -- the host packages are the tools which build the other packages, e.g. the toolchains, + -- they do not depend on the project configuration and they are shared between the projects, + -- so they have their own policy, @see https://github.com/xmake-io/xmake/issues/7716 + ["package.host.install_locally"] = {description = "Install the host packages in the local project folder.", default = false, type = "boolean"}, -- Keep package source code after installing (disable source dir cleanup) ["package.keep_source"] = {description = "Keep package source code after installing.", default = false, type = "boolean"}, -- Set custom headers when downloading package diff --git a/xmake/core/sandbox/modules/import/core/base/scheduler.lua b/xmake/core/sandbox/modules/import/core/base/scheduler.lua index 222bee391..a3f9741c3 100644 --- a/xmake/core/sandbox/modules/import/core/base/scheduler.lua +++ b/xmake/core/sandbox/modules/import/core/base/scheduler.lua @@ -96,7 +96,11 @@ end -- resume the given coroutine function sandbox_core_base_scheduler.co_resume(co, ...) - return scheduler:resume(co:thread(), ...) + local ok, errors = scheduler:co_resume(co, ...) + if not ok then + raise(errors) + end + return ok, errors end -- suspend the current coroutine diff --git a/xmake/core/sandbox/modules/import/lib/lua/error.lua b/xmake/core/sandbox/modules/import/lib/lua/error.lua new file mode 100644 index 000000000..4f38f1647 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/error.lua @@ -0,0 +1,36 @@ +--!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 error.lua +-- + +-- the native lua `error` +-- +-- it is not in the sandbox by default, `raise` is the one to use: it formats the +-- message and it is what `try`/`catch` understands. `error` is the plain one, for the +-- code which wants to throw a value rather than a message +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.error") +-- +-- error("something went wrong") +-- error({code = 1}) -- a value, not a message +-- +return error diff --git a/xmake/core/sandbox/modules/import/lib/lua/getmetatable.lua b/xmake/core/sandbox/modules/import/lib/lua/getmetatable.lua new file mode 100644 index 000000000..fcef76eb3 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/getmetatable.lua @@ -0,0 +1,32 @@ +--!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 getmetatable.lua +-- + +-- the native lua `getmetatable` +-- +-- @note the same in lua 5.1 and 5.4, it returns the `__metatable` field when the +-- metatable is protected +-- +-- e.g. +-- +-- import("lib.lua.getmetatable") +-- +-- local mt = getmetatable(obj) +-- +return getmetatable diff --git a/xmake/core/sandbox/modules/import/lib/lua/next.lua b/xmake/core/sandbox/modules/import/lib/lua/next.lua new file mode 100644 index 000000000..65313dd1a --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/next.lua @@ -0,0 +1,36 @@ +--!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 next.lua +-- + +-- the native lua `next` +-- +-- it is not in the sandbox by default, `pairs` covers the iteration of a table. `next` +-- is what is left for the two things `pairs` cannot say: whether a table is empty, and +-- stepping a traversal by hand +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.next") +-- +-- if next(tbl) == nil then ... end -- the table is empty +-- local key, value = next(tbl) -- the first entry, in no particular order +-- +return next diff --git a/xmake/core/sandbox/modules/import/lib/lua/pcall.lua b/xmake/core/sandbox/modules/import/lib/lua/pcall.lua new file mode 100644 index 000000000..1ad150943 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/pcall.lua @@ -0,0 +1,36 @@ +--!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 pcall.lua +-- + +-- the native lua `pcall` +-- +-- it is not in the sandbox by default, `try`/`catch` is the idiomatic way to handle the +-- errors of a script, and it keeps the traceback and the error message which xmake +-- builds. `pcall` is the plain one, for the code which only needs a boolean +-- +-- @note the same in lua 5.1 and 5.4. `xpcall` is not exported, its message handler +-- takes the extra arguments only since 5.2 +-- +-- e.g. +-- +-- import("lib.lua.pcall") +-- +-- local ok, result = pcall(function () return 1 end) +-- +return pcall diff --git a/xmake/core/sandbox/modules/import/lib/lua/rawequal.lua b/xmake/core/sandbox/modules/import/lib/lua/rawequal.lua new file mode 100644 index 000000000..b9f9ea683 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/rawequal.lua @@ -0,0 +1,33 @@ +--!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 rawequal.lua +-- + +-- the native lua `rawequal` +-- +-- it compares two values without going through the `__eq` metamethod +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.rawequal") +-- +-- if rawequal(a, b) then ... end +-- +return rawequal diff --git a/xmake/core/sandbox/modules/import/lib/lua/rawget.lua b/xmake/core/sandbox/modules/import/lib/lua/rawget.lua new file mode 100644 index 000000000..fe5115001 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/rawget.lua @@ -0,0 +1,34 @@ +--!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 rawget.lua +-- + +-- the native lua `rawget` +-- +-- it reads a field of a table without going through its `__index` metamethod, so it +-- sees what the table itself holds and not what its metatable would answer +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.rawget") +-- +-- local value = rawget(tbl, "key") +-- +return rawget diff --git a/xmake/core/sandbox/modules/import/lib/lua/rawset.lua b/xmake/core/sandbox/modules/import/lib/lua/rawset.lua new file mode 100644 index 000000000..917bc3d86 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/rawset.lua @@ -0,0 +1,33 @@ +--!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 rawset.lua +-- + +-- the native lua `rawset` +-- +-- it writes a field of a table without going through its `__newindex` metamethod +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.rawset") +-- +-- rawset(tbl, "key", value) +-- +return rawset diff --git a/xmake/core/sandbox/modules/import/lib/lua/select.lua b/xmake/core/sandbox/modules/import/lib/lua/select.lua new file mode 100644 index 000000000..45fb1bbc9 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/select.lua @@ -0,0 +1,36 @@ +--!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 select.lua +-- + +-- the native lua `select` +-- +-- it is not in the sandbox by default, the scripts of a project rarely need to look at +-- a raw argument list, but it is the only way to count the arguments of a vararg +-- function without losing the nils in it +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.select") +-- +-- local count = select("#", ...) -- how many arguments, nils included +-- local second = select(2, ...) -- everything from the second one on +-- +return select diff --git a/xmake/core/sandbox/modules/import/lib/lua/setmetatable.lua b/xmake/core/sandbox/modules/import/lib/lua/setmetatable.lua new file mode 100644 index 000000000..6f1d4c330 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/setmetatable.lua @@ -0,0 +1,36 @@ +--!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 setmetatable.lua +-- + +-- the native lua `setmetatable` +-- +-- it is not in the sandbox by default: a module which builds objects with metatables is +-- a module which is hard to serialize and to cache, and xmake passes plain tables +-- around on purpose. it is here for the code which really wants operator overloading or +-- an `__index` fallback +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.setmetatable") +-- +-- local obj = setmetatable({}, {__index = function (tbl, key) return "?" end}) +-- +return setmetatable diff --git a/xmake/languages/c/load.lua b/xmake/languages/c/load.lua index a265f0dbd..7497cc004 100644 --- a/xmake/languages/c/load.lua +++ b/xmake/languages/c/load.lua @@ -61,6 +61,7 @@ function _get_apis() , "package.add_defines" , "package.add_undefines" , "package.add_frameworks" + , "package.add_vectorexts" , "package.add_rpathdirs" , "package.add_linkdirs" , "package.add_includedirs" --@note we need not uses paths for package, see https://github.com/xmake-io/xmake/issues/717 diff --git a/xmake/modules/detect/sdks/find_mingw.lua b/xmake/modules/detect/sdks/find_mingw.lua index c70bebb11..d6d7e0d8e 100644 --- a/xmake/modules/detect/sdks/find_mingw.lua +++ b/xmake/modules/detect/sdks/find_mingw.lua @@ -108,7 +108,8 @@ function _find_mingw(sdkdir, opt) -- find cross toolchain local toolchain = find_cross_toolchain(sdkdir or bindir, {bindir = bindir, cross = cross}) - if not toolchain then -- fallback, e.g. gcc.exe without cross + -- fallback, e.g. gcc.exe without cross + if not toolchain and (is_host("windows") or is_subhost("msys", "cygwin")) then toolchain = find_cross_toolchain(sdkdir or bindir, {bindir = bindir}) end if toolchain then diff --git a/xmake/modules/package/tools/xmake.lua b/xmake/modules/package/tools/xmake.lua index 4efee0974..305074df0 100644 --- a/xmake/modules/package/tools/xmake.lua +++ b/xmake/modules/package/tools/xmake.lua @@ -283,6 +283,14 @@ function _get_configs(package, configs, opt) if not package:use_external_includes() and (not policies or not policies:find("package.include_external_headers", 1, true)) then table.insert(policies_list, "package.include_external_headers:n") end + -- the sub-process must install its packages locally too, otherwise they go to the + -- global directory while we expect them under our build directory, + -- @see https://github.com/xmake-io/xmake/issues/7716 + for _, policyname in ipairs({"package.install_locally", "package.host.install_locally"}) do + if project.policy(policyname) and (not policies or not policies:find(policyname, 1, true)) then + table.insert(policies_list, policyname) + end + end if policies and policies:find("package.build.ccache", 1, true) then table.insert(configs, "--ccachedir=" .. path.join(path.directory(package:cachedir()), "build_cache")) table.insert(policies_list, "build.ccache") @@ -527,14 +535,19 @@ function install(package, configs, opt) -- get build environments local envs = opt.envs or buildenvs(package) - -- if the package is installed locally, pass the local packages directory - -- to the child xmake process so it can find already-installed deps - -- without re-installing them to the global directory + -- if the package is installed locally, pass our local packages directory to the + -- child xmake process, so the packages it installs locally land in the same place + -- and the deps we have already installed are found instead of installed again + -- + -- @note we must not override `XMAKE_PKG_INSTALLDIR` here: it is the *global* root + -- of the child, and overriding it hides `~/.xmake/packages` from it, so the host + -- packages it needs (e.g. the toolchains) would be installed again under our + -- build directory, @see https://github.com/xmake-io/xmake/issues/7716 + -- -- @see https://github.com/xmake-io/xmake/discussions/7441 if package:is_local() and not package:is_source_embed() then envs = table.clone(envs) - envs.XMAKE_PKG_INSTALLDIR = package_core.installdir({localdir = true}) - envs.XMAKE_PKG_CACHEDIR = package_core.cachedir({localdir = true}) + envs.XMAKE_PKG_LOCALDIR = package_core.installdir({localdir = true}) end -- pass local repositories diff --git a/xmake/modules/private/utils/toolchain.lua b/xmake/modules/private/utils/toolchain.lua index bd673fa0c..3b4fe8296 100644 --- a/xmake/modules/private/utils/toolchain.lua +++ b/xmake/modules/private/utils/toolchain.lua @@ -695,7 +695,7 @@ function get_zig_target(toolchain) end if toolchain:is_plat("cross") then - -- xmake f -p cross --toolchain=zig --cross=mips64el-linux-gnuabi64 + -- xmake f -p cross --toolchain=zigcc --cross=mips64el-linux-gnuabi64 elseif toolchain:is_plat("macosx") then --@see https://github.com/ziglang/zig/issues/14226 target = arch .. "-macos-none" diff --git a/xmake/platforms/bsd/xmake.lua b/xmake/platforms/bsd/xmake.lua index 98143d019..89ab580fe 100644 --- a/xmake/platforms/bsd/xmake.lua +++ b/xmake/platforms/bsd/xmake.lua @@ -21,7 +21,7 @@ platform("bsd") set_os("bsd") set_hosts("bsd") - set_archs("i386", "x86_64") + set_archs("i386", "x86_64", "arm", "arm64", "ppc", "ppc64", "ppc64el", "riscv64", "sparc64") set_formats("static", "lib$(name).a") set_formats("object", "$(name).o") @@ -53,5 +53,3 @@ platform("bsd") , {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" } } } - - diff --git a/xmake/platforms/cross/xmake.lua b/xmake/platforms/cross/xmake.lua index 98bb31634..462fc961b 100644 --- a/xmake/platforms/cross/xmake.lua +++ b/xmake/platforms/cross/xmake.lua @@ -20,7 +20,7 @@ platform("cross") set_hosts("macosx", "linux", "windows", "bsd") - set_archs("i386", "x86_64", "arm", "arm64", "mips", "mips64", "riscv", "riscv64", "loong64", "s390x", "ppc", "ppc64", "sh4") + set_archs("i386", "x86_64", "arm", "armv7", "arm64", "mips", "mips64", "mips64el", "riscv", "riscv64", "loong64", "s390x", "ppc", "ppc64", "ppc64el", "sh4", "sparc64") set_formats("static", "lib$(name).a") set_formats("object", "$(name).o") @@ -28,5 +28,3 @@ platform("cross") set_formats("symbol", "$(name).sym") set_toolchains("envs", "cross") - - diff --git a/xmake/platforms/linux/xmake.lua b/xmake/platforms/linux/xmake.lua index c4d09880e..c26f99fb5 100644 --- a/xmake/platforms/linux/xmake.lua +++ b/xmake/platforms/linux/xmake.lua @@ -21,7 +21,7 @@ platform("linux") set_os("linux") set_hosts("macosx", "linux", "windows", "bsd") - set_archs("i386", "x86_64", "armv7", "armv7s", "arm64", "mips", "mips64", "mipsel", "mips64el", "loong64") + set_archs("i386", "x86_64", "armv7", "armv7s", "arm64", "mips", "mips64", "mipsel", "mips64el", "loong64", "riscv64", "s390x", "ppc", "ppc64", "ppc64el", "sparc64") set_formats("static", "lib$(name).a") set_formats("object", "$(name).o") diff --git a/xmake/platforms/solaris/xmake.lua b/xmake/platforms/solaris/xmake.lua index 5abdde4fb..260bc138b 100644 --- a/xmake/platforms/solaris/xmake.lua +++ b/xmake/platforms/solaris/xmake.lua @@ -21,7 +21,7 @@ platform("solaris") set_os("solaris") set_hosts("solaris") - set_archs("i386", "x86_64") + set_archs("i386", "x86_64", "sparc64") set_formats("static", "lib$(name).a") set_formats("object", "$(name).o") @@ -53,5 +53,3 @@ platform("solaris") , {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" } } } - - diff --git a/xmake/plugins/doxygen/main.lua b/xmake/plugins/doxygen/main.lua index 80fd77675..b84754cb2 100644 --- a/xmake/plugins/doxygen/main.lua +++ b/xmake/plugins/doxygen/main.lua @@ -71,6 +71,10 @@ end function main() + -- @note we cannot use utils.warning() here, it's queued and only shown at the end + cprint("${bright color.warning}${text.warning}: ${color.warning}the builtin `xmake doxygen` plugin is deprecated, " .. + "please use the doxygen-plugin addon: `xmake addon --install doxygen-plugin`") + -- load configuration config.load() diff --git a/xmake/plugins/format/main.lua b/xmake/plugins/format/main.lua index 408de0421..c8f50a15e 100644 --- a/xmake/plugins/format/main.lua +++ b/xmake/plugins/format/main.lua @@ -103,6 +103,10 @@ end -- main function main() + -- @note we cannot use utils.warning() here, it's queued and only shown at the end + cprint("${bright color.warning}${text.warning}: ${color.warning}the builtin `xmake format` plugin is deprecated, " .. + "please use the format-plugin addon: `xmake addon --install format-plugin`") + -- load configuration config.load() diff --git a/xmake/plugins/macro/main.lua b/xmake/plugins/macro/main.lua index 86b50e2da..6c2c8c734 100644 --- a/xmake/plugins/macro/main.lua +++ b/xmake/plugins/macro/main.lua @@ -309,6 +309,10 @@ end -- main function main() + -- @note we cannot use utils.warning() here, it's queued and only shown at the end + cprint("${bright color.warning}${text.warning}: ${color.warning}the builtin `xmake macro` plugin is deprecated, " .. + "please use the macro-plugin addon: `xmake addon --install macro-plugin`") + -- list macros if option.get("list") then diff --git a/xmake/plugins/project/clang/compile_commands.lua b/xmake/plugins/project/clang/compile_commands.lua index 2f25194cc..a8fdb547f 100644 --- a/xmake/plugins/project/clang/compile_commands.lua +++ b/xmake/plugins/project/clang/compile_commands.lua @@ -69,10 +69,13 @@ end -- specify windows sdk verison function _get_windows_sdk_arguments(target) local args = {} - local msvc = target:toolchain("msvc") - if msvc then - local envs = msvc:runenvs() - if envs then + if target and target:is_plat("windows") then + local toolchain = target:toolchain("msvc") or + target:toolchain("clang-cl") or + target:toolchain("clang") or + target:toolchain("llvm") + local envs = toolchain and toolchain:runenvs() + if envs and envs.INCLUDE then for _, dir in ipairs(path.splitenv(envs.INCLUDE)) do table.insert(args, "-imsvc") table.insert(args, dir) diff --git a/xmake/rules/c++/modules/builder.lua b/xmake/rules/c++/modules/builder.lua index d0863ad98..b988ff152 100644 --- a/xmake/rules/c++/modules/builder.lua +++ b/xmake/rules/c++/modules/builder.lua @@ -194,6 +194,10 @@ function should_build(target, module) local dependinfo = {} dependinfo.files = {module.sourcefile} dependinfo.values = {compinst:program(), compflags} + if module.bmifile and not module.headerunit and support.has_two_phase_compilation_support(target) then + local bmi_mode = support.has_precompile_reduced_bmi_support(target) and support.get_modulesprecompilereducedbmiflag(target) or "--precompile" + table.insert(dependinfo.values, bmi_mode) + end local objectfile_exists = (module.headerunit or support.is_bmionly(target, module.sourcefile)) and true or os.isfile(module.objectfile) dependinfo.lastmtime = (os.isfile(module.bmifile or module.objectfile) and objectfile_exists) and os.mtime(dependfile) or 0 @@ -241,6 +245,7 @@ function build_modules_for_jobgraph(target, jobgraph, built_modules) profiler.enter(target:fullname(), "c++ modules", "builder", "schedule module bmi build jobs") local builder = _builder(target) local has_two_phase_compilation_support = support.has_two_phase_compilation_support(target) + local has_precompile_reduced_bmi = support.has_precompile_reduced_bmi_support(target) local jobdeps = {} local buildfilejobs = {} @@ -272,19 +277,24 @@ function build_modules_for_jobgraph(target, jobgraph, built_modules) local buildfilejob = _get_module_buildfilejob_for(target, sourcefile, moduletype) table.insert(buildfilejobs, buildfilejob) jobgraph:add(buildfilejob, function(_, _, jobopt) - progress.set_target(jobopt.progress, target) + local moduleopt = table.clone(jobopt) + progress.set_target(moduleopt.progress, target) -- build bmi if named job - jobopt.bmi = module.name + moduleopt.bmi = module.name -- build objectfile here if two phase compilation is not supported - jobopt.objectfile = not has_two_phase_compilation_support and not bmionly - builder.make_module_job(target, module, jobopt) + moduleopt.objectfile = not has_two_phase_compilation_support and not bmionly + builder.make_module_job(target, module, moduleopt) end) _merge_jobdeps(jobdeps, _get_jobdeps(target, module, jobgraph, buildfilejob)) -- if two phase compilation supported set jobdeps for objectfile job if has_two_phase_compilation_support and not bmionly then local objbuildfilejob = _get_module_buildfilejob_for(target, sourcefile, "objectfile") - _merge_jobdeps(jobdeps, {[objbuildfilejob] = {buildfilejob}}) + if has_precompile_reduced_bmi then + _merge_jobdeps(jobdeps, _get_jobdeps(target, module, jobgraph, objbuildfilejob)) + else + _merge_jobdeps(jobdeps, {[objbuildfilejob] = {buildfilejob}}) + end end end end) @@ -327,10 +337,11 @@ function build_objectfiles_for_jobgraph(target, jobgraph, built_modules) local module = mapper.get(target, sourcefile) local buildfilejob = _get_module_buildfilejob_for(target, sourcefile, "objectfile") jobgraph:add(buildfilejob, function(_, _, jobopt) - progress.set_target(jobopt.progress, target) - jobopt.bmi = false - jobopt.objectfile = true - builder.make_module_job(target, module, jobopt) + local moduleopt = table.clone(jobopt) + progress.set_target(moduleopt.progress, target) + moduleopt.bmi = false + moduleopt.objectfile = true + builder.make_module_job(target, module, moduleopt) end) end end @@ -719,6 +730,16 @@ function build_bmis(target, jobgraph, _, opt) local built_modules, built_headerunits, _ = scanner.sort_modules_by_dependencies(target, modules, {jobgraph = target:policy("build.jobgraph")}) local headerunits, stlheaderunits = scanner.sort_headerunits(target, built_headerunits) if jobgraph.add_orders then -- jobgraph + if support.has_precompile_reduced_bmi_support(target) then + -- schedule object jobs in the BMI stage so both jobs can run concurrently + -- after their imported BMIs are ready + local append_requires_flags = _builder(target).append_requires_flags + if append_requires_flags then + append_requires_flags(target, built_modules) + end + build_objectfiles_for_jobgraph(target, jobgraph, built_modules) + end + -- build headerunits if stlheaderunits or headerunits then build_headerunits_for_jobgraph(target, jobgraph, stlheaderunits, headerunits) @@ -760,6 +781,10 @@ function build_objectfiles(target, jobgraph, _, opt) if target:is_moduleonly() and not target:data("cxx.modules.reused") or target:is_phony() then return end + if jobgraph.add_orders and support.has_precompile_reduced_bmi_support(target) then + -- object jobs have already been scheduled by build_bmis() + return + end profiler.enter(target:fullname(), "c++ modules", "builder", "objectfiles") local modules = scanner.get_modules(target) -- avoid building non referenced modules diff --git a/xmake/rules/c++/modules/clang/builder.lua b/xmake/rules/c++/modules/clang/builder.lua index 4839733e0..4ecafb17e 100644 --- a/xmake/rules/c++/modules/clang/builder.lua +++ b/xmake/rules/c++/modules/clang/builder.lua @@ -65,6 +65,8 @@ function _make_modulebuildflags(target, module, opt) local modules_reduced_bmi_flag = support.get_modulesreducedbmiflag(target) local has_two_phases = target:policy("build.c++.modules.two_phases") + local has_precompile_reduced_bmi = support.has_precompile_reduced_bmi_support(target) + local modules_precompile_reduced_bmi_flag = has_precompile_reduced_bmi and support.get_modulesprecompilereducedbmiflag(target) local flags if opt.bmi then local module_outputflag = support.get_moduleoutputflag(target) @@ -72,7 +74,7 @@ function _make_modulebuildflags(target, module, opt) flags = {"-x", "c++-module"} if not opt.objectfile then - table.insert(flags, "--precompile") + table.insert(flags, modules_precompile_reduced_bmi_flag or "--precompile") if target:has_tool("cxx", "clang_cl") then table.join2(flags, "/clang:-o", "/clang:" .. module.bmifile) end @@ -92,7 +94,7 @@ function _make_modulebuildflags(target, module, opt) end else flags = {} - if not has_two_phases or not module.bmifile then + if (has_precompile_reduced_bmi and support.has_module_extension(module.sourcefile)) or not has_two_phases or not module.bmifile then flags = {"-x", "c++"} end local std = (module.name == "std" or module.name == "std.compat") @@ -171,7 +173,7 @@ function _compile(target, flags, module, opt) opt = opt or {} local sourcefile = module.sourcefile - if not opt.bmi and opt.objectfile and module.bmifile then + if not support.has_precompile_reduced_bmi_support(target) and not opt.bmi and opt.objectfile and module.bmifile then sourcefile = module.bmifile end local outputfile = ((opt.bmi and not opt.objectfile) or opt.headerunit) and module.bmifile or module.objectfile diff --git a/xmake/rules/c++/modules/clang/scanner.lua b/xmake/rules/c++/modules/clang/scanner.lua index d73c40621..f0023cb7c 100644 --- a/xmake/rules/c++/modules/clang/scanner.lua +++ b/xmake/rules/c++/modules/clang/scanner.lua @@ -59,7 +59,8 @@ function scan_dependency_for(target, sourcefile, rescan, opt) if option.get("verbose") then print(os.args(table.join(clangscandeps, dependency_flags))) end - local outdata, errdata = os.iorunv(clangscandeps, dependency_flags) + local outdata, errdata = os.iorunv(clangscandeps, dependency_flags, + {envs = compinst:runenvs()}) assert(outdata, errdata) io.writefile(jsonfile, outdata) @@ -77,7 +78,7 @@ function scan_dependency_for(target, sourcefile, rescan, opt) end) local ifile = path.translate(path.join(outputdir, path.filename(file) .. ".i")) compflags = table.join(compflags or {}, keepsystemincludesflag or {}, {"-E", "-x", "c++", file, "-o", ifile}) - os.vrunv(compinst:program(), compflags) + os.vrunv(compinst:program(), compflags, {envs = compinst:runenvs()}) local content = io.readfile(ifile) os.rm(ifile) return content diff --git a/xmake/rules/c++/modules/clang/support.lua b/xmake/rules/c++/modules/clang/support.lua index b1699d21a..a010fdde1 100644 --- a/xmake/rules/c++/modules/clang/support.lua +++ b/xmake/rules/c++/modules/clang/support.lua @@ -46,7 +46,10 @@ function _get_toolchain_includedirs_for_stlheaders(target, includedirs, clang) table.insert(argv, 1, "-stdlib=libstdc++") end end - local result = try {function () return os.iorunv(clang, argv, {envs = compinst:runenvs()}) end} + local compinst = target:compiler("cxx") + local result = try {function () + return os.iorunv(clang, argv, {envs = compinst and compinst:runenvs()}) + end} if result then for _, line in ipairs(result:split("\n", {plain = true})) do local line = line:trim() @@ -64,17 +67,25 @@ end function _get_std_module_manifest_path(target) local print_module_manifest_flag = get_print_library_module_manifest_path_flag(target) - local clang_path = path.directory(get_clang_path(target)) + local clang_path = get_clang_path(target) + if not clang_path then + return + end + local clang_dir = path.directory(clang_path) if print_module_manifest_flag then local compinst = target:compiler("cxx") - local outdata, _ = try { function() return os.iorunv(compinst:program(), {"-std=c++23", "-stdlib=libc++", "--sysroot=" .. path.join(clang_path, ".."), print_module_manifest_flag}, {envs = compinst:runenvs()}) end } + local sysroot = "--sysroot=" .. path.join(clang_dir, "..") + local flags = {"-std=c++23", "-stdlib=libc++", sysroot, print_module_manifest_flag} + local outdata, _ = try {function() + return os.iorunv(compinst:program(), flags, {envs = compinst:runenvs()}) + end} if outdata and not outdata:startswith("<NOT PRESENT>") then return outdata:trim() end end -- fallback on custom detection -- manifest can be found in <llvm_path>/lib subdirectory (i.e on debian it should be <llvm_path>/lib/x86_64-unknown-linux-gnu/) - local clang_lib_path = path.join(clang_path, "..", "lib") + local clang_lib_path = path.join(clang_dir, "..", "lib") local modules_json_path = path.join(clang_lib_path, "libc++.modules.json") if not os.isfile(modules_json_path) then modules_json_path = find_file("*/libc++.modules.json", clang_lib_path) @@ -119,6 +130,13 @@ function has_two_phase_compilation_support(target) return target:policy("build.c++.modules.two_phases") end +function has_precompile_reduced_bmi_support(target) + if not target:policy("build.c++.modules.clang.precompile_reduced_bmi") or not has_two_phase_compilation_support(target) then + return false + end + return get_modulesprecompilereducedbmiflag(target) ~= nil +end + -- flags that doesn't affect bmi generation function strippeable_flags() -- speculative list as there is no resource that list flags that prevent reusability, this list will likely be improve over time @@ -161,7 +179,11 @@ function toolchain_includedirs(target) runtime_flag = "-stdlib=libstdc++" end end - local _, result = try {function () return os.iorunv(clang, table.join({"-E", "-Wp,-v", "-xc++", os.nuldev()}, runtime_flag or {})) end} + local compinst = target:compiler("cxx") + local flags = table.join({"-E", "-Wp,-v", "-xc++", os.nuldev()}, runtime_flag or {}) + local _, result = try {function () + return os.iorunv(clang, flags, {envs = compinst and compinst:runenvs()}) + end} if result then for _, line in ipairs(result:split("\n", {plain = true})) do local line = line:trim() @@ -183,8 +205,10 @@ function get_clang_path(target) if not clang_path then local program, toolname = target:tool("cxx") if program and toolname:startswith("clang") then + local compinst = target:compiler("cxx") + local envs = compinst and compinst:runenvs() or os.getenvs() local clang = find_tool(toolname, {program = program, - envs = os.getenvs(), cachekey = "modules_support_clang_" .. toolname}) + envs = envs, cachekey = "modules_support_clang_" .. toolname}) if clang then clang_path = clang.program end @@ -201,8 +225,10 @@ function get_clang_version(target) if not clang_version then local program, toolname = target:tool("cxx") if program and toolname:startswith("clang") then + local compinst = target:compiler("cxx") + local envs = compinst and compinst:runenvs() or os.getenvs() local clang = find_tool(toolname, {program = program, version = true, - envs = os.getenvs(), cachekey = "modules_support_clang_" .. toolname}) + envs = envs, cachekey = "modules_support_clang_" .. toolname}) if clang then clang_version = clang.version end @@ -229,10 +255,13 @@ function get_clang_scan_deps(target) if dir and dir ~= "." and os.isdir(dir) then program = path.join(dir, program) end - local result = find_tool("clang-scan-deps", {program = program, version = true}) + local compinst = target:compiler("cxx") + local envs = compinst and compinst:runenvs() or os.getenvs() + local result = find_tool("clang-scan-deps", + {program = program, version = true, envs = envs}) if not result then -- find a system wide alternative - result = find_tool("clang-scan-deps", {version = true}) + result = find_tool("clang-scan-deps", {version = true, envs = envs}) end if result then clang_scan_deps = result.program @@ -295,9 +324,16 @@ function get_stdmodules(target) return {path.normalize(path.join(try_std_module_directory, "std.cppm")), path.normalize(path.join(try_std_module_directory, "std.compat.cppm"))} end -- then try the directory relative to clang bin directory - try_std_module_directory = path.join(path.directory(get_original_file(get_clang_path(target))), std_module_directory) - if os.isdir(try_std_module_directory) then - return {path.normalize(path.join(try_std_module_directory, "std.cppm")), path.normalize(path.join(try_std_module_directory, "std.compat.cppm"))} + local clang_path = get_clang_path(target) + if clang_path then + local clang_dir = path.directory(get_original_file(clang_path)) + try_std_module_directory = path.join(clang_dir, std_module_directory) + if os.isdir(try_std_module_directory) then + return { + path.normalize(path.join(try_std_module_directory, "std.cppm")), + path.normalize(path.join(try_std_module_directory, "std.compat.cppm")) + } + end end elseif cpplib == "stdc++" then -- dont be greedy and don't enable stdc++ std module support for llvm < 19 @@ -382,6 +418,25 @@ function get_modulesreducedbmiflag(target) return modulesreducedbmiflag or nil end +function get_modulesprecompilereducedbmiflag(target) + local modulesprecompilereducedbmiflag = _g.modulesprecompilereducedbmiflag + if modulesprecompilereducedbmiflag == nil then + local compinst = target:compiler("cxx") + local checkflags = "--precompile-reduced-bmi" + if target:has_tool("cxx", "clang_cl") then + -- clang_cl.has_flags() appends -c and treats unused-argument warnings as errors, + -- but --precompile-reduced-bmi does not use -c. Ignore that specific warning and + -- treat unknown-argument warnings as errors to reject unsupported flags. + checkflags = {checkflags, "-Wno-unused-command-line-argument", "-Werror=unknown-argument"} + end + if compinst:has_flags(checkflags, "cxxflags", {flagskey = "clang_modules_precompile_reduced_bmi", tryrun = true}) then + modulesprecompilereducedbmiflag = "--precompile-reduced-bmi" + end + _g.modulesprecompilereducedbmiflag = modulesprecompilereducedbmiflag or false + end + return modulesprecompilereducedbmiflag or nil +end + function has_clangscandepssupport(target) local support_clangscandeps = _g.support_clangscandeps if support_clangscandeps == nil then diff --git a/xmake/rules/c++/modules/gcc/support.lua b/xmake/rules/c++/modules/gcc/support.lua index 1204d207d..e57bd5a63 100644 --- a/xmake/rules/c++/modules/gcc/support.lua +++ b/xmake/rules/c++/modules/gcc/support.lua @@ -79,6 +79,13 @@ function has_two_phase_compilation_support(_) return false end +function has_precompile_reduced_bmi_support(_) + return false +end + +function get_modulesprecompilereducedbmiflag(_) +end + -- flags that doesn't affect bmi generation function strippeable_flags() -- speculative list as there is no resource that list flags that prevent reusability, this list will likely be improve over time diff --git a/xmake/rules/c++/modules/msvc/support.lua b/xmake/rules/c++/modules/msvc/support.lua index 588921d0e..caaeb9cc6 100644 --- a/xmake/rules/c++/modules/msvc/support.lua +++ b/xmake/rules/c++/modules/msvc/support.lua @@ -120,6 +120,13 @@ function has_two_phase_compilation_support(_) return false end +function has_precompile_reduced_bmi_support(_) + return false +end + +function get_modulesprecompilereducedbmiflag(_) +end + -- build c++23 standard modules if needed function get_stdmodules(target, opt) opt = opt or {} diff --git a/xmake/rules/c++/modules/support.lua b/xmake/rules/c++/modules/support.lua index 126e25c61..78d74ae6c 100644 --- a/xmake/rules/c++/modules/support.lua +++ b/xmake/rules/c++/modules/support.lua @@ -92,7 +92,15 @@ function get_cpplibrary_name(target) end elseif target:is_plat("macosx", "iphoneos", "watchos", "appletvos", "applexros", "bsd", "harmony") then return "c++" - elseif target:is_plat("linux", "mingw", "cygwin", "msys", "haiku") then + elseif target:is_plat("linux", "cygwin", "msys", "haiku") then + return "stdc++" + elseif target:is_plat("mingw") then + local toolchain_inst = target:toolchain("mingw") + local is_clang = (toolchain_inst and toolchain_inst:config("clang")) or + target:has_tool("cxx", "clang", "clangxx", "clang_cl") + if is_clang then + return "c++" + end return "stdc++" elseif target:is_plat("windows") then return "msstl" @@ -103,6 +111,14 @@ function has_two_phase_compilation_support(target) return _support(target).has_two_phase_compilation_support(target) end +function has_precompile_reduced_bmi_support(target) + return _support(target).has_precompile_reduced_bmi_support(target) +end + +function get_modulesprecompilereducedbmiflag(target) + return _support(target).get_modulesprecompilereducedbmiflag(target) +end + -- strip flags not relevent for module reuse function strip_flags(target, flags, opt) @@ -429,4 +445,3 @@ function add_installfiles_for_modules(target, modules) end end end - diff --git a/xmake/toolchains/mingw/xmake.lua b/xmake/toolchains/mingw/xmake.lua index d0695dcfe..a75ab3cce 100644 --- a/xmake/toolchains/mingw/xmake.lua +++ b/xmake/toolchains/mingw/xmake.lua @@ -22,7 +22,7 @@ toolchain("mingw") set_kind("standalone") set_homepage("http://www.mingw.org/") set_description("Minimalist GNU for Windows") - set_runtimes("stdc++_static", "stdc++_shared") + set_runtimes("stdc++_static", "stdc++_shared", "c++_static", "c++_shared") on_check("check") on_load(function (toolchain) |
