Conversation
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a significant improvement to toolchain configuration by allowing a more concise syntax, such as toolchain[config]. The changes are well-integrated into the core logic, affecting toolchain parsing, project loading, and platform handling. Support for clang in the llvm-mingw toolchain and gcc in the ndk toolchain are also valuable additions.
My review has identified a couple of bugs in the new configuration parsing logic within toolchain.parsename that could lead to incorrect behavior with complex config strings. I've provided a detailed comment with a suggested fix. Additionally, I've pointed out an opportunity to refactor duplicated code in toolchain.load and toolchain.load_withinfo to improve maintainability. With these adjustments, this will be a solid and robust enhancement.
| if toolchain_name_raw and configs_str then | ||
| configs_str = configs_str:gsub("%[(.*)%]", function (w) | ||
| return w:replace(",", ":") | ||
| end) | ||
| requirestr = configs_str | ||
| toolchain_name = toolchain_name_raw | ||
| local splitinfo = configs_str:split(",", {plain = true}) | ||
| for _, v in ipairs(splitinfo) do | ||
| local parts = v:split("=", {plain = true}) | ||
| local k = parts[1] | ||
| v = parts[2] | ||
| requireconfs = requireconfs or {} | ||
| if v then | ||
| if v:find(":", 1 ,true) then | ||
| requireconfs[k] = v:split(":", {plain = true}) | ||
| else | ||
| requireconfs[k] = option.boolean(v) | ||
| end | ||
| else | ||
| requireconfs[k] = true | ||
| end | ||
| end | ||
| end |
There was a problem hiding this comment.
There are a couple of issues in the parsing logic for toolchain configs:
-
The
gsubpattern on line 631 is greedy."%[(.*)%]"will cause incorrect parsing if there are multiple[...]sections in the config string. For example, withtoolchain[config1=[a,b],config2=[c,d]], the pattern will matcha,b],config2=[c,d. You should use a non-greedy pattern like"%[([^]]*)%]"to correctly handle this. -
When parsing a list-like value (e.g.,
sdk=[1,2]), the code on line 644 splits a string like"[1:2]"by the colon, which results in{"[1", "2]"}. The surrounding brackets should be removed before splitting the string. You could usev:sub(2, -2)to strip them.
Here's a suggested implementation that addresses both issues:
if toolchain_name_raw and configs_str then
configs_str = configs_str:gsub("%%[([^\]]*)%%]", function (w)
return w:replace(",", ":")
end)
requirestr = configs_str
toolchain_name = toolchain_name_raw
local splitinfo = configs_str:split(",", {plain = true})
for _, v in ipairs(splitinfo) do
local parts = v:split("=", {plain = true})
local k = parts[1]
v = parts[2]
requireconfs = requireconfs or {}
if v then
if v:find(":", 1 ,true) then
if v:startswith("[") and v:endswith("]") then
v = v:sub(2, -2)
end
requireconfs[k] = v:split(":", {plain = true})
else
requireconfs[k] = option.boolean(v)
end
else
requireconfs[k] = true
end
end
end
| -- parse toolchain name | ||
| local parseinfo = toolchain.parsename(name) | ||
| name = parseinfo.name | ||
|
|
||
| -- init configs | ||
| local configs = parseinfo.requireconfs or {} | ||
| table.join2(configs, opt) | ||
| configs.packages = opt.packages or parseinfo.packages | ||
| configs.plat = opt.plat or config.get("plat") or os.host() | ||
| configs.arch = opt.arch or config.get("arch") or os.arch() |
There was a problem hiding this comment.
The logic for parsing the toolchain name and initializing the configs table is duplicated here and in toolchain.load_withinfo (lines 777-786). To improve maintainability and reduce redundancy, you could extract this common logic into a private helper function.
For example, you could create a function toolchain._prepare_load_params(name, opt):
function toolchain._prepare_load_params(name, opt)
opt = opt or {}
local parseinfo = toolchain.parsename(name)
local name = parseinfo.name
local configs = parseinfo.requireconfs or {}
table.join2(configs, opt)
configs.packages = opt.packages or parseinfo.packages
configs.plat = opt.plat or config.get("plat") or os.host()
configs.arch = opt.arch or config.get("arch") or os.arch()
return name, configs, parseinfo
endThen both toolchain.load and toolchain.load_withinfo can be simplified by calling this helper.
set_toolchains("mingw[clang]"), it is equivalent toset_toolchains("mingw", {clang = true})xmake f --toolchain=mingw[clang]add_configsin toolchains to define and check toolchain configsxmake f --toolchain=mingw[clang] --sdk=/xxx/llvm-mingwset_toolchains("mingw[clang]@llvm-mingw")xmake f -p android --toolchain=ndk[gcc] --ndk=/xxxxSimplify toolchain configs