aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/generate_rust_analyzer.py
blob: 75bb611bd7516cd12f5948a2194420c18d2e27cb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/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()
>doc: document diff/merge.guitool config keysDenton Liu2-0/+14 2018-10-25completion: support `git mergetool --[no-]gui`Denton Liu1-1/+1 2018-10-25mergetool: accept -g/--[no-]gui as argumentsDenton Liu3-7/+31 2018-10-25repack -ad: prune the list of shallow commitsJohannes Schindelin2-1/+7 2018-10-25shallow: offer to prune only non-existing entriesJohannes Schindelin3-8/+21 2018-10-25repack: point out a bug handling stale shallow infoJohannes Schindelin1-0/+27 2018-10-25t5410: use longer path for sample scriptJeff King1-1/+1 2018-10-25run-command: mark path lookup errors with ENOENTJeff King2-5/+29 2018-10-24khash: silence -Wunused-function for delta-islandsCarlo Marcelo Arenas Belón1-1/+1 2018-10-24commit-slabs: move MAYBE_UNUSED outCarlo Marcelo Arenas Belón2-2/+4 2018-10-24mingw: fix getcwd when the parent directory cannot be queriedAnton Serbulov1-0/+39 2018-10-24mingw: ensure `getcwd()` reports the correct caseJohannes Schindelin1-2/+9 2018-10-24mingw: load system libraries the recommended wayJohannes Schindelin2-2/+4 2018-10-24rebase --autostash: fix issue with dirty submodulesJohannes Schindelin2-2/+2 2018-10-24rebase --autostash: demonstrate a problem with dirty submodulesJohannes Schindelin1-0/+10 2018-10-24mingw: implement nanosecond-precision file timesKarsten Blees3-20/+36 2018-10-24mingw: replace MSVCRT's fstat() with a Win32-based implementationKarsten Blees1-10/+21 2018-10-24mingw: factor out code to set stat() dataJohannes Schindelin1-14/+25 2018-10-24Documentation/config.txt: fix typo in core.alternateRefsCommandTaylor Blau1-1/+1 2018-10-24fsck: s/++i > 1/i++/Junio C Hamano1-1/+1