summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2022-10-08 18:13:35 +0800
committerGitHub <[email protected]>2022-10-08 18:13:35 +0800
commit17532b0ea38967d3d594cf7004c2d6a992d270fa (patch)
tree4d90eb43d469d978c2f817030501ed2d0d0382d2
parent2c4ce2f510178a00c43cd16d7c85819b4a289423 (diff)
parent35aa721e0eb879324e5f985a085d51ddfb251e05 (diff)
Merge pull request #2903 from xmake-io/rule
Add embed package rule support
-rw-r--r--xmake/actions/config/main.lua42
-rw-r--r--xmake/core/project/package.lua105
-rw-r--r--xmake/core/project/project.lua13
-rw-r--r--xmake/core/project/rule.lua83
-rw-r--r--xmake/core/project/target.lua30
-rw-r--r--xmake/modules/private/action/require/impl/actions/install.lua6
6 files changed, 197 insertions, 82 deletions
diff --git a/xmake/actions/config/main.lua b/xmake/actions/config/main.lua
index 6a454abe5..c8705d945 100644
--- a/xmake/actions/config/main.lua
+++ b/xmake/actions/config/main.lua
@@ -196,6 +196,45 @@ function _config_targets(targetname)
end
end
+-- load rules in the required packages for target
+function _load_package_rules_for_target(target)
+ for _, rulename in ipairs(target:get("rules")) do
+ local packagename = rulename:match("@(.-)/")
+ if packagename then
+ local pkginfo = project.required_package(packagename)
+ if pkginfo then
+ local r = pkginfo:rule(rulename)
+ if r then
+ target:rule_add(r)
+ for _, dep in pairs(r:deps()) do
+ target:rule_add(dep)
+ end
+ end
+ end
+ end
+ end
+end
+
+-- load rules in the required packages for targets
+-- @see https://github.com/xmake-io/xmake/issues/2374
+--
+-- @code
+-- add_requires("zlib", {system = false})
+-- target("test")
+-- set_kind("binary")
+-- add_files("src/*.cpp")
+-- add_packages("zlib")
+-- add_rules("@zlib/test")
+-- @endcode
+--
+function _load_package_rules_for_targets()
+ for _, target in ipairs(project.ordertargets()) do
+ if target:is_enabled() then
+ _load_package_rules_for_target(target)
+ end
+ end
+end
+
-- find default mode
function _find_default_mode()
local mode = config.mode()
@@ -442,6 +481,9 @@ force to build in current directory via run `xmake -P .`]], os.projectdir())
_check_target_toolchains()
end
+ -- load package rules for targets
+ _load_package_rules_for_targets()
+
-- config targets
_config_targets(targetname)
end
diff --git a/xmake/core/project/package.lua b/xmake/core/project/package.lua
index 9918bcbc1..6c9155daf 100644
--- a/xmake/core/project/package.lua
+++ b/xmake/core/project/package.lua
@@ -20,6 +20,7 @@
-- define module
local package = {}
+local _instance = _instance or {}
-- load modules
local io = require("base/io")
@@ -27,24 +28,20 @@ local os = require("base/os")
local path = require("base/path")
local table = require("base/table")
local utils = require("base/utils")
-local config = require("project/config")
local semver = require("base/semver")
+local rule = require("project/rule")
+local config = require("project/config")
local sandbox = require("sandbox/sandbox")
local localcache = require("cache/localcache")
--- get cache
-function package._cache()
- return localcache.cache("package")
-end
-
-- save the requires info to the cache
-function package:save()
+function _instance:save()
package._cache():set(self:name(), self._INFO)
package._cache():save()
end
-- clear the package
-function package:clear()
+function _instance:clear()
local info = self._INFO
if info then
for k, v in pairs(info) do
@@ -56,22 +53,22 @@ function package:clear()
end
-- dump this package
-function package:dump()
+function _instance:dump()
utils.dump(self._INFO)
end
-- get the require info
-function package:get(infoname)
+function _instance:get(infoname)
return self._INFO[infoname]
end
--- get the require name
-function package:name()
+-- get the package name (with alias name)
+function _instance:name()
return self._NAME
end
-- get the package version
-function package:version()
+function _instance:version()
-- get it from cache first
if self._VERSION ~= nil then
@@ -89,37 +86,37 @@ function package:version()
end
-- get the package license
-function package:license()
+function _instance:license()
return self:get("license")
end
-- has static libraries?
-function package:has_static()
+function _instance:has_static()
return self:get("static")
end
-- has shared libraries?
-function package:has_shared()
+function _instance:has_shared()
return self:get("shared")
end
-- get the require string
-function package:requirestr()
+function _instance:requirestr()
return self:get("__requirestr")
end
-- get the install directory
-function package:installdir()
+function _instance:installdir()
return self:get("__installdir")
end
-- get library files
-function package:libraryfiles()
+function _instance:libraryfiles()
return self:get("libfiles")
end
-- get the extra info from the given name
-function package:extra(name)
+function _instance:extra(name)
local extrainfo = self:extrainfo()
if extrainfo then
return extrainfo[name]
@@ -127,12 +124,12 @@ function package:extra(name)
end
-- get the extra info
-function package:extrainfo()
+function _instance:extrainfo()
return self:get("__extrainfo")
end
-- set the value to the requires info
-function package:set(name_or_info, ...)
+function _instance:set(name_or_info, ...)
if type(name_or_info) == "string" then
local args = ...
if args ~= nil then
@@ -148,7 +145,7 @@ function package:set(name_or_info, ...)
end
-- add the value to the requires info
-function package:add(name_or_info, ...)
+function _instance:add(name_or_info, ...)
if type(name_or_info) == "string" then
local info = table.wrap(self._INFO[name_or_info])
self._INFO[name_or_info] = table.unwrap(table.unique(table.join(info, ...)))
@@ -160,32 +157,70 @@ function package:add(name_or_info, ...)
end
-- this require info is enabled?
-function package:enabled()
+function _instance:enabled()
return self:get("__enabled")
end
-- enable or disable this require info
---
--- @param enabled enable it?
---
-function package:enable(enabled)
+function _instance:enable(enabled)
self:set("__enabled", enabled)
end
--- load the requires info from the cache
-function package.load(name)
+-- get the given rule
+function _instance:rule(name)
+ return self:rules()[name]
+end
+
+-- get package rules
+function _instance:rules()
+ local rules = self._RULES
+ if rules == nil then
+ local ruleinfos = {}
+ local installdir = self:installdir()
+ local rulesdir = path.join(installdir, "rules")
+ if os.isdir(rulesdir) then
+ local files = os.match(path.join(rulesdir, "**.lua"))
+ if files then
+ for _, filepath in ipairs(files) do
+ local results, errors = rule._load(filepath)
+ if results then
+ table.join2(ruleinfos, results)
+ else
+ os.raise(errors)
+ end
+ end
+ end
+ end
+
+ -- make rule instances
+ rules = {}
+ for rulename, ruleinfo in pairs(ruleinfos) do
+ rulename = "@" .. self:name() .. "/" .. rulename
+ local instance = rule.new(rulename, ruleinfo, {package = self})
+ rules[rulename] = instance
+ end
+ self._RULES = rules
+ end
+ return rules
+end
- -- check
- assert(name)
+-- get cache
+function package._cache()
+ return localcache.cache("package")
+end
- -- get info
+-- load the package from the cache
+function package.load(name)
local info = package._cache():get(name)
if info == nil then
return
end
+ return package.load_withinfo(name, info)
+end
- -- init package instance
- local instance = table.inherit(package)
+-- load package from the give package info
+function package.load_withinfo(name, info)
+ local instance = table.inherit(_instance)
instance._INFO = info
instance._NAME = name
return instance
diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua
index 0a227d016..8e53dbc4e 100644
--- a/xmake/core/project/project.lua
+++ b/xmake/core/project/project.lua
@@ -375,7 +375,8 @@ function project._load_targets()
t._RULES[deprule:name()] = deprule
end
end
- else
+ -- we need ignore `@package/rulename`, it will be loaded later
+ elseif not rulename:match("@.-/") then
return nil, string.format("unknown rule(%s) in target(%s)!", rulename, t:name())
end
end
@@ -484,7 +485,7 @@ function project._load_requires()
for _, requirestr in ipairs(table.wrap(requires_str)) do
-- get the package name
- local packagename = requirestr:split('%s')[1]
+ local packagename = requirestr:split("%s")[1]
-- get alias
local alias = nil
@@ -494,11 +495,11 @@ function project._load_requires()
end
-- load it from cache first (@note will discard scripts in extrainfo)
- local instance = project_package.load(alias or packagename)
+ local name = alias or packagename
+ local instance = project_package.load(name)
if not instance then
- instance = table.inherit(project_package)
- instance._NAME = alias or packagename
- instance._INFO = { __requirestr = requirestr, __extrainfo = extrainfo }
+ local info = {__requirestr = requirestr, __extrainfo = extrainfo}
+ instance = project_package.load_withinfo(name, info)
end
-- add require info
diff --git a/xmake/core/project/rule.lua b/xmake/core/project/rule.lua
index 155f96754..4d2a058a0 100644
--- a/xmake/core/project/rule.lua
+++ b/xmake/core/project/rule.lua
@@ -35,6 +35,11 @@ local sandbox = require("sandbox/sandbox")
local sandbox_os = require("sandbox/modules/os")
local sandbox_module = require("sandbox/modules/import/core/sandbox/module")
+-- get package
+function _instance:_package()
+ return self._PACKAGE
+end
+
-- invalidate the previous cache
function _instance:_invalidate(name)
if name == "deps" then
@@ -45,9 +50,12 @@ end
-- build deps
function _instance:_build_deps()
- local instances = rule.rules()
+ local instances = table.clone(rule.rules())
if rule._project() then
- instances = table.join(rule.rules(), rule._project().rules())
+ table.join2(instances, rule._project().rules())
+ end
+ if self:_package() then
+ table.join2(instances, self:_package():rules())
end
self._DEPS = self._DEPS or {}
self._ORDERDEPS = self._ORDERDEPS or {}
@@ -59,6 +67,7 @@ function _instance:clone()
local instance = rule.new(self:name(), self._INFO:clone())
instance._DEPS = self._DEPS
instance._ORDERDEPS = self._ORDERDEPS
+ instance._PACKAGE = self._PACKAGE
return instance
end
@@ -84,6 +93,11 @@ function _instance:extraconf(name, item, key)
return self._INFO:extraconf(name, item, key)
end
+-- set the extra configuration
+function _instance:extraconf_set(name, item, key, value)
+ return self._INFO:extraconf_set(name, item, key, value)
+end
+
-- get the rule name
function _instance:name()
return self._NAME
@@ -275,30 +289,6 @@ function rule._load(filepath)
return results
end
--- load deps
---
--- e.g.
---
--- a.deps = b
--- b.deps = c
---
--- orderdeps: c -> b -> a
---
-function rule._load_deps(self, rules, deps, orderdeps)
-
- -- get dep rules
- for _, dep in ipairs(table.wrap(self:get("deps"))) do
- local deprule = rules[dep]
- if deprule then
- rule._load_deps(deprule, rules, deps, orderdeps)
- if not deps[dep] then
- deps[dep] = deprule
- table.insert(orderdeps, deprule)
- end
- end
- end
-end
-
-- get rule apis
function rule.apis()
@@ -367,10 +357,47 @@ function rule.apis()
end
-- new a rule instance
-function rule.new(name, info)
+function rule.new(name, info, opt)
+ opt = opt or {}
local instance = table.inherit(_instance)
instance._NAME = name
instance._INFO = info
+ instance._PACKAGE = opt.package
+ if opt.package then
+ -- replace deps in package, @bar -> @zlib/bar
+ -- @see https://github.com/xmake-io/xmake/issues/2374
+ --
+ -- packages/z/zlib/rules/foo.lua
+ -- @code
+ -- rule("foo")
+ -- add_deps("@bar")
+ -- @endcode
+ --
+ -- package/z/zlib/rules/foo.lua
+ -- @code
+ -- rule("bar")
+ -- ...
+ -- @endcode
+ --
+ local deps = {}
+ for _, depname in ipairs(table.wrap(instance:get("deps"))) do
+ -- @xxx -> @package/xxx
+ if depname:startswith("@") and not depname:find("/", 1, true) then
+ depname = "@" .. opt.package:name() .. "/" .. depname:sub(2)
+ end
+ table.insert(deps, depname)
+ end
+ deps = table.unwrap(deps)
+ if deps and #deps > 0 then
+ instance:set("deps", deps)
+ end
+ for depname, extraconf in pairs(table.wrap(instance:extraconf("deps"))) do
+ if depname:startswith("@") and not depname:find("/", 1, true) then
+ depname = "@" .. opt.package:name() .. "/" .. depname:sub(2)
+ instance:extraconf_set("deps", depname, extraconf)
+ end
+ end
+ end
return instance
end
@@ -386,7 +413,7 @@ function rule.rules()
local ruleinfos = {}
local dirs = rule._directories()
for _, dir in ipairs(dirs) do
- local files = os.match(path.join(dir, "**/xmake.lua"))
+ local files = os.files(path.join(dir, "**/xmake.lua"))
if files then
for _, filepath in ipairs(files) do
local results, errors = rule._load(filepath)
diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua
index 22ddd267c..08fa6593c 100644
--- a/xmake/core/project/target.lua
+++ b/xmake/core/project/target.lua
@@ -876,24 +876,28 @@ function _instance:orderopts(opt)
end
-- get the enabled package
-function _instance:pkg(name)
- return self:pkgs()[name]
+function _instance:pkg(name, opt)
+ return self:pkgs(opt)[name]
end
-- get the enabled packages
-function _instance:pkgs()
-
- -- attempt to get it from cache first
- if self._PKGS_ENABLED then
- return self._PKGS_ENABLED
+function _instance:pkgs(opt)
+ opt = opt or {}
+ local cachekey = "pkgs"
+ if opt.public then
+ cachekey = cachekey .. "_public"
+ elseif opt.interface then
+ cachekey = cachekey .. "_interface"
end
-
- -- load packages if be enabled
- self._PKGS_ENABLED = {}
- for _, pkg in ipairs(self:orderpkgs()) do
- self._PKGS_ENABLED[pkg:name()] = pkg
+ local packages = self:_memcache():get(cachekey)
+ if not packages then
+ packages = {}
+ for _, pkg in ipairs(self:orderpkgs(opt)) do
+ packages[pkg:name()] = pkg
+ end
+ self:_memcache():set(cachekey, packages)
end
- return self._PKGS_ENABLED
+ return packages
end
-- get the required packages with {interface|public = ..}
diff --git a/xmake/modules/private/action/require/impl/actions/install.lua b/xmake/modules/private/action/require/impl/actions/install.lua
index 10412c0a9..045e6a02f 100644
--- a/xmake/modules/private/action/require/impl/actions/install.lua
+++ b/xmake/modules/private/action/require/impl/actions/install.lua
@@ -299,6 +299,12 @@ function main(package)
filter.call(script, package, {oldenvs = oldenvs})
end
+ -- install rules
+ local rulesdir = path.join(package:scriptdir(), "rules")
+ if os.isdir(rulesdir) then
+ os.cp(rulesdir, package:installdir())
+ end
+
-- leave the environments of all package dependencies
os.setenvs(oldenvs)