Interop with pigweed upstream rust crates

Change-Id: I76dd8117576820080fae5e400b01e5908632b2c6
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/maize/+/254807
Commit-Queue: Erik Gilling <konkers@google.com>
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
Reviewed-by: Dave Roth <davidroth@google.com>
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/.bazelignore b/.bazelignore
new file mode 100644
index 0000000..fcbafa8
--- /dev/null
+++ b/.bazelignore
@@ -0,0 +1 @@
+build/crates_io/rust_crates
diff --git a/.bazelversion b/.bazelversion
index 41b382c..3447823 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-1ff5af18d045e8f30a2a0367470db4e8225a785c
+46341b1a59c7a1cc8ca0dc604ad53b6de7fee653
diff --git a/MODULE.bazel b/MODULE.bazel
index b70061f..612b179 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -70,14 +70,25 @@
 
 crate = use_extension("@rules_rust//crate_universe:extension.bzl", "crate")
 
-crate.spec(package = "cortex-m", version = "0.7.7")
-crate.spec(package = "cortex-m-rt", version = "0.7.5")
-crate.spec(package = "cortex-m-semihosting", version = "0.5.0")
-crate.spec(package = "panic-halt", version = "1.0.0")
+crate.from_cargo(
+    name = "crates_no_std",
+    cargo_lockfile = "//build/crates_io/crates_no_std:Cargo.lock",
+    manifests = ["//build/crates_io/crates_no_std:Cargo.toml"],
+)
+use_repo(crate, "crates_no_std")
 
-# Use a different name to avoid conflicting with protobuf's crates.
-crate.from_specs(name = "rust_crates")
-use_repo(crate, "rust_crates")
+crate.from_cargo(
+    name = "crates_std",
+    cargo_lockfile = "//build/crates_io/crates_std:Cargo.lock",
+    manifests = ["//build/crates_io/crates_std:Cargo.toml"],
+)
+use_repo(crate, "crates_std")
+
+local_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:local.bzl", "local_repository")
+local_repository(name = "rust_crates", path = "build/crates_io/rust_crates")
+
+pw_rust_crates = use_extension("@pigweed//pw_build:pw_rust_crates_extension.bzl", "pw_rust_crates_extension")
+override_repo(pw_rust_crates, rust_crates = "rust_crates")
 
 cipd_client_repository = use_repo_rule("@pigweed//pw_env_setup/bazel/cipd_setup:cipd_rules.bzl", "_cipd_client_repository")
 cipd_client_repository(name = "cipd_client")
diff --git a/build/crates_io/.gitignore b/build/crates_io/.gitignore
new file mode 100644
index 0000000..fa8d85a
--- /dev/null
+++ b/build/crates_io/.gitignore
@@ -0,0 +1,2 @@
+Cargo.lock
+target
diff --git a/build/crates_io/Cargo.toml b/build/crates_io/Cargo.toml
new file mode 100644
index 0000000..3884621
--- /dev/null
+++ b/build/crates_io/Cargo.toml
@@ -0,0 +1,27 @@
+# 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.
+
+[package]
+name = "rust_crates"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+cargo_toml = "0.15.2"
+clap = { version = "4.1.8", features = ["derive"] }
+handlebars = "4.3.6"
+serde = { version = "1", features = ["derive"] }
+toml = "0.7.3"
diff --git a/build/crates_io/config.toml b/build/crates_io/config.toml
new file mode 100644
index 0000000..28123fb
--- /dev/null
+++ b/build/crates_io/config.toml
@@ -0,0 +1,19 @@
+# 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.
+
+manifests = ["crates_no_std/Cargo.toml", "crates_std/Cargo.toml"]
+
+[bazel_aliases]
+crates_no_std = { constraint = ":no_std", path = "@crates_no_std//" }
+crates_std = { constraint = ":std", path = "@crates_std//" }
diff --git a/build/crates_io/crates_no_std/BUILD.bazel b/build/crates_io/crates_no_std/BUILD.bazel
new file mode 100644
index 0000000..ef4d136
--- /dev/null
+++ b/build/crates_io/crates_no_std/BUILD.bazel
@@ -0,0 +1,13 @@
+# 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.
diff --git a/build/crates_io/crates_no_std/Cargo.lock b/build/crates_io/crates_no_std/Cargo.lock
new file mode 100644
index 0000000..04c6f50
--- /dev/null
+++ b/build/crates_io/crates_no_std/Cargo.lock
@@ -0,0 +1,180 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "bare-metal"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
+dependencies = [
+ "rustc_version",
+]
+
+[[package]]
+name = "bitfield"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
+
+[[package]]
+name = "cortex-m"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
+dependencies = [
+ "bare-metal",
+ "bitfield",
+ "embedded-hal",
+ "volatile-register",
+]
+
+[[package]]
+name = "cortex-m-rt"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6"
+dependencies = [
+ "cortex-m-rt-macros",
+]
+
+[[package]]
+name = "cortex-m-rt-macros"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "cortex-m-semihosting"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0"
+dependencies = [
+ "cortex-m",
+]
+
+[[package]]
+name = "crates_no_std"
+version = "0.1.0"
+dependencies = [
+ "cortex-m",
+ "cortex-m-rt",
+ "cortex-m-semihosting",
+ "panic-halt",
+]
+
+[[package]]
+name = "embedded-hal"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
+dependencies = [
+ "nb 0.1.3",
+ "void",
+]
+
+[[package]]
+name = "nb"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
+dependencies = [
+ "nb 1.1.0",
+]
+
+[[package]]
+name = "nb"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
+
+[[package]]
+name = "panic-halt"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+dependencies = [
+ "semver-parser",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+
+[[package]]
+name = "syn"
+version = "2.0.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+
+[[package]]
+name = "vcell"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
+
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
+[[package]]
+name = "volatile-register"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
+dependencies = [
+ "vcell",
+]
diff --git a/build/crates_io/crates_no_std/Cargo.toml b/build/crates_io/crates_no_std/Cargo.toml
new file mode 100644
index 0000000..d149a2f
--- /dev/null
+++ b/build/crates_io/crates_no_std/Cargo.toml
@@ -0,0 +1,29 @@
+# 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.
+
+[package]
+name = "crates_no_std"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+path = "fake.rs"
+
+[dependencies]
+cortex-m = "0.7.7"
+cortex-m-rt = "0.7.5"
+cortex-m-semihosting = "0.5.0"
+panic-halt = "1.0.0"
+
+[features]
diff --git a/build/crates_io/crates_std/BUILD.bazel b/build/crates_io/crates_std/BUILD.bazel
new file mode 100644
index 0000000..ef4d136
--- /dev/null
+++ b/build/crates_io/crates_std/BUILD.bazel
@@ -0,0 +1,13 @@
+# 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.
diff --git a/build/crates_io/crates_std/Cargo.lock b/build/crates_io/crates_std/Cargo.lock
new file mode 100644
index 0000000..43a15a4
--- /dev/null
+++ b/build/crates_io/crates_std/Cargo.lock
@@ -0,0 +1,206 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "bare-metal"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
+dependencies = [
+ "rustc_version",
+]
+
+[[package]]
+name = "bitfield"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
+
+[[package]]
+name = "cortex-m"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
+dependencies = [
+ "bare-metal",
+ "bitfield",
+ "embedded-hal",
+ "volatile-register",
+]
+
+[[package]]
+name = "cortex-m-rt"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6"
+dependencies = [
+ "cortex-m-rt-macros",
+]
+
+[[package]]
+name = "cortex-m-rt-macros"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "cortex-m-semihosting"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0"
+dependencies = [
+ "cortex-m",
+]
+
+[[package]]
+name = "crates_std"
+version = "0.1.0"
+dependencies = [
+ "cortex-m",
+ "cortex-m-rt",
+ "cortex-m-semihosting",
+ "nom",
+ "panic-halt",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "embedded-hal"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
+dependencies = [
+ "nb 0.1.3",
+ "void",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "nb"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
+dependencies = [
+ "nb 1.1.0",
+]
+
+[[package]]
+name = "nb"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "panic-halt"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+dependencies = [
+ "semver-parser",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+
+[[package]]
+name = "syn"
+version = "2.0.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+
+[[package]]
+name = "vcell"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
+
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
+[[package]]
+name = "volatile-register"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
+dependencies = [
+ "vcell",
+]
diff --git a/build/crates_io/crates_std/Cargo.toml b/build/crates_io/crates_std/Cargo.toml
new file mode 100644
index 0000000..1c8a336
--- /dev/null
+++ b/build/crates_io/crates_std/Cargo.toml
@@ -0,0 +1,33 @@
+# 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.
+
+[package]
+name = "crates_std"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+path = "fake.rs"
+
+[dependencies]
+cortex-m = "0.7.7"
+cortex-m-rt = "0.7.5"
+cortex-m-semihosting = "0.5.0"
+nom = "7.1.3"
+panic-halt = "1.0.0"
+proc-macro2 = "1.0.92"
+quote = "1.0.37"
+syn = "2.0.90"
+
+[features]
diff --git a/build/crates_io/rust_crates/BUILD.bazel b/build/crates_io/rust_crates/BUILD.bazel
new file mode 100644
index 0000000..f0ed290
--- /dev/null
+++ b/build/crates_io/rust_crates/BUILD.bazel
@@ -0,0 +1,35 @@
+# 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(":aliases.bzl", "make_crate_aliases")
+
+constraint_setting(
+    name = "std_enabled",
+    default_constraint_value = ":std",
+    visibility = ["//visibility:public"],
+)
+
+constraint_value(
+    name = "std",
+    constraint_setting = ":std_enabled",
+    visibility = ["//visibility:public"],
+)
+
+constraint_value(
+    name = "no_std",
+    constraint_setting = ":std_enabled",
+    visibility = ["//visibility:public"],
+)
+
+make_crate_aliases()
diff --git a/build/crates_io/rust_crates/REPO.bazel b/build/crates_io/rust_crates/REPO.bazel
new file mode 100644
index 0000000..ef4d136
--- /dev/null
+++ b/build/crates_io/rust_crates/REPO.bazel
@@ -0,0 +1,13 @@
+# 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.
diff --git a/build/crates_io/rust_crates/aliases.bzl b/build/crates_io/rust_crates/aliases.bzl
new file mode 100644
index 0000000..7151e53
--- /dev/null
+++ b/build/crates_io/rust_crates/aliases.bzl
@@ -0,0 +1,122 @@
+# 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.
+
+# THIS FILE IS AUTO-GENERATED. DO NOT EDIT MANUALLY!!!
+# See //README.md for information on updating
+
+def make_crate_aliases():
+  native.alias (
+    name = "cortex-m",
+    target_compatible_with = select({
+      ":no_std": [],
+      ":std": [],
+      "//conditions:default": ["@platforms//:incompatible"],
+    }),
+    actual = select({
+      ":no_std": "@crates_no_std//:cortex-m",
+      ":std": "@crates_std//:cortex-m",
+    }),
+    visibility = ["//visibility:public"],
+  )
+
+  native.alias (
+    name = "cortex-m-rt",
+    target_compatible_with = select({
+      ":no_std": [],
+      ":std": [],
+      "//conditions:default": ["@platforms//:incompatible"],
+    }),
+    actual = select({
+      ":no_std": "@crates_no_std//:cortex-m-rt",
+      ":std": "@crates_std//:cortex-m-rt",
+    }),
+    visibility = ["//visibility:public"],
+  )
+
+  native.alias (
+    name = "cortex-m-semihosting",
+    target_compatible_with = select({
+      ":no_std": [],
+      ":std": [],
+      "//conditions:default": ["@platforms//:incompatible"],
+    }),
+    actual = select({
+      ":no_std": "@crates_no_std//:cortex-m-semihosting",
+      ":std": "@crates_std//:cortex-m-semihosting",
+    }),
+    visibility = ["//visibility:public"],
+  )
+
+  native.alias (
+    name = "nom",
+    target_compatible_with = select({
+      ":std": [],
+      "//conditions:default": ["@platforms//:incompatible"],
+    }),
+    actual = select({
+      ":std": "@crates_std//:nom",
+    }),
+    visibility = ["//visibility:public"],
+  )
+
+  native.alias (
+    name = "panic-halt",
+    target_compatible_with = select({
+      ":no_std": [],
+      ":std": [],
+      "//conditions:default": ["@platforms//:incompatible"],
+    }),
+    actual = select({
+      ":no_std": "@crates_no_std//:panic-halt",
+      ":std": "@crates_std//:panic-halt",
+    }),
+    visibility = ["//visibility:public"],
+  )
+
+  native.alias (
+    name = "proc-macro2",
+    target_compatible_with = select({
+      ":std": [],
+      "//conditions:default": ["@platforms//:incompatible"],
+    }),
+    actual = select({
+      ":std": "@crates_std//:proc-macro2",
+    }),
+    visibility = ["//visibility:public"],
+  )
+
+  native.alias (
+    name = "quote",
+    target_compatible_with = select({
+      ":std": [],
+      "//conditions:default": ["@platforms//:incompatible"],
+    }),
+    actual = select({
+      ":std": "@crates_std//:quote",
+    }),
+    visibility = ["//visibility:public"],
+  )
+
+  native.alias (
+    name = "syn",
+    target_compatible_with = select({
+      ":std": [],
+      "//conditions:default": ["@platforms//:incompatible"],
+    }),
+    actual = select({
+      ":std": "@crates_std//:syn",
+    }),
+    visibility = ["//visibility:public"],
+  )
+
diff --git a/build/crates_io/src/aliases.rs b/build/crates_io/src/aliases.rs
new file mode 100644
index 0000000..af8e216
--- /dev/null
+++ b/build/crates_io/src/aliases.rs
@@ -0,0 +1,109 @@
+// 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.
+
+use std::collections::{BTreeMap, BTreeSet};
+
+use cargo_toml::Manifest;
+use handlebars::Handlebars;
+use serde::Serialize;
+
+use crate::Config;
+
+#[derive(Serialize)]
+struct Alias {
+    pub name: String,
+    // Using BTreeSet and BTreeMap here for a stable output order.
+    pub target_compatible_with: BTreeSet<String>,
+    pub actual: BTreeMap<String, String>,
+}
+
+// Create a wrapper struct so that we expose `aliases` as a single element
+// in the template's global namespace.
+#[derive(Serialize)]
+struct TemplateData<'a> {
+    aliases: &'a BTreeMap<String, Alias>,
+}
+
+pub fn generate(config: &Config) {
+    // Using BTreeMap here for a stable output order.
+    let mut aliases: BTreeMap<String, Alias> = BTreeMap::new();
+
+    for manifest_path in &config.manifests {
+        let manifest = Manifest::from_path(manifest_path).expect("manifest parses");
+        let package_name = &manifest.package().name;
+        let Some(mapping) = config.bazel_aliases.get(package_name) else {
+            panic!("No mapping for {package_name} in config.");
+        };
+
+        for dep_name in manifest.dependencies.keys() {
+            let alias = aliases.entry(dep_name.clone()).or_insert(Alias {
+                name: dep_name.clone(),
+                target_compatible_with: BTreeSet::new(),
+                actual: BTreeMap::new(),
+            });
+            alias
+                .target_compatible_with
+                .insert(mapping.constraint.clone());
+
+            let dep_path = format!("{}:{dep_name}", mapping.path);
+            alias.actual.insert(mapping.constraint.clone(), dep_path);
+        }
+    }
+
+    let template = r#"
+# 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.
+
+# THIS FILE IS AUTO-GENERATED. DO NOT EDIT MANUALLY!!!
+# See //README.md for information on updating
+
+def make_crate_aliases():
+{{#each aliases}}
+  native.alias (
+    name = "{{this.name}}",
+    target_compatible_with = select({
+      {{#each this.target_compatible_with}}
+      "{{this}}": [],
+      {{/each}}
+      "//conditions:default": ["@platforms//:incompatible"],
+    }),
+    actual = select({
+      {{#each this.actual}}
+      "{{@key}}": "{{this}}",
+      {{/each}}
+    }),
+    visibility = ["//visibility:public"],
+  )
+
+{{/each}}
+"#
+    .trim();
+
+    let output = Handlebars::new()
+        .render_template(template, &TemplateData { aliases: &aliases })
+        .expect("Template renders");
+
+    print!("{}", output);
+}
diff --git a/build/crates_io/src/main.rs b/build/crates_io/src/main.rs
new file mode 100644
index 0000000..6b3b491
--- /dev/null
+++ b/build/crates_io/src/main.rs
@@ -0,0 +1,49 @@
+// 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.
+
+use std::{
+    collections::{HashMap, HashSet},
+    path::PathBuf,
+};
+
+use clap::Parser;
+use serde::Deserialize;
+use std::fs;
+
+mod aliases;
+
+#[derive(Debug, Parser)]
+struct Args {
+    #[arg(long, required(true))]
+    config: PathBuf,
+}
+
+#[derive(Deserialize)]
+pub struct Config {
+    manifests: HashSet<String>,
+    bazel_aliases: HashMap<String, Mapping>,
+}
+
+#[derive(Deserialize)]
+struct Mapping {
+    constraint: String,
+    path: String,
+}
+
+fn main() {
+    let args = Args::parse();
+    let config_str = fs::read_to_string(args.config).expect("config file exists");
+    let config: Config = toml::from_str(&config_str).expect("config file parses");
+    aliases::generate(&config);
+}