aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/generate_rust_analyzer.py
blob: 7c3ea2b55041f864b01d5fba627449758bd4d8af (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#!/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 os
import pathlib
import subprocess
import sys

def args_crates_cfgs(cfgs):
    crates_cfgs = {}
    for cfg in cfgs:
        crate, vals = cfg.split("=", 1)
        crates_cfgs[crate] = vals.replace("--cfg", "").split()

    return crates_cfgs

def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edition):
    # 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 = {}
    crates_cfgs = args_crates_cfgs(cfgs)

    def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False, edition="2021"):
        crate = {
            "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": edition,
            "env": {
                "RUST_MODFILE": "This is only for rust-analyzer"
            }
        }
        if is_proc_macro:
            proc_macro_dylib_name = subprocess.check_output(
                [os.environ["RUSTC"], "--print", "file-names", "--crate-name", display_name, "--crate-type", "proc-macro", "-"],
                stdin=subprocess.DEVNULL,
            ).decode('utf-8').strip()
            crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}"
        crates_indexes[display_name] = len(crates)
        crates.append(crate)

    def append_sysroot_crate(
        display_name,
        deps,
        cfg=[],
        edition="2021",
    ):
        append_crate(
            display_name,
            sysroot_src / display_name / "src" / "lib.rs",
            deps,
            cfg,
            is_workspace_member=False,
            edition=edition,
        )

    # NB: sysroot crates reexport items from one another so setting up our transitive dependencies
    # here is important for ensuring that rust-analyzer can resolve symbols. The sources of truth
    # for this dependency graph are `(sysroot_src / crate / "Cargo.toml" for crate in crates)`.
    append_sysroot_crate("core", [], cfg=crates_cfgs.get("core", []), edition=core_edition)
    append_sysroot_crate("alloc", ["core"])
    append_sysroot_crate("std", ["alloc", "core"])
    append_sysroot_crate("proc_macro", ["core", "std"])

    append_crate(
        "compiler_builtins",
        srctree / "rust" / "compiler_builtins.rs",
        [],
    )

    append_crate(
        "macros",
        srctree / "rust" / "macros" / "lib.rs",
        ["std", "proc_macro"],
        is_proc_macro=True,
    )

    append_crate(
        "build_error",
        srctree / "rust" / "build_error.rs",
        ["core", "compiler_builtins"],
    )

    append_crate(
        "pin_init_internal",
        srctree / "rust" / "pin-init" / "internal" / "src" / "lib.rs",
        [],
        cfg=["kernel"],
        is_proc_macro=True,
    )

    append_crate(
        "pin_init",
        srctree / "rust" / "pin-init" / "src" / "lib.rs",
        ["core", "pin_init_internal", "macros"],
        cfg=["kernel"],
    )

    append_crate(
        "ffi",
        srctree / "rust" / "ffi.rs",
        ["core", "compiler_builtins"],
    )

    def append_crate_with_generated(
        display_name,
        deps,
    ):
        append_crate(
            display_name,
            srctree / "rust"/ display_name / "lib.rs",
            deps,
            cfg=cfg,
        )
        crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True))
        crates[-1]["source"] = {
            "include_dirs": [
                str(srctree / "rust" / display_name),
                str(objtree / "rust")
            ],
            "exclude_dirs": [],
        }

    append_crate_with_generated("bindings", ["core", "ffi"])
    append_crate_with_generated("uapi", ["core", "ffi"])
    append_crate_with_generated("kernel", ["core", "macros", "build_error", "pin_init", "ffi", "bindings", "uapi"])

    def is_root_crate(build_file, target):
        try:
            return f"{target}.o" in open(build_file).read()
        except FileNotFoundError:
            return False

    # Then, the rest outside of `rust/`.
    #
    # We explicitly mention the top-level folders we want to cover.
    extra_dirs = map(lambda dir: srctree / dir, ("samples", "drivers"))
    if external_src is not None:
        extra_dirs = [external_src]
    for folder in extra_dirs:
        for path in folder.rglob("*.rs"):
            logging.info("Checking %s", path)
            name = path.name.replace(".rs", "")

            # Skip those that are not crate roots.
            if not is_root_crate(path.parent / "Makefile", name) and \
               not is_root_crate(path.parent / "Kbuild", name):
                continue

            logging.info("Adding %s", name)
            append_crate(
                name,
                path,
                ["core", "kernel"],
                cfg=cfg,
            )

    return crates

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--verbose', '-v', action='store_true')
    parser.add_argument('--cfgs', action='append', default=[])
    parser.add_argument("core_edition")
    parser.add_argument("srctree", type=pathlib.Path)
    parser.add_argument("objtree", type=pathlib.Path)
    parser.add_argument("sysroot", type=pathlib.Path)
    parser.add_argument("sysroot_src", type=pathlib.Path)
    parser.add_argument("exttree", type=pathlib.Path, nargs="?")
    args = parser.parse_args()

    logging.basicConfig(
        format="[%(asctime)s] [%(levelname)s] %(message)s",
        level=logging.INFO if args.verbose else logging.WARNING
    )

    # Making sure that the `sysroot` and `sysroot_src` belong to the same toolchain.
    assert args.sysroot in args.sysroot_src.parents

    rust_project = {
        "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs, args.core_edition),
        "sysroot": str(args.sysroot),
    }

    json.dump(rust_project, sys.stdout, sort_keys=True, indent=4)

if __name__ == "__main__":
    main()
1&id=56a8aea0c61c26e2644514ede24cec35b06ee0d0&follow=1'>git-check-ref-format.txt: typo, s/avoids/avoid/Nguyễn Thái Ngọc Duy1-1/+1 Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2015-12-04document submodule sync --recursiveStefan Beller1-1/+4 The git-submodule(1) is inconsistent. In the synopsis, it says: git submodule [--quiet] sync [--recursive] [--] [<path>...] The description of the sync does not mention --recursive, and the description of --recursive says that it is only available for foreach, update and status. The option was introduced (82f49f294c, Teach --recursive to submodule sync, 2012-10-26) a while ago, so let's document it, too. Reported-by: Per Cederqvist <cederp@opera.com> Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2015-12-04Prepare for 2.6.4Junio C Hamano2-1/+49 Signed-off-by: Junio C Hamano <gitster@pobox.com> 2015-12-04RelNotes update for 2.7Junio C Hamano1-0/+51 Signed-off-by: Junio C Hamano <gitster@pobox.com> 2015-12-01verify_pack: do not ignore return value of verification functionDavid Turner1-1/+1 In verify_pack, a caller-supplied verification function is called. The function returns an int. If that return value is non-zero, verify_pack should fail. The only caller of verify_pack is in builtin/fsck.c, whose verify_fn returns a meaningful error code (which was then ignored). Now, fsck might return a different error code (with more detail). This would happen in the unlikely event that a commit or tree that is a valid git object but not a valid instance of its type gets into a pack. Signed-off-by: David Turner <dturner@twopensource.com> Signed-off-by: Jeff King <peff@peff.net> 2015-12-01Make error message after failing commit_lock_file() less confusingSZEDER Gábor4-5/+8 The error message after a failing commit_lock_file() call sometimes looks like this, causing confusion: $ git remote add remote git@server.com/repo.git error: could not commit config file .git/config # Huh?! # I didn't want to commit anything, especially not my config file! While in the narrow context of the lockfile module using the verb 'commit' in the error message makes perfect sense, in the broader context of git the word 'commit' already has a very specific meaning, hence the confusion. Reword these error messages to say "could not write" instead of "could not commit". While at it, include strerror in the error messages after writing the config file or the credential store fails to provide some information about the cause of the failure, and update the style of the error message after writing the reflog fails to match surrounding error messages (i.e. no '' around the pathname and no () around the error description). Signed-off-by: SZEDER Gábor <szeder@ira.uka.de> Signed-off-by: Jeff King <peff@peff.net> 2015-11-28wt-status: correct and simplify check for detached HEADRené Scharfe1-5/+4 If a branch name is longer than four characters then memcmp() reads over the end of the static string "HEAD". This causes the following test failures with AddressSanitizer: t3203-branch-output.sh (Wstat: 256 Tests: 18 Failed: 4) Failed tests: 12, 15-17 Non-zero exit status: 1 t3412-rebase-root.sh (Wstat: 256 Tests: 31 Failed: 3) Failed tests: 28-29, 31 Non-zero exit status: 1 t3507-cherry-pick-conflict.sh (Wstat: 256 Tests: 31 Failed: 4) Failed tests: 14, 29-31 Non-zero exit status: 1 t3510-cherry-pick-sequence.sh (Wstat: 256 Tests: 39 Failed: 14) Failed tests: 17, 22-26, 28-30, 34-35, 37-39 Non-zero exit status: 1 t3420-rebase-autostash.sh (Wstat: 256 Tests: 28 Failed: 4) Failed tests: 24-27 Non-zero exit status: 1 t3404-rebase-interactive.sh (Wstat: 256 Tests: 91 Failed: 57) Failed tests: 17, 19, 21-42, 44, 46-74, 77, 81-82 Non-zero exit status: 1 t3900-i18n-commit.sh (Wstat: 256 Tests: 34 Failed: 1) Failed test: 34 Non-zero exit status: 1 t5407-post-rewrite-hook.sh (Wstat: 256 Tests: 14 Failed: 6) Failed tests: 9-14 Non-zero exit status: 1 t7001-mv.sh (Wstat: 256 Tests: 46 Failed: 5) Failed tests: 39-43 Non-zero exit status: 1 t7509-commit.sh (Wstat: 256 Tests: 12 Failed: 2) Failed tests: 11-12 Non-zero exit status: 1 t7512-status-help.sh (Wstat: 256 Tests: 39 Failed: 35) Failed tests: 5-39 Non-zero exit status: 1 t6030-bisect-porcelain.sh (Wstat: 256 Tests: 70 Failed: 1) Failed test: 13 Non-zero exit status: 1 And if a branch is named "H", "HE", or "HEA" then the current if clause erroneously considers it as matching "HEAD" because it only compares up to the end of the branch name. Fix that by doing the comparison using strcmp() and only after the branch name is extracted. This way neither too less nor too many characters are checked. While at it call strchrnul() to find the end of the branch name instead of open-coding it. Helped-by: Jeff King <peff@peff.net> Signed-off-by: Rene Scharfe <l.s.r@web.de> Signed-off-by: Jeff King <peff@peff.net> 2015-11-28ident.c: add support for IPv6Elia Pinto1-4/+27 Add IPv6 support by implementing name resolution with the protocol agnostic getaddrinfo(3) API. The old gethostbyname(3) code is still available when git is compiled with NO_IPV6. Signed-off-by: Elia Pinto <gitter.spiros@gmail.com> Helped-by: Jeff King <peff@peff.net> Helped-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Jeff King <peff@peff.net>