From 8512dce671af24d2f293728bfdb9e65f81e5ed38 Mon Sep 17 00:00:00 2001 From: Akaps316 <48785708+Akaps316@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:43:14 +0530 Subject: feat(show): export target dependency graph as JSON Add a graph-oriented mode to `xmake show` for exporting target\ndependency relationships as JSON.\n\nThis adds `--target_graph` support for whole-project output and\noptional root-target filtering with `--target`.\n\nAdd a plugin test covering full-graph and single-target graph export.\n\nRefs #7475 --- tests/plugins/show/test.lua | 85 ++++++++++++++++++++++ xmake/plugins/show/info/target_graph.lua | 120 +++++++++++++++++++++++++++++++ xmake/plugins/show/main.lua | 2 + xmake/plugins/show/xmake.lua | 2 +- 4 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 tests/plugins/show/test.lua create mode 100644 xmake/plugins/show/info/target_graph.lua diff --git a/tests/plugins/show/test.lua b/tests/plugins/show/test.lua new file mode 100644 index 000000000..0c0f783e6 --- /dev/null +++ b/tests/plugins/show/test.lua @@ -0,0 +1,85 @@ +import("core.base.json") + +local function _prepare_xmake_env() + local xmake = path.absolute(os.programfile()) + local xmake_program_dir = path.absolute(os.programdir()) + os.setenv("XMAKE_PROGRAM_FILE", xmake) + os.setenv("XMAKE_PROGRAM_DIR", xmake_program_dir) + return xmake +end + +local function _create_project(tempdir) + io.writefile(path.join(tempdir, "xmake.lua"), [[ +add_rules("mode.debug", "mode.release") + +target("core") + set_kind("static") + add_files("src/core.c") + +target("ui") + set_kind("static") + add_deps("core") + add_files("src/ui.c") + +target("app") + set_kind("binary") + add_deps("core", "ui") + add_files("src/main.c") +]]) + os.mkdir(path.join(tempdir, "src")) + io.writefile(path.join(tempdir, "src", "core.c"), "int core(void) { return 0; }\n") + io.writefile(path.join(tempdir, "src", "ui.c"), "int ui(void) { return 0; }\n") + io.writefile(path.join(tempdir, "src", "main.c"), "int main(void) { return 0; }\n") +end + +function test_target_graph_json(t) + local tempdir = os.tmpfile() + os.mkdir(tempdir) + _create_project(tempdir) + + local homedir = path.join(tempdir, "home") + os.setenv("HOME", homedir) + os.mkdir(homedir) + os.mkdir(path.join(homedir, ".xmake")) + + local xmake = _prepare_xmake_env() + local outdata = os.iorunv(xmake, {"show", "-P", tempdir, "--target_graph", "--json"}) + local graph = json.decode(outdata) + + t:are_equal(graph.root_targets, {"app"}) + t:require(#graph.targets == 3) + + local entries = {} + for _, target in ipairs(graph.targets) do + entries[target.name] = target + end + t:are_equal(entries.core.deps, {}) + t:are_equal(entries.ui.deps, {"core"}) + t:are_equal(entries.app.deps, {"core", "ui"}) + t:are_equal(entries.app.orderdeps, {"core", "ui"}) + t:are_equal(entries.app.kind, "binary") +end + +function test_target_graph_json_for_single_target(t) + local tempdir = os.tmpfile() + os.mkdir(tempdir) + _create_project(tempdir) + + local homedir = path.join(tempdir, "home") + os.setenv("HOME", homedir) + os.mkdir(homedir) + os.mkdir(path.join(homedir, ".xmake")) + + local xmake = _prepare_xmake_env() + local outdata = os.iorunv(xmake, {"show", "-P", tempdir, "--target_graph", "--target=app", "--json"}) + local graph = json.decode(outdata) + + t:are_equal(graph.root_targets, {"app"}) + t:require(#graph.targets == 3) + + local names = {} + for _, target in ipairs(graph.targets) do + table.insert(names, target.name) + end + t:are_equal(names, {"core", "ui", "app"}) +end diff --git a/xmake/plugins/show/info/target_graph.lua b/xmake/plugins/show/info/target_graph.lua new file mode 100644 index 000000000..30c977fc3 --- /dev/null +++ b/xmake/plugins/show/info/target_graph.lua @@ -0,0 +1,120 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file target_graph.lua +-- + +-- imports +import("core.base.option") +import("core.base.json") +import("core.project.config") +import("core.project.project") +import("private.detect.check_targetname") + +local function _collect_target_entry(target) + local deps = {} + for _, dep in pairs(target:deps() or {}) do + table.insert(deps, dep:name()) + end + table.sort(deps) + + local orderdeps = {} + for _, dep in ipairs(target:orderdeps() or {}) do + table.insert(orderdeps, dep:name()) + end + + return { + name = target:name(), + kind = target:kind(), + group = target:get("group"), + default = target:is_default(), + deps = deps, + orderdeps = orderdeps + } +end + +local function _collect_target_graph(root_target) + local targets = {} + local selected = {} + if root_target then + selected[root_target:name()] = true + for _, dep in ipairs(root_target:orderdeps() or {}) do + selected[dep:name()] = true + end + end + + for _, target in ipairs(project.ordertargets()) do + if not root_target or selected[target:name()] then + table.insert(targets, _collect_target_entry(target)) + end + end + + local roots = {} + if root_target then + table.insert(roots, root_target:name()) + else + local indegrees = {} + for _, target in ipairs(targets) do + indegrees[target.name] = 0 + end + for _, target in ipairs(targets) do + for _, depname in ipairs(target.deps) do + if indegrees[depname] ~= nil then + indegrees[depname] = indegrees[depname] + 1 + end + end + end + for _, target in ipairs(targets) do + if indegrees[target.name] == 0 then + table.insert(roots, target.name) + end + end + end + + return { + root_targets = roots, + targets = targets + } +end + +local function _print_target_graph(graph) + print("The dependency graph of targets:") + for _, target in ipairs(graph.targets) do + local deps = #target.deps > 0 and table.concat(target.deps, ", ") or "(none)" + cprint(" ${color.dump.string}%s${clear}: %s", target.name, deps) + end +end + +function main(name) + config.load() + + local root_target + if name then + root_target = assert(check_targetname(name)) + end + + local graph = _collect_target_graph(root_target) + if option.get("json") then + local json_opt + if option.get("pretty") then + json_opt = {pretty = true, orderkeys = true} + end + print(json.encode(graph, json_opt)) + else + _print_target_graph(graph) + end +end diff --git a/xmake/plugins/show/main.lua b/xmake/plugins/show/main.lua index 9dc4f519a..2b337b13e 100644 --- a/xmake/plugins/show/main.lua +++ b/xmake/plugins/show/main.lua @@ -32,6 +32,8 @@ function main() local listname = option.get("list") if listname then return _show_list(listname) + elseif option.get("target_graph") then + return assert(import("info.target_graph", {try = true, anonymous = true}))(option.get("target")) else -- show the information of the given object for _, filepath in ipairs(os.files(path.join(os.scriptdir(), "info", "*.lua"))) do diff --git a/xmake/plugins/show/xmake.lua b/xmake/plugins/show/xmake.lua index 331aeb468..3e3709877 100644 --- a/xmake/plugins/show/xmake.lua +++ b/xmake/plugins/show/xmake.lua @@ -32,6 +32,7 @@ task("show") {'g', "group", "kv", nil, "Filter targets by the given group name."}, {nil, "json", "k", false, "Show information with json format."}, {nil, "pretty", "k", false, "Enable pretty formatted json output."}, + {nil, "target_graph", "k", false, "Show the dependency graph of targets."}, {'t', "target", "kv", nil, "Show the information of the given target.", values = function (complete, opt) return import("private.utils.complete_helper.targets")(complete, opt) @@ -40,4 +41,3 @@ task("show") } - -- cgit v1.3.1 From f2179c9ccf0d199af1ea2c3320945f20a2f12f6e Mon Sep 17 00:00:00 2001 From: Akaps316 <48785708+Akaps316@users.noreply.github.com> Date: Sat, 11 Apr 2026 21:28:37 +0530 Subject: Address code review feedback by waruqi: refactor parameter parsing, remove local functions, and use simpler test env --- tests/plugins/show/test.lua | 14 +--- xmake/plugins/show/info/depgraph.lua | 120 +++++++++++++++++++++++++++++++ xmake/plugins/show/info/target_graph.lua | 120 ------------------------------- xmake/plugins/show/main.lua | 24 ++++--- xmake/plugins/show/xmake.lua | 2 +- 5 files changed, 137 insertions(+), 143 deletions(-) create mode 100644 xmake/plugins/show/info/depgraph.lua delete mode 100644 xmake/plugins/show/info/target_graph.lua diff --git a/tests/plugins/show/test.lua b/tests/plugins/show/test.lua index 0c0f783e6..4bffa5bff 100644 --- a/tests/plugins/show/test.lua +++ b/tests/plugins/show/test.lua @@ -1,13 +1,5 @@ import("core.base.json") -local function _prepare_xmake_env() - local xmake = path.absolute(os.programfile()) - local xmake_program_dir = path.absolute(os.programdir()) - os.setenv("XMAKE_PROGRAM_FILE", xmake) - os.setenv("XMAKE_PROGRAM_DIR", xmake_program_dir) - return xmake -end - local function _create_project(tempdir) io.writefile(path.join(tempdir, "xmake.lua"), [[ add_rules("mode.debug", "mode.release") @@ -42,8 +34,7 @@ function test_target_graph_json(t) os.mkdir(homedir) os.mkdir(path.join(homedir, ".xmake")) - local xmake = _prepare_xmake_env() - local outdata = os.iorunv(xmake, {"show", "-P", tempdir, "--target_graph", "--json"}) + local outdata = os.iorunv("xmake", {"show", "-P", tempdir, "--info=depgraph", "--json"}) local graph = json.decode(outdata) t:are_equal(graph.root_targets, {"app"}) @@ -70,8 +61,7 @@ function test_target_graph_json_for_single_target(t) os.mkdir(homedir) os.mkdir(path.join(homedir, ".xmake")) - local xmake = _prepare_xmake_env() - local outdata = os.iorunv(xmake, {"show", "-P", tempdir, "--target_graph", "--target=app", "--json"}) + local outdata = os.iorunv("xmake", {"show", "-P", tempdir, "--info=depgraph", "--target=app", "--json"}) local graph = json.decode(outdata) t:are_equal(graph.root_targets, {"app"}) diff --git a/xmake/plugins/show/info/depgraph.lua b/xmake/plugins/show/info/depgraph.lua new file mode 100644 index 000000000..cd5f3ad69 --- /dev/null +++ b/xmake/plugins/show/info/depgraph.lua @@ -0,0 +1,120 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file depgraph.lua +-- + +-- imports +import("core.base.option") +import("core.base.json") +import("core.project.config") +import("core.project.project") +import("private.detect.check_targetname") + +function _collect_target_entry(target) + local deps = {} + for _, dep in pairs(target:deps() or {}) do + table.insert(deps, dep:name()) + end + table.sort(deps) + + local orderdeps = {} + for _, dep in ipairs(target:orderdeps() or {}) do + table.insert(orderdeps, dep:name()) + end + + return { + name = target:name(), + kind = target:kind(), + group = target:get("group"), + default = target:is_default(), + deps = deps, + orderdeps = orderdeps + } +end + +function _collect_target_graph(root_target) + local targets = {} + local selected = {} + if root_target then + selected[root_target:name()] = true + for _, dep in ipairs(root_target:orderdeps() or {}) do + selected[dep:name()] = true + end + end + + for _, target in ipairs(project.ordertargets()) do + if not root_target or selected[target:name()] then + table.insert(targets, _collect_target_entry(target)) + end + end + + local roots = {} + if root_target then + table.insert(roots, root_target:name()) + else + local indegrees = {} + for _, target in ipairs(targets) do + indegrees[target.name] = 0 + end + for _, target in ipairs(targets) do + for _, depname in ipairs(target.deps) do + if indegrees[depname] ~= nil then + indegrees[depname] = indegrees[depname] + 1 + end + end + end + for _, target in ipairs(targets) do + if indegrees[target.name] == 0 then + table.insert(roots, target.name) + end + end + end + + return { + root_targets = roots, + targets = targets + } +end + +function _print_target_graph(graph) + print("The dependency graph of targets:") + for _, target in ipairs(graph.targets) do + local deps = #target.deps > 0 and table.concat(target.deps, ", ") or "(none)" + cprint(" ${color.dump.string}%s${clear}: %s", target.name, deps) + end +end + +function main(name) + config.load() + + local root_target + if name then + root_target = assert(check_targetname(name)) + end + + local graph = _collect_target_graph(root_target) + if option.get("json") then + local json_opt + if option.get("pretty") then + json_opt = {pretty = true, orderkeys = true} + end + print(json.encode(graph, json_opt)) + else + _print_target_graph(graph) + end +end diff --git a/xmake/plugins/show/info/target_graph.lua b/xmake/plugins/show/info/target_graph.lua deleted file mode 100644 index 30c977fc3..000000000 --- a/xmake/plugins/show/info/target_graph.lua +++ /dev/null @@ -1,120 +0,0 @@ ---!A cross-platform build utility based on Lua --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- --- Copyright (C) 2015-present, Xmake Open Source Community. --- --- @author ruki --- @file target_graph.lua --- - --- imports -import("core.base.option") -import("core.base.json") -import("core.project.config") -import("core.project.project") -import("private.detect.check_targetname") - -local function _collect_target_entry(target) - local deps = {} - for _, dep in pairs(target:deps() or {}) do - table.insert(deps, dep:name()) - end - table.sort(deps) - - local orderdeps = {} - for _, dep in ipairs(target:orderdeps() or {}) do - table.insert(orderdeps, dep:name()) - end - - return { - name = target:name(), - kind = target:kind(), - group = target:get("group"), - default = target:is_default(), - deps = deps, - orderdeps = orderdeps - } -end - -local function _collect_target_graph(root_target) - local targets = {} - local selected = {} - if root_target then - selected[root_target:name()] = true - for _, dep in ipairs(root_target:orderdeps() or {}) do - selected[dep:name()] = true - end - end - - for _, target in ipairs(project.ordertargets()) do - if not root_target or selected[target:name()] then - table.insert(targets, _collect_target_entry(target)) - end - end - - local roots = {} - if root_target then - table.insert(roots, root_target:name()) - else - local indegrees = {} - for _, target in ipairs(targets) do - indegrees[target.name] = 0 - end - for _, target in ipairs(targets) do - for _, depname in ipairs(target.deps) do - if indegrees[depname] ~= nil then - indegrees[depname] = indegrees[depname] + 1 - end - end - end - for _, target in ipairs(targets) do - if indegrees[target.name] == 0 then - table.insert(roots, target.name) - end - end - end - - return { - root_targets = roots, - targets = targets - } -end - -local function _print_target_graph(graph) - print("The dependency graph of targets:") - for _, target in ipairs(graph.targets) do - local deps = #target.deps > 0 and table.concat(target.deps, ", ") or "(none)" - cprint(" ${color.dump.string}%s${clear}: %s", target.name, deps) - end -end - -function main(name) - config.load() - - local root_target - if name then - root_target = assert(check_targetname(name)) - end - - local graph = _collect_target_graph(root_target) - if option.get("json") then - local json_opt - if option.get("pretty") then - json_opt = {pretty = true, orderkeys = true} - end - print(json.encode(graph, json_opt)) - else - _print_target_graph(graph) - end -end diff --git a/xmake/plugins/show/main.lua b/xmake/plugins/show/main.lua index 2b337b13e..7e04b7a43 100644 --- a/xmake/plugins/show/main.lua +++ b/xmake/plugins/show/main.lua @@ -32,16 +32,20 @@ function main() local listname = option.get("list") if listname then return _show_list(listname) - elseif option.get("target_graph") then - return assert(import("info.target_graph", {try = true, anonymous = true}))(option.get("target")) - else - -- show the information of the given object - for _, filepath in ipairs(os.files(path.join(os.scriptdir(), "info", "*.lua"))) do - local name = path.basename(filepath) - if option.get(name) then - local show_info = assert(import("info." .. name, {try = true, anonymous = true}), "unknown option name(%s)", name) - return show_info(option.get(name)) - end + end + + local infoname = option.get("info") + if infoname then + local show_info = assert(import("info." .. infoname, {try = true, anonymous = true}), "unknown info name(%s)", infoname) + return show_info(option.get("target")) + end + + -- fallback to legacy options format + for _, filepath in ipairs(os.files(path.join(os.scriptdir(), "info", "*.lua"))) do + local name = path.basename(filepath) + if option.get(name) then + local show_info = assert(import("info." .. name, {try = true, anonymous = true}), "unknown option name(%s)", name) + return show_info(option.get(name)) end end diff --git a/xmake/plugins/show/xmake.lua b/xmake/plugins/show/xmake.lua index 3e3709877..cb16ff207 100644 --- a/xmake/plugins/show/xmake.lua +++ b/xmake/plugins/show/xmake.lua @@ -32,7 +32,7 @@ task("show") {'g', "group", "kv", nil, "Filter targets by the given group name."}, {nil, "json", "k", false, "Show information with json format."}, {nil, "pretty", "k", false, "Enable pretty formatted json output."}, - {nil, "target_graph", "k", false, "Show the dependency graph of targets."}, + {'i', "info", "kv", nil, "Show the given information."}, {'t', "target", "kv", nil, "Show the information of the given target.", values = function (complete, opt) return import("private.utils.complete_helper.targets")(complete, opt) -- cgit v1.3.1 From 0c36a9b4acb9150c607b3d70291ad50148785038 Mon Sep 17 00:00:00 2001 From: Akaps316 <48785708+Akaps316@users.noreply.github.com> Date: Sat, 11 Apr 2026 21:45:14 +0530 Subject: Refactor to use test project fixture and ordered dependencies --- tests/plugins/show/test.lua | 75 ------------------------- tests/projects/plugins/show/depgraph/src/core.c | 1 + tests/projects/plugins/show/depgraph/src/main.c | 1 + tests/projects/plugins/show/depgraph/src/ui.c | 1 + tests/projects/plugins/show/depgraph/test.lua | 32 +++++++++++ tests/projects/plugins/show/depgraph/xmake.lua | 15 +++++ xmake/plugins/show/info/depgraph.lua | 11 +--- 7 files changed, 52 insertions(+), 84 deletions(-) delete mode 100644 tests/plugins/show/test.lua create mode 100644 tests/projects/plugins/show/depgraph/src/core.c create mode 100644 tests/projects/plugins/show/depgraph/src/main.c create mode 100644 tests/projects/plugins/show/depgraph/src/ui.c create mode 100644 tests/projects/plugins/show/depgraph/test.lua create mode 100644 tests/projects/plugins/show/depgraph/xmake.lua diff --git a/tests/plugins/show/test.lua b/tests/plugins/show/test.lua deleted file mode 100644 index 4bffa5bff..000000000 --- a/tests/plugins/show/test.lua +++ /dev/null @@ -1,75 +0,0 @@ -import("core.base.json") - -local function _create_project(tempdir) - io.writefile(path.join(tempdir, "xmake.lua"), [[ -add_rules("mode.debug", "mode.release") - -target("core") - set_kind("static") - add_files("src/core.c") - -target("ui") - set_kind("static") - add_deps("core") - add_files("src/ui.c") - -target("app") - set_kind("binary") - add_deps("core", "ui") - add_files("src/main.c") -]]) - os.mkdir(path.join(tempdir, "src")) - io.writefile(path.join(tempdir, "src", "core.c"), "int core(void) { return 0; }\n") - io.writefile(path.join(tempdir, "src", "ui.c"), "int ui(void) { return 0; }\n") - io.writefile(path.join(tempdir, "src", "main.c"), "int main(void) { return 0; }\n") -end - -function test_target_graph_json(t) - local tempdir = os.tmpfile() - os.mkdir(tempdir) - _create_project(tempdir) - - local homedir = path.join(tempdir, "home") - os.setenv("HOME", homedir) - os.mkdir(homedir) - os.mkdir(path.join(homedir, ".xmake")) - - local outdata = os.iorunv("xmake", {"show", "-P", tempdir, "--info=depgraph", "--json"}) - local graph = json.decode(outdata) - - t:are_equal(graph.root_targets, {"app"}) - t:require(#graph.targets == 3) - - local entries = {} - for _, target in ipairs(graph.targets) do - entries[target.name] = target - end - t:are_equal(entries.core.deps, {}) - t:are_equal(entries.ui.deps, {"core"}) - t:are_equal(entries.app.deps, {"core", "ui"}) - t:are_equal(entries.app.orderdeps, {"core", "ui"}) - t:are_equal(entries.app.kind, "binary") -end - -function test_target_graph_json_for_single_target(t) - local tempdir = os.tmpfile() - os.mkdir(tempdir) - _create_project(tempdir) - - local homedir = path.join(tempdir, "home") - os.setenv("HOME", homedir) - os.mkdir(homedir) - os.mkdir(path.join(homedir, ".xmake")) - - local outdata = os.iorunv("xmake", {"show", "-P", tempdir, "--info=depgraph", "--target=app", "--json"}) - local graph = json.decode(outdata) - - t:are_equal(graph.root_targets, {"app"}) - t:require(#graph.targets == 3) - - local names = {} - for _, target in ipairs(graph.targets) do - table.insert(names, target.name) - end - t:are_equal(names, {"core", "ui", "app"}) -end diff --git a/tests/projects/plugins/show/depgraph/src/core.c b/tests/projects/plugins/show/depgraph/src/core.c new file mode 100644 index 000000000..87a413095 --- /dev/null +++ b/tests/projects/plugins/show/depgraph/src/core.c @@ -0,0 +1 @@ +int core(void) { return 0; } diff --git a/tests/projects/plugins/show/depgraph/src/main.c b/tests/projects/plugins/show/depgraph/src/main.c new file mode 100644 index 000000000..78f2de106 --- /dev/null +++ b/tests/projects/plugins/show/depgraph/src/main.c @@ -0,0 +1 @@ +int main(void) { return 0; } diff --git a/tests/projects/plugins/show/depgraph/src/ui.c b/tests/projects/plugins/show/depgraph/src/ui.c new file mode 100644 index 000000000..c15794f4d --- /dev/null +++ b/tests/projects/plugins/show/depgraph/src/ui.c @@ -0,0 +1 @@ +int ui(void) { return 0; } diff --git a/tests/projects/plugins/show/depgraph/test.lua b/tests/projects/plugins/show/depgraph/test.lua new file mode 100644 index 000000000..28ae7c188 --- /dev/null +++ b/tests/projects/plugins/show/depgraph/test.lua @@ -0,0 +1,32 @@ +import("core.base.json") + +function test_depgraph_json(t) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--json"}) + local graph = json.decode(outdata) + + t:are_equal(graph.root_targets, {"app"}) + t:require(#graph.targets == 3) + + local entries = {} + for _, target in ipairs(graph.targets) do + entries[target.name] = target + end + t:are_equal(entries.core.deps, {}) + t:are_equal(entries.ui.deps, {"core"}) + t:are_equal(entries.app.deps, {"core", "ui"}) + t:are_equal(entries.app.kind, "binary") +end + +function test_depgraph_json_for_single_target(t) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--target=app", "--json"}) + local graph = json.decode(outdata) + + t:are_equal(graph.root_targets, {"app"}) + t:require(#graph.targets == 3) + + local names = {} + for _, target in ipairs(graph.targets) do + table.insert(names, target.name) + end + t:are_equal(names, {"core", "ui", "app"}) +end diff --git a/tests/projects/plugins/show/depgraph/xmake.lua b/tests/projects/plugins/show/depgraph/xmake.lua new file mode 100644 index 000000000..7077424f3 --- /dev/null +++ b/tests/projects/plugins/show/depgraph/xmake.lua @@ -0,0 +1,15 @@ +add_rules("mode.debug", "mode.release") + +target("core") + set_kind("static") + add_files("src/core.c") + +target("ui") + set_kind("static") + add_deps("core") + add_files("src/ui.c") + +target("app") + set_kind("binary") + add_deps("core", "ui") + add_files("src/main.c") diff --git a/xmake/plugins/show/info/depgraph.lua b/xmake/plugins/show/info/depgraph.lua index cd5f3ad69..1f3142309 100644 --- a/xmake/plugins/show/info/depgraph.lua +++ b/xmake/plugins/show/info/depgraph.lua @@ -27,14 +27,8 @@ import("private.detect.check_targetname") function _collect_target_entry(target) local deps = {} - for _, dep in pairs(target:deps() or {}) do - table.insert(deps, dep:name()) - end - table.sort(deps) - - local orderdeps = {} for _, dep in ipairs(target:orderdeps() or {}) do - table.insert(orderdeps, dep:name()) + table.insert(deps, dep:name()) end return { @@ -42,8 +36,7 @@ function _collect_target_entry(target) kind = target:kind(), group = target:get("group"), default = target:is_default(), - deps = deps, - orderdeps = orderdeps + deps = deps } end -- cgit v1.3.1 From 7eada8439652626e484c0011a4ae536b916cc7fe Mon Sep 17 00:00:00 2001 From: Akaps316 <48785708+Akaps316@users.noreply.github.com> Date: Sun, 12 Apr 2026 19:40:20 +0530 Subject: fix(depgraph): use direct deps and align print output with JSON MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Switch from target:orderdeps() to target:get('deps') to show only direct dependencies declared via add_deps(), not transitive ones - Print output now shows all fields: root targets, name, kind, group, default, and deps — matching the JSON structure - Add kind assertion to test --- tests/projects/plugins/show/depgraph/test.lua | 1 + xmake/plugins/show/info/depgraph.lua | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/projects/plugins/show/depgraph/test.lua b/tests/projects/plugins/show/depgraph/test.lua index 28ae7c188..229e715de 100644 --- a/tests/projects/plugins/show/depgraph/test.lua +++ b/tests/projects/plugins/show/depgraph/test.lua @@ -12,6 +12,7 @@ function test_depgraph_json(t) entries[target.name] = target end t:are_equal(entries.core.deps, {}) + t:are_equal(entries.core.kind, "static") t:are_equal(entries.ui.deps, {"core"}) t:are_equal(entries.app.deps, {"core", "ui"}) t:are_equal(entries.app.kind, "binary") diff --git a/xmake/plugins/show/info/depgraph.lua b/xmake/plugins/show/info/depgraph.lua index 1f3142309..0807d865a 100644 --- a/xmake/plugins/show/info/depgraph.lua +++ b/xmake/plugins/show/info/depgraph.lua @@ -27,8 +27,11 @@ import("private.detect.check_targetname") function _collect_target_entry(target) local deps = {} - for _, dep in ipairs(target:orderdeps() or {}) do - table.insert(deps, dep:name()) + local plain_deps = target:get("deps") + if plain_deps then + for _, dep in ipairs(plain_deps) do + table.insert(deps, dep) + end end return { @@ -86,9 +89,18 @@ end function _print_target_graph(graph) print("The dependency graph of targets:") + cprint("") + cprint(" ${color.dump.string}root targets${clear}: %s", table.concat(graph.root_targets, ", ")) + cprint("") for _, target in ipairs(graph.targets) do local deps = #target.deps > 0 and table.concat(target.deps, ", ") or "(none)" - cprint(" ${color.dump.string}%s${clear}: %s", target.name, deps) + cprint(" ${color.dump.string}%s${clear}:", target.name) + cprint(" ${dim}kind${clear}: %s", target.kind) + if target.group then + cprint(" ${dim}group${clear}: %s", target.group) + end + cprint(" ${dim}default${clear}: %s", tostring(target.default)) + cprint(" ${dim}deps${clear}: %s", deps) end end -- cgit v1.3.1 From 8d210b47dae26b061131004f61ba48cce6429d4e Mon Sep 17 00:00:00 2001 From: Akaps316 <48785708+Akaps316@users.noreply.github.com> Date: Sat, 18 Apr 2026 12:38:56 +0530 Subject: refactor: simplify target deps retrieval per PR review --- xmake/plugins/show/info/depgraph.lua | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/xmake/plugins/show/info/depgraph.lua b/xmake/plugins/show/info/depgraph.lua index 0807d865a..c2a4db1ea 100644 --- a/xmake/plugins/show/info/depgraph.lua +++ b/xmake/plugins/show/info/depgraph.lua @@ -26,13 +26,7 @@ import("core.project.project") import("private.detect.check_targetname") function _collect_target_entry(target) - local deps = {} - local plain_deps = target:get("deps") - if plain_deps then - for _, dep in ipairs(plain_deps) do - table.insert(deps, dep) - end - end + local deps = target:get("deps") or {} return { name = target:name(), -- cgit v1.3.1 From 8a58cf9cb94e016c8a2297f1edab6b883d02e847 Mon Sep 17 00:00:00 2001 From: Akaps316 <48785708+Akaps316@users.noreply.github.com> Date: Sat, 18 Apr 2026 13:05:03 +0530 Subject: fix(depgraph): wrap deps in table to avoid json string literal on single dep --- .../objc/macapp_external_dylib/ext/libextfoo.dylib | Bin 0 -> 16800 bytes xmake/plugins/show/info/depgraph.lua | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100755 tests/projects/objc/macapp_external_dylib/ext/libextfoo.dylib diff --git a/tests/projects/objc/macapp_external_dylib/ext/libextfoo.dylib b/tests/projects/objc/macapp_external_dylib/ext/libextfoo.dylib new file mode 100755 index 000000000..c92515666 Binary files /dev/null and b/tests/projects/objc/macapp_external_dylib/ext/libextfoo.dylib differ diff --git a/xmake/plugins/show/info/depgraph.lua b/xmake/plugins/show/info/depgraph.lua index c2a4db1ea..55a2d7360 100644 --- a/xmake/plugins/show/info/depgraph.lua +++ b/xmake/plugins/show/info/depgraph.lua @@ -26,7 +26,7 @@ import("core.project.project") import("private.detect.check_targetname") function _collect_target_entry(target) - local deps = target:get("deps") or {} + local deps = table.wrap(target:get("deps")) return { name = target:name(), -- cgit v1.3.1 From 51be800bddfa199774206393cb8d7e0749f59756 Mon Sep 17 00:00:00 2001 From: ruki Date: Sat, 18 Apr 2026 21:21:33 +0800 Subject: improve xmake show --info --- xmake/plugins/show/info/depgraph.lua | 7 +++++-- xmake/plugins/show/info/target.lua | 1 + xmake/plugins/show/list.lua | 12 ++++++++++++ xmake/plugins/show/xmake.lua | 5 ++++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/xmake/plugins/show/info/depgraph.lua b/xmake/plugins/show/info/depgraph.lua index 55a2d7360..60e667002 100644 --- a/xmake/plugins/show/info/depgraph.lua +++ b/xmake/plugins/show/info/depgraph.lua @@ -27,6 +27,7 @@ import("private.detect.check_targetname") function _collect_target_entry(target) local deps = table.wrap(target:get("deps")) + json.mark_as_array(deps) return { name = target:name(), @@ -75,6 +76,7 @@ function _collect_target_graph(root_target) end end + json.mark_as_array(roots) return { root_targets = roots, targets = targets @@ -87,14 +89,15 @@ function _print_target_graph(graph) cprint(" ${color.dump.string}root targets${clear}: %s", table.concat(graph.root_targets, ", ")) cprint("") for _, target in ipairs(graph.targets) do - local deps = #target.deps > 0 and table.concat(target.deps, ", ") or "(none)" cprint(" ${color.dump.string}%s${clear}:", target.name) cprint(" ${dim}kind${clear}: %s", target.kind) if target.group then cprint(" ${dim}group${clear}: %s", target.group) end cprint(" ${dim}default${clear}: %s", tostring(target.default)) - cprint(" ${dim}deps${clear}: %s", deps) + if #target.deps > 0 then + cprint(" ${dim}deps${clear}: %s", table.concat(target.deps, ", ")) + end end end diff --git a/xmake/plugins/show/info/target.lua b/xmake/plugins/show/info/target.lua index e63a51ea7..bfa88ad92 100644 --- a/xmake/plugins/show/info/target.lua +++ b/xmake/plugins/show/info/target.lua @@ -367,6 +367,7 @@ function main(name) json = option.get("json"), pretty = option.get("pretty") } + assert(name, "please specify the target name, e.g. xmake show --info=target --target=xxx") local target = assert(check_targetname(name)) local info = _collect_target_info(target) diff --git a/xmake/plugins/show/list.lua b/xmake/plugins/show/list.lua index fb2914964..301048ce2 100644 --- a/xmake/plugins/show/list.lua +++ b/xmake/plugins/show/list.lua @@ -29,3 +29,15 @@ function lists() end return values end + +-- get all info values +function infos() + local values = {} + for _, filepath in ipairs(os.files(path.join(os.scriptdir(), "info", "*.lua"))) do + local name = path.basename(filepath) + if name ~= "basic" and name ~= "target" then + table.insert(values, name) + end + end + return values +end diff --git a/xmake/plugins/show/xmake.lua b/xmake/plugins/show/xmake.lua index cb16ff207..77d2be2b3 100644 --- a/xmake/plugins/show/xmake.lua +++ b/xmake/plugins/show/xmake.lua @@ -32,7 +32,10 @@ task("show") {'g', "group", "kv", nil, "Filter targets by the given group name."}, {nil, "json", "k", false, "Show information with json format."}, {nil, "pretty", "k", false, "Enable pretty formatted json output."}, - {'i', "info", "kv", nil, "Show the given information."}, + {'i', "info", "kv", nil, "Show the given information.", + values = function (complete, opt) + return import("list").infos() + end}, {'t', "target", "kv", nil, "Show the information of the given target.", values = function (complete, opt) return import("private.utils.complete_helper.targets")(complete, opt) -- cgit v1.3.1 From fea8ad3d654e497ba83315f26902647dd64f561e Mon Sep 17 00:00:00 2001 From: ruki Date: Sat, 18 Apr 2026 21:52:57 +0800 Subject: add --dot output --- tests/plugins/show/src/core.c | 1 + tests/plugins/show/src/main.c | 1 + tests/plugins/show/src/ui.c | 1 + tests/plugins/show/test.lua | 58 +++++++++++++++++++++++++ tests/plugins/show/xmake.lua | 15 +++++++ tests/projects/plugins/show/depgraph/src/core.c | 1 - tests/projects/plugins/show/depgraph/src/main.c | 1 - tests/projects/plugins/show/depgraph/src/ui.c | 1 - tests/projects/plugins/show/depgraph/test.lua | 33 -------------- tests/projects/plugins/show/depgraph/xmake.lua | 15 ------- xmake/plugins/show/info/depgraph.lua | 58 ++++++++++++++++++------- xmake/plugins/show/xmake.lua | 1 + 12 files changed, 119 insertions(+), 67 deletions(-) create mode 100644 tests/plugins/show/src/core.c create mode 100644 tests/plugins/show/src/main.c create mode 100644 tests/plugins/show/src/ui.c create mode 100644 tests/plugins/show/test.lua create mode 100644 tests/plugins/show/xmake.lua delete mode 100644 tests/projects/plugins/show/depgraph/src/core.c delete mode 100644 tests/projects/plugins/show/depgraph/src/main.c delete mode 100644 tests/projects/plugins/show/depgraph/src/ui.c delete mode 100644 tests/projects/plugins/show/depgraph/test.lua delete mode 100644 tests/projects/plugins/show/depgraph/xmake.lua diff --git a/tests/plugins/show/src/core.c b/tests/plugins/show/src/core.c new file mode 100644 index 000000000..87a413095 --- /dev/null +++ b/tests/plugins/show/src/core.c @@ -0,0 +1 @@ +int core(void) { return 0; } diff --git a/tests/plugins/show/src/main.c b/tests/plugins/show/src/main.c new file mode 100644 index 000000000..78f2de106 --- /dev/null +++ b/tests/plugins/show/src/main.c @@ -0,0 +1 @@ +int main(void) { return 0; } diff --git a/tests/plugins/show/src/ui.c b/tests/plugins/show/src/ui.c new file mode 100644 index 000000000..c15794f4d --- /dev/null +++ b/tests/plugins/show/src/ui.c @@ -0,0 +1 @@ +int ui(void) { return 0; } diff --git a/tests/plugins/show/test.lua b/tests/plugins/show/test.lua new file mode 100644 index 000000000..451b13ade --- /dev/null +++ b/tests/plugins/show/test.lua @@ -0,0 +1,58 @@ +import("core.base.json") + +function test_depgraph_json(t) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--json"}) + local graph = json.decode(outdata) + + t:are_equal(graph.root_targets, {"app"}) + t:require(#graph.targets == 3) + + local entries = {} + for _, target in ipairs(graph.targets) do + entries[target.name] = target + end + t:are_equal(entries.core.deps, {}) + t:are_equal(entries.ui.deps, {"core"}) + t:are_equal(entries.app.deps, {"core", "ui"}) +end + +function test_depgraph_json_for_single_target(t) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--target=app", "--json", }) + local graph = json.decode(outdata) + + t:are_equal(graph.root_targets, {"app"}) + t:require(#graph.targets == 3) + + local names = {} + for _, target in ipairs(graph.targets) do + table.insert(names, target.name) + end + t:are_equal(names, {"core", "ui", "app"}) +end + +function test_depgraph_tree(t) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", }) + t:require(outdata:find("app", 1, true)) + t:require(outdata:find("core", 1, true)) + t:require(outdata:find("ui", 1, true)) + t:require(outdata:find("├── ", 1, true) or outdata:find("+-- ", 1, true)) + t:require(outdata:find("└── ", 1, true) or outdata:find("\\-- ", 1, true)) +end + +function test_depgraph_dot(t) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--dot", }) + t:require(outdata:find("digraph {", 1, true)) + t:require(outdata:find('"core"', 1, true)) + t:require(outdata:find('"ui" -> "core"', 1, true)) + t:require(outdata:find('"app" -> "core"', 1, true)) + t:require(outdata:find('"app" -> "ui"', 1, true)) + t:require(outdata:find("}", 1, true)) +end + +function test_depgraph_dot_for_single_target(t) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--target=ui", "--dot", }) + t:require(outdata:find("digraph {", 1, true)) + t:require(outdata:find('"core"', 1, true)) + t:require(outdata:find('"ui" -> "core"', 1, true)) + t:require(not outdata:find('"app"', 1, true)) +end diff --git a/tests/plugins/show/xmake.lua b/tests/plugins/show/xmake.lua new file mode 100644 index 000000000..7077424f3 --- /dev/null +++ b/tests/plugins/show/xmake.lua @@ -0,0 +1,15 @@ +add_rules("mode.debug", "mode.release") + +target("core") + set_kind("static") + add_files("src/core.c") + +target("ui") + set_kind("static") + add_deps("core") + add_files("src/ui.c") + +target("app") + set_kind("binary") + add_deps("core", "ui") + add_files("src/main.c") diff --git a/tests/projects/plugins/show/depgraph/src/core.c b/tests/projects/plugins/show/depgraph/src/core.c deleted file mode 100644 index 87a413095..000000000 --- a/tests/projects/plugins/show/depgraph/src/core.c +++ /dev/null @@ -1 +0,0 @@ -int core(void) { return 0; } diff --git a/tests/projects/plugins/show/depgraph/src/main.c b/tests/projects/plugins/show/depgraph/src/main.c deleted file mode 100644 index 78f2de106..000000000 --- a/tests/projects/plugins/show/depgraph/src/main.c +++ /dev/null @@ -1 +0,0 @@ -int main(void) { return 0; } diff --git a/tests/projects/plugins/show/depgraph/src/ui.c b/tests/projects/plugins/show/depgraph/src/ui.c deleted file mode 100644 index c15794f4d..000000000 --- a/tests/projects/plugins/show/depgraph/src/ui.c +++ /dev/null @@ -1 +0,0 @@ -int ui(void) { return 0; } diff --git a/tests/projects/plugins/show/depgraph/test.lua b/tests/projects/plugins/show/depgraph/test.lua deleted file mode 100644 index 229e715de..000000000 --- a/tests/projects/plugins/show/depgraph/test.lua +++ /dev/null @@ -1,33 +0,0 @@ -import("core.base.json") - -function test_depgraph_json(t) - local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--json"}) - local graph = json.decode(outdata) - - t:are_equal(graph.root_targets, {"app"}) - t:require(#graph.targets == 3) - - local entries = {} - for _, target in ipairs(graph.targets) do - entries[target.name] = target - end - t:are_equal(entries.core.deps, {}) - t:are_equal(entries.core.kind, "static") - t:are_equal(entries.ui.deps, {"core"}) - t:are_equal(entries.app.deps, {"core", "ui"}) - t:are_equal(entries.app.kind, "binary") -end - -function test_depgraph_json_for_single_target(t) - local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--target=app", "--json"}) - local graph = json.decode(outdata) - - t:are_equal(graph.root_targets, {"app"}) - t:require(#graph.targets == 3) - - local names = {} - for _, target in ipairs(graph.targets) do - table.insert(names, target.name) - end - t:are_equal(names, {"core", "ui", "app"}) -end diff --git a/tests/projects/plugins/show/depgraph/xmake.lua b/tests/projects/plugins/show/depgraph/xmake.lua deleted file mode 100644 index 7077424f3..000000000 --- a/tests/projects/plugins/show/depgraph/xmake.lua +++ /dev/null @@ -1,15 +0,0 @@ -add_rules("mode.debug", "mode.release") - -target("core") - set_kind("static") - add_files("src/core.c") - -target("ui") - set_kind("static") - add_deps("core") - add_files("src/ui.c") - -target("app") - set_kind("binary") - add_deps("core", "ui") - add_files("src/main.c") diff --git a/xmake/plugins/show/info/depgraph.lua b/xmake/plugins/show/info/depgraph.lua index 60e667002..199754772 100644 --- a/xmake/plugins/show/info/depgraph.lua +++ b/xmake/plugins/show/info/depgraph.lua @@ -28,12 +28,8 @@ import("private.detect.check_targetname") function _collect_target_entry(target) local deps = table.wrap(target:get("deps")) json.mark_as_array(deps) - return { name = target:name(), - kind = target:kind(), - group = target:get("group"), - default = target:is_default(), deps = deps } end @@ -83,22 +79,49 @@ function _collect_target_graph(root_target) } end +function _print_dep_tree(targets_map, name, prefix, expanded) + expanded[name] = true + local entry = targets_map[name] + local deps = entry and entry.deps or {} + for i, dep in ipairs(deps) do + local is_last = (i == #deps) + local connector = is_last and "└── " or "├── " + local next_prefix = prefix .. (is_last and " " or "│ ") + local dep_entry = targets_map[dep] + local dep_deps = dep_entry and dep_entry.deps or {} + if expanded[dep] and #dep_deps > 0 then + cprint("%s%s${color.dump.string}%s${clear} ${dim}(*)${clear}", prefix, connector, dep) + else + cprint("%s%s${color.dump.string}%s${clear}", prefix, connector, dep) + _print_dep_tree(targets_map, dep, next_prefix, expanded) + end + end +end + function _print_target_graph(graph) - print("The dependency graph of targets:") - cprint("") - cprint(" ${color.dump.string}root targets${clear}: %s", table.concat(graph.root_targets, ", ")) - cprint("") + local targets_map = {} for _, target in ipairs(graph.targets) do - cprint(" ${color.dump.string}%s${clear}:", target.name) - cprint(" ${dim}kind${clear}: %s", target.kind) - if target.group then - cprint(" ${dim}group${clear}: %s", target.group) - end - cprint(" ${dim}default${clear}: %s", tostring(target.default)) - if #target.deps > 0 then - cprint(" ${dim}deps${clear}: %s", table.concat(target.deps, ", ")) + targets_map[target.name] = target + end + local expanded = {} + for _, root in ipairs(graph.root_targets) do + cprint("${color.dump.string}%s${clear}", root) + _print_dep_tree(targets_map, root, "", expanded) + end +end + +function _print_dot_graph(graph) + print("digraph {") + for _, target in ipairs(graph.targets) do + if #target.deps == 0 then + print(string.format(" \"%s\"", target.name)) + else + for _, dep in ipairs(target.deps) do + print(string.format(" \"%s\" -> \"%s\"", target.name, dep)) + end end end + print("}") end function main(name) @@ -110,12 +133,15 @@ function main(name) end local graph = _collect_target_graph(root_target) + assert(not (option.get("json") and option.get("dot")), "--json and --dot are mutually exclusive") if option.get("json") then local json_opt if option.get("pretty") then json_opt = {pretty = true, orderkeys = true} end print(json.encode(graph, json_opt)) + elseif option.get("dot") then + _print_dot_graph(graph) else _print_target_graph(graph) end diff --git a/xmake/plugins/show/xmake.lua b/xmake/plugins/show/xmake.lua index 77d2be2b3..de7a5a1c5 100644 --- a/xmake/plugins/show/xmake.lua +++ b/xmake/plugins/show/xmake.lua @@ -32,6 +32,7 @@ task("show") {'g', "group", "kv", nil, "Filter targets by the given group name."}, {nil, "json", "k", false, "Show information with json format."}, {nil, "pretty", "k", false, "Enable pretty formatted json output."}, + {nil, "dot", "k", false, "Output dependency graph in graphviz DOT format."}, {'i', "info", "kv", nil, "Show the given information.", values = function (complete, opt) return import("list").infos() -- cgit v1.3.1 From 1f673c158867dffbf4edb78909fa87fbb02fc2e5 Mon Sep 17 00:00:00 2001 From: ruki Date: Sat, 18 Apr 2026 22:02:06 +0800 Subject: improve show test --- tests/plugins/show/test.lua | 8 ++++---- xmake/plugins/show/xmake.lua | 8 +++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/plugins/show/test.lua b/tests/plugins/show/test.lua index 451b13ade..cac268c96 100644 --- a/tests/plugins/show/test.lua +++ b/tests/plugins/show/test.lua @@ -17,7 +17,7 @@ function test_depgraph_json(t) end function test_depgraph_json_for_single_target(t) - local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--target=app", "--json", }) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--target=app", "--json"}) local graph = json.decode(outdata) t:are_equal(graph.root_targets, {"app"}) @@ -31,7 +31,7 @@ function test_depgraph_json_for_single_target(t) end function test_depgraph_tree(t) - local outdata = os.iorunv("xmake", {"show", "--info=depgraph", }) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph"}) t:require(outdata:find("app", 1, true)) t:require(outdata:find("core", 1, true)) t:require(outdata:find("ui", 1, true)) @@ -40,7 +40,7 @@ function test_depgraph_tree(t) end function test_depgraph_dot(t) - local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--dot", }) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--dot"}) t:require(outdata:find("digraph {", 1, true)) t:require(outdata:find('"core"', 1, true)) t:require(outdata:find('"ui" -> "core"', 1, true)) @@ -50,7 +50,7 @@ function test_depgraph_dot(t) end function test_depgraph_dot_for_single_target(t) - local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--target=ui", "--dot", }) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--target=ui", "--dot"}) t:require(outdata:find("digraph {", 1, true)) t:require(outdata:find('"core"', 1, true)) t:require(outdata:find('"ui" -> "core"', 1, true)) diff --git a/xmake/plugins/show/xmake.lua b/xmake/plugins/show/xmake.lua index de7a5a1c5..6d040da92 100644 --- a/xmake/plugins/show/xmake.lua +++ b/xmake/plugins/show/xmake.lua @@ -32,8 +32,14 @@ task("show") {'g', "group", "kv", nil, "Filter targets by the given group name."}, {nil, "json", "k", false, "Show information with json format."}, {nil, "pretty", "k", false, "Enable pretty formatted json output."}, - {nil, "dot", "k", false, "Output dependency graph in graphviz DOT format."}, + {nil, "dot", "k", false, "Output dependency graph in graphviz DOT format (only for --info=depgraph)."}, {'i', "info", "kv", nil, "Show the given information.", + "e.g.", + " - xmake show --info=depgraph", + " - xmake show --info=depgraph --target=app", + " - xmake show --info=depgraph --json --pretty", + " - xmake show --info=depgraph --dot", + "values:", values = function (complete, opt) return import("list").infos() end}, -- cgit v1.3.1 From ad3d0090c4b6184157321a01e814be622b37edd7 Mon Sep 17 00:00:00 2001 From: ruki Date: Sat, 18 Apr 2026 22:08:56 +0800 Subject: improve show output --- tests/plugins/show/test.lua | 4 ++-- xmake/plugins/show/info/depgraph.lua | 26 ++++++++++++++++---------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/plugins/show/test.lua b/tests/plugins/show/test.lua index cac268c96..4152338f3 100644 --- a/tests/plugins/show/test.lua +++ b/tests/plugins/show/test.lua @@ -35,8 +35,8 @@ function test_depgraph_tree(t) t:require(outdata:find("app", 1, true)) t:require(outdata:find("core", 1, true)) t:require(outdata:find("ui", 1, true)) - t:require(outdata:find("├── ", 1, true) or outdata:find("+-- ", 1, true)) - t:require(outdata:find("└── ", 1, true) or outdata:find("\\-- ", 1, true)) + t:require(outdata:find("|-- ", 1, true)) + t:require(outdata:find("\\-- ", 1, true)) end function test_depgraph_dot(t) diff --git a/xmake/plugins/show/info/depgraph.lua b/xmake/plugins/show/info/depgraph.lua index 199754772..e399a46df 100644 --- a/xmake/plugins/show/info/depgraph.lua +++ b/xmake/plugins/show/info/depgraph.lua @@ -26,10 +26,16 @@ import("core.project.project") import("private.detect.check_targetname") function _collect_target_entry(target) - local deps = table.wrap(target:get("deps")) + local deps = {} + for _, depname in ipairs(table.wrap(target:get("deps"))) do + local dep = target:dep(depname) + if dep then + table.insert(deps, dep:fullname()) + end + end json.mark_as_array(deps) return { - name = target:name(), + name = target:fullname(), deps = deps } end @@ -38,21 +44,21 @@ function _collect_target_graph(root_target) local targets = {} local selected = {} if root_target then - selected[root_target:name()] = true + selected[root_target:fullname()] = true for _, dep in ipairs(root_target:orderdeps() or {}) do - selected[dep:name()] = true + selected[dep:fullname()] = true end end for _, target in ipairs(project.ordertargets()) do - if not root_target or selected[target:name()] then + if not root_target or selected[target:fullname()] then table.insert(targets, _collect_target_entry(target)) end end local roots = {} if root_target then - table.insert(roots, root_target:name()) + table.insert(roots, root_target:fullname()) else local indegrees = {} for _, target in ipairs(targets) do @@ -85,14 +91,14 @@ function _print_dep_tree(targets_map, name, prefix, expanded) local deps = entry and entry.deps or {} for i, dep in ipairs(deps) do local is_last = (i == #deps) - local connector = is_last and "└── " or "├── " - local next_prefix = prefix .. (is_last and " " or "│ ") + local connector = is_last and "\\-- " or "|-- " + local next_prefix = prefix .. (is_last and " " or "| ") local dep_entry = targets_map[dep] local dep_deps = dep_entry and dep_entry.deps or {} if expanded[dep] and #dep_deps > 0 then - cprint("%s%s${color.dump.string}%s${clear} ${dim}(*)${clear}", prefix, connector, dep) + cprint("%s%s${color.dump.reference}%s${clear} ${dim}(*)${clear}", prefix, connector, dep) else - cprint("%s%s${color.dump.string}%s${clear}", prefix, connector, dep) + cprint("%s%s${color.dump.reference}%s${clear}", prefix, connector, dep) _print_dep_tree(targets_map, dep, next_prefix, expanded) end end -- cgit v1.3.1 From 4e94d5537ac3673c353942d58535212968836d6d Mon Sep 17 00:00:00 2001 From: ruki Date: Sat, 18 Apr 2026 22:11:17 +0800 Subject: improve show test --- tests/plugins/show/src/net.c | 1 + tests/plugins/show/test.lua | 31 +++++++++++++++++++++++++++---- tests/plugins/show/xmake.lua | 7 ++++++- 3 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 tests/plugins/show/src/net.c diff --git a/tests/plugins/show/src/net.c b/tests/plugins/show/src/net.c new file mode 100644 index 000000000..abde7c554 --- /dev/null +++ b/tests/plugins/show/src/net.c @@ -0,0 +1 @@ +int net(void) { return 0; } diff --git a/tests/plugins/show/test.lua b/tests/plugins/show/test.lua index 4152338f3..3e360a4d6 100644 --- a/tests/plugins/show/test.lua +++ b/tests/plugins/show/test.lua @@ -5,7 +5,7 @@ function test_depgraph_json(t) local graph = json.decode(outdata) t:are_equal(graph.root_targets, {"app"}) - t:require(#graph.targets == 3) + t:require(#graph.targets == 4) local entries = {} for _, target in ipairs(graph.targets) do @@ -13,7 +13,8 @@ function test_depgraph_json(t) end t:are_equal(entries.core.deps, {}) t:are_equal(entries.ui.deps, {"core"}) - t:are_equal(entries.app.deps, {"core", "ui"}) + t:are_equal(entries["ext::net"].deps, {"core"}) + t:are_equal(entries.app.deps, {"core", "ui", "ext::net"}) end function test_depgraph_json_for_single_target(t) @@ -21,13 +22,32 @@ function test_depgraph_json_for_single_target(t) local graph = json.decode(outdata) t:are_equal(graph.root_targets, {"app"}) - t:require(#graph.targets == 3) + t:require(#graph.targets == 4) local names = {} for _, target in ipairs(graph.targets) do table.insert(names, target.name) end - t:are_equal(names, {"core", "ui", "app"}) + t:require(table.contains(names, "core")) + t:require(table.contains(names, "ui")) + t:require(table.contains(names, "ext::net")) + t:require(table.contains(names, "app")) +end + +function test_depgraph_json_namespace(t) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--target=ext::net", "--json"}) + local graph = json.decode(outdata) + + t:are_equal(graph.root_targets, {"ext::net"}) + t:require(#graph.targets == 2) + + local entries = {} + for _, target in ipairs(graph.targets) do + entries[target.name] = target + end + t:require(entries["ext::net"]) + t:are_equal(entries["ext::net"].deps, {"core"}) + t:are_equal(entries.core.deps, {}) end function test_depgraph_tree(t) @@ -35,6 +55,7 @@ function test_depgraph_tree(t) t:require(outdata:find("app", 1, true)) t:require(outdata:find("core", 1, true)) t:require(outdata:find("ui", 1, true)) + t:require(outdata:find("ext::net", 1, true)) t:require(outdata:find("|-- ", 1, true)) t:require(outdata:find("\\-- ", 1, true)) end @@ -46,6 +67,8 @@ function test_depgraph_dot(t) t:require(outdata:find('"ui" -> "core"', 1, true)) t:require(outdata:find('"app" -> "core"', 1, true)) t:require(outdata:find('"app" -> "ui"', 1, true)) + t:require(outdata:find('"ext::net" -> "core"', 1, true)) + t:require(outdata:find('"app" -> "ext::net"', 1, true)) t:require(outdata:find("}", 1, true)) end diff --git a/tests/plugins/show/xmake.lua b/tests/plugins/show/xmake.lua index 7077424f3..15344a72a 100644 --- a/tests/plugins/show/xmake.lua +++ b/tests/plugins/show/xmake.lua @@ -9,7 +9,12 @@ target("ui") add_deps("core") add_files("src/ui.c") +target("ext::net") + set_kind("static") + add_deps("core") + add_files("src/net.c") + target("app") set_kind("binary") - add_deps("core", "ui") + add_deps("core", "ui", "ext::net") add_files("src/main.c") -- cgit v1.3.1 From 35d37f98381d8486f23b7761c90acdba3fc2e9d1 Mon Sep 17 00:00:00 2001 From: ruki Date: Mon, 20 Apr 2026 22:35:18 +0800 Subject: remove dylib --- .../objc/macapp_external_dylib/ext/libextfoo.dylib | Bin 16800 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 tests/projects/objc/macapp_external_dylib/ext/libextfoo.dylib diff --git a/tests/projects/objc/macapp_external_dylib/ext/libextfoo.dylib b/tests/projects/objc/macapp_external_dylib/ext/libextfoo.dylib deleted file mode 100755 index c92515666..000000000 Binary files a/tests/projects/objc/macapp_external_dylib/ext/libextfoo.dylib and /dev/null differ -- cgit v1.3.1 From d782aae00f82bd160b0fc5c0cdac1ba27ae8ade1 Mon Sep 17 00:00:00 2001 From: ruki Date: Mon, 20 Apr 2026 22:37:26 +0800 Subject: add --format --- tests/plugins/show/test.lua | 4 ++-- xmake/actions/require/xmake.lua | 4 ++-- xmake/modules/private/action/require/depgraph.lua | 4 ++-- xmake/modules/private/xrepo/action/info.lua | 4 ++-- xmake/plugins/show/info/basic.lua | 13 +++++++++---- xmake/plugins/show/info/depgraph.lua | 17 +++++++++++------ xmake/plugins/show/info/target.lua | 19 +++++++++++-------- xmake/plugins/show/xmake.lua | 16 ++++++++++------ 8 files changed, 49 insertions(+), 32 deletions(-) diff --git a/tests/plugins/show/test.lua b/tests/plugins/show/test.lua index 3e360a4d6..dea98c204 100644 --- a/tests/plugins/show/test.lua +++ b/tests/plugins/show/test.lua @@ -61,7 +61,7 @@ function test_depgraph_tree(t) end function test_depgraph_dot(t) - local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--dot"}) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--format=dot"}) t:require(outdata:find("digraph {", 1, true)) t:require(outdata:find('"core"', 1, true)) t:require(outdata:find('"ui" -> "core"', 1, true)) @@ -73,7 +73,7 @@ function test_depgraph_dot(t) end function test_depgraph_dot_for_single_target(t) - local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--target=ui", "--dot"}) + local outdata = os.iorunv("xmake", {"show", "--info=depgraph", "--target=ui", "--format=dot"}) t:require(outdata:find("digraph {", 1, true)) t:require(outdata:find('"core"', 1, true)) t:require(outdata:find('"ui" -> "core"', 1, true)) diff --git a/xmake/actions/require/xmake.lua b/xmake/actions/require/xmake.lua index 3a0b15802..e1596da52 100644 --- a/xmake/actions/require/xmake.lua +++ b/xmake/actions/require/xmake.lua @@ -74,8 +74,8 @@ task("require") "e.g.", " $ xmake require --info --format=json zlib", " $ xmake require --depgraph --format=dot libpng", - "values: json (for --info/--depgraph), tree/dot (for --depgraph only)", - values = {"tree", "json", "dot"} } + "values: json (for --info/--depgraph), dot (for --depgraph only)", + values = {"plain", "json", "dot"} } , {nil, "check", "k", nil, "Check whether the given package is supported", "e.g.", " $ xmake require --check tbox" } diff --git a/xmake/modules/private/action/require/depgraph.lua b/xmake/modules/private/action/require/depgraph.lua index ba1fb9ff4..200d9ed3e 100644 --- a/xmake/modules/private/action/require/depgraph.lua +++ b/xmake/modules/private/action/require/depgraph.lua @@ -139,7 +139,7 @@ end -- show the given package dependency graph -- -- supported output formats (via --format): --- tree (default): ASCII tree view +-- plain (default): ASCII tree view -- json: structured JSON output -- dot: graphviz DOT format -- @@ -164,7 +164,7 @@ function main(requires_raw) local graph = _collect_package_graph(instances) -- output in the specified format - local format = option.get("format") or "tree" + local format = option.get("format") or "plain" if format == "json" then print(json.encode(graph, {pretty = true, orderkeys = true})) elseif format == "dot" then diff --git a/xmake/modules/private/xrepo/action/info.lua b/xmake/modules/private/xrepo/action/info.lua index d7420533d..0a9c1c514 100644 --- a/xmake/modules/private/xrepo/action/info.lua +++ b/xmake/modules/private/xrepo/action/info.lua @@ -49,8 +49,8 @@ function menu_options() "e.g.", " - xrepo info --format=json zlib", " - xrepo info --depgraph --format=dot libpng", - "values: json (for --info/--depgraph), tree/dot (for --depgraph only)", - values = {"tree", "json", "dot"}}, + "values: json (for --info/--depgraph), dot (for --depgraph only)", + values = {"plain", "json", "dot"}}, {}, {nil, "packages", "vs", nil, "The packages list.", "e.g.", diff --git a/xmake/plugins/show/info/basic.lua b/xmake/plugins/show/info/basic.lua index 4ad14fe98..8a29dc2c0 100644 --- a/xmake/plugins/show/info/basic.lua +++ b/xmake/plugins/show/info/basic.lua @@ -128,8 +128,13 @@ function main() config.load() + -- support --format=json, with --json/--pretty backward compatibility + local format = option.get("format") or "plain" + if format == "plain" and option.get("json") then + format = "json" + end local opt = { - json = option.get("json"), + json = format == "json", pretty = option.get("pretty") } local result = opt.json and {} or nil @@ -138,9 +143,9 @@ function main() result = _show_project_info(opt, result) if opt.json then - local json_opt - if opt.pretty then - json_opt = {pretty = true, orderkeys = true} + local json_opt = {pretty = true, orderkeys = true} + if option.get("json") and not option.get("pretty") then + json_opt = nil end print(json.encode(result or {}, json_opt)) end diff --git a/xmake/plugins/show/info/depgraph.lua b/xmake/plugins/show/info/depgraph.lua index e399a46df..2c73f3abc 100644 --- a/xmake/plugins/show/info/depgraph.lua +++ b/xmake/plugins/show/info/depgraph.lua @@ -139,14 +139,19 @@ function main(name) end local graph = _collect_target_graph(root_target) - assert(not (option.get("json") and option.get("dot")), "--json and --dot are mutually exclusive") - if option.get("json") then - local json_opt - if option.get("pretty") then - json_opt = {pretty = true, orderkeys = true} + + -- support --format=json/dot/plain, with --json/--pretty backward compatibility + local format = option.get("format") or "plain" + if format == "plain" and option.get("json") then + format = "json" + end + if format == "json" then + local json_opt = {pretty = true, orderkeys = true} + if option.get("json") and not option.get("pretty") then + json_opt = nil end print(json.encode(graph, json_opt)) - elseif option.get("dot") then + elseif format == "dot" then _print_dot_graph(graph) else _print_target_graph(graph) diff --git a/xmake/plugins/show/info/target.lua b/xmake/plugins/show/info/target.lua index bfa88ad92..75f31f9a5 100644 --- a/xmake/plugins/show/info/target.lua +++ b/xmake/plugins/show/info/target.lua @@ -363,19 +363,22 @@ function main(name) -- get target config.load() - local opt = { - json = option.get("json"), - pretty = option.get("pretty") - } + + -- support --format=json, with --json/--pretty backward compatibility + local format = option.get("format") or "plain" + if format == "plain" and option.get("json") then + format = "json" + end + assert(name, "please specify the target name, e.g. xmake show --info=target --target=xxx") local target = assert(check_targetname(name)) local info = _collect_target_info(target) - if opt.json then + if format == "json" then info.api_entries = nil - local json_opt - if opt.pretty then - json_opt = {pretty = true, orderkeys = true} + local json_opt = {pretty = true, orderkeys = true} + if option.get("json") and not option.get("pretty") then + json_opt = nil end print(json.encode(info or {}, json_opt)) else diff --git a/xmake/plugins/show/xmake.lua b/xmake/plugins/show/xmake.lua index 6d040da92..ef3ea0fe2 100644 --- a/xmake/plugins/show/xmake.lua +++ b/xmake/plugins/show/xmake.lua @@ -30,16 +30,20 @@ task("show") return import("list").lists() end}, {'g', "group", "kv", nil, "Filter targets by the given group name."}, - {nil, "json", "k", false, "Show information with json format."}, - {nil, "pretty", "k", false, "Enable pretty formatted json output."}, - {nil, "dot", "k", false, "Output dependency graph in graphviz DOT format (only for --info=depgraph)."}, + {nil, "json", "k", false, "Show information with json format (deprecated, use --format=json)."}, + {nil, "pretty", "k", false, "Enable pretty formatted output."}, + {nil, "format", "kv", nil, "Set the output format.", + "e.g.", + " - xmake show --format=json", + " - xmake show --info=depgraph --format=dot", + "values: json (for all), dot (for --info=depgraph only)", + values = {"plain", "json", "dot"}}, {'i', "info", "kv", nil, "Show the given information.", "e.g.", " - xmake show --info=depgraph", " - xmake show --info=depgraph --target=app", - " - xmake show --info=depgraph --json --pretty", - " - xmake show --info=depgraph --dot", - "values:", + " - xmake show --info=depgraph --format=json", + " - xmake show --info=depgraph --format=dot", values = function (complete, opt) return import("list").infos() end}, -- cgit v1.3.1 From 9897b3063e72ce1489d21398c17e8e81af7ee92e Mon Sep 17 00:00:00 2001 From: ruki Date: Mon, 20 Apr 2026 22:48:42 +0800 Subject: improve output --- xmake/modules/private/action/require/depgraph.lua | 34 +++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/xmake/modules/private/action/require/depgraph.lua b/xmake/modules/private/action/require/depgraph.lua index 200d9ed3e..46a1a8a7f 100644 --- a/xmake/modules/private/action/require/depgraph.lua +++ b/xmake/modules/private/action/require/depgraph.lua @@ -41,6 +41,7 @@ function _collect_package_entry(instance) return { name = instance:fullname(), version = instance:version_str(), + configs_str = package.get_configs_str(instance), deps = deps } end @@ -74,11 +75,27 @@ function _collect_package_graph(instances) } end +-- format version and configs as a suffix string for plain output +-- e.g. " v1.3.2 [shared:y, debug:n]" +function _format_package_suffix(entry) + local parts = {} + if entry.version then + table.insert(parts, entry.version) + end + if entry.configs_str and #entry.configs_str > 0 then + table.insert(parts, entry.configs_str) + end + if #parts > 0 then + return " " .. table.concat(parts, " ") + end + return "" +end + -- print dependency tree recursively -- -- e.g. --- libpng --- \-- zlib +-- libpng v1.6.56 +-- \-- zlib v1.3.2 -- -- already expanded subtrees are marked with (*) to avoid duplication -- @@ -92,10 +109,11 @@ function _print_dep_tree(packages_map, name, prefix, expanded) local next_prefix = prefix .. (is_last and " " or "| ") local dep_entry = packages_map[dep] local dep_deps = dep_entry and dep_entry.deps or {} + local suffix = dep_entry and _format_package_suffix(dep_entry) or "" if expanded[dep] and #dep_deps > 0 then - cprint("%s%s${color.dump.reference}%s${clear} ${dim}(*)${clear}", prefix, connector, dep) + cprint("%s%s${color.dump.reference}%s${clear}${dim}%s (*)${clear}", prefix, connector, dep, suffix) else - cprint("%s%s${color.dump.reference}%s${clear}", prefix, connector, dep) + cprint("%s%s${color.dump.reference}%s${clear}${dim}%s${clear}", prefix, connector, dep, suffix) _print_dep_tree(packages_map, dep, next_prefix, expanded) end end @@ -109,7 +127,9 @@ function _print_package_graph(graph) end local expanded = {} for _, root in ipairs(graph.root_packages) do - cprint("${color.dump.string}%s${clear}", root) + local entry = packages_map[root] + local suffix = entry and _format_package_suffix(entry) or "" + cprint("${color.dump.string}%s${clear}${dim}%s${clear}", root, suffix) _print_dep_tree(packages_map, root, "", expanded) end end @@ -166,6 +186,10 @@ function main(requires_raw) -- output in the specified format local format = option.get("format") or "plain" if format == "json" then + -- strip configs_str, it's only for plain display + for _, pkg in ipairs(graph.packages) do + pkg.configs_str = nil + end print(json.encode(graph, {pretty = true, orderkeys = true})) elseif format == "dot" then _print_dot_graph(graph) -- cgit v1.3.1 From 4e3f6b16db88b9c1afad898a7f5dfeaecdfd0f27 Mon Sep 17 00:00:00 2001 From: ruki Date: Mon, 20 Apr 2026 22:48:50 +0800 Subject: improve output --- xmake/modules/private/action/require/depgraph.lua | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/xmake/modules/private/action/require/depgraph.lua b/xmake/modules/private/action/require/depgraph.lua index 46a1a8a7f..e022bdee4 100644 --- a/xmake/modules/private/action/require/depgraph.lua +++ b/xmake/modules/private/action/require/depgraph.lua @@ -108,10 +108,22 @@ function _print_dep_tree(packages_map, name, prefix, expanded) local connector = is_last and "\\-- " or "|-- " local next_prefix = prefix .. (is_last and " " or "| ") local dep_entry = packages_map[dep] - local dep_deps = dep_entry and dep_entry.deps or {} local suffix = dep_entry and _format_package_suffix(dep_entry) or "" - if expanded[dep] and #dep_deps > 0 then - cprint("%s%s${color.dump.reference}%s${clear}${dim}%s (*)${clear}", prefix, connector, dep, suffix) + if expanded[dep] then + -- already expanded, show with (*) and list direct children as references + local dep_deps = dep_entry and dep_entry.deps or {} + if #dep_deps > 0 then + cprint("%s%s${color.dump.reference}%s${clear}${dim}%s${clear}", prefix, connector, dep, suffix) + for j, subdep in ipairs(dep_deps) do + local sub_is_last = (j == #dep_deps) + local sub_connector = sub_is_last and "\\-- " or "|-- " + local sub_entry = packages_map[subdep] + local sub_suffix = sub_entry and _format_package_suffix(sub_entry) or "" + cprint("%s%s${dim}%s%s (*)${clear}", next_prefix, sub_connector, subdep, sub_suffix) + end + else + cprint("%s%s${color.dump.reference}%s${clear}${dim}%s (*)${clear}", prefix, connector, dep, suffix) + end else cprint("%s%s${color.dump.reference}%s${clear}${dim}%s${clear}", prefix, connector, dep, suffix) _print_dep_tree(packages_map, dep, next_prefix, expanded) -- cgit v1.3.1