summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2026-06-23 14:07:27 +0800
committerGitHub <[email protected]>2026-06-23 14:07:27 +0800
commit44711c34a5bfcb192df4985a30e4dfb1c4441c23 (patch)
tree74233e858202b943169542b4b8e3edd68e9e9269
parentbcd6a836dd03db0418a6f5c604d63c96f887483a (diff)
parentfd3181633dc59463bd40300c00d51816d0af6e03 (diff)
Merge pull request #7614 from xmake-io/cargo
improve cargo/install_package
-rw-r--r--xmake/modules/package/manager/cargo/install_package.lua91
1 files changed, 91 insertions, 0 deletions
diff --git a/xmake/modules/package/manager/cargo/install_package.lua b/xmake/modules/package/manager/cargo/install_package.lua
index 1dd81a09e..71459f866 100644
--- a/xmake/modules/package/manager/cargo/install_package.lua
+++ b/xmake/modules/package/manager/cargo/install_package.lua
@@ -47,6 +47,90 @@ function _translate_local_path_in_deps(cargotoml, rootdir)
io.writefile(cargotoml, content)
end
+-- is it a cargo workspace manifest? (it contains a [workspace] or [workspace.xxx] table)
+function _is_workspace_manifest(content)
+ for _, line in ipairs(content:split("\n", {plain = true, strict = true})) do
+ if line:match("^%s*%[workspace[%].]") then
+ return true
+ end
+ end
+ return false
+end
+
+-- get the workspace inheritance tables from the workspace root manifest
+--
+-- if the given Cargo.toml is a member of a cargo workspace and uses workspace inheritance,
+-- e.g. `anyhow.workspace = true`, `version.workspace = true`, `[lints] workspace = true`,
+-- we need to inject the `[workspace.package]`/`[workspace.dependencies]`/`[workspace.lints]`
+-- tables from the workspace root manifest, otherwise cargo will fail to resolve them, e.g.
+--
+-- error inheriting `anyhow` from workspace root manifest's `workspace.dependencies.anyhow`
+-- `workspace.dependencies` was not defined
+--
+-- @see https://github.com/xmake-io/xmake/issues/7619
+-- https://doc.rust-lang.org/cargo/reference/workspaces.html#the-workspacedependencies-table
+function _get_workspace_inherited_tables(cargo_toml)
+
+ -- find the workspace root manifest by walking up
+ local rootmanifest
+ local dir = path.directory(path.absolute(cargo_toml))
+ while dir and #dir > 0 do
+ local manifest = path.join(dir, "Cargo.toml")
+ if os.isfile(manifest) then
+ local content = io.readfile(manifest)
+ if content and _is_workspace_manifest(content) then
+ rootmanifest = manifest
+ break
+ end
+ end
+ local parentdir = path.directory(dir)
+ if parentdir == dir then
+ break
+ end
+ dir = parentdir
+ end
+
+ -- not a workspace member, or the manifest itself is the workspace root (self-contained)
+ if not rootmanifest or path.absolute(rootmanifest) == path.absolute(cargo_toml) then
+ return
+ end
+
+ -- extract all the [workspace.xxx] sub-tables, e.g. [workspace.package]/[workspace.dependencies]/[workspace.lints]
+ -- we do not copy the bare [workspace] table (members/exclude), otherwise cargo will search for the member crates.
+ local content = io.readfile(rootmanifest)
+ if not content then
+ return
+ end
+ local result = {}
+ local in_subtable = false
+ for _, line in ipairs(content:split("\n", {plain = true, strict = true})) do
+ local header = line:match("^%s*%[(.-)%]%s*$")
+ if header then
+ in_subtable = header:trim():startswith("workspace.")
+ if in_subtable then
+ table.insert(result, line)
+ end
+ elseif in_subtable then
+ table.insert(result, line)
+ end
+ end
+ if #result == 0 then
+ return
+ end
+
+ -- translate the local paths in the workspace dependencies, they are relative to the workspace root directory
+ local rootdir = path.directory(rootmanifest)
+ local workspace_toml = table.concat(result, "\n")
+ workspace_toml = workspace_toml:gsub("path%s+=%s+\"(.-)\"", function (localpath)
+ if not path.is_absolute(localpath) then
+ localpath = path.absolute(localpath, rootdir)
+ end
+ localpath = localpath:gsub("\\", "/")
+ return "path = \"" .. localpath .. "\""
+ end)
+ return workspace_toml
+end
+
-- install package
--
-- e.g.
@@ -101,6 +185,13 @@ function main(name, opt)
tomlfile:print("")
tomlfile:print("[workspace]")
tomlfile:print("")
+ -- inject the workspace inheritance tables if the given Cargo.toml is a workspace member,
+ -- e.g. `anyhow.workspace = true`. @see https://github.com/xmake-io/xmake/issues/7619
+ local workspace_toml = _get_workspace_inherited_tables(configs.cargo_toml)
+ if workspace_toml then
+ tomlfile:write(workspace_toml)
+ tomlfile:print("")
+ end
tomlfile:close()
else
local tomlfile = io.open(cargotoml, "w")