summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2026-08-16 22:28:05 +0800
committerruki <[email protected]>2026-08-16 22:28:05 +0800
commitd7fc1e30a747c0457b4f45194946fcff747c76db (patch)
treebeb7b01b9f2f04e54169689023e8ad5e8fe3eff6
parent1678e141d274309ab56917f585a8fb036571541b (diff)
improve find addon includes
-rw-r--r--xmake/core/base/interpreter.lua61
-rw-r--r--xmake/core/package/addon.lua30
-rw-r--r--xmake/core/project/project.lua4
3 files changed, 65 insertions, 30 deletions
diff --git a/xmake/core/base/interpreter.lua b/xmake/core/base/interpreter.lua
index ad62168fb..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,6 +879,19 @@ function interpreter:scriptdir()
return path.directory(self._PRIVATE._CURFILE)
end
+-- add a resolver for the references of includes(), e.g. includes("@addon/esp32/check")
+--
+-- @param resolver function (interp, reference), it returns the files, or nil and errors
+--
+-- @note the interpreter knows nothing about the references, the callers register the
+-- resolvers which they support, e.g. @see project._interpreter()
+--
+function interpreter:includes_resolver_add(resolver)
+ local resolvers = self._PRIVATE._INCLUDES_RESOLVERS or {}
+ table.insert(resolvers, resolver)
+ self._PRIVATE._INCLUDES_RESOLVERS = resolvers
+end
+
-- do we ignore the unresolvable references of includes()? e.g. includes("@addon/esp32/board")
function interpreter:includes_unresolved()
return self._PRIVATE._INCLUDES_UNRESOLVED
@@ -1810,30 +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
- -- it has not been installed yet? the caller may install it and load this file again
- if self:includes_unresolved() then
- return {}
- end
- 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
@@ -1853,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
diff --git a/xmake/core/package/addon.lua b/xmake/core/package/addon.lua
index 6e7d62eb4..e35a58317 100644
--- a/xmake/core/package/addon.lua
+++ b/xmake/core/package/addon.lua
@@ -566,6 +566,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/project/project.lua b/xmake/core/project/project.lua
index f67ac9a67..b92c5cfab 100644
--- a/xmake/core/project/project.lua
+++ b/xmake/core/project/project.lua
@@ -860,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())