diff --git a/.gitignore b/.gitignore index 1de6a8d..ee6ae9b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ *.rmeta Module.symvers modules.order +rust-project.json diff --git a/Makefile b/Makefile index 45b702b..6705fd1 100644 --- a/Makefile +++ b/Makefile @@ -4,3 +4,10 @@ KDIR ?= /lib/modules/`uname -r`/build default: $(MAKE) -C $(KDIR) M=$$PWD + +rust-analyzer: + $(MAKE) -C $(KDIR) rust-analyzer + $(Q) ./scripts/generate_rust_analyzer.py $(KDIR) `ls *.rs | head -n 1` > rust-project.json + +clean: + $(MAKE) -C $(KDIR) M=$$PWD clean diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py new file mode 100755 index 0000000..8dbb4eb --- /dev/null +++ b/scripts/generate_rust_analyzer.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +"""generate_rust_analyzer - Generates an out-of-tree module `rust-project.json` file for `rust-analyzer` +based on the kernel rust-project.json. +""" + +import argparse +import json +import logging +import os +import pathlib +import sys + +def generate_rust_project(kdir, root_module): + with open(kdir / "rust-project.json") as fd: + rust_project = json.loads(fd.read()) + + crate_indices = {} + + for i, crate in enumerate(rust_project["crates"]): + crate_indices[crate["display_name"]] = i + + # Prepend kdir to existing root_module + crate["root_module"] = os.path.join(kdir, crate["root_module"]) + if crate.get("source"): + if "exclude_dirs" in crate["source"]: + crate["source"]["exclude_dirs"] = [ + os.path.join(kdir, e_dir) for e_dir in crate["source"]["exclude_dirs"] + ] + if "include_dirs" in crate["source"]: + crate["source"]["include_dirs"] = [ + os.path.join(kdir, i_dir) for i_dir in crate["source"]["include_dirs"] + ] + + # Finally, append this module as a crate + rust_project["crates"].append({ + "display_name": root_module.removesuffix(".rs"), + "root_module": root_module, + "is_workspace_member": False, + "is_proc_macro": False, + "deps": [ + {"crate": index, "name": name} + for name, index in crate_indices.items() + if name == "kernel" + ], + "cfg": [], + "edition": "2021", + "env": { + "RUST_MODFILE": "This is only for rust-analyzer" + } + }) + return rust_project + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--verbose', '-v', action='store_true') + parser.add_argument("kdir", type=pathlib.Path) + parser.add_argument("root_module", type=str) + args = parser.parse_args() + + logging.basicConfig( + format="[%(asctime)s] [%(levelname)s] %(message)s", + level=logging.INFO if args.verbose else logging.WARNING + ) + + rust_project = generate_rust_project(args.kdir, args.root_module) + json.dump(rust_project, sys.stdout, sort_keys=True, indent=4) + +if __name__ == "__main__": + main()