summaryrefslogtreecommitdiff
path: root/xmake
diff options
context:
space:
mode:
Diffstat (limited to 'xmake')
-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/core/sandbox/modules/import/lib/lua/error.lua36
-rw-r--r--xmake/core/sandbox/modules/import/lib/lua/getmetatable.lua32
-rw-r--r--xmake/core/sandbox/modules/import/lib/lua/next.lua36
-rw-r--r--xmake/core/sandbox/modules/import/lib/lua/pcall.lua36
-rw-r--r--xmake/core/sandbox/modules/import/lib/lua/rawequal.lua33
-rw-r--r--xmake/core/sandbox/modules/import/lib/lua/rawget.lua34
-rw-r--r--xmake/core/sandbox/modules/import/lib/lua/rawset.lua33
-rw-r--r--xmake/core/sandbox/modules/import/lib/lua/select.lua36
-rw-r--r--xmake/core/sandbox/modules/import/lib/lua/setmetatable.lua36
-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/plugins/project/clang/compile_commands.lua11
-rw-r--r--xmake/rules/c++/modules/clang/scanner.lua5
-rw-r--r--xmake/rules/c++/modules/clang/support.lua53
-rw-r--r--xmake/rules/c++/modules/support.lua10
-rw-r--r--xmake/toolchains/mingw/xmake.lua2
41 files changed, 690 insertions, 302 deletions
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/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/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/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/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..71bd2e735 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)
@@ -161,7 +172,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 +198,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 +218,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 +248,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 +317,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
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)