Commit | Line | Data |
---|---|---|
8c4555cc MO |
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 | ||
ecaa6ddf GG |
70 | append_crate( |
71 | "build_error", | |
72 | srctree / "rust" / "build_error.rs", | |
73 | ["core", "compiler_builtins"], | |
74 | ) | |
75 | ||
8c4555cc MO |
76 | append_crate( |
77 | "bindings", | |
78 | srctree / "rust"/ "bindings" / "lib.rs", | |
79 | ["core"], | |
80 | cfg=cfg, | |
81 | ) | |
82 | crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True)) | |
83 | ||
84 | append_crate( | |
85 | "kernel", | |
86 | srctree / "rust" / "kernel" / "lib.rs", | |
ecaa6ddf | 87 | ["core", "alloc", "macros", "build_error", "bindings"], |
8c4555cc MO |
88 | cfg=cfg, |
89 | ) | |
90 | crates[-1]["source"] = { | |
91 | "include_dirs": [ | |
92 | str(srctree / "rust" / "kernel"), | |
93 | str(objtree / "rust") | |
94 | ], | |
95 | "exclude_dirs": [], | |
96 | } | |
97 | ||
98 | # Then, the rest outside of `rust/`. | |
99 | # | |
100 | # We explicitly mention the top-level folders we want to cover. | |
101 | for folder in ("samples", "drivers"): | |
102 | for path in (srctree / folder).rglob("*.rs"): | |
103 | logging.info("Checking %s", path) | |
104 | name = path.name.replace(".rs", "") | |
105 | ||
106 | # Skip those that are not crate roots. | |
5c7548d5 AL |
107 | try: |
108 | if f"{name}.o" not in open(path.parent / "Makefile").read(): | |
109 | continue | |
110 | except FileNotFoundError: | |
8c4555cc MO |
111 | continue |
112 | ||
113 | logging.info("Adding %s", name) | |
114 | append_crate( | |
115 | name, | |
116 | path, | |
117 | ["core", "alloc", "kernel"], | |
118 | cfg=cfg, | |
119 | ) | |
120 | ||
121 | return crates | |
122 | ||
123 | def main(): | |
124 | parser = argparse.ArgumentParser() | |
125 | parser.add_argument('--verbose', '-v', action='store_true') | |
126 | parser.add_argument("srctree", type=pathlib.Path) | |
127 | parser.add_argument("objtree", type=pathlib.Path) | |
128 | parser.add_argument("sysroot_src", type=pathlib.Path) | |
129 | args = parser.parse_args() | |
130 | ||
131 | logging.basicConfig( | |
132 | format="[%(asctime)s] [%(levelname)s] %(message)s", | |
133 | level=logging.INFO if args.verbose else logging.WARNING | |
134 | ) | |
135 | ||
136 | rust_project = { | |
137 | "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src), | |
138 | "sysroot_src": str(args.sysroot_src), | |
139 | } | |
140 | ||
141 | json.dump(rust_project, sys.stdout, sort_keys=True, indent=4) | |
142 | ||
143 | if __name__ == "__main__": | |
144 | main() |