gpui: Switch from `linkme` to `inventory` for action registration (#24087)

someone13574 created

This switches how actions are registered in GPUI from
[dtolnay/linkme](https://github.com/dtolnay/linkme) to
[dtolany/inventory](https://github.com/dtolnay/inventory), fixing the
linking error seen in #15902, which also occurs on nightly toolchains.
I'm not sure if that issue should be closed or not given the other
problems on Chimera though.

This also fixes zed-industries/create-gpui-app#10

Release Notes:

- N/A

Change summary

Cargo.lock                                | 53 +++++++++---------------
crates/gpui/Cargo.toml                    |  2 
crates/gpui/src/action.rs                 | 12 +---
crates/gpui/src/gpui.rs                   |  2 
crates/gpui_macros/src/register_action.rs | 11 +---
5 files changed, 31 insertions(+), 49 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -2182,7 +2182,7 @@ dependencies = [
  "cap-primitives",
  "cap-std",
  "io-lifetimes",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -2210,7 +2210,7 @@ dependencies = [
  "ipnet",
  "maybe-owned",
  "rustix",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
  "winx",
 ]
 
@@ -4220,7 +4220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -4883,7 +4883,7 @@ checksum = "5e2e6123af26f0f2c51cc66869137080199406754903cc926a7690401ce09cb4"
 dependencies = [
  "io-lifetimes",
  "rustix",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -5428,8 +5428,8 @@ dependencies = [
  "gpui_macros",
  "http_client",
  "image",
+ "inventory",
  "itertools 0.14.0",
- "linkme",
  "log",
  "lyon",
  "media",
@@ -6479,6 +6479,15 @@ dependencies = [
  "syn 2.0.90",
 ]
 
+[[package]]
+name = "inventory"
+version = "0.3.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54b12ebb6799019b044deaf431eadfe23245b259bba5a2c0796acec3943a3cdb"
+dependencies = [
+ "rustversion",
+]
+
 [[package]]
 name = "io-extras"
 version = "0.18.4"
@@ -6486,7 +6495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2285ddfe3054097ef4b2fe909ef8c3bcd1ea52a8f0d274416caebeef39f04a65"
 dependencies = [
  "io-lifetimes",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -7091,7 +7100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
 dependencies = [
  "cfg-if",
- "windows-targets 0.48.5",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -7185,26 +7194,6 @@ dependencies = [
  "memchr",
 ]
 
-[[package]]
-name = "linkme"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "566336154b9e58a4f055f6dd4cbab62c7dc0826ce3c0a04e63b2d2ecd784cdae"
-dependencies = [
- "linkme-impl",
-]
-
-[[package]]
-name = "linkme-impl"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edbe595006d355eaf9ae11db92707d4338cd2384d16866131cc1afdbdd35d8d9"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.90",
-]
-
 [[package]]
 name = "linux-raw-sys"
 version = "0.4.14"
@@ -10373,7 +10362,7 @@ dependencies = [
  "once_cell",
  "socket2",
  "tracing",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -11259,7 +11248,7 @@ dependencies = [
  "libc",
  "linux-raw-sys",
  "once_cell",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -12981,7 +12970,7 @@ dependencies = [
  "fd-lock",
  "io-lifetimes",
  "rustix",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
  "winx",
 ]
 
@@ -13115,7 +13104,7 @@ dependencies = [
  "getrandom 0.3.1",
  "once_cell",
  "rustix",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -15872,7 +15861,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d"
 dependencies = [
  "bitflags 2.8.0",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]

crates/gpui/Cargo.toml 🔗

@@ -79,8 +79,8 @@ futures.workspace = true
 gpui_macros.workspace = true
 http_client = { optional = true, workspace = true }
 image = "0.25.1"
+inventory = "0.3.19"
 itertools.workspace = true
-linkme = "0.3"
 log.workspace = true
 num_cpus = "1.13"
 parking = "2.0.0"

crates/gpui/src/action.rs 🔗

@@ -173,7 +173,7 @@ struct ActionData {
 /// This type must be public so that our macros can build it in other crates.
 /// But this is an implementation detail and should not be used directly.
 #[doc(hidden)]
-pub type MacroActionBuilder = fn() -> MacroActionData;
+pub struct MacroActionBuilder(pub fn() -> MacroActionData);
 
 /// This type must be public so that our macros can build it in other crates.
 /// But this is an implementation detail and should not be used directly.
@@ -186,17 +186,13 @@ pub struct MacroActionData {
     pub json_schema: fn(&mut schemars::gen::SchemaGenerator) -> Option<schemars::schema::Schema>,
 }
 
-/// This constant must be public to be accessible from other crates.
-/// But its existence is an implementation detail and should not be used directly.
-#[doc(hidden)]
-#[linkme::distributed_slice]
-pub static __GPUI_ACTIONS: [MacroActionBuilder];
+inventory::collect!(MacroActionBuilder);
 
 impl ActionRegistry {
     /// Load all registered actions into the registry.
     pub(crate) fn load_actions(&mut self) {
-        for builder in __GPUI_ACTIONS {
-            let action = builder();
+        for builder in inventory::iter::<MacroActionBuilder> {
+            let action = builder.0();
             self.insert_action(action);
         }
     }

crates/gpui/src/gpui.rs 🔗

@@ -104,7 +104,7 @@ mod window;
 #[doc(hidden)]
 pub mod private {
     pub use anyhow;
-    pub use linkme;
+    pub use inventory;
     pub use schemars;
     pub use serde;
     pub use serde_derive;

crates/gpui_macros/src/register_action.rs 🔗

@@ -13,9 +13,6 @@ pub fn register_action_macro(ident: TokenStream) -> TokenStream {
 }
 
 pub(crate) fn register_action(type_name: &Ident) -> proc_macro2::TokenStream {
-    let static_slice_name =
-        format_ident!("__GPUI_ACTIONS_{}", type_name.to_string().to_uppercase());
-
     let action_builder_fn_name = format_ident!(
         "__gpui_actions_builder_{}",
         type_name.to_string().to_lowercase()
@@ -38,10 +35,10 @@ pub(crate) fn register_action(type_name: &Ident) -> proc_macro2::TokenStream {
                         json_schema: <#type_name as gpui::Action>::action_json_schema,
                     }
                 }
-                #[doc(hidden)]
-                #[gpui::private::linkme::distributed_slice(gpui::__GPUI_ACTIONS)]
-                #[linkme(crate = gpui::private::linkme)]
-                static #static_slice_name: gpui::MacroActionBuilder = #action_builder_fn_name;
+
+                gpui::private::inventory::submit! {
+                    gpui::MacroActionBuilder(#action_builder_fn_name)
+                }
             }
         }