milos-linux/scripts/generate_rust_analyzer.py

382 lines
12 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0
"""generate_rust_analyzer - Generates the `rust-project.json` file for `rust-analyzer`.
"""
import argparse
import json
import logging
import os
import pathlib
rust: use host dylib naming convention to support macOS Because the `macros` crate exposes procedural macros, it must be compiled as a dynamic library (so it can be loaded by the compiler at compile-time). Before this change the resulting artifact was always named `libmacros.so`, which works on hosts where this matches the naming convention for dynamic libraries. However the proper name on macOS would be `libmacros.dylib`. This turns out to matter even when the dependency is passed with a path (`--extern macros=path/to/libmacros.so` rather than `--extern macros`) because rustc uses the file name to infer the type of the library (see link). This is because there's no way to specify both the path to and the type of the external library via CLI flags. The compiler could speculatively parse the file to determine its type, but it does not do so today. This means that libraries that match neither rustc's naming convention for static libraries nor the platform's naming convention for dynamic libraries are *rejected*. The only solution I've found is to follow the host platform's naming convention. This patch does that by querying the compiler to determine the appropriate name for the artifact. This allows the kernel to build with CONFIG_RUST=y on macOS. Link: https://github.com/rust-lang/rust/blob/d829780/compiler/rustc_metadata/src/locator.rs#L728-L752 Tested-by: Daniel Gomez <da.gomez@samsung.com> Co-developed-by: Fiona Behrens <me@kloenk.dev> Signed-off-by: Fiona Behrens <me@kloenk.dev> Signed-off-by: Tamir Duberstein <tamird@gmail.com> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20241216-b4-dylib-host-macos-v7-1-cfc507681447@gmail.com [ Added `MAKEFLAGS=`s to avoid jobserver warnings. Removed space. Reworded title. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-12-16 10:54:22 -05:00
import subprocess
import sys
from typing import Dict, Iterable, List, Literal, Optional, TypedDict
rust: support overriding crate_name Currently you cannot filter out the crate-name argument RUSTFLAGS_REMOVE_stem.o because the Rust filter-out invocation does not include that particular argument. Since --crate-name is an argument that can't be passed multiple times, this means that it's currently not possible to override the crate name. Thus, remove the --crate-name argument for drivers. This allows them to override the crate name using the #![crate_name] annotation. This affects symbol names, but has no effect on the filenames of object files and other things generated by the build, as we always use --emit with a fixed output filename. The --crate-name argument is kept for the crates under rust/ for simplicity and to avoid changing many of them by adding #![crate_name]. The rust analyzer script is updated to use rustc to obtain the crate name of the driver crates, which picks up the right name whether it is configured via #![crate_name] or not. For readability, the logic to invoke 'rustc' is extracted to its own function. Note that the crate name in the python script is not actually that important - the only place where the name actually affects anything is in the 'deps' array which specifies an index and name for each dependency, and determines what that dependency is called in *this* crate. (The same crate may be called different things in each dependency.) Since driver crates are leaf crates, this doesn't apply and the rustc invocation only affects the 'display_name' parameter. Acked-by: Gary Guo <gary@garyguo.net> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Jesung Yang <y.jems.n@gmail.com> Acked-by: Tamir Duberstein <tamird@kernel.org> Link: https://patch.msgid.link/20260402-binder-crate-name-v4-1-ec3919b87909@google.com [ Applied Python type hints. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2026-04-02 10:55:33 +00:00
def invoke_rustc(args: List[str]) -> str:
return subprocess.check_output(
[os.environ["RUSTC"]] + args,
stdin=subprocess.DEVNULL,
).decode('utf-8').strip()
def args_crates_cfgs(cfgs: List[str]) -> Dict[str, List[str]]:
crates_cfgs = {}
for cfg in cfgs:
crate, vals = cfg.split("=", 1)
crates_cfgs[crate] = vals.split()
return crates_cfgs
class Dependency(TypedDict):
crate: int
name: str
class Source(TypedDict):
include_dirs: List[str]
exclude_dirs: List[str]
class Crate(TypedDict):
display_name: str
root_module: str
is_workspace_member: bool
deps: List[Dependency]
cfg: List[str]
edition: str
env: Dict[str, str]
class ProcMacroCrate(Crate):
is_proc_macro: Literal[True]
proc_macro_dylib_path: str # `pathlib.Path` is not JSON serializable.
class CrateWithGenerated(Crate):
source: Source
def generate_crates(
srctree: pathlib.Path,
objtree: pathlib.Path,
sysroot_src: pathlib.Path,
external_src: Optional[pathlib.Path],
cfgs: List[str],
core_edition: str,
) -> List[Crate]:
# Generate the configuration list.
generated_cfg = []
with open(objtree / "include" / "generated" / "rustc_cfg") as fd:
for line in fd:
line = line.replace("--cfg=", "")
line = line.replace("\n", "")
generated_cfg.append(line)
# Now fill the crates list.
crates: List[Crate] = []
crates_cfgs = args_crates_cfgs(cfgs)
rust: support overriding crate_name Currently you cannot filter out the crate-name argument RUSTFLAGS_REMOVE_stem.o because the Rust filter-out invocation does not include that particular argument. Since --crate-name is an argument that can't be passed multiple times, this means that it's currently not possible to override the crate name. Thus, remove the --crate-name argument for drivers. This allows them to override the crate name using the #![crate_name] annotation. This affects symbol names, but has no effect on the filenames of object files and other things generated by the build, as we always use --emit with a fixed output filename. The --crate-name argument is kept for the crates under rust/ for simplicity and to avoid changing many of them by adding #![crate_name]. The rust analyzer script is updated to use rustc to obtain the crate name of the driver crates, which picks up the right name whether it is configured via #![crate_name] or not. For readability, the logic to invoke 'rustc' is extracted to its own function. Note that the crate name in the python script is not actually that important - the only place where the name actually affects anything is in the 'deps' array which specifies an index and name for each dependency, and determines what that dependency is called in *this* crate. (The same crate may be called different things in each dependency.) Since driver crates are leaf crates, this doesn't apply and the rustc invocation only affects the 'display_name' parameter. Acked-by: Gary Guo <gary@garyguo.net> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Jesung Yang <y.jems.n@gmail.com> Acked-by: Tamir Duberstein <tamird@kernel.org> Link: https://patch.msgid.link/20260402-binder-crate-name-v4-1-ec3919b87909@google.com [ Applied Python type hints. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2026-04-02 10:55:33 +00:00
def get_crate_name(path: pathlib.Path) -> str:
return invoke_rustc(["--print", "crate-name", str(path)])
def build_crate(
display_name: str,
root_module: pathlib.Path,
deps: List[Dependency],
*,
cfg: Optional[List[str]],
is_workspace_member: Optional[bool],
edition: Optional[str],
) -> Crate:
cfg = cfg if cfg is not None else crates_cfgs.get(display_name, [])
is_workspace_member = (
is_workspace_member if is_workspace_member is not None else True
)
edition = edition if edition is not None else "2021"
return {
"display_name": display_name,
"root_module": str(root_module),
"is_workspace_member": is_workspace_member,
"deps": deps,
"cfg": cfg,
"edition": edition,
"env": {
"RUST_MODFILE": "This is only for rust-analyzer"
}
rust: use host dylib naming convention to support macOS Because the `macros` crate exposes procedural macros, it must be compiled as a dynamic library (so it can be loaded by the compiler at compile-time). Before this change the resulting artifact was always named `libmacros.so`, which works on hosts where this matches the naming convention for dynamic libraries. However the proper name on macOS would be `libmacros.dylib`. This turns out to matter even when the dependency is passed with a path (`--extern macros=path/to/libmacros.so` rather than `--extern macros`) because rustc uses the file name to infer the type of the library (see link). This is because there's no way to specify both the path to and the type of the external library via CLI flags. The compiler could speculatively parse the file to determine its type, but it does not do so today. This means that libraries that match neither rustc's naming convention for static libraries nor the platform's naming convention for dynamic libraries are *rejected*. The only solution I've found is to follow the host platform's naming convention. This patch does that by querying the compiler to determine the appropriate name for the artifact. This allows the kernel to build with CONFIG_RUST=y on macOS. Link: https://github.com/rust-lang/rust/blob/d829780/compiler/rustc_metadata/src/locator.rs#L728-L752 Tested-by: Daniel Gomez <da.gomez@samsung.com> Co-developed-by: Fiona Behrens <me@kloenk.dev> Signed-off-by: Fiona Behrens <me@kloenk.dev> Signed-off-by: Tamir Duberstein <tamird@gmail.com> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20241216-b4-dylib-host-macos-v7-1-cfc507681447@gmail.com [ Added `MAKEFLAGS=`s to avoid jobserver warnings. Removed space. Reworded title. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-12-16 10:54:22 -05:00
}
def append_proc_macro_crate(
display_name: str,
root_module: pathlib.Path,
deps: List[Dependency],
*,
cfg: Optional[List[str]] = None,
is_workspace_member: Optional[bool] = None,
edition: Optional[str] = None,
) -> Dependency:
crate = build_crate(
display_name,
root_module,
deps,
cfg=cfg,
is_workspace_member=is_workspace_member,
edition=edition,
)
rust: support overriding crate_name Currently you cannot filter out the crate-name argument RUSTFLAGS_REMOVE_stem.o because the Rust filter-out invocation does not include that particular argument. Since --crate-name is an argument that can't be passed multiple times, this means that it's currently not possible to override the crate name. Thus, remove the --crate-name argument for drivers. This allows them to override the crate name using the #![crate_name] annotation. This affects symbol names, but has no effect on the filenames of object files and other things generated by the build, as we always use --emit with a fixed output filename. The --crate-name argument is kept for the crates under rust/ for simplicity and to avoid changing many of them by adding #![crate_name]. The rust analyzer script is updated to use rustc to obtain the crate name of the driver crates, which picks up the right name whether it is configured via #![crate_name] or not. For readability, the logic to invoke 'rustc' is extracted to its own function. Note that the crate name in the python script is not actually that important - the only place where the name actually affects anything is in the 'deps' array which specifies an index and name for each dependency, and determines what that dependency is called in *this* crate. (The same crate may be called different things in each dependency.) Since driver crates are leaf crates, this doesn't apply and the rustc invocation only affects the 'display_name' parameter. Acked-by: Gary Guo <gary@garyguo.net> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Jesung Yang <y.jems.n@gmail.com> Acked-by: Tamir Duberstein <tamird@kernel.org> Link: https://patch.msgid.link/20260402-binder-crate-name-v4-1-ec3919b87909@google.com [ Applied Python type hints. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2026-04-02 10:55:33 +00:00
proc_macro_dylib_name = invoke_rustc([
"--print",
"file-names",
"--crate-name",
display_name,
"--crate-type",
"proc-macro",
"-",
])
proc_macro_crate: ProcMacroCrate = {
**crate,
"is_proc_macro": True,
"proc_macro_dylib_path": str(objtree / "rust" / proc_macro_dylib_name),
}
return register_crate(proc_macro_crate)
def register_crate(crate: Crate) -> Dependency:
index = len(crates)
rust: use host dylib naming convention to support macOS Because the `macros` crate exposes procedural macros, it must be compiled as a dynamic library (so it can be loaded by the compiler at compile-time). Before this change the resulting artifact was always named `libmacros.so`, which works on hosts where this matches the naming convention for dynamic libraries. However the proper name on macOS would be `libmacros.dylib`. This turns out to matter even when the dependency is passed with a path (`--extern macros=path/to/libmacros.so` rather than `--extern macros`) because rustc uses the file name to infer the type of the library (see link). This is because there's no way to specify both the path to and the type of the external library via CLI flags. The compiler could speculatively parse the file to determine its type, but it does not do so today. This means that libraries that match neither rustc's naming convention for static libraries nor the platform's naming convention for dynamic libraries are *rejected*. The only solution I've found is to follow the host platform's naming convention. This patch does that by querying the compiler to determine the appropriate name for the artifact. This allows the kernel to build with CONFIG_RUST=y on macOS. Link: https://github.com/rust-lang/rust/blob/d829780/compiler/rustc_metadata/src/locator.rs#L728-L752 Tested-by: Daniel Gomez <da.gomez@samsung.com> Co-developed-by: Fiona Behrens <me@kloenk.dev> Signed-off-by: Fiona Behrens <me@kloenk.dev> Signed-off-by: Tamir Duberstein <tamird@gmail.com> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20241216-b4-dylib-host-macos-v7-1-cfc507681447@gmail.com [ Added `MAKEFLAGS=`s to avoid jobserver warnings. Removed space. Reworded title. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-12-16 10:54:22 -05:00
crates.append(crate)
return {"crate": index, "name": crate["display_name"]}
def append_crate(
display_name: str,
root_module: pathlib.Path,
deps: List[Dependency],
*,
cfg: Optional[List[str]] = None,
is_workspace_member: Optional[bool] = None,
edition: Optional[str] = None,
) -> Dependency:
return register_crate(
build_crate(
display_name,
root_module,
deps,
cfg=cfg,
is_workspace_member=is_workspace_member,
edition=edition,
)
)
scripts: generate_rust_analyzer: add missing macros deps The macros crate has depended on std and proc_macro since its introduction in commit 1fbde52bde73 ("rust: add `macros` crate"). These dependencies were omitted from commit 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") resulting in missing go-to-definition and autocomplete, and false-positive warnings emitted from rust-analyzer such as: [{ "resource": "/Users/tamird/src/linux/rust/macros/module.rs", "owner": "_generated_diagnostic_collection_name_#1", "code": { "value": "non_snake_case", "target": { "$mid": 1, "path": "/rustc/", "scheme": "https", "authority": "doc.rust-lang.org", "query": "search=non_snake_case" } }, "severity": 4, "message": "Variable `None` should have snake_case name, e.g. `none`", "source": "rust-analyzer", "startLineNumber": 123, "startColumn": 17, "endLineNumber": 123, "endColumn": 21 }] Add the missing dependencies to improve the developer experience. [ Fiona had a different approach (thanks!) at: https://lore.kernel.org/rust-for-linux/20241205115438.234221-1-me@kloenk.dev/ But Tamir and Fiona agreed to this one. - Miguel ] Fixes: 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") Reviewed-by: Fiona Behrens <me@kloenk.dev> Diagnosed-by: Chayim Refael Friedman <chayimfr@gmail.com> Link: https://github.com/rust-lang/rust-analyzer/issues/17759#issuecomment-2646328275 Signed-off-by: Tamir Duberstein <tamird@gmail.com> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20250210-rust-analyzer-macros-core-dep-v3-1-45eb4836f218@gmail.com [ Removed `return`. Changed tag name. Added Link. Slightly reworded. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2025-02-10 12:03:24 -05:00
def append_sysroot_crate(
display_name: str,
deps: List[Dependency],
*,
cfg: Optional[List[str]] = None,
) -> Dependency:
return append_crate(
scripts: generate_rust_analyzer: add missing macros deps The macros crate has depended on std and proc_macro since its introduction in commit 1fbde52bde73 ("rust: add `macros` crate"). These dependencies were omitted from commit 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") resulting in missing go-to-definition and autocomplete, and false-positive warnings emitted from rust-analyzer such as: [{ "resource": "/Users/tamird/src/linux/rust/macros/module.rs", "owner": "_generated_diagnostic_collection_name_#1", "code": { "value": "non_snake_case", "target": { "$mid": 1, "path": "/rustc/", "scheme": "https", "authority": "doc.rust-lang.org", "query": "search=non_snake_case" } }, "severity": 4, "message": "Variable `None` should have snake_case name, e.g. `none`", "source": "rust-analyzer", "startLineNumber": 123, "startColumn": 17, "endLineNumber": 123, "endColumn": 21 }] Add the missing dependencies to improve the developer experience. [ Fiona had a different approach (thanks!) at: https://lore.kernel.org/rust-for-linux/20241205115438.234221-1-me@kloenk.dev/ But Tamir and Fiona agreed to this one. - Miguel ] Fixes: 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") Reviewed-by: Fiona Behrens <me@kloenk.dev> Diagnosed-by: Chayim Refael Friedman <chayimfr@gmail.com> Link: https://github.com/rust-lang/rust-analyzer/issues/17759#issuecomment-2646328275 Signed-off-by: Tamir Duberstein <tamird@gmail.com> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20250210-rust-analyzer-macros-core-dep-v3-1-45eb4836f218@gmail.com [ Removed `return`. Changed tag name. Added Link. Slightly reworded. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2025-02-10 12:03:24 -05:00
display_name,
sysroot_src / display_name / "src" / "lib.rs",
deps,
cfg=cfg,
scripts: generate_rust_analyzer: add missing macros deps The macros crate has depended on std and proc_macro since its introduction in commit 1fbde52bde73 ("rust: add `macros` crate"). These dependencies were omitted from commit 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") resulting in missing go-to-definition and autocomplete, and false-positive warnings emitted from rust-analyzer such as: [{ "resource": "/Users/tamird/src/linux/rust/macros/module.rs", "owner": "_generated_diagnostic_collection_name_#1", "code": { "value": "non_snake_case", "target": { "$mid": 1, "path": "/rustc/", "scheme": "https", "authority": "doc.rust-lang.org", "query": "search=non_snake_case" } }, "severity": 4, "message": "Variable `None` should have snake_case name, e.g. `none`", "source": "rust-analyzer", "startLineNumber": 123, "startColumn": 17, "endLineNumber": 123, "endColumn": 21 }] Add the missing dependencies to improve the developer experience. [ Fiona had a different approach (thanks!) at: https://lore.kernel.org/rust-for-linux/20241205115438.234221-1-me@kloenk.dev/ But Tamir and Fiona agreed to this one. - Miguel ] Fixes: 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") Reviewed-by: Fiona Behrens <me@kloenk.dev> Diagnosed-by: Chayim Refael Friedman <chayimfr@gmail.com> Link: https://github.com/rust-lang/rust-analyzer/issues/17759#issuecomment-2646328275 Signed-off-by: Tamir Duberstein <tamird@gmail.com> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20250210-rust-analyzer-macros-core-dep-v3-1-45eb4836f218@gmail.com [ Removed `return`. Changed tag name. Added Link. Slightly reworded. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2025-02-10 12:03:24 -05:00
is_workspace_member=False,
# Miguel Ojeda writes:
#
# > ... in principle even the sysroot crates may have different
# > editions.
# >
# > For instance, in the move to 2024, it seems all happened at once
# > in 1.87.0 in these upstream commits:
# >
# > 0e071c2c6a58 ("Migrate core to Rust 2024")
# > f505d4e8e380 ("Migrate alloc to Rust 2024")
# > 0b2489c226c3 ("Migrate proc_macro to Rust 2024")
# > 993359e70112 ("Migrate std to Rust 2024")
# >
# > But in the previous move to 2021, `std` moved in 1.59.0, while
# > the others in 1.60.0:
# >
# > b656384d8398 ("Update stdlib to the 2021 edition")
# > 06a1c14d52a8 ("Switch all libraries to the 2021 edition")
#
# Link: https://lore.kernel.org/all/CANiq72kd9bHdKaAm=8xCUhSHMy2csyVed69bOc4dXyFAW4sfuw@mail.gmail.com/
#
# At the time of writing all rust versions we support build the
# sysroot crates with the same edition. We may need to relax this
# assumption if future edition moves span multiple rust versions.
edition=core_edition,
scripts: generate_rust_analyzer: add missing macros deps The macros crate has depended on std and proc_macro since its introduction in commit 1fbde52bde73 ("rust: add `macros` crate"). These dependencies were omitted from commit 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") resulting in missing go-to-definition and autocomplete, and false-positive warnings emitted from rust-analyzer such as: [{ "resource": "/Users/tamird/src/linux/rust/macros/module.rs", "owner": "_generated_diagnostic_collection_name_#1", "code": { "value": "non_snake_case", "target": { "$mid": 1, "path": "/rustc/", "scheme": "https", "authority": "doc.rust-lang.org", "query": "search=non_snake_case" } }, "severity": 4, "message": "Variable `None` should have snake_case name, e.g. `none`", "source": "rust-analyzer", "startLineNumber": 123, "startColumn": 17, "endLineNumber": 123, "endColumn": 21 }] Add the missing dependencies to improve the developer experience. [ Fiona had a different approach (thanks!) at: https://lore.kernel.org/rust-for-linux/20241205115438.234221-1-me@kloenk.dev/ But Tamir and Fiona agreed to this one. - Miguel ] Fixes: 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") Reviewed-by: Fiona Behrens <me@kloenk.dev> Diagnosed-by: Chayim Refael Friedman <chayimfr@gmail.com> Link: https://github.com/rust-lang/rust-analyzer/issues/17759#issuecomment-2646328275 Signed-off-by: Tamir Duberstein <tamird@gmail.com> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20250210-rust-analyzer-macros-core-dep-v3-1-45eb4836f218@gmail.com [ Removed `return`. Changed tag name. Added Link. Slightly reworded. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2025-02-10 12:03:24 -05:00
)
# NB: sysroot crates reexport items from one another so setting up our transitive dependencies
# here is important for ensuring that rust-analyzer can resolve symbols. The sources of truth
# for this dependency graph are `(sysroot_src / crate / "Cargo.toml" for crate in crates)`.
core = append_sysroot_crate("core", [])
alloc = append_sysroot_crate("alloc", [core])
std = append_sysroot_crate("std", [alloc, core])
proc_macro = append_sysroot_crate("proc_macro", [core, std])
compiler_builtins = append_crate(
"compiler_builtins",
srctree / "rust" / "compiler_builtins.rs",
[core],
)
proc_macro2 = append_crate(
"proc_macro2",
srctree / "rust" / "proc-macro2" / "lib.rs",
[core, alloc, std, proc_macro],
)
quote = append_crate(
"quote",
srctree / "rust" / "quote" / "lib.rs",
[core, alloc, std, proc_macro, proc_macro2],
edition="2018",
)
syn = append_crate(
"syn",
srctree / "rust" / "syn" / "lib.rs",
[std, proc_macro, proc_macro2, quote],
)
macros = append_proc_macro_crate(
"macros",
srctree / "rust" / "macros" / "lib.rs",
[std, proc_macro, proc_macro2, quote, syn],
)
build_error = append_crate(
"build_error",
srctree / "rust" / "build_error.rs",
[core, compiler_builtins],
)
pin_init_internal = append_proc_macro_crate(
"pin_init_internal",
srctree / "rust" / "pin-init" / "internal" / "src" / "lib.rs",
[std, proc_macro, proc_macro2, quote, syn],
)
pin_init = append_crate(
"pin_init",
srctree / "rust" / "pin-init" / "src" / "lib.rs",
[core, compiler_builtins, pin_init_internal, macros],
)
ffi = append_crate(
"ffi",
srctree / "rust" / "ffi.rs",
[core, compiler_builtins],
)
scripts: generate_rust_analyzer: add missing include_dirs Commit 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") specified OBJTREE for the bindings crate, and `source.include_dirs` for the kernel crate, likely in an attempt to support out-of-source builds for those crates where the generated files reside in `objtree` rather than `srctree`. This was insufficient because both bits of configuration are required for each crate; the result is that rust-analyzer is unable to resolve generated files for either crate in an out-of-source build. [ Originally we were not using `OBJTREE` in the `kernel` crate, but we did pass the variable anyway, so conceptually it could have been there since then. Regarding `include_dirs`, it started in `kernel` before being in mainline because we included the bindings directly there (i.e. there was no `bindings` crate). However, when that crate got created, we moved the `OBJTREE` there but not the `include_dirs`. Nowadays, though, we happen to need the `include_dirs` also in the `kernel` crate for `generated_arch_static_branch_asm.rs` which was not there back then -- Tamir confirms it is indeed required for that reason. - Miguel ] Add the missing bits to improve the developer experience. Fixes: 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") Signed-off-by: Tamir Duberstein <tamird@gmail.com> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20250210-rust-analyzer-bindings-include-v2-1-23dff845edc3@gmail.com [ Slightly reworded title. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2025-02-10 13:04:16 -05:00
def append_crate_with_generated(
display_name: str,
deps: List[Dependency],
) -> Dependency:
crate = build_crate(
scripts: generate_rust_analyzer: add missing include_dirs Commit 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") specified OBJTREE for the bindings crate, and `source.include_dirs` for the kernel crate, likely in an attempt to support out-of-source builds for those crates where the generated files reside in `objtree` rather than `srctree`. This was insufficient because both bits of configuration are required for each crate; the result is that rust-analyzer is unable to resolve generated files for either crate in an out-of-source build. [ Originally we were not using `OBJTREE` in the `kernel` crate, but we did pass the variable anyway, so conceptually it could have been there since then. Regarding `include_dirs`, it started in `kernel` before being in mainline because we included the bindings directly there (i.e. there was no `bindings` crate). However, when that crate got created, we moved the `OBJTREE` there but not the `include_dirs`. Nowadays, though, we happen to need the `include_dirs` also in the `kernel` crate for `generated_arch_static_branch_asm.rs` which was not there back then -- Tamir confirms it is indeed required for that reason. - Miguel ] Add the missing bits to improve the developer experience. Fixes: 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") Signed-off-by: Tamir Duberstein <tamird@gmail.com> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20250210-rust-analyzer-bindings-include-v2-1-23dff845edc3@gmail.com [ Slightly reworded title. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2025-02-10 13:04:16 -05:00
display_name,
srctree / "rust"/ display_name / "lib.rs",
deps,
cfg=generated_cfg,
is_workspace_member=True,
edition=None,
scripts: generate_rust_analyzer: add missing include_dirs Commit 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") specified OBJTREE for the bindings crate, and `source.include_dirs` for the kernel crate, likely in an attempt to support out-of-source builds for those crates where the generated files reside in `objtree` rather than `srctree`. This was insufficient because both bits of configuration are required for each crate; the result is that rust-analyzer is unable to resolve generated files for either crate in an out-of-source build. [ Originally we were not using `OBJTREE` in the `kernel` crate, but we did pass the variable anyway, so conceptually it could have been there since then. Regarding `include_dirs`, it started in `kernel` before being in mainline because we included the bindings directly there (i.e. there was no `bindings` crate). However, when that crate got created, we moved the `OBJTREE` there but not the `include_dirs`. Nowadays, though, we happen to need the `include_dirs` also in the `kernel` crate for `generated_arch_static_branch_asm.rs` which was not there back then -- Tamir confirms it is indeed required for that reason. - Miguel ] Add the missing bits to improve the developer experience. Fixes: 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") Signed-off-by: Tamir Duberstein <tamird@gmail.com> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20250210-rust-analyzer-bindings-include-v2-1-23dff845edc3@gmail.com [ Slightly reworded title. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2025-02-10 13:04:16 -05:00
)
crate["env"]["OBJTREE"] = str(objtree.resolve(True))
crate_with_generated: CrateWithGenerated = {
**crate,
"source": {
"include_dirs": [
str(srctree / "rust" / display_name),
str(objtree / "rust"),
],
"exclude_dirs": [],
},
scripts: generate_rust_analyzer: add missing include_dirs Commit 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") specified OBJTREE for the bindings crate, and `source.include_dirs` for the kernel crate, likely in an attempt to support out-of-source builds for those crates where the generated files reside in `objtree` rather than `srctree`. This was insufficient because both bits of configuration are required for each crate; the result is that rust-analyzer is unable to resolve generated files for either crate in an out-of-source build. [ Originally we were not using `OBJTREE` in the `kernel` crate, but we did pass the variable anyway, so conceptually it could have been there since then. Regarding `include_dirs`, it started in `kernel` before being in mainline because we included the bindings directly there (i.e. there was no `bindings` crate). However, when that crate got created, we moved the `OBJTREE` there but not the `include_dirs`. Nowadays, though, we happen to need the `include_dirs` also in the `kernel` crate for `generated_arch_static_branch_asm.rs` which was not there back then -- Tamir confirms it is indeed required for that reason. - Miguel ] Add the missing bits to improve the developer experience. Fixes: 8c4555ccc55c ("scripts: add `generate_rust_analyzer.py`") Signed-off-by: Tamir Duberstein <tamird@gmail.com> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20250210-rust-analyzer-bindings-include-v2-1-23dff845edc3@gmail.com [ Slightly reworded title. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2025-02-10 13:04:16 -05:00
}
return register_crate(crate_with_generated)
bindings = append_crate_with_generated("bindings", [core, ffi, pin_init])
uapi = append_crate_with_generated("uapi", [core, ffi, pin_init])
kernel = append_crate_with_generated(
"kernel", [core, macros, build_error, pin_init, ffi, bindings, uapi]
)
scripts = srctree / "scripts"
makefile = (scripts / "Makefile").read_text()
for path in scripts.glob("*.rs"):
name = path.stem
if f"{name}-rust" not in makefile:
continue
append_crate(
name,
path,
[std],
)
def is_root_crate(build_file: pathlib.Path, target: str) -> bool:
try:
contents = build_file.read_text()
except FileNotFoundError:
return False
return f"{target}.o" in contents
# Then, the rest outside of `rust/`.
#
# We explicitly mention the top-level folders we want to cover.
extra_dirs: Iterable[pathlib.Path] = (
srctree / dir for dir in ("samples", "drivers")
)
if external_src is not None:
extra_dirs = [external_src]
for folder in extra_dirs:
for path in folder.rglob("*.rs"):
logging.info("Checking %s", path)
rust: support overriding crate_name Currently you cannot filter out the crate-name argument RUSTFLAGS_REMOVE_stem.o because the Rust filter-out invocation does not include that particular argument. Since --crate-name is an argument that can't be passed multiple times, this means that it's currently not possible to override the crate name. Thus, remove the --crate-name argument for drivers. This allows them to override the crate name using the #![crate_name] annotation. This affects symbol names, but has no effect on the filenames of object files and other things generated by the build, as we always use --emit with a fixed output filename. The --crate-name argument is kept for the crates under rust/ for simplicity and to avoid changing many of them by adding #![crate_name]. The rust analyzer script is updated to use rustc to obtain the crate name of the driver crates, which picks up the right name whether it is configured via #![crate_name] or not. For readability, the logic to invoke 'rustc' is extracted to its own function. Note that the crate name in the python script is not actually that important - the only place where the name actually affects anything is in the 'deps' array which specifies an index and name for each dependency, and determines what that dependency is called in *this* crate. (The same crate may be called different things in each dependency.) Since driver crates are leaf crates, this doesn't apply and the rustc invocation only affects the 'display_name' parameter. Acked-by: Gary Guo <gary@garyguo.net> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Jesung Yang <y.jems.n@gmail.com> Acked-by: Tamir Duberstein <tamird@kernel.org> Link: https://patch.msgid.link/20260402-binder-crate-name-v4-1-ec3919b87909@google.com [ Applied Python type hints. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2026-04-02 10:55:33 +00:00
file_name = path.stem
# Skip those that are not crate roots.
rust: support overriding crate_name Currently you cannot filter out the crate-name argument RUSTFLAGS_REMOVE_stem.o because the Rust filter-out invocation does not include that particular argument. Since --crate-name is an argument that can't be passed multiple times, this means that it's currently not possible to override the crate name. Thus, remove the --crate-name argument for drivers. This allows them to override the crate name using the #![crate_name] annotation. This affects symbol names, but has no effect on the filenames of object files and other things generated by the build, as we always use --emit with a fixed output filename. The --crate-name argument is kept for the crates under rust/ for simplicity and to avoid changing many of them by adding #![crate_name]. The rust analyzer script is updated to use rustc to obtain the crate name of the driver crates, which picks up the right name whether it is configured via #![crate_name] or not. For readability, the logic to invoke 'rustc' is extracted to its own function. Note that the crate name in the python script is not actually that important - the only place where the name actually affects anything is in the 'deps' array which specifies an index and name for each dependency, and determines what that dependency is called in *this* crate. (The same crate may be called different things in each dependency.) Since driver crates are leaf crates, this doesn't apply and the rustc invocation only affects the 'display_name' parameter. Acked-by: Gary Guo <gary@garyguo.net> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Jesung Yang <y.jems.n@gmail.com> Acked-by: Tamir Duberstein <tamird@kernel.org> Link: https://patch.msgid.link/20260402-binder-crate-name-v4-1-ec3919b87909@google.com [ Applied Python type hints. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2026-04-02 10:55:33 +00:00
if not is_root_crate(path.parent / "Makefile", file_name) and \
not is_root_crate(path.parent / "Kbuild", file_name):
continue
rust: support overriding crate_name Currently you cannot filter out the crate-name argument RUSTFLAGS_REMOVE_stem.o because the Rust filter-out invocation does not include that particular argument. Since --crate-name is an argument that can't be passed multiple times, this means that it's currently not possible to override the crate name. Thus, remove the --crate-name argument for drivers. This allows them to override the crate name using the #![crate_name] annotation. This affects symbol names, but has no effect on the filenames of object files and other things generated by the build, as we always use --emit with a fixed output filename. The --crate-name argument is kept for the crates under rust/ for simplicity and to avoid changing many of them by adding #![crate_name]. The rust analyzer script is updated to use rustc to obtain the crate name of the driver crates, which picks up the right name whether it is configured via #![crate_name] or not. For readability, the logic to invoke 'rustc' is extracted to its own function. Note that the crate name in the python script is not actually that important - the only place where the name actually affects anything is in the 'deps' array which specifies an index and name for each dependency, and determines what that dependency is called in *this* crate. (The same crate may be called different things in each dependency.) Since driver crates are leaf crates, this doesn't apply and the rustc invocation only affects the 'display_name' parameter. Acked-by: Gary Guo <gary@garyguo.net> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Jesung Yang <y.jems.n@gmail.com> Acked-by: Tamir Duberstein <tamird@kernel.org> Link: https://patch.msgid.link/20260402-binder-crate-name-v4-1-ec3919b87909@google.com [ Applied Python type hints. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2026-04-02 10:55:33 +00:00
crate_name = get_crate_name(path)
logging.info("Adding %s", crate_name)
append_crate(
rust: support overriding crate_name Currently you cannot filter out the crate-name argument RUSTFLAGS_REMOVE_stem.o because the Rust filter-out invocation does not include that particular argument. Since --crate-name is an argument that can't be passed multiple times, this means that it's currently not possible to override the crate name. Thus, remove the --crate-name argument for drivers. This allows them to override the crate name using the #![crate_name] annotation. This affects symbol names, but has no effect on the filenames of object files and other things generated by the build, as we always use --emit with a fixed output filename. The --crate-name argument is kept for the crates under rust/ for simplicity and to avoid changing many of them by adding #![crate_name]. The rust analyzer script is updated to use rustc to obtain the crate name of the driver crates, which picks up the right name whether it is configured via #![crate_name] or not. For readability, the logic to invoke 'rustc' is extracted to its own function. Note that the crate name in the python script is not actually that important - the only place where the name actually affects anything is in the 'deps' array which specifies an index and name for each dependency, and determines what that dependency is called in *this* crate. (The same crate may be called different things in each dependency.) Since driver crates are leaf crates, this doesn't apply and the rustc invocation only affects the 'display_name' parameter. Acked-by: Gary Guo <gary@garyguo.net> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Jesung Yang <y.jems.n@gmail.com> Acked-by: Tamir Duberstein <tamird@kernel.org> Link: https://patch.msgid.link/20260402-binder-crate-name-v4-1-ec3919b87909@google.com [ Applied Python type hints. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2026-04-02 10:55:33 +00:00
crate_name,
path,
[core, kernel, pin_init],
cfg=generated_cfg,
)
return crates
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument('--verbose', '-v', action='store_true')
parser.add_argument('--cfgs', action='append', default=[])
parser.add_argument("core_edition")
parser.add_argument("srctree", type=pathlib.Path)
parser.add_argument("objtree", type=pathlib.Path)
rust: Support latest version of `rust-analyzer` Sets the `sysroot` field in rust-project.json which is now needed in newer versions of rust-analyzer instead of the `sysroot_src` field. Till [1] `rust-analyzer` used to guess the `sysroot` based on the `sysroot_src` at [2]. Now `sysroot` is a required parameter for a `rust-project.json` file. It is required because `rust-analyzer` need it to find the proc-macro server [3]. In the current version of `rust-analyzer` the `sysroot_src` is only used to include the inbuilt library crates (std, core, alloc, etc) [4]. Since we already specify the core library to be included in the `rust-project.json` we don't need to define the `sysroot_src`. Code editors like VS Code try to use the latest version of rust-analyzer (which is updated every week) instead of the version of rust-analyzer that comes with the rustup toolchain (which is updated every six weeks along with the rust version). Without this change `rust-analyzer` is breaking for anyone using VS Code. As they are getting the latest version of `rust-analyzer` with the changes made in [1]. `rust-analyzer` will also start breaking for other developers as they update their rust version (assuming that also updates the rust-analyzer version on their system). This patch should work with every setup as there is no more guess work being done by `rust-analyzer`. [ Lukas, who leads the rust-analyzer team, says: `sysroot_src` is required now if you want to have the sysroot source libraries be loaded. I think we used to infer it as `{sysroot}/lib/rustlib/src/rust/library` before when only the `sysroot` field was given but that was since changed to make it possible in having a sysroot without the standard library sources (that is only have the binaries available). So if you want the library sources to be loaded by rust-analyzer you will have to set that field as well now. - Miguel ] Link: https://github.com/rust-lang/rust-analyzer/pull/17287 [1] Link: https://github.com/rust-lang/rust-analyzer/blob/f372a8a1176ff8dd5f45ab2ddd45f3530db0374f/crates/project-model/src/workspace.rs#L367-L374 [2] Link: https://github.com/rust-lang/rust-analyzer/blob/eeb192b79aeac47b40add66347022af17a74fbaf/crates/project-model/src/sysroot.rs#L180-L192 [3] Link: https://github.com/search?q=repo%3AVeykril%2Frust-analyzer%20src_root()&type=code [4] Tested-by: Dirk Behme <dirk.behme@de.bosch.com> Signed-off-by: Sarthak Singh <sarthak.singh99@gmail.com> Link: https://rust-for-linux.zulipchat.com/#narrow/stream/291565-Help/topic/How.20to.20rust-analyzer.20correctly.20working Link: https://lore.kernel.org/r/20240724172713.899399-1-sarthak.singh99@gmail.com [ Formatted comment, fixed typo and removed spurious empty line. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-07-24 22:57:06 +05:30
parser.add_argument("sysroot", type=pathlib.Path)
parser.add_argument("sysroot_src", type=pathlib.Path)
parser.add_argument("exttree", type=pathlib.Path, nargs="?")
class Args(argparse.Namespace):
verbose: bool
cfgs: List[str]
srctree: pathlib.Path
objtree: pathlib.Path
sysroot: pathlib.Path
sysroot_src: pathlib.Path
exttree: Optional[pathlib.Path]
core_edition: str
args = parser.parse_args(namespace=Args())
logging.basicConfig(
format="[%(asctime)s] [%(levelname)s] %(message)s",
level=logging.INFO if args.verbose else logging.WARNING
)
rust_project = {
"crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs, args.core_edition),
rust: Support latest version of `rust-analyzer` Sets the `sysroot` field in rust-project.json which is now needed in newer versions of rust-analyzer instead of the `sysroot_src` field. Till [1] `rust-analyzer` used to guess the `sysroot` based on the `sysroot_src` at [2]. Now `sysroot` is a required parameter for a `rust-project.json` file. It is required because `rust-analyzer` need it to find the proc-macro server [3]. In the current version of `rust-analyzer` the `sysroot_src` is only used to include the inbuilt library crates (std, core, alloc, etc) [4]. Since we already specify the core library to be included in the `rust-project.json` we don't need to define the `sysroot_src`. Code editors like VS Code try to use the latest version of rust-analyzer (which is updated every week) instead of the version of rust-analyzer that comes with the rustup toolchain (which is updated every six weeks along with the rust version). Without this change `rust-analyzer` is breaking for anyone using VS Code. As they are getting the latest version of `rust-analyzer` with the changes made in [1]. `rust-analyzer` will also start breaking for other developers as they update their rust version (assuming that also updates the rust-analyzer version on their system). This patch should work with every setup as there is no more guess work being done by `rust-analyzer`. [ Lukas, who leads the rust-analyzer team, says: `sysroot_src` is required now if you want to have the sysroot source libraries be loaded. I think we used to infer it as `{sysroot}/lib/rustlib/src/rust/library` before when only the `sysroot` field was given but that was since changed to make it possible in having a sysroot without the standard library sources (that is only have the binaries available). So if you want the library sources to be loaded by rust-analyzer you will have to set that field as well now. - Miguel ] Link: https://github.com/rust-lang/rust-analyzer/pull/17287 [1] Link: https://github.com/rust-lang/rust-analyzer/blob/f372a8a1176ff8dd5f45ab2ddd45f3530db0374f/crates/project-model/src/workspace.rs#L367-L374 [2] Link: https://github.com/rust-lang/rust-analyzer/blob/eeb192b79aeac47b40add66347022af17a74fbaf/crates/project-model/src/sysroot.rs#L180-L192 [3] Link: https://github.com/search?q=repo%3AVeykril%2Frust-analyzer%20src_root()&type=code [4] Tested-by: Dirk Behme <dirk.behme@de.bosch.com> Signed-off-by: Sarthak Singh <sarthak.singh99@gmail.com> Link: https://rust-for-linux.zulipchat.com/#narrow/stream/291565-Help/topic/How.20to.20rust-analyzer.20correctly.20working Link: https://lore.kernel.org/r/20240724172713.899399-1-sarthak.singh99@gmail.com [ Formatted comment, fixed typo and removed spurious empty line. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-07-24 22:57:06 +05:30
"sysroot": str(args.sysroot),
}
json.dump(rust_project, sys.stdout, sort_keys=True, indent=4)
if __name__ == "__main__":
main()