diff --git a/tests/apis/namespace/rule/.gitignore b/tests/apis/namespace/rule/.gitignore new file mode 100644 index 00000000000..15210576129 --- /dev/null +++ b/tests/apis/namespace/rule/.gitignore @@ -0,0 +1,8 @@ +# Xmake cache +.xmake/ +build/ + +# MacOS Cache +.DS_Store + + diff --git a/tests/apis/namespace/rule/src/bar.cpp b/tests/apis/namespace/rule/src/bar.cpp new file mode 100644 index 00000000000..2c00cc6b62f --- /dev/null +++ b/tests/apis/namespace/rule/src/bar.cpp @@ -0,0 +1,5 @@ +#include "bar.h" + +int sub(int a, int b) { + return a - b; +} diff --git a/tests/apis/namespace/rule/src/bar.h b/tests/apis/namespace/rule/src/bar.h new file mode 100644 index 00000000000..47d8a7251e3 --- /dev/null +++ b/tests/apis/namespace/rule/src/bar.h @@ -0,0 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + +int sub(int a, int b); + +#ifdef __cplusplus +} +#endif diff --git a/tests/apis/namespace/rule/src/foo.cpp b/tests/apis/namespace/rule/src/foo.cpp new file mode 100644 index 00000000000..1a1fb3425c5 --- /dev/null +++ b/tests/apis/namespace/rule/src/foo.cpp @@ -0,0 +1,5 @@ +#include "foo.h" + +int add(int a, int b) { + return a + b; +} diff --git a/tests/apis/namespace/rule/src/foo.h b/tests/apis/namespace/rule/src/foo.h new file mode 100644 index 00000000000..d2506bca987 --- /dev/null +++ b/tests/apis/namespace/rule/src/foo.h @@ -0,0 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + +int add(int a, int b); + +#ifdef __cplusplus +} +#endif diff --git a/tests/apis/namespace/rule/src/main.cpp b/tests/apis/namespace/rule/src/main.cpp new file mode 100644 index 00000000000..4cf7b5e624a --- /dev/null +++ b/tests/apis/namespace/rule/src/main.cpp @@ -0,0 +1,9 @@ +#include "foo.h" +#include "bar.h" +#include + +int main(int argc, char** argv) { + std::cout << "add(1, 2) = " << add(1, 2) << std::endl; + std::cout << "sub(2, 1) = " << sub(2, 1) << std::endl; + return 0; +} diff --git a/tests/apis/namespace/rule/test.lua b/tests/apis/namespace/rule/test.lua new file mode 100644 index 00000000000..83c0a954648 --- /dev/null +++ b/tests/apis/namespace/rule/test.lua @@ -0,0 +1,3 @@ +function main() + os.exec("xmake -vD") +end diff --git a/tests/apis/namespace/rule/xmake.lua b/tests/apis/namespace/rule/xmake.lua new file mode 100644 index 00000000000..96b80271d8d --- /dev/null +++ b/tests/apis/namespace/rule/xmake.lua @@ -0,0 +1,37 @@ +add_rules("mode.debug", "mode.release") + +rule("rule0") + on_load(function (target) + target:add("defines", "RULE0") + end) + +namespace("ns1", function () + rule("rule1") + on_load(function (target) + target:add("defines", "NS1_RULE1") + end) + + target("foo") + set_kind("static") + add_files("src/foo.cpp") + add_rules("rule1") + + namespace("ns2", function() + rule("rule2") + on_load(function (target) + target:add("defines", "NS2_RULE2") + end) + + target("bar") + set_kind("static") + add_files("src/bar.cpp") + add_rules("rule2") + end) + + target("test") + set_kind("binary") + add_deps("foo", "ns2::bar") + add_files("src/main.cpp") + add_rules("rule0", "rule1", "ns2::rule2") +end) + diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua index a266bf1db6b..8afcee6b914 100644 --- a/xmake/core/project/project.lua +++ b/xmake/core/project/project.lua @@ -383,7 +383,7 @@ function project._load_targets() end rulenames = table.unique(rulenames) for _, rulename in ipairs(rulenames) do - local r = project.rule(rulename) or rule.rule(rulename) + local r = project.rule(rulename, {namespace = t:namespace()}) or rule.rule(rulename) if r then -- only add target rules if r:kind() == "target" then @@ -1087,8 +1087,13 @@ function project.requireslock_version() end -- get the given rule -function project.rule(name) - return project.rules()[name] +function project.rule(name, opt) + opt = opt or {} + local r = project.rules()[name] + if r == nil and opt.namespace then + r = project.rules()[opt.namespace .. "::" .. name] + end + return r end -- get project rules diff --git a/xmake/core/project/rule.lua b/xmake/core/project/rule.lua index 75da4da39d2..5d44f7c251f 100644 --- a/xmake/core/project/rule.lua +++ b/xmake/core/project/rule.lua @@ -60,12 +60,12 @@ function _instance:_build_deps() end self._DEPS = self._DEPS or {} self._ORDERDEPS = self._ORDERDEPS or {} - instance_deps.load_deps(self, instances, self._DEPS, self._ORDERDEPS, {self:name()}) + instance_deps.load_deps(self, instances, self._DEPS, self._ORDERDEPS, {self:fullname()}) end -- clone rule function _instance:clone() - local instance = rule.new(self:name(), self._INFO:clone()) + local instance = rule.new(self:fullname(), self._INFO:clone()) instance._DEPS = self._DEPS instance._ORDERDEPS = self._ORDERDEPS instance._PACKAGE = self._PACKAGE @@ -106,7 +106,23 @@ end -- set the rule name function _instance:name_set(name) - self._NAME = name + local parts = name:split("::", {plain = true}) + self._NAME = parts[#parts] + table.remove(parts) + if #parts > 0 then + self._NAMESPACE = table.concat(parts, "::") + end +end + +-- get the namespace +function _instance:namespace() + return self._NAMESPACE +end + +-- get the full name +function _instance:fullname() + local namespace = self:namespace() + return namespace and namespace .. "::" .. self:name() or self:name() end -- get the rule kind @@ -331,7 +347,7 @@ end function rule.new(name, info, opt) opt = opt or {} local instance = table.inherit(_instance) - instance._NAME = name + instance:name_set(name) instance._INFO = info instance._PACKAGE = opt.package if opt.package then diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua index 03e68629f98..9d5a9c07a67 100644 --- a/xmake/core/project/target.lua +++ b/xmake/core/project/target.lua @@ -75,7 +75,7 @@ end function _instance:_load_rule(ruleinst, suffix) -- init cache - local key = ruleinst:name() .. (suffix and ("_" .. suffix) or "") + local key = ruleinst:fullname() .. (suffix and ("_" .. suffix) or "") local cache = self._RULES_LOADED or {} -- do load @@ -90,7 +90,7 @@ function _instance:_load_rule(ruleinst, suffix) -- before_load has been deprecated if on_load and suffix == "before" then - deprecated.add(ruleinst:name() .. ".on_load", ruleinst:name() .. ".before_load") + deprecated.add(ruleinst:fullname() .. ".on_load", ruleinst:fullname() .. ".before_load") end end @@ -208,7 +208,7 @@ function _instance:_update_filerules() end rulenames = table.unique(rulenames) for _, rulename in ipairs(rulenames) do - local r = target._project() and target._project().rule(rulename) or rule.rule(rulename) + local r = target._project() and target._project().rule(rulename, {namespace = self:namespace()}) or rule.rule(rulename) if r then -- only add target rules if r:kind() == "target" then @@ -1163,7 +1163,11 @@ end -- get target rule from the given rule name function _instance:rule(name) if self._RULES then - return self._RULES[name] + local r = self._RULES[name] + if r == nil and self:namespace() then + r = self._RULES[self:namespace() .. "::" .. name] + end + return r end end @@ -1173,7 +1177,7 @@ end -- it will be replaced in the target:rules() and target:orderules(), but will be not replaced globally in the project.rules() function _instance:rule_add(r) self._RULES = self._RULES or {} - self._RULES[r:name()] = r + self._RULES[r:fullname()] = r self._ORDERULES = nil end @@ -1750,7 +1754,8 @@ function _instance:filerules(sourcefile) if filerules then override = filerules.override for _, rulename in ipairs(table.wrap(filerules)) do - local r = target._project().rule(rulename) or rule.rule(rulename) or self:rule(rulename) + local r = target._project().rule(rulename, {namespace = self:namespace()}) or + rule.rule(rulename) or self:rule(rulename) if r then table.insert(rules, r) end diff --git a/xmake/modules/private/utils/rule_groups.lua b/xmake/modules/private/utils/rule_groups.lua index ae7279e785e..d64a75d62fc 100644 --- a/xmake/modules/private/utils/rule_groups.lua +++ b/xmake/modules/private/utils/rule_groups.lua @@ -27,7 +27,8 @@ import("core.project.project") -- get rule -- @note we need to get rule from target first, because we maybe will inject and replace builtin rule in target function get_rule(target, rulename) - local ruleinst = assert(target:rule(rulename) or project.rule(rulename) or rule.rule(rulename), "unknown rule: %s", rulename) + local ruleinst = assert(target:rule(rulename) or project.rule(rulename, {namespace = target:namespace()}) or + rule.rule(rulename), "unknown rule: %s", rulename) return ruleinst end diff --git a/xmake/plugins/project/utils/target_cmds.lua b/xmake/plugins/project/utils/target_cmds.lua index 0b98a4ed7c4..332e4858d3e 100644 --- a/xmake/plugins/project/utils/target_cmds.lua +++ b/xmake/plugins/project/utils/target_cmds.lua @@ -64,7 +64,8 @@ function get_target_buildcmd_files(target, cmds, sourcebatch, opt) -- get rule local rulename = assert(sourcebatch.rulename, "unknown rule for sourcebatch!") - local ruleinst = assert(target:rule(rulename) or project.rule(rulename) or rule.rule(rulename), "unknown rule: %s", rulename) + local ruleinst = assert(target:rule(rulename) or project.rule(rulename, {namespace = target:namespace()}) or + rule.rule(rulename), "unknown rule: %s", rulename) local ignored_rules = hashset.from(opt.ignored_rules or {}) if ignored_rules:has(ruleinst:name()) then return