[PATCH] scripts: generate_rust_analyzer: reduce the output file size

Jesung Yang via B4 Relay posted 1 patch 1 month, 1 week ago
scripts/generate_rust_analyzer.py | 34 ++++++++++++++++++++--------------
1 file changed, 20 insertions(+), 14 deletions(-)
[PATCH] scripts: generate_rust_analyzer: reduce the output file size
Posted by Jesung Yang via B4 Relay 1 month, 1 week ago
From: Jesung Yang <y.j3ms.n@gmail.com>

Use the `cfg_groups` field to aggregate common configurations into a
single project-level definition. This avoids repeating identical `cfg`s
across crates.

As a result, the size of the generated `rust-project.json` is reduced
from 11MiB to 406KiB (about 96% reduction).

Signed-off-by: Jesung Yang <y.j3ms.n@gmail.com>
---
This patch depends on [1] to ensure it merges cleanly without conflicts.

[1] https://lore.kernel.org/rust-for-linux/20260101-ra-fix-primitive-v1-1-def809357b4e@gmail.com/
---
 scripts/generate_rust_analyzer.py | 34 ++++++++++++++++++++--------------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
index 6178a53516ec35f308897e65c5001edd81b0d3dd..2a8578fb784d08b2a5e628bfab935080759d2dce 100755
--- a/scripts/generate_rust_analyzer.py
+++ b/scripts/generate_rust_analyzer.py
@@ -19,15 +19,7 @@ def args_crates_cfgs(cfgs):
 
     return crates_cfgs
 
-def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
-    # Generate the configuration list.
-    cfg = []
-    with open(objtree / "include" / "generated" / "rustc_cfg") as fd:
-        for line in fd:
-            line = line.replace("--cfg=", "")
-            line = line.replace("\n", "")
-            cfg.append(line)
-
+def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, kernel_cfg_group):
     # Now fill the crates list -- dependencies need to come first.
     #
     # Avoid O(n^2) iterations by keeping a map of indexes.
@@ -35,7 +27,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
     crates_indexes = {}
     crates_cfgs = args_crates_cfgs(cfgs)
 
-    def append_crate(display_name, root_module, deps, cfg=[], crate_attrs=[], is_workspace_member=True, is_proc_macro=False, edition="2021"):
+    def append_crate(display_name, root_module, deps, cfg=[], cfg_groups=[], crate_attrs=[], is_workspace_member=True, is_proc_macro=False, edition="2021"):
         crate = {
             "display_name": display_name,
             "root_module": str(root_module),
@@ -48,6 +40,8 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
                 "RUST_MODFILE": "This is only for rust-analyzer"
             }
         }
+        if len(cfg_groups) > 0:
+            crate["cfg_groups"] = cfg_groups
         if len(crate_attrs) > 0:
             crate["crate_attrs"] = crate_attrs
         if is_proc_macro:
@@ -134,7 +128,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
             display_name,
             srctree / "rust"/ display_name / "lib.rs",
             deps,
-            cfg=cfg,
+            cfg_groups=[kernel_cfg_group],
             crate_attrs=crate_attrs,
         )
         crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True))
@@ -189,7 +183,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
                 name,
                 path,
                 ["kernel"],
-                cfg=cfg,
+                cfg_groups=[kernel_cfg_group],
                 crate_attrs=["no_std"],
             )
 
@@ -214,10 +208,22 @@ def main():
     # Making sure that the `sysroot` and `sysroot_src` belong to the same toolchain.
     assert args.sysroot in args.sysroot_src.parents
 
+    # Generate the configuration list.
+    cfg = []
+    with open(args.objtree / "include" / "generated" / "rustc_cfg") as fd:
+        for line in fd:
+            line = line.replace("--cfg=", "")
+            line = line.replace("\n", "")
+            cfg.append(line)
+    kernel_cfg_group = "kernel"
+
     rust_project = {
-        "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs),
+        "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs, kernel_cfg_group),
         "sysroot": str(args.sysroot),
-        "sysroot_src": str(args.sysroot_src)
+        "sysroot_src": str(args.sysroot_src),
+        "cfg_groups": {
+            kernel_cfg_group: cfg,
+        },
     }
 
     json.dump(rust_project, sys.stdout, sort_keys=True, indent=4)

---
base-commit: f8f9c1f4d0c7a64600e2ca312dec824a0bc2f1da
change-id: 20260101-rust-project-reduce-size-d829a7a708ae
prerequisite-change-id: 20260101-ra-fix-primitive-78154fe8173f:v1
prerequisite-patch-id: 0544fdf5522949047a81c3580960183375574fd3

Best regards,
-- 
Jesung Yang <y.j3ms.n@gmail.com>
Re: [PATCH] scripts: generate_rust_analyzer: reduce the output file size
Posted by Tamir Duberstein 1 month ago
On Thu, Jan 1, 2026 at 3:22 AM Jesung Yang via B4 Relay
<devnull+y.j3ms.n.gmail.com@kernel.org> wrote:
>
> From: Jesung Yang <y.j3ms.n@gmail.com>
>
> Use the `cfg_groups` field to aggregate common configurations into a
> single project-level definition. This avoids repeating identical `cfg`s
> across crates.
>
> As a result, the size of the generated `rust-project.json` is reduced
> from 11MiB to 406KiB (about 96% reduction).
>
> Signed-off-by: Jesung Yang <y.j3ms.n@gmail.com>
> ---
> This patch depends on [1] to ensure it merges cleanly without conflicts.
>
> [1] https://lore.kernel.org/rust-for-linux/20260101-ra-fix-primitive-v1-1-def809357b4e@gmail.com/
> ---
>  scripts/generate_rust_analyzer.py | 34 ++++++++++++++++++++--------------
>  1 file changed, 20 insertions(+), 14 deletions(-)
>
> diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
> index 6178a53516ec35f308897e65c5001edd81b0d3dd..2a8578fb784d08b2a5e628bfab935080759d2dce 100755
> --- a/scripts/generate_rust_analyzer.py
> +++ b/scripts/generate_rust_analyzer.py
> @@ -19,15 +19,7 @@ def args_crates_cfgs(cfgs):
>
>      return crates_cfgs
>
> -def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
> -    # Generate the configuration list.
> -    cfg = []
> -    with open(objtree / "include" / "generated" / "rustc_cfg") as fd:
> -        for line in fd:
> -            line = line.replace("--cfg=", "")
> -            line = line.replace("\n", "")
> -            cfg.append(line)
> -
> +def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, kernel_cfg_group):
>      # Now fill the crates list -- dependencies need to come first.
>      #
>      # Avoid O(n^2) iterations by keeping a map of indexes.
> @@ -35,7 +27,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
>      crates_indexes = {}
>      crates_cfgs = args_crates_cfgs(cfgs)
>
> -    def append_crate(display_name, root_module, deps, cfg=[], crate_attrs=[], is_workspace_member=True, is_proc_macro=False, edition="2021"):
> +    def append_crate(display_name, root_module, deps, cfg=[], cfg_groups=[], crate_attrs=[], is_workspace_member=True, is_proc_macro=False, edition="2021"):
>          crate = {
>              "display_name": display_name,
>              "root_module": str(root_module),
> @@ -48,6 +40,8 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
>                  "RUST_MODFILE": "This is only for rust-analyzer"
>              }
>          }
> +        if len(cfg_groups) > 0:
> +            crate["cfg_groups"] = cfg_groups
>          if len(crate_attrs) > 0:
>              crate["crate_attrs"] = crate_attrs
>          if is_proc_macro:
> @@ -134,7 +128,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
>              display_name,
>              srctree / "rust"/ display_name / "lib.rs",
>              deps,
> -            cfg=cfg,
> +            cfg_groups=[kernel_cfg_group],
>              crate_attrs=crate_attrs,
>          )
>          crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True))
> @@ -189,7 +183,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
>                  name,
>                  path,
>                  ["kernel"],
> -                cfg=cfg,
> +                cfg_groups=[kernel_cfg_group],
>                  crate_attrs=["no_std"],
>              )
>
> @@ -214,10 +208,22 @@ def main():
>      # Making sure that the `sysroot` and `sysroot_src` belong to the same toolchain.
>      assert args.sysroot in args.sysroot_src.parents
>
> +    # Generate the configuration list.
> +    cfg = []
> +    with open(args.objtree / "include" / "generated" / "rustc_cfg") as fd:
> +        for line in fd:
> +            line = line.replace("--cfg=", "")
> +            line = line.replace("\n", "")
> +            cfg.append(line)
> +    kernel_cfg_group = "kernel"
> +
>      rust_project = {
> -        "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs),
> +        "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs, kernel_cfg_group),
>          "sysroot": str(args.sysroot),
> -        "sysroot_src": str(args.sysroot_src)
> +        "sysroot_src": str(args.sysroot_src),
> +        "cfg_groups": {
> +            kernel_cfg_group: cfg,
> +        },
>      }
>
>      json.dump(rust_project, sys.stdout, sort_keys=True, indent=4)
>
> ---
> base-commit: f8f9c1f4d0c7a64600e2ca312dec824a0bc2f1da
> change-id: 20260101-rust-project-reduce-size-d829a7a708ae
> prerequisite-change-id: 20260101-ra-fix-primitive-78154fe8173f:v1
> prerequisite-patch-id: 0544fdf5522949047a81c3580960183375574fd3
>
> Best regards,
> --
> Jesung Yang <y.j3ms.n@gmail.com>

FWIW this was previously sent in
https://lore.kernel.org/all/20250424-rust-analyzer-host-v6-13-40e67fe5c38a@gmail.com/
back in April.
Re: [PATCH] scripts: generate_rust_analyzer: reduce the output file size
Posted by Gary Guo 1 month ago
On Thu, 01 Jan 2026 08:21:24 +0000
Jesung Yang via B4 Relay <devnull+y.j3ms.n.gmail.com@kernel.org> wrote:

> From: Jesung Yang <y.j3ms.n@gmail.com>
> 
> Use the `cfg_groups` field to aggregate common configurations into a
> single project-level definition. This avoids repeating identical `cfg`s
> across crates.
> 
> As a result, the size of the generated `rust-project.json` is reduced
> from 11MiB to 406KiB (about 96% reduction).

This feature is not available with Rust Analyzer 1.78.

Best,
Gary

> 
> Signed-off-by: Jesung Yang <y.j3ms.n@gmail.com>
> ---
> This patch depends on [1] to ensure it merges cleanly without conflicts.
> 
> [1] https://lore.kernel.org/rust-for-linux/20260101-ra-fix-primitive-v1-1-def809357b4e@gmail.com/
> ---
>  scripts/generate_rust_analyzer.py | 34 ++++++++++++++++++++--------------
>  1 file changed, 20 insertions(+), 14 deletions(-)
> 
> diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
> index 6178a53516ec35f308897e65c5001edd81b0d3dd..2a8578fb784d08b2a5e628bfab935080759d2dce 100755
> --- a/scripts/generate_rust_analyzer.py
> +++ b/scripts/generate_rust_analyzer.py
> @@ -19,15 +19,7 @@ def args_crates_cfgs(cfgs):
>  
>      return crates_cfgs
>  
> -def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
> -    # Generate the configuration list.
> -    cfg = []
> -    with open(objtree / "include" / "generated" / "rustc_cfg") as fd:
> -        for line in fd:
> -            line = line.replace("--cfg=", "")
> -            line = line.replace("\n", "")
> -            cfg.append(line)
> -
> +def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, kernel_cfg_group):
>      # Now fill the crates list -- dependencies need to come first.
>      #
>      # Avoid O(n^2) iterations by keeping a map of indexes.
> @@ -35,7 +27,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
>      crates_indexes = {}
>      crates_cfgs = args_crates_cfgs(cfgs)
>  
> -    def append_crate(display_name, root_module, deps, cfg=[], crate_attrs=[], is_workspace_member=True, is_proc_macro=False, edition="2021"):
> +    def append_crate(display_name, root_module, deps, cfg=[], cfg_groups=[], crate_attrs=[], is_workspace_member=True, is_proc_macro=False, edition="2021"):
>          crate = {
>              "display_name": display_name,
>              "root_module": str(root_module),
> @@ -48,6 +40,8 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
>                  "RUST_MODFILE": "This is only for rust-analyzer"
>              }
>          }
> +        if len(cfg_groups) > 0:
> +            crate["cfg_groups"] = cfg_groups
>          if len(crate_attrs) > 0:
>              crate["crate_attrs"] = crate_attrs
>          if is_proc_macro:
> @@ -134,7 +128,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
>              display_name,
>              srctree / "rust"/ display_name / "lib.rs",
>              deps,
> -            cfg=cfg,
> +            cfg_groups=[kernel_cfg_group],
>              crate_attrs=crate_attrs,
>          )
>          crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True))
> @@ -189,7 +183,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
>                  name,
>                  path,
>                  ["kernel"],
> -                cfg=cfg,
> +                cfg_groups=[kernel_cfg_group],
>                  crate_attrs=["no_std"],
>              )
>  
> @@ -214,10 +208,22 @@ def main():
>      # Making sure that the `sysroot` and `sysroot_src` belong to the same toolchain.
>      assert args.sysroot in args.sysroot_src.parents
>  
> +    # Generate the configuration list.
> +    cfg = []
> +    with open(args.objtree / "include" / "generated" / "rustc_cfg") as fd:
> +        for line in fd:
> +            line = line.replace("--cfg=", "")
> +            line = line.replace("\n", "")
> +            cfg.append(line)
> +    kernel_cfg_group = "kernel"
> +
>      rust_project = {
> -        "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs),
> +        "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs, kernel_cfg_group),
>          "sysroot": str(args.sysroot),
> -        "sysroot_src": str(args.sysroot_src)
> +        "sysroot_src": str(args.sysroot_src),
> +        "cfg_groups": {
> +            kernel_cfg_group: cfg,
> +        },
>      }
>  
>      json.dump(rust_project, sys.stdout, sort_keys=True, indent=4)
> 
> ---
> base-commit: f8f9c1f4d0c7a64600e2ca312dec824a0bc2f1da
> change-id: 20260101-rust-project-reduce-size-d829a7a708ae
> prerequisite-change-id: 20260101-ra-fix-primitive-78154fe8173f:v1
> prerequisite-patch-id: 0544fdf5522949047a81c3580960183375574fd3
> 
> Best regards,
Re: [PATCH] scripts: generate_rust_analyzer: reduce the output file size
Posted by Jesung Yang 1 month ago
On Fri, Jan 2, 2026 at 7:09 AM Gary Guo <gary@garyguo.net> wrote:
>
> On Thu, 01 Jan 2026 08:21:24 +0000
> Jesung Yang via B4 Relay <devnull+y.j3ms.n.gmail.com@kernel.org> wrote:
>
> > From: Jesung Yang <y.j3ms.n@gmail.com>
> >
> > Use the `cfg_groups` field to aggregate common configurations into a
> > single project-level definition. This avoids repeating identical `cfg`s
> > across crates.
> >
> > As a result, the size of the generated `rust-project.json` is reduced
> > from 11MiB to 406KiB (about 96% reduction).
>
> This feature is not available with Rust Analyzer 1.78.

I suspect you are referring to the rust-analyzer component shipped via
rustup when the 1.78 toolchain is active.

Do we apply our MSRV policy to rust-analyzer as well? The latest
rust-analyzer release supports older Rust versions, including 1.78. In
practice, I believe many people who rely on a language server use the
version provided by their editor extension or IDE, which is usually the
most recent release. AFAIK, it is actually more difficult to use an old
release of rust-analyzer, as it often requires extra setup to manually
downgrade or pin the version.

By the way, thanks for pointing this out!

Best regards,
Jesung
Re: [PATCH] scripts: generate_rust_analyzer: reduce the output file size
Posted by Gary Guo 1 month ago
On Fri, 2 Jan 2026 10:04:08 +0900
Jesung Yang <y.j3ms.n@gmail.com> wrote:

> On Fri, Jan 2, 2026 at 7:09 AM Gary Guo <gary@garyguo.net> wrote:
> >
> > On Thu, 01 Jan 2026 08:21:24 +0000
> > Jesung Yang via B4 Relay <devnull+y.j3ms.n.gmail.com@kernel.org> wrote:
> >  
> > > From: Jesung Yang <y.j3ms.n@gmail.com>
> > >
> > > Use the `cfg_groups` field to aggregate common configurations into a
> > > single project-level definition. This avoids repeating identical `cfg`s
> > > across crates.
> > >
> > > As a result, the size of the generated `rust-project.json` is reduced
> > > from 11MiB to 406KiB (about 96% reduction).  
> >
> > This feature is not available with Rust Analyzer 1.78.  
> 
> I suspect you are referring to the rust-analyzer component shipped via
> rustup when the 1.78 toolchain is active.
> 
> Do we apply our MSRV policy to rust-analyzer as well? The latest
> rust-analyzer release supports older Rust versions, including 1.78.

This statement is not generally true. Rust analyzer needs the ability to
talk directly with proc macro dylibs and AFAIK it only retains limited
backward compatibility with old rustc versions.

https://rust-analyzer.github.io/book/installation.html also mentions that
the only officially supported version is the latest stable and users are
recommended to use older Rust analyzer versions with older compilers.

> practice, I believe many people who rely on a language server use the
> version provided by their editor extension or IDE, which is usually the
> most recent release. AFAIK, it is actually more difficult to use an old
> release of rust-analyzer, as it often requires extra setup to manually
> downgrade or pin the version.

Many editors just use rust analyzer binaries in the PATH, which can quite
often be the one provided by rustup. I guess the "IDE" you're talking
about here is VSCode, and I just configure it to use the one in path too,
instead of the binary shipped with the extension.

This the Rust analyzer version string of the one that I am using:

	rust-analyzer 1.78.0 (9b00956 2024-04-29)

So I'd say while your change is desired, we need to wait until we bump
MSRV to a high enough version as I suspect there're a lot more developers
that use Rust analyzer in the same way I do.

Best,
Gary
Re: [PATCH] scripts: generate_rust_analyzer: reduce the output file size
Posted by Jesung Yang 1 month ago
On Fri, Jan 2, 2026 at 7:36 PM Gary Guo <gary@garyguo.net> wrote:
>
> On Fri, 2 Jan 2026 10:04:08 +0900
> Jesung Yang <y.j3ms.n@gmail.com> wrote:
>
> > On Fri, Jan 2, 2026 at 7:09 AM Gary Guo <gary@garyguo.net> wrote:
> > >
> > > On Thu, 01 Jan 2026 08:21:24 +0000
> > > Jesung Yang via B4 Relay <devnull+y.j3ms.n.gmail.com@kernel.org> wrote:
> > >
> > > > From: Jesung Yang <y.j3ms.n@gmail.com>
> > > >
> > > > Use the `cfg_groups` field to aggregate common configurations into a
> > > > single project-level definition. This avoids repeating identical `cfg`s
> > > > across crates.
> > > >
> > > > As a result, the size of the generated `rust-project.json` is reduced
> > > > from 11MiB to 406KiB (about 96% reduction).
> > >
> > > This feature is not available with Rust Analyzer 1.78.
> >
> > I suspect you are referring to the rust-analyzer component shipped via
> > rustup when the 1.78 toolchain is active.
> >
> > Do we apply our MSRV policy to rust-analyzer as well? The latest
> > rust-analyzer release supports older Rust versions, including 1.78.
>
> This statement is not generally true. Rust analyzer needs the ability to
> talk directly with proc macro dylibs and AFAIK it only retains limited
> backward compatibility with old rustc versions.
>
> https://rust-analyzer.github.io/book/installation.html also mentions that
> the only officially supported version is the latest stable and users are
> recommended to use older Rust analyzer versions with older compilers.

You're right, I missed that point.

> > practice, I believe many people who rely on a language server use the
> > version provided by their editor extension or IDE, which is usually the
> > most recent release. AFAIK, it is actually more difficult to use an old
> > release of rust-analyzer, as it often requires extra setup to manually
> > downgrade or pin the version.
>
> Many editors just use rust analyzer binaries in the PATH, which can quite
> often be the one provided by rustup. I guess the "IDE" you're talking
> about here is VSCode, and I just configure it to use the one in path too,
> instead of the binary shipped with the extension.
>
> This the Rust analyzer version string of the one that I am using:
>
>         rust-analyzer 1.78.0 (9b00956 2024-04-29)
>
> So I'd say while your change is desired, we need to wait until we bump
> MSRV to a high enough version as I suspect there're a lot more developers
> that use Rust analyzer in the same way I do.

Overall, I think I overlooked the diversity of local setups; I was
indeed focused on the VSCode extension's default behavior.

Thanks!

Best regards,
Jesung
Re: [PATCH] scripts: generate_rust_analyzer: reduce the output file size
Posted by Miguel Ojeda 1 month ago
On Fri, Jan 2, 2026 at 11:36 AM Gary Guo <gary@garyguo.net> wrote:
>
> So I'd say while your change is desired, we need to wait until we bump
> MSRV to a high enough version as I suspect there're a lot more developers
> that use Rust analyzer in the same way I do.

Yeah, distributions likely provide the rust-analyzer that works well
with their `rustc`, thus older ones in some cases.

Perhaps we should support several versions, just like for the rest of
the toolchain, i.e. query the version in the Python script and act
based on that.

Cheers,
Miguel
Re: [PATCH] scripts: generate_rust_analyzer: reduce the output file size
Posted by Jesung Yang 1 month ago
On Fri, Jan 2, 2026 at 7:56 PM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
[...]
>
> Perhaps we should support several versions, just like for the rest of
> the toolchain, i.e. query the version in the Python script and act
> based on that.

I could give that a try if you feel the benefits of supporting multiple
versions justify the added maintenance burden.

Best regards,
Jesung