#!/usr/bin/env python3# SPDX-License-Identifier: GPL-2.0"""generate_rust_analyzer - Generates the `rust-project.json` file for `rust-analyzer`.""" import argparseimport jsonimport loggingimport pathlibimport sys def generate_crates(srctree, objtree, sysroot_src): # 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) # Now fill the crates list -- dependencies need to come first. # # Avoid O(n^2) iterations by keeping a map of indexes. crates = [] crates_indexes = {} def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False): crates_indexes[display_name] = len(crates) crates.append({ "display_name": display_name, "root_module": str(root_module), "is_workspace_member": is_workspace_member, "is_proc_macro": is_proc_macro, "deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps], "cfg": cfg, "edition": "2021", "env": { "RUST_MODFILE": "This is only for rust-analyzer" } }) # First, the ones in `rust/` since they are a bit special. append_crate( "core", sysroot_src / "core" / "src" / "lib.rs", [], is_workspace_member=False, ) append_crate( "compiler_builtins", srctree / "rust" / "compiler_builtins.rs", [], ) append_crate( "alloc", srctree / "rust" / "alloc" / "lib.rs", ["core", "compiler_builtins"], ) append_crate( "macros", srctree / "rust" / "macros" / "lib.rs", [], is_proc_macro=True, ) crates[-1]["proc_macro_dylib_path"] = "rust/libmacros.so" append_crate( "bindings", srctree / "rust"/ "bindings" / "lib.rs", ["core"], cfg=cfg, ) crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True)) append_crate( "kernel", srctree / "rust" / "kernel" / "lib.rs", ["core", "alloc", "macros", "bindings"], cfg=cfg, ) crates[-1]["source"] = { "include_dirs": [ str(srctree / "rust" / "kernel"), str(objtree / "rust") ], "exclude_dirs": [], } # Then, the rest outside of `rust/`. # # We explicitly mention the top-level folders we want to cover. for folder in ("samples", "drivers"): for path in (srctree / folder).rglob("*.rs"): logging.info("Checking %s", path) name = path.name.replace(".rs", "") # Skip those that are not crate roots. if f"{name}.o" not in open(path.parent / "Makefile").read(): continue logging.info("Adding %s", name) append_crate( name, path, ["core", "alloc", "kernel"], cfg=cfg, ) return crates def main(): parser = argparse.ArgumentParser() parser.add_argument('--verbose', '-v', action='store_true') parser.add_argument("srctree", type=pathlib.Path) parser.add_argument("objtree", type=pathlib.Path) parser.add_argument("sysroot_src", type=pathlib.Path) args = parser.parse_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), "sysroot_src": str(args.sysroot_src), } json.dump(rust_project, sys.stdout, sort_keys=True, indent=4) if __name__ == "__main__": main()
#!/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 pathlib
import sys
def generate_crates(srctree, objtree, sysroot_src):
# 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)
# Now fill the crates list -- dependencies need to come first.
#
# Avoid O(n^2) iterations by keeping a map of indexes.
crates = []
crates_indexes = {}
def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False):
crates_indexes[display_name] = len(crates)
crates.append({
"display_name": display_name,
"root_module": str(root_module),
"is_workspace_member": is_workspace_member,
"is_proc_macro": is_proc_macro,
"deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps],
"cfg": cfg,
"edition": "2021",
"env": {
"RUST_MODFILE": "This is only for rust-analyzer"
}
})
# First, the ones in `rust/` since they are a bit special.
append_crate(
"core",
sysroot_src / "core" / "src" / "lib.rs",
[],
is_workspace_member=False,
)
append_crate(
"compiler_builtins",
srctree / "rust" / "compiler_builtins.rs",
[],
)
append_crate(
"alloc",
srctree / "rust" / "alloc" / "lib.rs",
["core", "compiler_builtins"],
)
append_crate(
"macros",
srctree / "rust" / "macros" / "lib.rs",
[],
is_proc_macro=True,
)
crates[-1]["proc_macro_dylib_path"] = "rust/libmacros.so"
append_crate(
"bindings",
srctree / "rust"/ "bindings" / "lib.rs",
["core"],
cfg=cfg,
)
crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True))
append_crate(
"kernel",
srctree / "rust" / "kernel" / "lib.rs",
["core", "alloc", "macros", "bindings"],
cfg=cfg,
)
crates[-1]["source"] = {
"include_dirs": [
str(srctree / "rust" / "kernel"),
str(objtree / "rust")
],
"exclude_dirs": [],
}
# Then, the rest outside of `rust/`.
#
# We explicitly mention the top-level folders we want to cover.
for folder in ("samples", "drivers"):
for path in (srctree / folder).rglob("*.rs"):
logging.info("Checking %s", path)
name = path.name.replace(".rs", "")
# Skip those that are not crate roots.
if f"{name}.o" not in open(path.parent / "Makefile").read():
continue
logging.info("Adding %s", name)
append_crate(
name,
path,
["core", "alloc", "kernel"],
cfg=cfg,
)
return crates
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--verbose', '-v', action='store_true')
parser.add_argument("srctree", type=pathlib.Path)
parser.add_argument("objtree", type=pathlib.Path)
parser.add_argument("sysroot_src", type=pathlib.Path)
args = parser.parse_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),
"sysroot_src": str(args.sysroot_src),
}
json.dump(rust_project, sys.stdout, sort_keys=True, indent=4)
if __name__ == "__main__":
main()