Skip to content

Commit 8c4555c

Browse files
committed
scripts: add generate_rust_analyzer.py
The `generate_rust_analyzer.py` script generates the configuration file (`rust-project.json`) for rust-analyzer. rust-analyzer is a modular compiler frontend for the Rust language. It provides an LSP server which can be used in editors such as VS Code, Emacs or Vim. Reviewed-by: Kees Cook <[email protected]> Co-developed-by: Alex Gaynor <[email protected]> Signed-off-by: Alex Gaynor <[email protected]> Co-developed-by: Finn Behrens <[email protected]> Signed-off-by: Finn Behrens <[email protected]> Co-developed-by: Wedson Almeida Filho <[email protected]> Signed-off-by: Wedson Almeida Filho <[email protected]> Co-developed-by: Gary Guo <[email protected]> Signed-off-by: Gary Guo <[email protected]> Co-developed-by: Boris-Chengbiao Zhou <[email protected]> Signed-off-by: Boris-Chengbiao Zhou <[email protected]> Co-developed-by: Björn Roy Baron <[email protected]> Signed-off-by: Björn Roy Baron <[email protected]> Signed-off-by: Miguel Ojeda <[email protected]>
1 parent 99115db commit 8c4555c

File tree

2 files changed

+138
-0
lines changed

2 files changed

+138
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,6 @@ x509.genkey
162162

163163
# Documentation toolchain
164164
sphinx_*/
165+
166+
# Rust analyzer configuration
167+
/rust-project.json

scripts/generate_rust_analyzer.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#!/usr/bin/env python3
2+
# SPDX-License-Identifier: GPL-2.0
3+
"""generate_rust_analyzer - Generates the `rust-project.json` file for `rust-analyzer`.
4+
"""
5+
6+
import argparse
7+
import json
8+
import logging
9+
import pathlib
10+
import sys
11+
12+
def generate_crates(srctree, objtree, sysroot_src):
13+
# Generate the configuration list.
14+
cfg = []
15+
with open(objtree / "include" / "generated" / "rustc_cfg") as fd:
16+
for line in fd:
17+
line = line.replace("--cfg=", "")
18+
line = line.replace("\n", "")
19+
cfg.append(line)
20+
21+
# Now fill the crates list -- dependencies need to come first.
22+
#
23+
# Avoid O(n^2) iterations by keeping a map of indexes.
24+
crates = []
25+
crates_indexes = {}
26+
27+
def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False):
28+
crates_indexes[display_name] = len(crates)
29+
crates.append({
30+
"display_name": display_name,
31+
"root_module": str(root_module),
32+
"is_workspace_member": is_workspace_member,
33+
"is_proc_macro": is_proc_macro,
34+
"deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps],
35+
"cfg": cfg,
36+
"edition": "2021",
37+
"env": {
38+
"RUST_MODFILE": "This is only for rust-analyzer"
39+
}
40+
})
41+
42+
# First, the ones in `rust/` since they are a bit special.
43+
append_crate(
44+
"core",
45+
sysroot_src / "core" / "src" / "lib.rs",
46+
[],
47+
is_workspace_member=False,
48+
)
49+
50+
append_crate(
51+
"compiler_builtins",
52+
srctree / "rust" / "compiler_builtins.rs",
53+
[],
54+
)
55+
56+
append_crate(
57+
"alloc",
58+
srctree / "rust" / "alloc" / "lib.rs",
59+
["core", "compiler_builtins"],
60+
)
61+
62+
append_crate(
63+
"macros",
64+
srctree / "rust" / "macros" / "lib.rs",
65+
[],
66+
is_proc_macro=True,
67+
)
68+
crates[-1]["proc_macro_dylib_path"] = "rust/libmacros.so"
69+
70+
append_crate(
71+
"bindings",
72+
srctree / "rust"/ "bindings" / "lib.rs",
73+
["core"],
74+
cfg=cfg,
75+
)
76+
crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True))
77+
78+
append_crate(
79+
"kernel",
80+
srctree / "rust" / "kernel" / "lib.rs",
81+
["core", "alloc", "macros", "bindings"],
82+
cfg=cfg,
83+
)
84+
crates[-1]["source"] = {
85+
"include_dirs": [
86+
str(srctree / "rust" / "kernel"),
87+
str(objtree / "rust")
88+
],
89+
"exclude_dirs": [],
90+
}
91+
92+
# Then, the rest outside of `rust/`.
93+
#
94+
# We explicitly mention the top-level folders we want to cover.
95+
for folder in ("samples", "drivers"):
96+
for path in (srctree / folder).rglob("*.rs"):
97+
logging.info("Checking %s", path)
98+
name = path.name.replace(".rs", "")
99+
100+
# Skip those that are not crate roots.
101+
if f"{name}.o" not in open(path.parent / "Makefile").read():
102+
continue
103+
104+
logging.info("Adding %s", name)
105+
append_crate(
106+
name,
107+
path,
108+
["core", "alloc", "kernel"],
109+
cfg=cfg,
110+
)
111+
112+
return crates
113+
114+
def main():
115+
parser = argparse.ArgumentParser()
116+
parser.add_argument('--verbose', '-v', action='store_true')
117+
parser.add_argument("srctree", type=pathlib.Path)
118+
parser.add_argument("objtree", type=pathlib.Path)
119+
parser.add_argument("sysroot_src", type=pathlib.Path)
120+
args = parser.parse_args()
121+
122+
logging.basicConfig(
123+
format="[%(asctime)s] [%(levelname)s] %(message)s",
124+
level=logging.INFO if args.verbose else logging.WARNING
125+
)
126+
127+
rust_project = {
128+
"crates": generate_crates(args.srctree, args.objtree, args.sysroot_src),
129+
"sysroot_src": str(args.sysroot_src),
130+
}
131+
132+
json.dump(rust_project, sys.stdout, sort_keys=True, indent=4)
133+
134+
if __name__ == "__main__":
135+
main()

0 commit comments

Comments
 (0)