From bd757996444f9268c3260a42df4a8019eacb0ac4 Mon Sep 17 00:00:00 2001 From: Alix-007 Date: Sat, 14 Mar 2026 03:45:03 +0800 Subject: [PATCH] fix(build): unblock strict 32-bit no-default-features builds (#3375) Co-authored-by: argenis de la rosa --- Cargo.lock | 1 + Cargo.toml | 11 ++++++----- crates/robot-kit/Cargo.toml | 3 +++ crates/robot-kit/src/safety.rs | 3 ++- src/channels/irc.rs | 9 +-------- src/channels/mod.rs | 7 ++----- src/gateway/mod.rs | 14 +++++++++----- src/observability/mod.rs | 12 ++++++------ src/peripherals/serial.rs | 2 +- 9 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc5cee085..759537d5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8021,6 +8021,7 @@ dependencies = [ "base64", "chrono", "directories", + "portable-atomic", "reqwest", "rppal", "serde", diff --git a/Cargo.toml b/Cargo.toml index 664be66a8..e36d7138e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,12 +82,12 @@ hex = "0.4" # CSPRNG for secure token generation rand = "0.10" +# Portable atomic fallbacks for targets without native 64-bit atomics +portable-atomic = "1" + # serde-big-array for wa-rs storage (large array serialization) serde-big-array = { version = "0.5", optional = true } -# Portable atomic fallbacks for 32-bit targets (no native 64-bit atomics) -portable-atomic = { version = "1", optional = true } - # Fast mutexes that don't poison on panic parking_lot = "0.12" @@ -187,13 +187,14 @@ landlock = { version = "0.4", optional = true } libc = "0.2" [features] -default = ["channel-nostr"] +default = ["observability-prometheus", "channel-nostr"] channel-nostr = ["dep:nostr-sdk"] hardware = ["nusb", "tokio-serial"] channel-matrix = ["dep:matrix-sdk"] channel-lark = ["dep:prost"] channel-feishu = ["channel-lark"] # Alias for Feishu users (Lark and Feishu are the same platform) memory-postgres = ["dep:postgres"] +observability-prometheus = ["dep:prometheus"] observability-otel = ["dep:opentelemetry", "dep:opentelemetry_sdk", "dep:opentelemetry-otlp"] peripheral-rpi = ["rppal"] # Browser backend feature alias used by cfg(feature = "browser-native") @@ -206,7 +207,7 @@ sandbox-bubblewrap = [] # Backward-compatible alias for older invocations landlock = ["sandbox-landlock"] # Prometheus metrics observer (requires 64-bit atomics; disable on 32-bit targets) -metrics = ["dep:prometheus"] +metrics = ["observability-prometheus"] # probe = probe-rs for Nucleo memory read (adds ~50 deps; optional) probe = ["dep:probe-rs"] # rag-pdf = PDF ingestion for datasheet RAG diff --git a/crates/robot-kit/Cargo.toml b/crates/robot-kit/Cargo.toml index 5da916503..c27b14d36 100644 --- a/crates/robot-kit/Cargo.toml +++ b/crates/robot-kit/Cargo.toml @@ -51,6 +51,9 @@ tracing = "0.1" # Time handling chrono = { version = "0.4", features = ["clock", "std"] } +# Portable atomics for 32-bit targets +portable-atomic = "1" + # User directories directories = "6.0" diff --git a/crates/robot-kit/src/safety.rs b/crates/robot-kit/src/safety.rs index 3a5f6cef4..c4019d974 100644 --- a/crates/robot-kit/src/safety.rs +++ b/crates/robot-kit/src/safety.rs @@ -19,7 +19,8 @@ use crate::config::{RobotConfig, SafetyConfig}; use crate::traits::ToolResult; use anyhow::Result; -use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use portable_atomic::{AtomicU64, Ordering}; +use std::sync::atomic::AtomicBool; use std::sync::Arc; use std::time::{Duration, Instant}; use tokio::sync::{broadcast, RwLock}; diff --git a/src/channels/irc.rs b/src/channels/irc.rs index 15946572e..a15871432 100644 --- a/src/channels/irc.rs +++ b/src/channels/irc.rs @@ -1,10 +1,6 @@ use crate::channels::traits::{Channel, ChannelMessage, SendMessage}; use async_trait::async_trait; -#[cfg(not(target_has_atomic = "64"))] -use std::sync::atomic::AtomicU32; -#[cfg(target_has_atomic = "64")] -use std::sync::atomic::AtomicU64; -use std::sync::atomic::Ordering; +use portable_atomic::{AtomicU64, Ordering}; use std::sync::Arc; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::sync::{mpsc, Mutex}; @@ -17,10 +13,7 @@ use tokio_rustls::rustls; const READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(300); /// Monotonic counter to ensure unique message IDs under burst traffic. -#[cfg(target_has_atomic = "64")] static MSG_SEQ: AtomicU64 = AtomicU64::new(0); -#[cfg(not(target_has_atomic = "64"))] -static MSG_SEQ: AtomicU32 = AtomicU32::new(0); /// IRC over TLS channel. /// diff --git a/src/channels/mod.rs b/src/channels/mod.rs index bef4b1241..e0aaf941c 100644 --- a/src/channels/mod.rs +++ b/src/channels/mod.rs @@ -84,16 +84,13 @@ use crate::security::SecurityPolicy; use crate::tools::{self, Tool}; use crate::util::truncate_with_ellipsis; use anyhow::{Context, Result}; +use portable_atomic::{AtomicU64, Ordering}; use serde::Deserialize; use std::collections::{HashMap, HashSet}; use std::fmt::Write; use std::path::{Path, PathBuf}; use std::process::Command; -#[cfg(not(target_has_atomic = "64"))] -use std::sync::atomic::AtomicU32; -#[cfg(target_has_atomic = "64")] -use std::sync::atomic::AtomicU64; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::AtomicBool; use std::sync::{Arc, Mutex, OnceLock}; use std::time::{Duration, Instant, SystemTime}; use tokio_util::sync::CancellationToken; diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index 130a3fbe9..59f9b4fe5 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -747,10 +747,14 @@ async fn handle_health(State(state): State) -> impl IntoResponse { /// Prometheus content type for text exposition format. const PROMETHEUS_CONTENT_TYPE: &str = "text/plain; version=0.0.4; charset=utf-8"; +fn prometheus_disabled_hint() -> String { + String::from("# Prometheus backend not enabled. Set [observability] backend = \"prometheus\" in config.\n") +} + /// GET /metrics — Prometheus text exposition format async fn handle_metrics(State(state): State) -> impl IntoResponse { let body = { - #[cfg(feature = "metrics")] + #[cfg(feature = "observability-prometheus")] { if let Some(prom) = state .observer @@ -760,13 +764,13 @@ async fn handle_metrics(State(state): State) -> impl IntoResponse { { prom.encode() } else { - String::from("# Prometheus backend not enabled. Set [observability] backend = \"prometheus\" in config.\n") + prometheus_disabled_hint() } } - #[cfg(not(feature = "metrics"))] + #[cfg(not(feature = "observability-prometheus"))] { let _ = &state; - String::from("# Prometheus backend not enabled. Set [observability] backend = \"prometheus\" in config.\n") + prometheus_disabled_hint() } }; @@ -1750,7 +1754,7 @@ mod tests { assert!(text.contains("Prometheus backend not enabled")); } - #[cfg(feature = "metrics")] + #[cfg(feature = "observability-prometheus")] #[tokio::test] async fn metrics_endpoint_renders_prometheus_output() { let prom = Arc::new(crate::observability::PrometheusObserver::new()); diff --git a/src/observability/mod.rs b/src/observability/mod.rs index b43692852..4bcfa4db1 100644 --- a/src/observability/mod.rs +++ b/src/observability/mod.rs @@ -3,7 +3,7 @@ pub mod multi; pub mod noop; #[cfg(feature = "observability-otel")] pub mod otel; -#[cfg(feature = "metrics")] +#[cfg(feature = "observability-prometheus")] pub mod prometheus; pub mod runtime_trace; pub mod traits; @@ -16,7 +16,7 @@ pub use self::multi::MultiObserver; pub use noop::NoopObserver; #[cfg(feature = "observability-otel")] pub use otel::OtelObserver; -#[cfg(feature = "metrics")] +#[cfg(feature = "observability-prometheus")] pub use prometheus::PrometheusObserver; pub use traits::{Observer, ObserverEvent}; #[allow(unused_imports)] @@ -29,14 +29,14 @@ pub fn create_observer(config: &ObservabilityConfig) -> Box { match config.backend.as_str() { "log" => Box::new(LogObserver::new()), "prometheus" => { - #[cfg(feature = "metrics")] + #[cfg(feature = "observability-prometheus")] { Box::new(PrometheusObserver::new()) } - #[cfg(not(feature = "metrics"))] + #[cfg(not(feature = "observability-prometheus"))] { tracing::warn!( - "Prometheus backend requested but this build was compiled without `metrics`; falling back to noop." + "Prometheus backend requested but this build was compiled without `observability-prometheus`; falling back to noop." ); Box::new(NoopObserver) } @@ -118,7 +118,7 @@ mod tests { backend: "prometheus".into(), ..ObservabilityConfig::default() }; - let expected = if cfg!(feature = "metrics") { + let expected = if cfg!(feature = "observability-prometheus") { "prometheus" } else { "noop" diff --git a/src/peripherals/serial.rs b/src/peripherals/serial.rs index 4b0654736..591658021 100644 --- a/src/peripherals/serial.rs +++ b/src/peripherals/serial.rs @@ -8,8 +8,8 @@ use crate::config::PeripheralBoardConfig; use crate::peripherals::Peripheral; use crate::tools::traits::{Tool, ToolResult}; use async_trait::async_trait; +use portable_atomic::{AtomicU64, Ordering}; use serde_json::{json, Value}; -use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::sync::Mutex;