summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/linux.yml9
-rw-r--r--CHANGELOG.md68
m---------core/src/tbox/tbox0
-rw-r--r--core/src/xmake/utf8/width.c6
-rw-r--r--core/xmake.lua2
-rwxr-xr-xcore/xmake.sh2
-rwxr-xr-xscripts/get.ps12
-rw-r--r--scripts/rpmbuild/xmake.spec2
-rw-r--r--tests/actions/addon/custom-override/addon.lua2
-rw-r--r--tests/actions/addon/custom-override/plugins/format/main.lua3
-rw-r--r--tests/actions/addon/custom-override/plugins/format/xmake.lua6
-rw-r--r--tests/actions/addon/projects/autofetch-badinclude/xmake-addons.lua2
-rw-r--r--tests/actions/addon/projects/autofetch-badinclude/xmake.lua2
-rw-r--r--tests/actions/addon/projects/autofetch-badname/xmake-addons.lua2
-rw-r--r--tests/actions/addon/projects/autofetch-badname/xmake.lua3
-rw-r--r--tests/actions/addon/projects/autofetch-build/xmake-addons.lua2
-rw-r--r--tests/actions/addon/projects/autofetch-build/xmake.lua3
-rw-r--r--tests/actions/addon/projects/autofetch-lockmiss/xmake-addons.lua1
-rw-r--r--tests/actions/addon/projects/autofetch-lockmiss/xmake.lua2
-rw-r--r--tests/actions/addon/projects/autofetch/xmake-addons.lua1
-rw-r--r--tests/actions/addon/projects/autofetch/xmake.lua3
-rw-r--r--tests/actions/addon/test.lua34
-rw-r--r--xmake/actions/addon/main.lua8
-rw-r--r--xmake/core/base/interpreter.lua95
-rw-r--r--xmake/core/base/poller.lua16
-rw-r--r--xmake/core/base/scheduler.lua14
-rw-r--r--xmake/core/base/task.lua36
-rw-r--r--xmake/core/package/addon.lua43
-rw-r--r--xmake/core/package/package.lua37
-rw-r--r--xmake/core/platform/menu.lua2
-rw-r--r--xmake/core/project/addons.lua110
-rw-r--r--xmake/core/project/policy.lua6
-rw-r--r--xmake/core/project/project.lua104
-rw-r--r--xmake/core/project/target.lua8
-rw-r--r--xmake/core/sandbox/modules/import/core/base/scheduler.lua6
-rw-r--r--xmake/core/sandbox/modules/import/core/package/addon.lua4
-rw-r--r--xmake/core/sandbox/modules/import/core/project/addons.lua17
-rw-r--r--xmake/languages/c/load.lua1
-rw-r--r--xmake/modules/detect/sdks/find_mingw.lua3
-rw-r--r--xmake/modules/package/tools/xmake.lua23
-rw-r--r--xmake/modules/private/action/addon/impl/install_addons.lua38
-rw-r--r--xmake/modules/private/utils/toolchain.lua2
-rw-r--r--xmake/platforms/bsd/xmake.lua4
-rw-r--r--xmake/platforms/cross/xmake.lua4
-rw-r--r--xmake/platforms/linux/xmake.lua2
-rw-r--r--xmake/platforms/solaris/xmake.lua4
-rw-r--r--xmake/plugins/doxygen/main.lua4
-rw-r--r--xmake/plugins/format/main.lua4
-rw-r--r--xmake/plugins/macro/main.lua4
-rw-r--r--xmake/rules/c++/modules/support.lua10
-rw-r--r--xmake/toolchains/mingw/xmake.lua2
51 files changed, 456 insertions, 312 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/projects/autofetch-badinclude/xmake-addons.lua b/tests/actions/addon/projects/autofetch-badinclude/xmake-addons.lua
deleted file mode 100644
index 6931855ae..000000000
--- a/tests/actions/addon/projects/autofetch-badinclude/xmake-addons.lua
+++ /dev/null
@@ -1,2 +0,0 @@
--- this file only declares the addons, it cannot reference them
-includes("@addon/custom-include/check")
diff --git a/tests/actions/addon/projects/autofetch-badinclude/xmake.lua b/tests/actions/addon/projects/autofetch-badinclude/xmake.lua
deleted file mode 100644
index 0d94cf61c..000000000
--- a/tests/actions/addon/projects/autofetch-badinclude/xmake.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-target("test")
- set_kind("phony")
diff --git a/tests/actions/addon/projects/autofetch-badname/xmake-addons.lua b/tests/actions/addon/projects/autofetch-badname/xmake-addons.lua
deleted file mode 100644
index 165325fb7..000000000
--- a/tests/actions/addon/projects/autofetch-badname/xmake-addons.lua
+++ /dev/null
@@ -1,2 +0,0 @@
--- the `addon` name is reserved for the addon references
-add_addons("addon")
diff --git a/tests/actions/addon/projects/autofetch-badname/xmake.lua b/tests/actions/addon/projects/autofetch-badname/xmake.lua
index 0d94cf61c..ffbf6cbe4 100644
--- a/tests/actions/addon/projects/autofetch-badname/xmake.lua
+++ b/tests/actions/addon/projects/autofetch-badname/xmake.lua
@@ -1,2 +1,5 @@
+-- the `addon` name is reserved for the addon references
+add_addons("addon")
+
target("test")
set_kind("phony")
diff --git a/tests/actions/addon/projects/autofetch-build/xmake-addons.lua b/tests/actions/addon/projects/autofetch-build/xmake-addons.lua
deleted file mode 100644
index 2091e3b7f..000000000
--- a/tests/actions/addon/projects/autofetch-build/xmake-addons.lua
+++ /dev/null
@@ -1,2 +0,0 @@
--- the addons which this project needs, they are installed automatically when we load it
-add_addons("custom-include", "custom-rule", "custom-toolchain")
diff --git a/tests/actions/addon/projects/autofetch-build/xmake.lua b/tests/actions/addon/projects/autofetch-build/xmake.lua
index bad3f8928..862ddf676 100644
--- a/tests/actions/addon/projects/autofetch-build/xmake.lua
+++ b/tests/actions/addon/projects/autofetch-build/xmake.lua
@@ -1,3 +1,6 @@
+-- the addons which this project needs, they are installed automatically
+add_addons("custom-include", "custom-rule", "custom-toolchain")
+
-- the option comes from the includes file of an addon
includes("@addon/custom-include/check")
diff --git a/tests/actions/addon/projects/autofetch-lockmiss/xmake-addons.lua b/tests/actions/addon/projects/autofetch-lockmiss/xmake-addons.lua
deleted file mode 100644
index a85e0fe11..000000000
--- a/tests/actions/addon/projects/autofetch-lockmiss/xmake-addons.lua
+++ /dev/null
@@ -1 +0,0 @@
-add_addons("custom-include")
diff --git a/tests/actions/addon/projects/autofetch-lockmiss/xmake.lua b/tests/actions/addon/projects/autofetch-lockmiss/xmake.lua
index 0d94cf61c..a96a4e713 100644
--- a/tests/actions/addon/projects/autofetch-lockmiss/xmake.lua
+++ b/tests/actions/addon/projects/autofetch-lockmiss/xmake.lua
@@ -1,2 +1,4 @@
+add_addons("custom-include")
+
target("test")
set_kind("phony")
diff --git a/tests/actions/addon/projects/autofetch/xmake-addons.lua b/tests/actions/addon/projects/autofetch/xmake-addons.lua
deleted file mode 100644
index a85e0fe11..000000000
--- a/tests/actions/addon/projects/autofetch/xmake-addons.lua
+++ /dev/null
@@ -1 +0,0 @@
-add_addons("custom-include")
diff --git a/tests/actions/addon/projects/autofetch/xmake.lua b/tests/actions/addon/projects/autofetch/xmake.lua
index 4eaca0785..75c909904 100644
--- a/tests/actions/addon/projects/autofetch/xmake.lua
+++ b/tests/actions/addon/projects/autofetch/xmake.lua
@@ -1,3 +1,6 @@
+-- the addons which this project needs, they are installed automatically
+add_addons("custom-include")
+
-- the addon is installed automatically, so we can use its includes file here
includes("@addon/custom-include/check")
diff --git a/tests/actions/addon/test.lua b/tests/actions/addon/test.lua
index 01030c4b8..fcc5c2efc 100644
--- a/tests/actions/addon/test.lua
+++ b/tests/actions/addon/test.lua
@@ -305,7 +305,7 @@ int main(int argc, char** argv) { return 0; }
end)
end
--- the addons which a project declares in `xmake-addons.lua` are installed automatically
+-- the addons which a project declares with `add_addons` are installed automatically
--
-- @note they must be installed before loading the project, it may use their includes files
function test_autofetch(t)
@@ -345,7 +345,7 @@ function test_autofetch_skipped_for_option_menu(t)
end)
end
--- a complete project which declares its addons in `xmake-addons.lua` and builds with them,
+-- a complete project which declares its addons with `add_addons` and builds with them,
-- @see tests/actions/addon/projects/autofetch-build
function test_autofetch_build(t)
@@ -396,13 +396,11 @@ function test_autofetch_lock_missing_version(t)
end)
end
--- the addons file only declares the addons, it cannot reference them
+-- the declared addons are checked, e.g. the reserved names
function test_autofetch_invalid(t)
- for _, name in ipairs({"autofetch-badinclude", "autofetch-badname"}) do
- _with_project(name, function ()
- t:require_not(try { function () os.runv("xmake", {"config", "-y"}); return true end })
- end)
- end
+ _with_project("autofetch-badname", function ()
+ t:require_not(try { function () os.runv("xmake", {"config", "-y"}); return true end })
+ end)
end
-- the addons can be installed from a repository, by plain name and by repo@name
@@ -469,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/xmake/actions/addon/main.lua b/xmake/actions/addon/main.lua
index bf6f27f5d..99f92d125 100644
--- a/xmake/actions/addon/main.lua
+++ b/xmake/actions/addon/main.lua
@@ -21,6 +21,7 @@
-- imports
import("core.base.option")
import("core.package.addon")
+import("core.project.project")
import("devel.git")
import("private.action.addon.impl.install_addons")
import("private.action.addon.impl.xrepo", {alias = "xrepo_addon"})
@@ -228,9 +229,12 @@ function _remove()
end
end
--- upgrade the addons which the current project declares in its `xmake-addons.lua`
+-- upgrade the addons which the current project declares, e.g. add_addons("esp32-devel 1.0.x")
function _upgrade()
- install_addons(os.projectdir(), {upgrade = true})
+ local declarations = {addons = table.wrap(project.get("addons")),
+ repositories = table.wrap(project.get("repositories"))}
+ assert(#declarations.addons > 0, "no addons are declared in this project, e.g. add_addons(\"esp32-devel\")!")
+ install_addons(os.projectdir(), declarations, {upgrade = true})
end
-- search the addons from the repositories
diff --git a/xmake/core/base/interpreter.lua b/xmake/core/base/interpreter.lua
index 01b689fe6..8dc0e4880 100644
--- a/xmake/core/base/interpreter.lua
+++ b/xmake/core/base/interpreter.lua
@@ -30,7 +30,6 @@ local string = require("base/string")
local hashset = require("base/hashset")
local scopeinfo = require("base/scopeinfo")
local deprecated = require("base/deprecated")
-local addon = require("package/addon")
local sandbox = require("sandbox/sandbox")
-- the rules to reword the raw lua error messages into friendly ones, {pattern, replacement}
@@ -880,40 +879,37 @@ function interpreter:scriptdir()
return path.directory(self._PRIVATE._CURFILE)
end
--- set root scope kind
---
--- the root api will affect these scopes
+-- add a resolver for the references of includes(), e.g. includes("@addon/esp32/check")
--
--- get the root file name of the included directories, e.g. includes("subdir") -> subdir/xmake.lua
-function interpreter:includes_rootfilename()
- return self._PRIVATE._INCLUDES_ROOTFILENAME or "xmake.lua"
-end
-
--- set the root file name of the included directories
+-- @param resolver function (interp, reference), it returns the files, or nil and errors
--
--- e.g. interp:includes_rootfilename_set("xmake-addons.lua") -> includes("subdir") -> subdir/xmake-addons.lua
+-- @note the interpreter knows nothing about the references, the callers register the
+-- resolvers which they support, e.g. @see project._interpreter()
--
-function interpreter:includes_rootfilename_set(filename)
- self._PRIVATE._INCLUDES_ROOTFILENAME = filename
+function interpreter:includes_resolver_add(resolver)
+ local resolvers = self._PRIVATE._INCLUDES_RESOLVERS or {}
+ table.insert(resolvers, resolver)
+ self._PRIVATE._INCLUDES_RESOLVERS = resolvers
end
--- can we include the referenced files? e.g. includes("@builtin/check"), includes("@addon/esp32/board")
-function interpreter:includes_references()
- return self._PRIVATE._INCLUDES_REFERENCES ~= false
+-- do we ignore the unresolvable references of includes()? e.g. includes("@addon/esp32/board")
+function interpreter:includes_unresolved()
+ return self._PRIVATE._INCLUDES_UNRESOLVED
end
--- enable/disable the referenced files of includes()
---
--- @param enabled enable them or not
--- @param hint the extra hint of the error message
+-- ignore the unresolvable references of includes() instead of raising errors
--
--- @note the addons file is loaded before the addons are installed, so it cannot reference them
+-- @note the project file may reference the resources which have not been installed yet,
+-- so the caller can load it, install them and load it again, @see project._load()
--
-function interpreter:includes_references_set(enabled, hint)
- self._PRIVATE._INCLUDES_REFERENCES = enabled
- self._PRIVATE._INCLUDES_REFERENCES_HINT = hint
+function interpreter:includes_unresolved_set(enabled)
+ self._PRIVATE._INCLUDES_UNRESOLVED = enabled
end
+-- set root scope kind
+--
+-- the root api will affect these scopes
+--
function interpreter:rootscope_set(scope_kind)
assert(self and self._PRIVATE)
self._PRIVATE._ROOTSCOPE = scope_kind
@@ -1826,26 +1822,6 @@ function interpreter:_find_builtin_includes(subpath)
return os.files(path.join(os.programdir(), "includes", builtin_path, "xmake.lua"))
end
--- find the include files of the addons, e.g. includes("@addon/esp32/check"), includes("@self/check")
-function interpreter:_find_addon_includes(subpath)
- local referenceinfo, errors = addon.resolve_reference(subpath, "/", "includes", {scriptdir = self:scriptdir()})
- if not referenceinfo then
- os.raise(errors)
- end
- local addon_path = referenceinfo.name
- local files
- if addon_path:endswith(".lua") then
- files = os.files(path.join(referenceinfo.dir, addon_path))
- else
- files = os.files(path.join(referenceinfo.dir, addon_path, "xmake.lua"))
- end
- -- the addon is installed, but it does not provide this file, we cannot ignore it
- if not files or #files == 0 then
- os.raise("includes(%s) not found!", subpath)
- end
- return files
-end
-
function interpreter:api_builtin_includes(...)
assert(self and self._PRIVATE and self._PRIVATE._ROOTDIR and self._PRIVATE._MTIMES)
local curfile = self._PRIVATE._CURFILE
@@ -1856,12 +1832,6 @@ function interpreter:api_builtin_includes(...)
local subpaths_matched = {}
for _, subpath in ipairs(subpaths) do
local found = false
- -- the referenced files are not always available, e.g. the addons file
- if subpath:startswith("@") and not self:includes_references() then
- local hint = self._PRIVATE._INCLUDES_REFERENCES_HINT
- os.raise("includes(%s): the referenced files are not supported in %s!%s",
- subpath, path.filename(curfile), hint and ("\n" .. hint) or "")
- end
-- attempt to find files from programdir/includes/*.lua
-- e.g. includes("@builtin/check")
if subpath:startswith("@builtin/") then
@@ -1871,11 +1841,24 @@ function interpreter:api_builtin_includes(...)
found = true
end
end
- -- attempt to find files from the includes of the addons
- -- e.g. includes("@addon/esp32/check"), includes("@self/check")
- if not found and addon.is_reference(subpath, "/") then
- table.join2(subpaths_matched, self:_find_addon_includes(subpath))
- found = true
+ -- attempt to find files from the registered resolvers of the references
+ -- e.g. includes("@addon/esp32/check"), @see interpreter:includes_resolver_add()
+ if not found and subpath:startswith("@") then
+ for _, resolver in ipairs(self._PRIVATE._INCLUDES_RESOLVERS or {}) do
+ local files, errors = resolver(self, subpath)
+ if files then
+ table.join2(subpaths_matched, files)
+ found = true
+ break
+ elseif errors then
+ -- it has not been resolved yet? the caller may load this file again
+ if self:includes_unresolved() then
+ found = true
+ break
+ end
+ os.raise(errors)
+ end
+ end
end
-- find the given files from the project directory
if not found then
@@ -1884,7 +1867,7 @@ function interpreter:api_builtin_includes(...)
files = os.files(subpath)
else
-- @see https://github.com/xmake-io/xmake/issues/6026
- files = os.files(path.join(subpath, self:includes_rootfilename()))
+ files = os.files(path.join(subpath, "xmake.lua"))
end
if files and #files > 0 then
table.join2(subpaths_matched, files)
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 6e7d62eb4..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
@@ -566,6 +573,36 @@ function addon.globalmodules()
return globalmodules
end
+-- find the include files of the given addon reference, e.g. includes("@addon/esp32/board")
+--
+-- @param interp the interpreter which is loading the file, @see interpreter:includes_resolver_add
+-- @param reference the reference, e.g. "@addon/esp32/board", "@self/board"
+--
+-- @return the files, or nil and errors
+--
+function addon.find_includes(interp, reference)
+ if not addon.is_reference(reference, "/") then
+ return
+ end
+ local referenceinfo, errors = addon.resolve_reference(reference, "/", "includes", {scriptdir = interp:scriptdir()})
+ if not referenceinfo then
+ return nil, errors
+ end
+ local name = referenceinfo.name
+ local files
+ if name:endswith(".lua") then
+ files = os.files(path.join(referenceinfo.dir, name))
+ else
+ files = os.files(path.join(referenceinfo.dir, name, "xmake.lua"))
+ end
+
+ -- the addon is installed, but it does not provide this file, we cannot ignore it
+ if not files or #files == 0 then
+ os.raise("includes(%s) not found!", reference)
+ end
+ return files
+end
+
-- get the payload directories of the given kind from all installed addons
--
-- @param kind the payload kind, e.g. "plugins", "rules"
diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua
index 78268351e..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
@@ -2529,9 +2535,20 @@ function _instance:_generate_runtime_configs(sourcekind)
self.sourcekinds = function (self)
return sourcekind
end
- configs.cxflags = self:compiler(sourcekind):map_flags("runtime", runtimes, {target = self})
- configs.ldflags = self:linker("binary", sourcekind):map_flags("runtime", runtimes, {target = self})
- configs.shflags = self:linker("shared", sourcekind):map_flags("runtime", runtimes, {target = self})
+ local cxflags = self:compiler(sourcekind):map_flags("runtime", runtimes, {target = self})
+ local ldflags = self:linker("binary", sourcekind):map_flags("runtime", runtimes, {target = self})
+ local shflags = self:linker("shared", sourcekind):map_flags("runtime", runtimes, {target = self})
+
+ -- @note the multi-argument flags must be checked as a whole, e.g. the clang runtime
+ -- flags on windows, `-Xclang --dependent-lib=xxx` would be broken if
+ -- `--dependent-lib=xxx` is checked and dropped separately
+ -- @see https://github.com/xmake-io/xmake/issues/7704
+ local group = function (flags)
+ return flags and #flags > 1 and {table.wrap_lock(flags)} or flags
+ end
+ configs.cxflags = group(cxflags)
+ configs.ldflags = group(ldflags)
+ configs.shflags = group(shflags)
self.sourcekinds = nil
end
return configs
@@ -3099,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/addons.lua b/xmake/core/project/addons.lua
index 169b7d033..c979a6f8d 100644
--- a/xmake/core/project/addons.lua
+++ b/xmake/core/project/addons.lua
@@ -29,23 +29,6 @@ local table = require("base/table")
local semver = require("base/semver")
local addon = require("package/addon")
--- the file which declares the addons of a project, e.g. <projectdir>/xmake-addons.lua
---
--- it's loaded before the project file, so that the addons are always installed when
--- we load the project, e.g. includes("@addon/esp32-devel/board")
---
--- e.g.
--- add_addons("esp32-devel 1.0.x", "serial-tools")
--- add_repositories("myrepo [email protected]:me/myrepo.git")
---
-function addons.filename()
- return "xmake-addons.lua"
-end
-
-function addons.file(projectdir)
- return path.join(projectdir or os.projectdir(), addons.filename())
-end
-
-- the lock file of the declared addons, e.g. <projectdir>/xmake-addons.lock
--
-- @note it's independent of `xmake-requires.lock`, the addons are always locked,
@@ -63,100 +46,29 @@ function addons.lockfile_version()
return "1.0"
end
--- get the apis of the addons file
---
--- @note it only declares which addons this project needs, the addon resources
--- are always referenced from the project file, e.g. add_rules("@addon/esp32-devel/app")
---
-function addons.apis()
- return {
- values = {
- "add_addons"
- -- the repositories which provide them, e.g. add_repositories("myrepo [email protected]:me/myrepo.git")
- , "add_repositories"
- }
- }
-end
-
--- the interpreter of the addons file
-function addons._interpreter()
- local interp = addons._INTERPRETER
- if interp == nil then
- -- we need to load it lazily, the interpreter also depends on the addon module
- local interpreter = require("base/interpreter")
- interp = interpreter.new()
- interp:api_define(addons.apis())
- -- the sub-projects declare their addons in this file too,
- -- e.g. includes("sub") -> sub/xmake-addons.lua
- interp:includes_rootfilename_set(addons.filename())
- -- and we cannot reference the addons here, they have not been installed yet,
- -- e.g. includes("@addon/esp32-devel/board")
- interp:includes_references_set(false, "please move it to the project file(xmake.lua)!")
- addons._INTERPRETER = interp
- end
- return interp
-end
-
--- load the declared addons of the given project directory
+-- check the addons which a project declares, e.g. add_addons("esp32-devel 1.0.x")
--
--- @return the addons information and errors, it will be nil if this project declares nothing,
--- e.g. {addons = {"esp32-devel 1.0.x"}, addons_extra = {...}}
+-- @return true, or false and errors
--
-function addons.load(projectdir)
- local filepath = addons.file(projectdir)
- if not os.isfile(filepath) then
- return
- end
-
- -- enter the project directory, the include paths are relative to it,
- -- e.g. includes("sub")
- local oldir, errors = os.cd(path.directory(filepath))
- if not oldir then
- return nil, errors
- end
-
- local rootinfo
- local interp = addons._interpreter()
- local ok, errors = interp:load(filepath)
- if ok then
- rootinfo, errors = interp:make("root", true, true)
- end
- os.cd(oldir)
- if not rootinfo then
- return nil, errors
- end
-
- local addonsinfo = {addons = table.wrap(rootinfo:get("addons")),
- addons_extra = rootinfo:extraconf("addons"),
- repositories = table.wrap(rootinfo:get("repositories"))}
-
- -- check the declared addons
+function addons.validate(requires)
local declared = {}
- for _, requirestr in ipairs(addonsinfo.addons) do
-
- -- this file is loaded before the addons are installed, so it cannot reference them
- if requirestr:startswith("@") then
- return nil, string.format("%s: cannot reference the addon resources(%s) here, please move it to the project file(xmake.lua)!",
- filepath, requirestr)
- end
-
+ for _, requirestr in ipairs(requires) do
local name = addons.requirename(requirestr)
if name == "addon" or name == "self" then
- return nil, string.format("%s: the addon name(%s) is reserved by xmake for the addon references, please rename it!",
- filepath, name)
+ return false, string.format("add_addons(%s): the name is reserved by xmake for the addon references, please rename it!", name)
end
if name == "." or name == ".." or name:find("[/\\:]") then
- return nil, string.format("%s: invalid addon name(%s)!", filepath, name)
+ return false, string.format("add_addons(%s): invalid addon name!", name)
end
-- we can only install one version of an addon for a project
if declared[name] then
- return nil, string.format("%s: the addon(%s) is declared twice, e.g. `%s` and `%s`, please merge them!",
- filepath, name, declared[name], requirestr)
+ return false, string.format("add_addons(%s): it is declared twice, e.g. `%s` and `%s`, please merge them!",
+ name, declared[name], requirestr)
end
declared[name] = requirestr
end
- return addonsinfo
+ return true
end
-- split the given declaration into the name and the version range
@@ -204,13 +116,13 @@ end
-- @note we need to check it in-process for every command which loads the project,
-- so we only check the locked versions here, the installer will resolve them again
--
-function addons.satisfied(addonsinfo, projectdir)
+function addons.satisfied(requires, projectdir)
local locked = addons.locked(projectdir)
if not locked then
return false
end
local installed = addon.addons()
- for _, requirestr in ipairs(addonsinfo.addons) do
+ for _, requirestr in ipairs(requires) do
local name = addons.requirename(requirestr)
local lockinfo = locked[name]
if not addons.locked_valid(requirestr, lockinfo) then
diff --git a/xmake/core/project/policy.lua b/xmake/core/project/policy.lua
index 617a792d6..81a8b6924 100644
--- a/xmake/core/project/policy.lua
+++ b/xmake/core/project/policy.lua
@@ -158,6 +158,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/project/project.lua b/xmake/core/project/project.lua
index 0cda89db1..b92c5cfab 100644
--- a/xmake/core/project/project.lua
+++ b/xmake/core/project/project.lua
@@ -234,14 +234,15 @@ end
-- @note we cannot install them here, we are loading the project, so we do it in a
-- sub-process, @see xmake/modules/private/action/addon/impl/install_addons.lua
--
-function project._install_addons()
+function project._install_addons(rootinfo)
-- @note we need to cache the result, the project may be loaded many times,
-- otherwise the failure would be ignored by the next load
- if not project._ADDONS_CHECKED then
- project._ADDONS_CHECKED = true
- project._ADDONS_OK, project._ADDONS_ERRORS = project._do_install_addons()
+ local result = project._ADDONS_RESULT
+ if result == nil then
+ result = project._do_install_addons(rootinfo)
+ project._ADDONS_RESULT = result
end
- return project._ADDONS_OK, project._ADDONS_ERRORS
+ return result
end
-- activate the addon versions which this project locks
@@ -263,33 +264,45 @@ function project._pin_addons()
end
-- do install the addons which this project declares
-function project._do_install_addons()
+-- install the addons which this project declares, e.g. add_addons("esp32-devel 1.0.x")
+--
+-- @return the result, e.g. {ok = true, installed = true}, {ok = false, errors = ".."}
+--
+function project._do_install_addons(rootinfo)
-- this project declares nothing?
- local addonsinfo, errors = addons.load()
- if errors then
- return false, errors
+ local requires = table.wrap(rootinfo:get("addons"))
+ if #requires == 0 then
+ return {ok = true}
end
- if not addonsinfo or #addonsinfo.addons == 0 then
- return true
+ local ok, errors = addons.validate(requires)
+ if not ok then
+ return {ok = false, errors = errors}
end
-- they have been installed already?
- project._pin_addons()
- if addons.satisfied(addonsinfo) then
- return true
+ if addons.satisfied(requires) then
+ return {ok = true}
end
-- tell the user why we are installing something, it may need to confirm and download,
-- e.g. `xmake --help` in a project directory which declares some addons
- utils.cprint("${color.warning}note: ${clear}%s: this project needs the addons(${bright}%s${clear}), installing them ..",
- addons.filename(), table.concat(addonsinfo.addons, ", "))
+ utils.cprint("${color.warning}note: ${clear}this project needs the addons(${bright}%s${clear}), installing them ..",
+ table.concat(requires, ", "))
if baseoption.get("help") then
-- the help menu also shows the options which the addons provide, but the user
-- did not ask for an installation, so we tell them how to skip it
utils.cprint("${dim}we can run it outside of the project directory to skip the installation${clear}")
end
+ -- we pass the declarations to the installer, it must not load this project again,
+ -- @see xmake/modules/private/action/addon/impl/install_addons.lua
+ local datafile = os.tmpfile()
+ local ok, errors = io.save(datafile, {addons = requires, repositories = table.wrap(rootinfo:get("repositories"))})
+ if not ok then
+ return {ok = false, errors = errors}
+ end
+
-- @note we run it in a working directory which has no project, @see addon.workdir(),
-- otherwise it would load this project again
--
@@ -310,9 +323,11 @@ function project._do_install_addons()
end
table.insert(argv, "private.action.addon.impl.install_addons")
table.insert(argv, os.projectdir())
- local ok, errors = os.execv(os.programfile(), argv, {curdir = addon.workdir()})
- if ok ~= 0 then
- return false, errors or "install the addons of this project failed!"
+ table.insert(argv, datafile)
+ local exitcode, errors = os.execv(os.programfile(), argv, {curdir = addon.workdir()})
+ os.rm(datafile)
+ if exitcode ~= 0 then
+ return {ok = false, errors = errors or "install the addons of this project failed!"}
end
-- we have loaded the registry and its caches before installing them, so we need to reload it
@@ -320,7 +335,7 @@ function project._do_install_addons()
project._pin_addons()
rule.clear()
task.clear()
- return true
+ return {ok = true, installed = true}
end
-- load the project file
@@ -329,26 +344,13 @@ end
-- - force: load the project file again even if it has been loaded
-- - disable_filter: disable the interpreter filter, e.g. `$(plat)`
-- - skip_addons: do not install the addons which this project declares
+-- - addons_installed: the addons have been installed, we are loading it again
--
function project._load(opt)
opt = opt or {}
- -- install the addons which this project declares in `xmake-addons.lua` first,
- -- it may use their rules, toolchains and includes files,
- -- e.g. includes("@addon/esp32-devel/board")
- --
- -- @note we need to check it before the cache, the project file may have been loaded
- -- already without them, e.g. by the option menu
- --
- if opt.skip_addons then
- -- we do not install them here, but we still need to use the locked versions
- project._pin_addons()
- else
- local ok, errors = project._install_addons()
- if not ok then
- return false, errors
- end
- end
+ -- use the locked versions of the addons which this project declares
+ project._pin_addons()
-- has already been loaded?
if project._memcache():get("rootinfo") and not opt.force then
@@ -364,6 +366,12 @@ function project._load(opt)
-- get interpreter
local interp = project.interpreter()
+ -- this project declares the addons which it needs, e.g. add_addons("esp32-devel"),
+ -- but we can only know them after loading it, so this pass must survive the references
+ -- of the addons which are not installed yet, and we load it again after installing them,
+ -- e.g. includes("@addon/esp32-devel/board")
+ interp:includes_unresolved_set(not opt.addons_installed)
+
-- load script
local ok, errors = interp:load(project.rootfile(), {on_load_data = function (data)
for _, xmakerc_file in ipairs(project.rcfiles()) do
@@ -386,6 +394,23 @@ function project._load(opt)
return false, errors
end
+ -- install the addons which this project declares, and then load it again with them
+ --
+ -- @note we do not install them for the option menu, it merges the project tasks in a
+ -- best-effort way and every command builds it, @see project._load_tasks()
+ --
+ if not opt.skip_addons and not opt.addons_installed then
+ local result = project._install_addons(rootinfo)
+ if not result.ok then
+ os.cd(oldir)
+ return false, result.errors
+ end
+ if result.installed then
+ os.cd(oldir)
+ return project._load({force = true, disable_filter = opt.disable_filter, addons_installed = true})
+ end
+ end
+
-- load the root info of the target
local rootinfo_target, errors = project._load_scope("root.target", true, not opt.disable_filter)
if not rootinfo_target then
@@ -780,6 +805,9 @@ function project.apis()
, "add_requires"
, "add_requireconfs"
, "add_repositories"
+ -- the addons which this project needs, they are installed automatically,
+ -- e.g. add_addons("esp32-devel 1.0.x"), @see core/project/addons.lua
+ , "add_addons"
}
, paths =
{
@@ -832,6 +860,10 @@ function project.interpreter()
-- set root scope
interp:rootscope_set("target")
+ -- the project file can reference the includes files of the addons,
+ -- e.g. includes("@addon/esp32-devel/board")
+ interp:includes_resolver_add(addon.find_includes)
+
-- define apis for rule
interp:api_define(rule.apis())
diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua
index 81b95cc96..e51ffeb8b 100644
--- a/xmake/core/project/target.lua
+++ b/xmake/core/project/target.lua
@@ -3296,6 +3296,14 @@ function target.linkname(filename, opt)
linkname, count = filename:gsub(target.filename("__pattern__", "static", {plat = "windows"}):gsub("%.", "%%."):gsub("__pattern__", "(.+)") .. "$", "%1")
end
if count > 0 and linkname then
+ -- the library name itself may end with `.lib`, e.g. vcpkg installs `Luau.CLI.lib.lib`,
+ -- we cannot strip it, nf_link() passes the names ending with `.lib` to the linker
+ -- as-is, and it would look for `Luau.CLI.lib`
+ --
+ -- @see https://github.com/xmake-io/xmake/issues/7708
+ if opt.plat == "windows" and linkname:endswith(".lib") then
+ return filename
+ end
return linkname
end
-- fallback to the generic unix library name, libxxx.a, libxxx.so, ..
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/core/package/addon.lua b/xmake/core/sandbox/modules/import/core/package/addon.lua
index 47d2b7793..9f080cc93 100644
--- a/xmake/core/sandbox/modules/import/core/package/addon.lua
+++ b/xmake/core/sandbox/modules/import/core/package/addon.lua
@@ -30,15 +30,11 @@ sandbox_core_package_addon.installdir = addon.installdir
sandbox_core_package_addon.workdir = addon.workdir
sandbox_core_package_addon.dirname = addon.dirname
sandbox_core_package_addon.owner = addon.owner
-sandbox_core_package_addon.is_reference = addon.is_reference
-sandbox_core_package_addon.payloads = addon.payloads
sandbox_core_package_addon.payloadinfos = addon.payloadinfos
sandbox_core_package_addon.payloads_of = addon.payloads_of
sandbox_core_package_addon.payloadroot = addon.payloadroot
sandbox_core_package_addon.addons = addon.addons
sandbox_core_package_addon.versions = addon.versions
-sandbox_core_package_addon.pin = addon.pin
-sandbox_core_package_addon.addondir = addon.addondir
sandbox_core_package_addon.unregister = addon.unregister
-- get the manifest of the given addon directory, e.g. <sourcedir>/addon.lua
diff --git a/xmake/core/sandbox/modules/import/core/project/addons.lua b/xmake/core/sandbox/modules/import/core/project/addons.lua
index 542cbaf4f..ff2fe14c0 100644
--- a/xmake/core/sandbox/modules/import/core/project/addons.lua
+++ b/xmake/core/sandbox/modules/import/core/project/addons.lua
@@ -23,30 +23,13 @@ local sandbox_core_project_addons = sandbox_core_project_addons or {}
-- load modules
local addons = require("project/addons")
-local raise = require("sandbox/modules/raise")
-- inherit some builtin interfaces
-sandbox_core_project_addons.file = addons.file
-sandbox_core_project_addons.filename = addons.filename
sandbox_core_project_addons.lockfile = addons.lockfile
sandbox_core_project_addons.lockfile_version = addons.lockfile_version
sandbox_core_project_addons.locked = addons.locked
sandbox_core_project_addons.locked_valid = addons.locked_valid
sandbox_core_project_addons.requirename = addons.requirename
-sandbox_core_project_addons.satisfied = addons.satisfied
-
--- load the declared addons of the given project directory
---
--- @param projectdir the project directory
--- @return the addons information, it will be nil if this project declares nothing
---
-function sandbox_core_project_addons.load(projectdir)
- local addonsinfo, errors = addons.load(projectdir)
- if errors then
- raise(errors)
- end
- return addonsinfo
-end
-- return module
return sandbox_core_project_addons
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/action/addon/impl/install_addons.lua b/xmake/modules/private/action/addon/impl/install_addons.lua
index 0a288f1a3..4cc5b0fba 100644
--- a/xmake/modules/private/action/addon/impl/install_addons.lua
+++ b/xmake/modules/private/action/addon/impl/install_addons.lua
@@ -28,9 +28,9 @@ import("private.action.addon.impl.xrepo", {alias = "xrepo_addon"})
-- @note we install the locked versions, but the declaration is authoritative, so we
-- resolve them again if the user has changed it or upgrades them
--
-function _get_requires(addonsinfo, locked)
+function _get_requires(declared, locked)
local requires = {}
- for _, requirestr in ipairs(addonsinfo.addons) do
+ for _, requirestr in ipairs(declared) do
local name = addons.requirename(requirestr)
local lockinfo = locked and locked[name]
if addons.locked_valid(requirestr, lockinfo) then
@@ -46,7 +46,7 @@ end
-- @note we get the installed versions from the addons registry, they are
-- registered when installing them, @see core/package/addon.lua
--
-function _lock_addons(projectdir, addonsinfo)
+function _lock_addons(projectdir, declared)
local lockinfo = {}
local locked = addons.locked(projectdir) or {}
@@ -54,7 +54,7 @@ function _lock_addons(projectdir, addonsinfo)
-- and we must not see them through the locked versions, we are locking them right now,
-- e.g. `xmake addon --upgrade` pins the old ones before loading this project
local installed = addon.addons({force = true, unpinned = true})
- for _, requirestr in ipairs(addonsinfo.addons) do
+ for _, requirestr in ipairs(declared) do
local name = addons.requirename(requirestr)
local addoninfo = assert(installed[addon.dirname(name)], "addon(%s) is not installed!", name)
local oldversion = locked[name] and locked[name].version
@@ -79,41 +79,49 @@ function _lock_addons(projectdir, addonsinfo)
os.rm(tmpfile)
end
--- install the addons which the given project declares in its `xmake-addons.lua`
+-- install the addons which a project declares, e.g. add_addons("esp32-devel 1.0.x")
--
-- @note we are also called from a sub-process, the project cannot be loaded until
-- its addons are installed, @see core/project/project.lua
--
-function main(projectdir, opt)
+-- install the addons which a project declares, e.g. add_addons("esp32-devel 1.0.x")
+--
+-- @param projectdir the project directory, we only read/write its lock file here
+-- @param datafile the declarations of the project, {addons = {...}, repositories = {...}}
+--
+-- @note we are always run in a working directory which has no project, we cannot load
+-- the project again here, @see xmake/core/project/project.lua
+--
+function main(projectdir, datafile, opt)
opt = opt or {}
projectdir = projectdir or os.projectdir()
- local addonsinfo = addons.load(projectdir)
- if not addonsinfo or #addonsinfo.addons == 0 then
+ local declarations = type(datafile) == "table" and datafile or io.load(datafile)
+ local declared = table.wrap(declarations and declarations.addons)
+ if #declared == 0 then
return
end
-- upgrade them? we need to resolve the declared versions again
local locked = not opt.upgrade and addons.locked(projectdir) or nil
- -- install them with xrepo, it installs the packages in its own working directory,
- -- so we need not a project here
-
-- this project declares its own repositories? we pass them to xrepo,
-- they are only used by this installation, we do not register them globally
local rcfile
- if #addonsinfo.repositories > 0 then
+ local repositories = table.wrap(declarations.repositories)
+ if #repositories > 0 then
rcfile = os.tmpfile() .. ".lua"
local file = io.open(rcfile, "w")
- for _, repo in ipairs(addonsinfo.repositories) do
+ for _, repo in ipairs(repositories) do
file:print("add_repositories(%q)", repo)
end
file:close()
end
+ -- install them with xrepo, it installs the packages in its own working directory
try
{
function ()
- xrepo_addon("install", _get_requires(addonsinfo, locked), {includes = rcfile})
+ xrepo_addon("install", _get_requires(declared, locked), {includes = rcfile})
end,
finally
{
@@ -130,5 +138,5 @@ function main(projectdir, opt)
}
-- and lock them, so that the other users get the same versions
- _lock_addons(projectdir, addonsinfo)
+ _lock_addons(projectdir, declared)
end
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/rules/c++/modules/support.lua b/xmake/rules/c++/modules/support.lua
index 126e25c61..38df28a05 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"
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)