]>
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 | |
49a9ef76 | 9 | import os |
8c4555cc MO |
10 | import pathlib |
11 | import sys | |
12 | ||
4f353e0d MRR |
13 | def args_crates_cfgs(cfgs): |
14 | crates_cfgs = {} | |
15 | for cfg in cfgs: | |
16 | crate, vals = cfg.split("=", 1) | |
17 | crates_cfgs[crate] = vals.replace("--cfg", "").split() | |
18 | ||
19 | return crates_cfgs | |
20 | ||
21 | def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): | |
8c4555cc MO |
22 | # Generate the configuration list. |
23 | cfg = [] | |
24 | with open(objtree / "include" / "generated" / "rustc_cfg") as fd: | |
25 | for line in fd: | |
26 | line = line.replace("--cfg=", "") | |
27 | line = line.replace("\n", "") | |
28 | cfg.append(line) | |
29 | ||
30 | # Now fill the crates list -- dependencies need to come first. | |
31 | # | |
32 | # Avoid O(n^2) iterations by keeping a map of indexes. | |
33 | crates = [] | |
34 | crates_indexes = {} | |
4f353e0d | 35 | crates_cfgs = args_crates_cfgs(cfgs) |
8c4555cc MO |
36 | |
37 | def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False): | |
38 | crates_indexes[display_name] = len(crates) | |
39 | crates.append({ | |
40 | "display_name": display_name, | |
41 | "root_module": str(root_module), | |
42 | "is_workspace_member": is_workspace_member, | |
43 | "is_proc_macro": is_proc_macro, | |
44 | "deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps], | |
45 | "cfg": cfg, | |
46 | "edition": "2021", | |
47 | "env": { | |
48 | "RUST_MODFILE": "This is only for rust-analyzer" | |
49 | } | |
50 | }) | |
51 | ||
52 | # First, the ones in `rust/` since they are a bit special. | |
53 | append_crate( | |
54 | "core", | |
55 | sysroot_src / "core" / "src" / "lib.rs", | |
56 | [], | |
4f353e0d | 57 | cfg=crates_cfgs.get("core", []), |
8c4555cc MO |
58 | is_workspace_member=False, |
59 | ) | |
60 | ||
61 | append_crate( | |
62 | "compiler_builtins", | |
63 | srctree / "rust" / "compiler_builtins.rs", | |
64 | [], | |
65 | ) | |
66 | ||
67 | append_crate( | |
68 | "alloc", | |
69 | srctree / "rust" / "alloc" / "lib.rs", | |
70 | ["core", "compiler_builtins"], | |
4f353e0d | 71 | cfg=crates_cfgs.get("alloc", []), |
8c4555cc MO |
72 | ) |
73 | ||
74 | append_crate( | |
75 | "macros", | |
76 | srctree / "rust" / "macros" / "lib.rs", | |
77 | [], | |
78 | is_proc_macro=True, | |
79 | ) | |
49a9ef76 | 80 | crates[-1]["proc_macro_dylib_path"] = f"{objtree}/rust/libmacros.so" |
8c4555cc | 81 | |
ecaa6ddf GG |
82 | append_crate( |
83 | "build_error", | |
84 | srctree / "rust" / "build_error.rs", | |
85 | ["core", "compiler_builtins"], | |
86 | ) | |
87 | ||
8c4555cc MO |
88 | append_crate( |
89 | "bindings", | |
90 | srctree / "rust"/ "bindings" / "lib.rs", | |
91 | ["core"], | |
92 | cfg=cfg, | |
93 | ) | |
94 | crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True)) | |
95 | ||
96 | append_crate( | |
97 | "kernel", | |
98 | srctree / "rust" / "kernel" / "lib.rs", | |
ecaa6ddf | 99 | ["core", "alloc", "macros", "build_error", "bindings"], |
8c4555cc MO |
100 | cfg=cfg, |
101 | ) | |
102 | crates[-1]["source"] = { | |
103 | "include_dirs": [ | |
104 | str(srctree / "rust" / "kernel"), | |
105 | str(objtree / "rust") | |
106 | ], | |
107 | "exclude_dirs": [], | |
108 | } | |
109 | ||
49a9ef76 VV |
110 | def is_root_crate(build_file, target): |
111 | try: | |
112 | return f"{target}.o" in open(build_file).read() | |
113 | except FileNotFoundError: | |
114 | return False | |
115 | ||
8c4555cc MO |
116 | # Then, the rest outside of `rust/`. |
117 | # | |
118 | # We explicitly mention the top-level folders we want to cover. | |
49a9ef76 VV |
119 | extra_dirs = map(lambda dir: srctree / dir, ("samples", "drivers")) |
120 | if external_src is not None: | |
121 | extra_dirs = [external_src] | |
122 | for folder in extra_dirs: | |
123 | for path in folder.rglob("*.rs"): | |
8c4555cc MO |
124 | logging.info("Checking %s", path) |
125 | name = path.name.replace(".rs", "") | |
126 | ||
127 | # Skip those that are not crate roots. | |
49a9ef76 VV |
128 | if not is_root_crate(path.parent / "Makefile", name) and \ |
129 | not is_root_crate(path.parent / "Kbuild", name): | |
8c4555cc MO |
130 | continue |
131 | ||
132 | logging.info("Adding %s", name) | |
133 | append_crate( | |
134 | name, | |
135 | path, | |
136 | ["core", "alloc", "kernel"], | |
137 | cfg=cfg, | |
138 | ) | |
139 | ||
140 | return crates | |
141 | ||
142 | def main(): | |
143 | parser = argparse.ArgumentParser() | |
144 | parser.add_argument('--verbose', '-v', action='store_true') | |
4f353e0d | 145 | parser.add_argument('--cfgs', action='append', default=[]) |
8c4555cc MO |
146 | parser.add_argument("srctree", type=pathlib.Path) |
147 | parser.add_argument("objtree", type=pathlib.Path) | |
148 | parser.add_argument("sysroot_src", type=pathlib.Path) | |
49a9ef76 | 149 | parser.add_argument("exttree", type=pathlib.Path, nargs="?") |
8c4555cc MO |
150 | args = parser.parse_args() |
151 | ||
152 | logging.basicConfig( | |
153 | format="[%(asctime)s] [%(levelname)s] %(message)s", | |
154 | level=logging.INFO if args.verbose else logging.WARNING | |
155 | ) | |
156 | ||
157 | rust_project = { | |
4f353e0d | 158 | "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs), |
8c4555cc MO |
159 | "sysroot_src": str(args.sysroot_src), |
160 | } | |
161 | ||
162 | json.dump(rust_project, sys.stdout, sort_keys=True, indent=4) | |
163 | ||
164 | if __name__ == "__main__": | |
165 | main() |