@@ -21,17 +21,19 @@ RECIPE_UPGRADE_EXTRA_TASKS += "do_update_crates"
# The directory where to search for Cargo.lock files
CARGO_LOCK_SRC_DIR ??= "${S}"
+# Comma-separated list of directories where to search for Cargo.lock files.
+# Crates found in multiple Cargo.lock files are listed only once, in the
+# section of the first Cargo.lock file that contains them.
+CARGO_LOCK_SRC_DIRS ??= "${CARGO_LOCK_SRC_DIR}"
python do_update_crates() {
- cargo_lock_src_dir = d.getVar("CARGO_LOCK_SRC_DIR")
-
- def get_crates(filename):
+ def get_crates(filename, src_dir, seen):
try:
import tomllib
except ImportError:
import bb._vendor.tomli as tomllib
- c_list = '# from %s' % os.path.relpath(filename, cargo_lock_src_dir)
+ c_list = '# from %s' % os.path.relpath(filename, src_dir)
c_list += '\nSRC_URI += " \\'
with open(filename, 'rb') as fp:
crates = tomllib.load(fp)
@@ -40,17 +42,28 @@ python do_update_crates() {
crates_candidates = list(filter(lambda c: 'crates.io' in c.get('source', ''), crates['package']))
if not crates_candidates:
- print("WARNING: Unable to find any candidate crates that use crates.io")
+ print("WARNING: Unable to find any candidate crates that use crates.io in %s" % filename)
return None
# Update crates uri and their checksum, to avoid name clashing on the checksum
# we need to rename crates with name and version to have a unique key
+ # Crates already emitted for a previous Cargo.lock are skipped.
cksum_list = ''
+ ncrates = 0
for c in crates_candidates:
rename = "%s-%s" % (c['name'], c['version'])
+ if rename in seen:
+ if seen[rename] != c.get('checksum'):
+ raise ValueError(f"Conflicting checksums for crate {rename}")
+ continue
+ seen[rename] = c.get('checksum')
c_list += '\n crate://crates.io/%s/%s \\' % (c['name'], c['version'])
if 'checksum' in c:
cksum_list += '\nSRC_URI[%s.sha256sum] = "%s"' % (rename, c['checksum'])
+ ncrates += 1
+
+ if not ncrates:
+ return None
c_list += '\n"\n'
c_list += cksum_list
@@ -62,23 +75,26 @@ python do_update_crates() {
pn = d.getVar("PN")
crates = f"# Autogenerated with 'bitbake -c update_crates {pn}'\n\n"
+ seen = {}
found = False
- for root, dirs, files in os.walk(cargo_lock_src_dir):
- # ignore git and patches directories
- if root.startswith(os.path.join(cargo_lock_src_dir, '.pc')):
- continue
- if root.startswith(os.path.join(cargo_lock_src_dir, '.git')):
- continue
- for file in files:
- if file == 'Cargo.lock':
- cargo_lock_path = os.path.join(root, file)
- c = get_crates(cargo_lock_path)
- if c is not None:
- crates += c
- found = True
+ cargo_lock_src_dirs = [x.strip() for x in d.getVar("CARGO_LOCK_SRC_DIRS").split(',') if x.strip()]
+ for cargo_lock_src_dir in cargo_lock_src_dirs:
+ for root, dirs, files in os.walk(cargo_lock_src_dir):
+ # ignore git and patches directories
+ if root.startswith(os.path.join(cargo_lock_src_dir, '.pc')):
+ continue
+ if root.startswith(os.path.join(cargo_lock_src_dir, '.git')):
+ continue
+ for file in files:
+ if file == 'Cargo.lock':
+ cargo_lock_path = os.path.join(root, file)
+ c = get_crates(cargo_lock_path, cargo_lock_src_dir, seen)
+ if c is not None:
+ crates += c
+ found = True
if not found:
- raise ValueError(f"Unable to find any Cargo.lock in {cargo_lock_src_dir}")
+ raise ValueError(f"Unable to find any Cargo.lock in {d.getVar('CARGO_LOCK_SRC_DIRS')}")
target_file = d.expand("${THISDIR}/${BPN}-crates.inc")
with open(target_file, 'w') as f:
Recipes using cargo's -Z build-std must also vendor the standard library's dependencies. The std sources staged by rust-native (.../rustlib/src/rust/library) ship a Cargo.lock but no vendor directory, so those crates need crate:// entries in SRC_URI as well. Until now only a single directory could be scanned (CARGO_LOCK_SRC_DIR), which forced the std crate list to be maintained by hand and go stale on toolchain upgrades, breaking do_compile with: error: failed to select a version for the requirement `cfg-if = "^1.0"` (locked to 1.0.4) Add CARGO_LOCK_SRC_DIRS, a comma-separated list of directories defaulting to CARGO_LOCK_SRC_DIR, allowing e.g.: CARGO_LOCK_SRC_DIRS = "${S},${STAGING_LIBDIR_NATIVE}/rustlib/src/rust/library" Crates found in multiple lockfiles are listed only once, in the section of the first Cargo.lock containing them; conflicting checksums for the same crate version now fail the task. The crates.io warning now names the lockfile it came from. Output for recipes with a single lockfile is unchanged. Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> --- .../cargo-update-recipe-crates.bbclass | 54 ++++++++++++++-------- 1 file changed, 35 insertions(+), 19 deletions(-)