From 5934eca052efaab3542df9fbb89742b8f019035b Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Wed, 21 Oct 2026 23:27:28 -0700 Subject: [PATCH] python3-ruff: Fix build on targets without 64-bit atomics std only provides AtomicU64 on targets with 64-bit atomics, so ruff fails to build for riscv32: error[E0432]: unresolved import `std::sync::atomic::AtomicU64` --> crates/ruff/src/cache.rs:7:25 Add a patch that uses portable-atomic's AtomicU64 for the cache timestamp on such targets, archived in the same on-disk format. AI-Generated: Uses Claude Code Signed-off-by: Khem Raj --- ...e-atomic-for-AtomicU64-on-targets-wi.patch | 162 ++++++++++++++++++ .../python/python3-ruff_0.17.1.bb | 2 + 2 files changed, 164 insertions(+) create mode 100644 meta-python/recipes-devtools/python/python3-ruff/0001-ruff-Use-portable-atomic-for-AtomicU64-on-targets-wi.patch diff --git a/meta-python/recipes-devtools/python/python3-ruff/0001-ruff-Use-portable-atomic-for-AtomicU64-on-targets-wi.patch b/meta-python/recipes-devtools/python/python3-ruff/0001-ruff-Use-portable-atomic-for-AtomicU64-on-targets-wi.patch new file mode 100644 index 0000000000..f2708bb6b0 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-ruff/0001-ruff-Use-portable-atomic-for-AtomicU64-on-targets-wi.patch @@ -0,0 +1,162 @@ +From: Khem Raj +Date: Wed, 21 Oct 2026 18:00:00 -0700 +Subject: [PATCH] ruff: Use portable-atomic for AtomicU64 on targets without + 64-bit atomics + +std only provides AtomicU64 on targets with 64-bit atomics, so ruff +fails to build for e.g. riscv32: + + error[E0432]: unresolved import `std::sync::atomic::AtomicU64` + --> crates/ruff/src/cache.rs:7:25 + | + 7 | use std::sync::atomic::{AtomicU64, Ordering}; + | ^^^^^^^^^ no `AtomicU64` in `sync::atomic` + +FileCache::last_seen holds milliseconds since the Unix epoch, so it has +to stay 64-bit. On targets without 64-bit atomics, use the AtomicU64 +from portable-atomic, which is already in the dependency tree, instead. +rkyv's AtomicLoad wrapper only supports the std atomics, so add an +equivalent wrapper that archives it as an ArchivedU64, which keeps the +on-disk cache format the same on all targets. Targets with 64-bit +atomics keep using std's AtomicU64 unchanged. + +Upstream-Status: Submitted [https://github.com/astral-sh/ruff/pull/29627] +Signed-off-by: Khem Raj +--- + Cargo.toml | 1 + + Cargo.lock | 1 + + crates/ruff/Cargo.toml | 3 +++ + crates/ruff/src/cache.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- + 4 files changed, 58 insertions(+), 4 deletions(-) + +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -170,6 +170,7 @@ + phf = { version = "0.11.3", default-features = false } + phf_codegen = { version = "0.11.3", default-features = false } + pep440_rs = { version = "0.7.1", default-features = false } ++portable-atomic = { version = "1.13.1", default-features = false, features = ["fallback"] } + pretty_assertions = { version = "1.3.0", default-features = false, features = ["std"] } + proc-macro2 = { version = "1.0.79", default-features = false, features = ["proc-macro"] } + pyproject-toml = { version = "0.13.4", default-features = false } +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -2523,6 +2523,7 @@ + "mimalloc", + "notify", + "path-absolutize", ++ "portable-atomic", + "rayon", + "regex", + "rkyv", +--- a/crates/ruff/Cargo.toml ++++ b/crates/ruff/Cargo.toml +@@ -77,6 +77,9 @@ + [target.'cfg(target_os = "windows")'.dependencies] + mimalloc = { workspace = true } + ++[target.'cfg(not(target_has_atomic = "64"))'.dependencies] ++portable-atomic = { workspace = true } ++ + [dev-dependencies] + # Enable test rules during development + ruff_linter = { workspace = true, features = ["clap", "test-rules"] } +--- a/crates/ruff/src/cache.rs ++++ b/crates/ruff/src/cache.rs +@@ -4,7 +4,9 @@ + use std::io::{self, Write}; + use std::path::{Path, PathBuf}; + use std::sync::Mutex; +-use std::sync::atomic::{AtomicU64, Ordering}; ++#[cfg(target_has_atomic = "64")] ++use std::sync::atomic::AtomicU64; ++use std::sync::atomic::Ordering; + use std::time::{Duration, SystemTime}; + + use anyhow::{Context, Result}; +@@ -23,6 +25,10 @@ + use ruff_workspace::Settings; + use ruff_workspace::resolver::Resolver; + ++// `std` only provides `AtomicU64` on targets with 64-bit atomics. ++#[cfg(not(target_has_atomic = "64"))] ++use portable_atomic::AtomicU64; ++ + /// [`Path`] that is relative to the package root in [`PackageCache`]. + pub(crate) type RelativePath = Path; + /// [`PathBuf`] that is relative to the package root in [`PackageCache`]. +@@ -341,12 +347,56 @@ + /// + /// Represented as the number of milliseconds since Unix epoch. This will + /// break in 1970 + ~584 years (~2554). +- #[rkyv(with = rkyv::with::AtomicLoad)] ++ #[cfg_attr( ++ target_has_atomic = "64", ++ rkyv(with = rkyv::with::AtomicLoad) ++ )] ++ #[cfg_attr(not(target_has_atomic = "64"), rkyv(with = AtomicU64LoadRelaxed))] + last_seen: AtomicU64, + + data: FileCacheData, + } + ++/// Archives a [`portable_atomic::AtomicU64`] as its value, like ++/// [`rkyv::with::AtomicLoad`] with [`rkyv::with::Relaxed`] does for the `std` ++/// one, so the on-disk format is the same on all targets. ++#[cfg(not(target_has_atomic = "64"))] ++struct AtomicU64LoadRelaxed; ++ ++#[cfg(not(target_has_atomic = "64"))] ++impl rkyv::with::ArchiveWith for AtomicU64LoadRelaxed { ++ type Archived = rkyv::primitive::ArchivedU64; ++ type Resolver = (); ++ ++ fn resolve_with(field: &AtomicU64, (): Self::Resolver, out: rkyv::Place) { ++ out.write(rkyv::primitive::ArchivedU64::from_native( ++ field.load(Ordering::Relaxed), ++ )); ++ } ++} ++ ++#[cfg(not(target_has_atomic = "64"))] ++impl rkyv::with::SerializeWith ++ for AtomicU64LoadRelaxed ++{ ++ fn serialize_with(_: &AtomicU64, _: &mut S) -> std::result::Result { ++ Ok(()) ++ } ++} ++ ++#[cfg(not(target_has_atomic = "64"))] ++impl ++ rkyv::with::DeserializeWith ++ for AtomicU64LoadRelaxed ++{ ++ fn deserialize_with( ++ field: &rkyv::primitive::ArchivedU64, ++ _: &mut D, ++ ) -> std::result::Result { ++ Ok(AtomicU64::new(field.to_native())) ++ } ++} ++ + impl FileCache { + /// Return whether or not the file in the cache was linted and found to have no diagnostics. + pub(crate) fn linted(&self) -> bool { +@@ -503,7 +553,6 @@ + use std::io; + use std::io::Write; + use std::path::{Path, PathBuf}; +- use std::sync::atomic::AtomicU64; + use std::time::SystemTime; + + use anyhow::Result; +@@ -522,7 +571,7 @@ + use ruff_workspace::Settings; + + use crate::cache::{self, ChangeData, FileCache, FileCacheData, FileCacheKey}; +- use crate::cache::{Cache, RelativePathBuf}; ++ use crate::cache::{AtomicU64, Cache, RelativePathBuf}; + use crate::commands::format::{FormatCommandError, FormatMode, FormatResult, format_path}; + use crate::diagnostics::{Diagnostics, lint_path}; + diff --git a/meta-python/recipes-devtools/python/python3-ruff_0.17.1.bb b/meta-python/recipes-devtools/python/python3-ruff_0.17.1.bb index 0028b6ede3..84da446937 100644 --- a/meta-python/recipes-devtools/python/python3-ruff_0.17.1.bb +++ b/meta-python/recipes-devtools/python/python3-ruff_0.17.1.bb @@ -6,6 +6,8 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=e679ca4f742cbfa29ab6a499529c2d39" DEPENDS += "python3-maturin-native" +SRC_URI += "file://0001-ruff-Use-portable-atomic-for-AtomicU64-on-targets-wi.patch" + SRC_URI[sha256sum] = "5bb796c5112e9fb9527f2ef2faa0a130d6312d19de92bcfaddd70dbb2d41020f" inherit pypi python_setuptools3_rust cargo-update-recipe-crates