summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2025-11-14 23:22:40 +0800
committerruki <[email protected]>2025-11-14 23:22:40 +0800
commit4a865b7a441ff44104fe4309d424666a9d32a9df (patch)
tree7dd46cc72bd04ffc8928f971108f45ad5193e630
parent08f0362fd876d8a0e7502a419aabcc1c91d91cb2 (diff)
add json output for show target
-rw-r--r--xmake/core/base/string.lua19
-rw-r--r--xmake/plugins/show/info/target.lua220
2 files changed, 188 insertions, 51 deletions
diff --git a/xmake/core/base/string.lua b/xmake/core/base/string.lua
index 2c7069cb9..658ca7345 100644
--- a/xmake/core/base/string.lua
+++ b/xmake/core/base/string.lua
@@ -238,6 +238,25 @@ function string.dump(object, deflate)
return string.serialize(object, deflate)
end
+-- convert object to json-serializable form
+function string.serializable(object, opt)
+ opt = opt or {}
+ local vtype = type(object)
+ if vtype == "table" then
+ local result = {}
+ for k, v in pairs(object) do
+ result[k] = string.serializable(v, opt)
+ end
+ return result
+ elseif vtype == "function" or vtype == "userdata" or vtype == "thread" then
+ if opt.stringify then
+ return opt.stringify(object)
+ end
+ return tostring(object)
+ end
+ return object
+end
+
-- serialize to string from the given object
--
-- @param opt serialize options
diff --git a/xmake/plugins/show/info/target.lua b/xmake/plugins/show/info/target.lua
index d5ddfbe76..5384a739d 100644
--- a/xmake/plugins/show/info/target.lua
+++ b/xmake/plugins/show/info/target.lua
@@ -20,34 +20,58 @@
-- imports
import("core.base.option")
+import("core.base.json")
import("core.base.hashset")
import("core.project.config")
import("core.language.language")
import("private.detect.check_targetname")
--- get source info string
-function _get_sourceinfo_str(target, name, item, opt)
+-- get source info data
+function _get_sourceinfo(target, name, item, opt)
opt = opt or {}
local sourceinfo = target:sourceinfo(name, item)
+ local tips = opt.tips
if sourceinfo then
- local tips = opt.tips
- if tips then
- tips = tips .. " -> "
- end
+ return {
+ file = sourceinfo.file,
+ line = sourceinfo.line,
+ tips = tips
+ }
+ elseif tips then
+ return {tips = tips}
+ end
+end
+
+-- format source info string with color
+function _format_sourceinfo(sourceinfo)
+ if not sourceinfo then
+ return ""
+ end
+ local tips = sourceinfo.tips
+ if tips then
+ tips = tips .. " -> "
+ end
+ if sourceinfo.file then
return string.format(" ${dim}-> %s%s:%s${clear}", tips or "", sourceinfo.file or "", sourceinfo.line or -1)
- elseif opt.tips then
- return string.format(" ${dim}-> %s${clear}", opt.tips)
+ elseif tips then
+ return string.format(" ${dim}-> %s${clear}", tips)
end
return ""
end
+-- get source info string
+function _get_sourceinfo_str(target, name, item, opt)
+ return _format_sourceinfo(_get_sourceinfo(target, name, item, opt))
+end
+
-- get values from target options
function _get_values_from_opts(target, name)
local values = {}
for _, opt_ in ipairs(target:orderopts()) do
for _, value in ipairs(opt_:get(name)) do
local tips = string.format("option(%s)", opt_:name())
- values[value] = _get_sourceinfo_str(opt_, name, value, {tips = tips})
+ local sourceinfo = _get_sourceinfo(opt_, name, value, {tips = tips})
+ values[value] = sourceinfo or {tips = tips}
end
end
return values
@@ -78,7 +102,8 @@ function _get_values_from_pkgs(target, name)
local info = components[component_name]
if info then
for _, value in ipairs(info[name]) do
- values[value] = string.format(" -> package(%s)", pkg:fullname())
+ local tips = string.format("package(%s)", pkg:fullname())
+ values[value] = {tips = tips}
end
else
local components_str = table.concat(table.wrap(configinfo.components), ", ")
@@ -90,12 +115,14 @@ function _get_values_from_pkgs(target, name)
-- e.g. `add_packages("xxx", {links = "xxx"})`
elseif configinfo and configinfo[name] then
for _, value in ipairs(configinfo[name]) do
- values[value] = _get_sourceinfo_str(target, "packages", pkg:name())
+ local sourceinfo = _get_sourceinfo(target, "packages", pkg:name())
+ values[value] = sourceinfo
end
else
-- get values from the builtin package configs
for _, value in ipairs(pkg:get(name)) do
- values[value] = string.format(" -> package(%s)", pkg:fullname())
+ local tips = string.format("package(%s)", pkg:fullname())
+ values[value] = {tips = tips}
end
end
end
@@ -112,18 +139,21 @@ function _get_values_from_deps(target, name)
local depinherit = target:extraconf("deps", dep:name(), "inherit")
if depinherit == nil or depinherit then
for _, value in ipairs(dep:get(name, {interface = true})) do
- values[value] = string.format(" -> dep(%s)", dep:name())
+ local tips = string.format("dep(%s)", dep:name())
+ values[value] = {tips = tips}
end
local values_chunks = dep:get_from(name, "option::*", {interface = true})
for _, values_chunk in ipairs(values_chunks) do
for _, value in ipairs(values_chunk) do
- values[value] = string.format(" -> dep(%s) -> options", dep:name())
+ local tips = string.format("dep(%s) -> options", dep:name())
+ values[value] = {tips = tips}
end
end
values_chunks = dep:get_from(name, "package::*", {interface = true})
for _, values_chunk in ipairs(values_chunks) do
for _, value in ipairs(values_chunk) do
- values[value] = string.format(" -> dep(%s) -> packages", dep:name())
+ local tips = string.format("dep(%s) -> packages", dep:name())
+ values[value] = {tips = tips}
end
end
end
@@ -131,27 +161,36 @@ function _get_values_from_deps(target, name)
return values
end
--- show target information
-function _show_target(target)
- print("The information of target(%s):", target:name())
- cprint(" ${color.dump.string}at${clear}: %s", path.join(target:scriptdir(), "xmake.lua"))
- cprint(" ${color.dump.string}kind${clear}: %s", target:kind())
+function _collect_target_info(target)
+ local info = {
+ name = target:name(),
+ at = path.join(target:scriptdir(), "xmake.lua"),
+ kind = target:kind()
+ }
local targetfile = target:targetfile()
if targetfile then
- cprint(" ${color.dump.string}targetfile${clear}: %s", targetfile)
+ info.targetfile = targetfile
end
local deps = target:get("deps")
if deps then
- cprint(" ${color.dump.string}deps${clear}:")
+ local entries = {}
for _, dep in ipairs(deps) do
- cprint(" ${color.dump.reference}->${clear} %s%s", dep, _get_sourceinfo_str(target, "deps", dep))
+ local entry = {name = dep, source = _get_sourceinfo(target, "deps", dep)}
+ table.insert(entries, entry)
+ end
+ if #entries > 0 then
+ info.deps = entries
end
end
local rules = target:get("rules")
if rules then
- cprint(" ${color.dump.string}rules${clear}:")
+ local entries = {}
for _, value in ipairs(rules) do
- cprint(" ${color.dump.reference}->${clear} %s%s", value, _get_sourceinfo_str(target, "rules", value))
+ local entry = {name = value, source = _get_sourceinfo(target, "rules", value)}
+ table.insert(entries, entry)
+ end
+ if #entries > 0 then
+ info.rules = entries
end
end
local options = {}
@@ -161,18 +200,25 @@ function _show_target(target)
end
end
if #options > 0 then
- cprint(" ${color.dump.string}options${clear}:")
+ local entries = {}
for _, value in ipairs(options) do
- cprint(" ${color.dump.reference}->${clear} %s%s", value, _get_sourceinfo_str(target, "options", value))
+ table.insert(entries, {name = value, source = _get_sourceinfo(target, "options", value)})
+ end
+ if #entries > 0 then
+ info.options = entries
end
end
local packages = target:get("packages")
if packages then
- cprint(" ${color.dump.string}packages${clear}:")
+ local entries = {}
for _, value in ipairs(packages) do
- cprint(" ${color.dump.reference}->${clear} %s%s", value, _get_sourceinfo_str(target, "packages", value))
+ table.insert(entries, {name = value, source = _get_sourceinfo(target, "packages", value)})
+ end
+ if #entries > 0 then
+ info.packages = entries
end
end
+ info.api_entries = {}
for _, apiname in ipairs(table.join(language.apis().values, language.apis().paths)) do
if apiname:startswith("target.") then
local valuename = apiname:split('.add_', {plain = true})[2]
@@ -181,38 +227,44 @@ function _show_target(target)
local values = table.unique(table.wrap(target:get(valuename)))
if #values > 0 then
for _, value in ipairs(values) do
- table.insert(results, {value = value, sourceinfo = _get_sourceinfo_str(target, valuename, value)})
+ local sourceinfo = _get_sourceinfo(target, valuename, value)
+ table.insert(results, {value = string.serializable(value), source = sourceinfo})
end
end
local values_from_opts = _get_values_from_opts(target, valuename)
for value, sourceinfo in pairs(values_from_opts) do
- table.insert(results, {value = value, sourceinfo = sourceinfo})
+ table.insert(results, {value = string.serializable(value), source = sourceinfo})
end
local values_from_pkgs = _get_values_from_pkgs(target, valuename)
for value, sourceinfo in pairs(values_from_pkgs) do
- table.insert(results, {value = value, sourceinfo = sourceinfo})
+ table.insert(results, {value = string.serializable(value), source = sourceinfo})
end
local values_from_deps = _get_values_from_deps(target, valuename)
for value, sourceinfo in pairs(values_from_deps) do
- table.insert(results, {value = value, sourceinfo = sourceinfo})
+ table.insert(results, {value = string.serializable(value), source = sourceinfo})
end
if #results > 0 then
- cprint(" ${color.dump.string}%s${clear}:", valuename)
+ local entries = {}
for _, result in ipairs(results) do
- cprint(" ${color.dump.reference}->${clear} %s%s", result.value, result.sourceinfo)
+ table.insert(entries, result)
end
+ info[valuename] = entries
+ table.insert(info.api_entries, {name = valuename, entries = entries})
end
end
end
end
local files = target:get("files")
if files then
- cprint(" ${color.dump.string}files${clear}:")
+ local entries = {}
for _, file in ipairs(files) do
if not file:startswith("__remove_") then
- cprint(" ${color.dump.reference}->${clear} %s%s", file, _get_sourceinfo_str(target, "files", file))
+ table.insert(entries, {path = file, source = _get_sourceinfo(target, "files", file)})
end
end
+ if #entries > 0 then
+ info.files = entries
+ end
end
local sourcekinds = hashset.new()
for _, sourcebatch in pairs(target:sourcebatches()) do
@@ -223,25 +275,85 @@ function _show_target(target)
for _, sourcekind in sourcekinds:keys() do
local compinst = target:compiler(sourcekind)
if compinst then
- cprint(" ${color.dump.string}compiler (%s)${clear}: %s", sourcekind, compinst:program())
- cprint(" ${color.dump.reference}->${clear} %s", os.args(compinst:compflags()))
+ info.compilers = info.compilers or {}
+ table.insert(info.compilers, {
+ sourcekind = sourcekind,
+ program = compinst:program(),
+ flags = os.args(compinst:compflags()),
+ flags_with_target = os.args(compinst:compflags({target = target}))
+ })
end
end
local linker = targetfile and target:linker()
if linker then
- cprint(" ${color.dump.string}linker (%s)${clear}: %s", linker:kind(), linker:program())
- cprint(" ${color.dump.reference}->${clear} %s", os.args(linker:linkflags()))
+ info.linker = {
+ kind = linker:kind(),
+ program = linker:program(),
+ flags = os.args(linker:linkflags()),
+ flags_with_target = os.args(linker:linkflags({target = target}))
+ }
end
- for _, sourcekind in sourcekinds:keys() do
- local compinst = target:compiler(sourcekind)
- if compinst then
- cprint(" ${color.dump.string}compflags (%s)${clear}:", sourcekind)
- cprint(" ${color.dump.reference}->${clear} %s", os.args(compinst:compflags({target = target})))
+ return info
+end
+
+function _print_entries(label, items, formatter)
+ if not items or #items == 0 then
+ return
+ end
+ cprint(" ${color.dump.string}%s${clear}:", label)
+ for _, item in ipairs(items) do
+ local text, source = formatter(item)
+ cprint(" ${color.dump.reference}->${clear} %s%s", text, source or "")
+ end
+end
+
+function _print_target_info(info)
+ print("The information of target(%s):", info.name)
+ cprint(" ${color.dump.string}at${clear}: %s", info.at)
+ cprint(" ${color.dump.string}kind${clear}: %s", info.kind)
+ if info.targetfile then
+ cprint(" ${color.dump.string}targetfile${clear}: %s", info.targetfile)
+ end
+ _print_entries("deps", info.deps, function(item)
+ return item.name, _format_sourceinfo(item.source)
+ end)
+ _print_entries("rules", info.rules, function(item)
+ return item.name, _format_sourceinfo(item.source)
+ end)
+ _print_entries("options", info.options, function(item)
+ return item.name, _format_sourceinfo(item.source)
+ end)
+ _print_entries("packages", info.packages, function(item)
+ return item.name, _format_sourceinfo(item.source)
+ end)
+ if info.api_entries then
+ for _, entry in ipairs(info.api_entries) do
+ _print_entries(entry.name, entry.entries, function(item)
+ local value = item.value
+ local source = _format_sourceinfo(item.source)
+ return value, source
+ end)
end
end
- if linker then
- cprint(" ${color.dump.string}linkflags (%s)${clear}:", linker:kind())
- cprint(" ${color.dump.reference}->${clear} %s", os.args(linker:linkflags({target = target})))
+ if info.files then
+ _print_entries("files", info.files, function(item)
+ return item.path, _format_sourceinfo(item.source)
+ end)
+ end
+ if info.compilers then
+ for _, compiler in ipairs(info.compilers) do
+ cprint(" ${color.dump.string}compiler (%s)${clear}: %s", compiler.sourcekind, compiler.program)
+ end
+ for _, compiler in ipairs(info.compilers) do
+ cprint(" ${color.dump.string}compflags (%s)${clear}:", compiler.sourcekind)
+ cprint(" ${color.dump.reference}->${clear} %s", compiler.flags_with_target)
+ end
+ end
+ if info.linker then
+ cprint(" ${color.dump.string}linker (%s)${clear}: %s", info.linker.kind, info.linker.program)
+ cprint(" ${color.dump.reference}->${clear} %s", info.linker.flags)
+ cprint(" ${color.dump.string}linkflags (%s)${clear}:", info.linker.kind)
+ cprint(" ${color.dump.reference}->${clear} %s", info.linker.flags_with_target)
end
end
@@ -249,8 +361,14 @@ function main(name)
-- get target
config.load()
+ local opt = {json = option.get("json")}
local target = assert(check_targetname(name))
- -- show target information
- _show_target(target)
+ local info = _collect_target_info(target)
+ if opt.json then
+ info.api_entries = nil
+ print(json.encode(string.serializable(info) or {}))
+ else
+ _print_target_info(info)
+ end
end