diff --git a/tests/apis/namespace/option/.gitignore b/tests/apis/namespace/option/.gitignore new file mode 100644 index 00000000000..15210576129 --- /dev/null +++ b/tests/apis/namespace/option/.gitignore @@ -0,0 +1,8 @@ +# Xmake cache +.xmake/ +build/ + +# MacOS Cache +.DS_Store + + diff --git a/tests/apis/namespace/option/src/bar.cpp b/tests/apis/namespace/option/src/bar.cpp new file mode 100644 index 00000000000..2c00cc6b62f --- /dev/null +++ b/tests/apis/namespace/option/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/option/src/bar.h b/tests/apis/namespace/option/src/bar.h new file mode 100644 index 00000000000..47d8a7251e3 --- /dev/null +++ b/tests/apis/namespace/option/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/option/src/foo.cpp b/tests/apis/namespace/option/src/foo.cpp new file mode 100644 index 00000000000..1a1fb3425c5 --- /dev/null +++ b/tests/apis/namespace/option/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/option/src/foo.h b/tests/apis/namespace/option/src/foo.h new file mode 100644 index 00000000000..d2506bca987 --- /dev/null +++ b/tests/apis/namespace/option/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/option/src/main.cpp b/tests/apis/namespace/option/src/main.cpp new file mode 100644 index 00000000000..4cf7b5e624a --- /dev/null +++ b/tests/apis/namespace/option/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/option/test.lua b/tests/apis/namespace/option/test.lua new file mode 100644 index 00000000000..83c0a954648 --- /dev/null +++ b/tests/apis/namespace/option/test.lua @@ -0,0 +1,3 @@ +function main() + os.exec("xmake -vD") +end diff --git a/tests/apis/namespace/option/xmake.lua b/tests/apis/namespace/option/xmake.lua new file mode 100644 index 00000000000..10f2d18f5b9 --- /dev/null +++ b/tests/apis/namespace/option/xmake.lua @@ -0,0 +1,25 @@ +add_rules("mode.debug", "mode.release") + +option("opt0", {default = true, defines = "OPT0", description = "option0"}) + +namespace("ns1", function () + option("opt1", {default = true, defines = "NS1_OPT1", description = "option1"}) + + target("foo") + set_kind("static") + add_files("src/foo.cpp") + + namespace("ns2", function() + option("opt2", {default = true, defines = "NS2_OPT2", description = "option2"}) + target("bar") + set_kind("static") + add_files("src/bar.cpp") + end) + + target("test") + set_kind("binary") + add_deps("foo", "ns2::bar") + add_files("src/main.cpp") + add_options("opt0", "opt1", "ns2::opt2") +end) + diff --git a/xmake/core/base/cli.lua b/xmake/core/base/cli.lua index a5d3db9bacb..9eb4dfb7183 100644 --- a/xmake/core/base/cli.lua +++ b/xmake/core/base/cli.lua @@ -89,7 +89,11 @@ function cli.parsev(argv, flags) table.insert(parsed, cli._make_segment("sep", "--", argv, index, {})) elseif value:startswith("--") then -- "--key:value", "--key=value", "--long-flag" - local sep = value:find("[=:]", 3, false) + local sep = value:find("[=]", 3, false) + -- ignore namespace, e.g. `--namespace::opt` + if sep and value:sub(sep, sep + 1) == "::" then + sep = nil + end if sep then table.insert(parsed, cli._make_option(value:sub(3, sep - 1), value:sub(sep + 1), false, argv, index)) else diff --git a/xmake/core/project/option.lua b/xmake/core/project/option.lua index 0e4499f57e4..18b9dc363f1 100644 --- a/xmake/core/project/option.lua +++ b/xmake/core/project/option.lua @@ -44,9 +44,14 @@ local sandbox_module = require("sandbox/modules/import/core/sandbox/module") -- new an instance function _instance.new(name, info) - local instance = table.inherit(_instance) - instance._NAME = name - instance._INFO = info + local instance = table.inherit(_instance) + local parts = name:split("::", {plain = true}) + instance._NAME = parts[#parts] + table.remove(parts) + if #parts > 0 then + instance._NAMESPACE = table.concat(parts, "::") + end + instance._INFO = info instance._CACHEID = 1 return instance end @@ -63,7 +68,7 @@ function _instance:_save() self:set("check_before", nil) -- save option - option._cache():set(self:name(), self:info()) + option._cache():set(self:fullname(), self:info()) -- restore scripts self:set("check", check) @@ -73,7 +78,7 @@ end -- clear the option info for cache function _instance:_clear() - option._cache():set(self:name(), nil) + option._cache():set(self:fullname(), nil) end -- check snippets @@ -129,7 +134,7 @@ function _instance:_do_check_cxsnippets(snippets) end end if #table.keys(snippets_output) > 1 then - return false, -1, string.format("option(%s): only support for only one snippet with output!", self:name()) + return false, -1, string.format("option(%s): only support for only one snippet with output!", self:fullname()) end end @@ -309,6 +314,10 @@ function _instance:_check() if name:startswith("__") then name = name:sub(3) end + local namespace = self:namespace() + if namespace then + name = namespace .. "::" .. name + end -- trace local result @@ -336,7 +345,7 @@ end function _instance:check() -- the option name - local name = self:name() + local name = self:fullname() -- get default value, TODO: enable will be deprecated local default = self:get("default") @@ -378,24 +387,24 @@ end -- get the option value function _instance:value() - return config.get(self:name()) + return config.get(self:fullname()) end -- set the option value function _instance:set_value(value) - config.set(self:name(), value) + config.set(self:fullname(), value) self:_save() end -- clear the option status and need recheck it function _instance:clear() - config.set(self:name(), nil) + config.set(self:fullname(), nil) self:_clear() end -- this option is enabled? function _instance:enabled() - return config.get(self:name()) + return config.get(self:fullname()) end -- enable or disable this option @@ -409,8 +418,8 @@ function _instance:enable(enabled, opt) opt = opt or {} -- enable or disable this option? - if not config.readonly(self:name()) or opt.force then - config.set(self:name(), enabled, opt) + if not config.readonly(self:fullname()) or opt.force then + config.set(self:fullname(), enabled, opt) end -- save or clear this option in cache @@ -474,7 +483,14 @@ end function _instance:dep(name) local deps = self:deps() if deps then - return deps[name] + local dep = deps[name] + if dep == nil then + local namespace = self:namespace() + if namespace then + dep = deps[namespace .. "::" .. name] + end + end + return dep end end @@ -493,9 +509,20 @@ function _instance:name() return self._NAME 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 option description function _instance:description() - return self:get("description") or ("The " .. self:name() .. " option") + return self:get("description") or ("The " .. self:fullname() .. " option") end -- get the cache key @@ -645,13 +672,12 @@ function option.new(name, info) end -- load the option info from the cache -function option.load(name) - - -- check - assert(name) - - -- get info +function option.load(name, opt) + opt = opt or {} local info = option._cache():get(name) + if info == nil and opt.namespace then + info = option._cache():get(opt.namespace .. "::" .. name) + end if info == nil then return end diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua index f395f5f6b52..a266bf1db6b 100644 --- a/xmake/core/project/project.lua +++ b/xmake/core/project/project.lua @@ -1191,7 +1191,7 @@ function project.menu() options_by_category[category] = options_by_category[category] or {} -- append option to the current category - options_by_category[category][opt:name()] = opt + options_by_category[category][opt:fullname()] = opt end -- make menu by category diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua index eed55c0bfa8..03e68629f98 100644 --- a/xmake/core/project/target.lua +++ b/xmake/core/project/target.lua @@ -1278,7 +1278,13 @@ function _instance:orderopts(opt) orderopts = {} for _, name in ipairs(table.wrap(self:get("options", opt))) do local opt_ = nil - if config.get(name) then opt_ = option.load(name) end + local enabled = config.get(name) + if enabled == nil and self:namespace() then + enabled = config.get(self:namespace() .. "::" .. name) + end + if enabled then + opt_ = option.load(name, {namespace = self:namespace()}) + end if opt_ then table.insert(orderopts, opt_) end diff --git a/xmake/core/sandbox/modules/import/core/project/project.lua b/xmake/core/sandbox/modules/import/core/project/project.lua index bada906d4db..b39fabaf603 100644 --- a/xmake/core/sandbox/modules/import/core/project/project.lua +++ b/xmake/core/sandbox/modules/import/core/project/project.lua @@ -98,15 +98,15 @@ function sandbox_core_project.check_options() if opt then -- check deps of this option first for _, dep in ipairs(opt:orderdeps()) do - if not checked[dep:name()] then + if not checked[dep:fullname()] then dep:check() - checked[dep:name()] = true + checked[dep:fullname()] = true end end -- check this option - if not checked[opt:name()] then + if not checked[opt:fullname()] then opt:check() - checked[opt:name()] = true + checked[opt:fullname()] = true end end end