console: Add console subsystem

Change-Id: I2aeead9ecb7cb9fbf5a223d680eb41e6c175d706
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/maize/+/259333
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
Reviewed-by: Travis Geiselbrecht <travisg@google.com>
Commit-Queue: Erik Gilling <konkers@google.com>
diff --git a/.bazelrc b/.bazelrc
index 84f3961..b5bd8a6 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -80,7 +80,7 @@
 # TODO - konkers: fix upstream stable toolchains
 common --@@rules_rust+//rust/toolchain/channel=nightly
 
-common --@pigweed//pw_log/rust:pw_log_backend=@pigweed//pw_log/rust:pw_log_backend_println
+common --@pigweed//pw_log/rust:pw_log_backend=//subsys/console:pw_log_backend
 
 # Clippy broken with embedded tests
 build:qemu-microbit --output_groups=-clippy_checks
diff --git a/arch/arm_cortex_m/spinlock_backend_cortex_m.rs b/arch/arm_cortex_m/spinlock_backend_cortex_m.rs
index 5c88aa6..6086a9d 100644
--- a/arch/arm_cortex_m/spinlock_backend_cortex_m.rs
+++ b/arch/arm_cortex_m/spinlock_backend_cortex_m.rs
@@ -72,6 +72,11 @@
     is_locked: UnsafeCell<bool>,
 }
 
+// Safety: Access to `is_locked` is protected by disabling interrupts and
+// proper barriers.
+unsafe impl Send for BareSpinLock {}
+unsafe impl Sync for BareSpinLock {}
+
 impl BareSpinLock {
     pub const fn new() -> Self {
         Self {
diff --git a/lib/pw_status/BUILD.bazel b/lib/pw_status/BUILD.bazel
new file mode 100644
index 0000000..e76a5d3
--- /dev/null
+++ b/lib/pw_status/BUILD.bazel
@@ -0,0 +1,43 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+load("@pigweed//pw_build:compatibility.bzl", "incompatible_with_mcu")
+load("@rules_rust//rust:defs.bzl", "rust_doc_test", "rust_library", "rust_test")
+
+rust_library(
+    name = "pw_status",
+    srcs = ["pw_status.rs"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "@rust_crates//:embedded-io",
+    ],
+)
+
+rust_test(
+    name = "pw_status_test",
+    srcs = ["pw_status_test.rs"],
+    use_libtest_harness = False,
+    visibility = ["//visibility:public"],
+    deps = [
+        ":pw_status",
+        "//lib/unittest",
+        "//target:linker_script",
+    ],
+)
+
+rust_doc_test(
+    name = "pw_status_doc_test",
+    crate = ":pw_status",
+    target_compatible_with = incompatible_with_mcu(),
+)
diff --git a/lib/pw_status/pw_status.rs b/lib/pw_status/pw_status.rs
new file mode 100644
index 0000000..99b8af1
--- /dev/null
+++ b/lib/pw_status/pw_status.rs
@@ -0,0 +1,111 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+//! # pw_status
+//!
+//! Rust error types using error codes compatible with Pigweed's
+//! [pw_status](https://pigweed.dev/pw_status).  In order to keep the interface
+//! idiomatic for Rust, `PW_STATUS_OK` is omitted from the Error enum and a
+//! `StatusCode` trait is provided to turn a `Result` into a canonical
+//! status code.
+//!
+//! For an in depth explanation of the values of the `Error` enum, see
+//! the [Pigweed status codes documentation](https://pigweed.dev/pw_status/#status-codes).
+//!
+//! # Example
+//!
+//! ```
+//! use pw_status::{Error, Result};
+//!
+//! fn div(numerator: u32, denominator: u32) -> Result<u32> {
+//!     if denominator == 0 {
+//!         Err(Error::FailedPrecondition)
+//!     } else {
+//!         Ok(numerator / denominator)
+//!     }
+//! }
+//!
+//! assert_eq!(div(4, 2), Ok(2));
+//! assert_eq!(div(4, 0), Err(Error::FailedPrecondition));
+//! ```
+
+#![no_std]
+
+/// Status code for no error.
+pub const OK: u32 = 0;
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+/// Error type compatible with Pigweed's [pw_status](https://pigweed.dev/pw_status).
+///
+/// For an in depth explanation of the values of the `Error` enum, see
+/// the [Pigweed status codes documentation](https://pigweed.dev/pw_status/#status-codes).
+pub enum Error {
+    Cancelled = 1,
+    Unknown = 2,
+    InvalidArgument = 3,
+    DeadlineExceeded = 4,
+    NotFound = 5,
+    AlreadyExists = 6,
+    PermissionDenied = 7,
+    ResourceExhausted = 8,
+    FailedPrecondition = 9,
+    Aborted = 10,
+    OutOfRange = 11,
+    Unimplemented = 12,
+    Internal = 13,
+    Unavailable = 14,
+    DataLoss = 15,
+    Unauthenticated = 16,
+}
+
+pub type Result<T> = core::result::Result<T, Error>;
+
+/// Convert a Result into an status code.
+pub trait StatusCode {
+    /// Return a pigweed compatible status code.
+    fn status_code(self) -> u32;
+}
+
+impl<T> StatusCode for Result<T> {
+    fn status_code(self) -> u32 {
+        match self {
+            Ok(_) => OK,
+            Err(e) => e as u32,
+        }
+    }
+}
+
+impl embedded_io::Error for Error {
+    fn kind(&self) -> embedded_io::ErrorKind {
+        use embedded_io::ErrorKind;
+        match self {
+            Error::Cancelled => ErrorKind::Interrupted,
+            Error::Unknown => ErrorKind::Other,
+            Error::InvalidArgument => ErrorKind::InvalidInput,
+            Error::DeadlineExceeded => ErrorKind::TimedOut,
+            Error::NotFound => ErrorKind::NotFound,
+            Error::AlreadyExists => ErrorKind::AlreadyExists,
+            Error::PermissionDenied => ErrorKind::PermissionDenied,
+            Error::ResourceExhausted => ErrorKind::OutOfMemory,
+            Error::FailedPrecondition => ErrorKind::InvalidInput,
+            Error::Aborted => ErrorKind::Interrupted,
+            Error::OutOfRange => ErrorKind::InvalidInput,
+            Error::Unimplemented => ErrorKind::Unsupported,
+            Error::Internal => ErrorKind::Unsupported,
+            Error::Unavailable => ErrorKind::Other,
+            Error::DataLoss => ErrorKind::Other,
+            Error::Unauthenticated => ErrorKind::Other,
+        }
+    }
+}
diff --git a/lib/pw_status/pw_status_test.rs b/lib/pw_status/pw_status_test.rs
new file mode 100644
index 0000000..288bf8c
--- /dev/null
+++ b/lib/pw_status/pw_status_test.rs
@@ -0,0 +1,44 @@
+// Copyright 2025 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#![no_std]
+#![no_main]
+
+use pw_status::*;
+use unittest::test;
+
+#[test]
+fn test_status_code() -> core::result::Result<(), unittest::TestError> {
+    unittest::assert_eq!(Result::Ok(()).status_code(), 0);
+    unittest::assert_eq!(Result::<()>::Err(Error::Cancelled).status_code(), 1);
+    unittest::assert_eq!(Result::<()>::Err(Error::Unknown).status_code(), 2);
+    unittest::assert_eq!(Result::<()>::Err(Error::InvalidArgument).status_code(), 3);
+    unittest::assert_eq!(Result::<()>::Err(Error::DeadlineExceeded).status_code(), 4);
+    unittest::assert_eq!(Result::<()>::Err(Error::NotFound).status_code(), 5);
+    unittest::assert_eq!(Result::<()>::Err(Error::AlreadyExists).status_code(), 6);
+    unittest::assert_eq!(Result::<()>::Err(Error::PermissionDenied).status_code(), 7);
+    unittest::assert_eq!(Result::<()>::Err(Error::ResourceExhausted).status_code(), 8);
+    unittest::assert_eq!(
+        Result::<()>::Err(Error::FailedPrecondition).status_code(),
+        9
+    );
+    unittest::assert_eq!(Result::<()>::Err(Error::Aborted).status_code(), 10);
+    unittest::assert_eq!(Result::<()>::Err(Error::OutOfRange).status_code(), 11);
+    unittest::assert_eq!(Result::<()>::Err(Error::Unimplemented).status_code(), 12);
+    unittest::assert_eq!(Result::<()>::Err(Error::Internal).status_code(), 13);
+    unittest::assert_eq!(Result::<()>::Err(Error::Unavailable).status_code(), 14);
+    unittest::assert_eq!(Result::<()>::Err(Error::DataLoss).status_code(), 15);
+    unittest::assert_eq!(Result::<()>::Err(Error::Unauthenticated).status_code(), 16);
+    Ok(())
+}
diff --git a/subsys/console/BUILD.bazel b/subsys/console/BUILD.bazel
new file mode 100644
index 0000000..24f77a3
--- /dev/null
+++ b/subsys/console/BUILD.bazel
@@ -0,0 +1,99 @@
+# Copyright 2025 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+load("@pigweed//pw_build:compatibility.bzl", "incompatible_with_mcu")
+load("@rules_rust//rust:defs.bzl", "rust_library", "rust_proc_macro")
+
+rust_library(
+    name = "console",
+    srcs = ["console.rs"],
+    deps = [
+        ":console_backend",
+        "//kernel/sync:spinlock",
+        "//lib/pw_status",
+        "@rust_crates//:embedded-io",
+    ],
+)
+
+rust_library(
+    name = "console_backend_stdio",
+    srcs = ["console_backend_stdio.rs"],
+    crate_name = "console_backend",
+    target_compatible_with = incompatible_with_mcu(),
+    deps = [
+        "//lib/pw_status",
+        "@rust_crates//:embedded-io",
+    ],
+)
+
+rust_library(
+    name = "console_backend_semihosting",
+    srcs = ["console_backend_semihosting.rs"],
+    crate_name = "console_backend",
+    target_compatible_with = select({
+        "@pigweed//pw_build/constraints/arm:cortex-m0": [],
+        "@pigweed//pw_build/constraints/arm:cortex-m3": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }),
+    deps = [
+        "//lib/pw_status",
+        "@rust_crates//:cortex-m-semihosting",
+        "@rust_crates//:embedded-io",
+    ],
+)
+
+rust_library(
+    name = "console_core",
+    srcs = ["console_core.rs"],
+    deps = [
+        "@rust_crates//:embedded-io",
+    ],
+)
+
+label_flag(
+    name = "console_backend",
+    build_setting_default = ":console_backend_stdio",
+)
+
+rust_proc_macro(
+    name = "pw_log_backend_macro",
+    srcs = [
+        "pw_log_backend_macro.rs",
+    ],
+    visibility = ["//visibility:public"],
+    deps = [
+        "@pigweed//pw_format/rust:pw_format",
+        "@pigweed//pw_log/rust:pw_log_backend_api",
+        "@pigweed//pw_status/rust:pw_status",
+        "@rust_crates//:proc-macro2",
+        "@rust_crates//:quote",
+        "@rust_crates//:syn",
+    ],
+)
+
+rust_library(
+    name = "pw_log_backend",
+    srcs = [
+        "pw_log_backend.rs",
+    ],
+    crate_name = "pw_log_backend",
+    proc_macro_deps = [":pw_log_backend_macro"],
+    tags = ["manual"],
+    visibility = ["//visibility:public"],
+    deps = [
+        ":console",
+        "@pigweed//pw_log/rust:pw_log_backend_api",
+        "@rust_crates//:embedded-io",
+    ],
+)
diff --git a/subsys/console/console.rs b/subsys/console/console.rs
new file mode 100644
index 0000000..0ef2ee2
--- /dev/null
+++ b/subsys/console/console.rs
@@ -0,0 +1,46 @@
+// Copyright 2025 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License
+
+#![no_std]
+
+use embedded_io::{ErrorType, Write};
+use spinlock::{BareSpinLock, BareSpinLockApi};
+
+use console_backend::ConsoleBackend;
+
+static CONSOLE_SPINLOCK: BareSpinLock = BareSpinLock::new();
+
+pub struct ConsoleLock {
+    _lock: <BareSpinLock as BareSpinLockApi>::Guard<'static>,
+}
+
+impl ErrorType for ConsoleLock {
+    type Error = pw_status::Error;
+}
+
+impl Write for ConsoleLock {
+    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
+        ConsoleBackend {}.write(buf)
+    }
+
+    fn flush(&mut self) -> Result<(), Self::Error> {
+        ConsoleBackend {}.flush()
+    }
+}
+
+pub fn get_console() -> ConsoleLock {
+    ConsoleLock {
+        _lock: CONSOLE_SPINLOCK.lock(),
+    }
+}
diff --git a/subsys/console/console_backend_semihosting.rs b/subsys/console/console_backend_semihosting.rs
new file mode 100644
index 0000000..542830a
--- /dev/null
+++ b/subsys/console/console_backend_semihosting.rs
@@ -0,0 +1,36 @@
+// Copyright 2025 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License
+
+#![no_std]
+
+use cortex_m_semihosting::hio::hstdout;
+use embedded_io::{ErrorType, Write};
+
+pub struct ConsoleBackend {}
+
+impl ErrorType for ConsoleBackend {
+    type Error = pw_status::Error;
+}
+
+impl Write for ConsoleBackend {
+    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
+        let mut stdout = hstdout().map_err(|_| Self::Error::Unavailable)?;
+        stdout.write_all(buf).map_err(|_| Self::Error::DataLoss)?;
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> Result<(), Self::Error> {
+        Ok(())
+    }
+}
diff --git a/subsys/console/console_backend_stdio.rs b/subsys/console/console_backend_stdio.rs
new file mode 100644
index 0000000..6ed5eec
--- /dev/null
+++ b/subsys/console/console_backend_stdio.rs
@@ -0,0 +1,33 @@
+// Copyright 2025 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License
+
+use std::io::{stdout, Write as StdWrite};
+
+use embedded_io::{ErrorType, Write};
+
+pub struct ConsoleBackend {}
+
+impl ErrorType for ConsoleBackend {
+    type Error = pw_status::Error;
+}
+
+impl Write for ConsoleBackend {
+    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
+        stdout().lock().write(buf).map_err(|_| Self::Error::Unknown)
+    }
+
+    fn flush(&mut self) -> Result<(), Self::Error> {
+        stdout().lock().flush().map_err(|_| Self::Error::Unknown)
+    }
+}
diff --git a/subsys/console/console_core.rs b/subsys/console/console_core.rs
new file mode 100644
index 0000000..ae7ce2b
--- /dev/null
+++ b/subsys/console/console_core.rs
@@ -0,0 +1,15 @@
+// Copyright 2025 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License
+
+#![no_std]
diff --git a/target/qemu/pw_log_backend_qemu/pw_log_backend.rs b/subsys/console/pw_log_backend.rs
similarity index 96%
rename from target/qemu/pw_log_backend_qemu/pw_log_backend.rs
rename to subsys/console/pw_log_backend.rs
index 6e81268..f14818f 100644
--- a/target/qemu/pw_log_backend_qemu/pw_log_backend.rs
+++ b/subsys/console/pw_log_backend.rs
@@ -18,6 +18,8 @@
 pub mod __private {
     pub use pw_log_backend_macro::{_pw_log_backend, _pw_logf_backend};
 
+    pub use console;
+    pub use embedded_io;
     use pw_log_backend_api::LogLevel;
 
     pub const fn log_level_tag(level: LogLevel) -> &'static str {
diff --git a/target/qemu/pw_log_backend_qemu/pw_log_backend_macro.rs b/subsys/console/pw_log_backend_macro.rs
similarity index 88%
rename from target/qemu/pw_log_backend_qemu/pw_log_backend_macro.rs
rename to subsys/console/pw_log_backend_macro.rs
index e5d5ee9..80b1d9a 100644
--- a/target/qemu/pw_log_backend_qemu/pw_log_backend_macro.rs
+++ b/subsys/console/pw_log_backend_macro.rs
@@ -49,7 +49,7 @@
 }
 
 // Generator that implements [`pw_format::CoreFmtFormatMacroGenerator`] to take
-// a log line and turn it into [`cortex_m_semihosting::hprintln] calls.
+// a log line output it through the system console.
 struct LogfGenerator<'a> {
     log_level: &'a Expr,
     args: Vec<TokenStream2>,
@@ -64,17 +64,21 @@
     }
 }
 
-// Use a [`pw_format::CoreFmtFormatMacroGenerator`] to prepare arguments to call
-// [`cortex_m_semihosting::hprintln`].
 impl CoreFmtFormatMacroGenerator for LogfGenerator<'_> {
     fn finalize(self, format_string: String) -> Result<TokenStream2> {
         let log_level = self.log_level;
         let args = &self.args;
-        let format_string = format!("[{{}}] {format_string}");
+        let format_string = format!("[{{}}] {format_string}\n");
         Ok(quote! {
           {
-            use cortex_m_semihosting::hprintln;
-            hprintln!(#format_string, __pw_log_backend_crate::log_level_tag(#log_level), #(#args),*);
+            use __pw_log_backend_crate::embedded_io::Write;
+            let mut console = __pw_log_backend_crate::console::get_console();
+            let _ = core::write!(
+                &mut console,
+                #format_string,
+                __pw_log_backend_crate::log_level_tag(#log_level),
+                #(#args),*
+            );
           }
         })
     }
diff --git a/target/qemu/BUILD.bazel b/target/qemu/BUILD.bazel
index ec2a5dc..43d64be 100644
--- a/target/qemu/BUILD.bazel
+++ b/target/qemu/BUILD.bazel
@@ -29,7 +29,7 @@
         "//lib/unittest:unittest_runner": "//lib/unittest:unittest_runner_cortex_m",
         "//kernel/sync:spinlock_backend": "//arch/arm_cortex_m:spinlock_backend_cortex_m",
         "//target:linker_script": "//target/qemu/linker_scripts:qemu_lm3s6965_linker_script",
-        "@pigweed//pw_log/rust:pw_log_backend": "//target/qemu/pw_log_backend_qemu:pw_log_backend",
+        "//subsys/console:console_backend": "//subsys/console:console_backend_semihosting",
     }),
 )
 
@@ -45,6 +45,6 @@
     flags = flags_from_dict({
         "//kernel/sync:spinlock_backend": "//arch/arm_cortex_m:spinlock_backend_cortex_m",
         "//target:linker_script": "//target/qemu/linker_scripts:qemu_nrf51823_linker_script",
-        "@pigweed//pw_log/rust:pw_log_backend": "//target/qemu/pw_log_backend_qemu:pw_log_backend",
+        "//subsys/console:console_backend": "//subsys/console:console_backend_semihosting",
     }),
 )
diff --git a/target/qemu/pw_log_backend_qemu/BUILD.bazel b/target/qemu/pw_log_backend_qemu/BUILD.bazel
deleted file mode 100644
index 744b920..0000000
--- a/target/qemu/pw_log_backend_qemu/BUILD.bazel
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2024 The Pigweed Authors
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not
-# use this file except in compliance with the License. You may obtain a copy of
-# the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations under
-# the License.
-
-load("@rules_rust//rust:defs.bzl", "rust_library", "rust_proc_macro")
-
-package(default_visibility = ["//visibility:public"])
-
-rust_proc_macro(
-    name = "pw_log_backend_macro",
-    srcs = [
-        "pw_log_backend_macro.rs",
-    ],
-    visibility = ["//visibility:public"],
-    deps = [
-        "@pigweed//pw_format/rust:pw_format",
-        "@pigweed//pw_log/rust:pw_log_backend_api",
-        "@pigweed//pw_status/rust:pw_status",
-        "@rust_crates//:proc-macro2",
-        "@rust_crates//:quote",
-        "@rust_crates//:syn",
-    ],
-)
-
-rust_library(
-    name = "pw_log_backend",
-    srcs = [
-        "pw_log_backend.rs",
-    ],
-    crate_name = "pw_log_backend",
-    proc_macro_deps = [":pw_log_backend_macro"],
-    tags = ["manual"],
-    visibility = ["//visibility:public"],
-    deps = [
-        "@pigweed//pw_log/rust:pw_log_backend_api",
-    ],
-)