diff options
| author | ruki <[email protected]> | 2022-10-08 18:13:35 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-10-08 18:13:35 +0800 |
| commit | 17532b0ea38967d3d594cf7004c2d6a992d270fa (patch) | |
| tree | 4d90eb43d469d978c2f817030501ed2d0d0382d2 | |
| parent | 2c4ce2f510178a00c43cd16d7c85819b4a289423 (diff) | |
| parent | 35aa721e0eb879324e5f985a085d51ddfb251e05 (diff) | |
Merge pull request #2903 from xmake-io/rule
Add embed package rule support
| -rw-r--r-- | xmake/actions/config/main.lua | 42 | ||||
| -rw-r--r-- | xmake/core/project/package.lua | 105 | ||||
| -rw-r--r-- | xmake/core/project/project.lua | 13 | ||||
| -rw-r--r-- | xmake/core/project/rule.lua | 83 | ||||
| -rw-r--r-- | xmake/core/project/target.lua | 30 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/impl/actions/install.lua | 6 |
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) |
