src/bootstrap/configure.py PYTHON 829 lines View on github.com → Search inside
1#!/usr/bin/env python23# ignore-tidy-file-linelength45from __future__ import absolute_import, division, print_function6import shlex7import sys8import os9import re1011rust_dir = os.path.dirname(os.path.abspath(__file__))12rust_dir = os.path.dirname(rust_dir)13rust_dir = os.path.dirname(rust_dir)14sys.path.append(os.path.join(rust_dir, "src", "bootstrap"))15import bootstrap  # noqa: E402161718class Option(object):19    def __init__(self, name, rustbuild, desc, value):20        self.name = name21        self.rustbuild = rustbuild22        self.desc = desc23        self.value = value242526options = []272829def o(*args):30    options.append(Option(*args, value=False))313233def v(*args):34    options.append(Option(*args, value=True))353637o(38    "debug",39    "rust.debug",40    "enables debugging environment; does not affect optimization of bootstrapped code",41)42o("docs", "build.docs", "build standard library documentation")43o("compiler-docs", "build.compiler-docs", "build compiler documentation")44o("optimize-tests", "rust.optimize-tests", "build tests with optimizations")45o("verbose-tests", "rust.verbose-tests", "enable verbose output when running tests")46o(47    "ccache",48    "build.ccache",49    "invoke gcc/clang/rustc via ccache to reuse object files between builds",50)51o(52    "sccache",53    None,54    "invoke gcc/clang/rustc via sccache to reuse object files between builds",55)56o("local-rust", None, "use an installed rustc rather than downloading a snapshot")57v("local-rust-root", None, "set prefix for local rust binary")58o(59    "local-rebuild",60    "build.local-rebuild",61    "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version",62)63o(64    "llvm-static-stdcpp",65    "llvm.static-libstdcpp",66    "statically link to libstdc++ for LLVM",67)68o(69    "llvm-link-shared",70    "llvm.link-shared",71    "prefer shared linking to LLVM (llvm-config --link-shared)",72)73o("rpath", "rust.rpath", "build rpaths into rustc itself")74o("codegen-tests", "rust.codegen-tests", "run the tests/codegen tests")75o(76    "ninja",77    "llvm.ninja",78    "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)",79)80o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")81o("vendor", "build.vendor", "enable usage of vendored Rust crates")82o(83    "sanitizers",84    "build.sanitizers",85    "build the sanitizer runtimes (asan, dfsan, lsan, msan, tsan, hwasan)",86)87o(88    "dist-src",89    "rust.dist-src",90    "when building tarballs enables building a source tarball",91)92o(93    "cargo-native-static",94    "build.cargo-native-static",95    "static native libraries in cargo",96)97o("profiler", "build.profiler", "build the profiler runtime")98o("full-tools", None, "enable all tools")99o("lld", "rust.lld", "build lld")100o("llvm-bitcode-linker", "rust.llvm-bitcode-linker", "build llvm bitcode linker")101o("clang", "llvm.clang", "build clang")102o("use-libcxx", "llvm.use-libcxx", "build LLVM with libc++")103o("control-flow-guard", "rust.control-flow-guard", "Enable Control Flow Guard")104o(105    "patch-binaries-for-nix",106    "build.patch-binaries-for-nix",107    "whether patch binaries for usage with Nix toolchains",108)109o("new-symbol-mangling", "rust.new-symbol-mangling", "use symbol-mangling-version v0")110111v("llvm-cflags", "llvm.cflags", "build LLVM with these extra compiler flags")112v("llvm-cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags")113v("llvm-ldflags", "llvm.ldflags", "build LLVM with these extra linker flags")114115v("llvm-libunwind", "rust.llvm-libunwind", "use LLVM libunwind")116117# Optimization and debugging options. These may be overridden by the release118# channel, etc.119o("optimize-llvm", "llvm.optimize", "build optimized LLVM")120o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")121o("llvm-enzyme", "llvm.enzyme", "build LLVM with enzyme")122o("llvm-offload", "llvm.offload", "build LLVM with gpu offload support")123o(124    "llvm-offload-clang-dir",125    "llvm.offload-clang-dir",126    "pass the absolute directory of ClangConfig.cmake",127)128o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface")129o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")130o(131    "debug-assertions-std",132    "rust.debug-assertions-std",133    "build the standard library with debugging assertions",134)135o("overflow-checks", "rust.overflow-checks", "build with overflow checks")136o(137    "overflow-checks-std",138    "rust.overflow-checks-std",139    "build the standard library with overflow checks",140)141o(142    "llvm-release-debuginfo",143    "llvm.release-debuginfo",144    "build LLVM with debugger metadata",145)146v("debuginfo-level", "rust.debuginfo-level", "debuginfo level for Rust code")147v(148    "debuginfo-level-rustc",149    "rust.debuginfo-level-rustc",150    "debuginfo level for the compiler",151)152v(153    "debuginfo-level-std",154    "rust.debuginfo-level-std",155    "debuginfo level for the standard library",156)157v(158    "debuginfo-level-tools",159    "rust.debuginfo-level-tools",160    "debuginfo level for the tools",161)162v(163    "debuginfo-level-tests",164    "rust.debuginfo-level-tests",165    "debuginfo level for the test suites run with compiletest",166)167v(168    "save-toolstates",169    "rust.save-toolstates",170    "save build and test status of external tools into this file",171)172173v("prefix", "install.prefix", "set installation prefix")174v("localstatedir", "install.localstatedir", "local state directory")175v("datadir", "install.datadir", "install data")176v("sysconfdir", "install.sysconfdir", "install system configuration files")177v("infodir", "install.infodir", "install additional info")178v("libdir", "install.libdir", "install libraries")179v("mandir", "install.mandir", "install man pages in PATH")180v("docdir", "install.docdir", "install documentation in PATH")181v("bindir", "install.bindir", "install binaries")182183v("llvm-root", None, "set LLVM root")184v("llvm-config", None, "set path to llvm-config")185v("llvm-filecheck", None, "set path to LLVM's FileCheck utility")186v("python", "build.python", "set path to python")187v("android-ndk", "build.android-ndk", "set path to Android NDK")188v(189    "musl-root",190    "target.x86_64-unknown-linux-musl.musl-root",191    "MUSL root installation directory (deprecated)",192)193v(194    "musl-root-x86_64",195    "target.x86_64-unknown-linux-musl.musl-root",196    "x86_64-unknown-linux-musl install directory",197)198v(199    "musl-root-i586",200    "target.i586-unknown-linux-musl.musl-root",201    "i586-unknown-linux-musl install directory",202)203v(204    "musl-root-i686",205    "target.i686-unknown-linux-musl.musl-root",206    "i686-unknown-linux-musl install directory",207)208v(209    "musl-root-arm",210    "target.arm-unknown-linux-musleabi.musl-root",211    "arm-unknown-linux-musleabi install directory",212)213v(214    "musl-root-armhf",215    "target.arm-unknown-linux-musleabihf.musl-root",216    "arm-unknown-linux-musleabihf install directory",217)218v(219    "musl-root-armv5te",220    "target.armv5te-unknown-linux-musleabi.musl-root",221    "armv5te-unknown-linux-musleabi install directory",222)223v(224    "musl-root-armv7",225    "target.armv7-unknown-linux-musleabi.musl-root",226    "armv7-unknown-linux-musleabi install directory",227)228v(229    "musl-root-armv7hf",230    "target.armv7-unknown-linux-musleabihf.musl-root",231    "armv7-unknown-linux-musleabihf install directory",232)233v(234    "musl-root-aarch64",235    "target.aarch64-unknown-linux-musl.musl-root",236    "aarch64-unknown-linux-musl install directory",237)238v(239    "musl-root-mips",240    "target.mips-unknown-linux-musl.musl-root",241    "mips-unknown-linux-musl install directory",242)243v(244    "musl-root-mipsel",245    "target.mipsel-unknown-linux-musl.musl-root",246    "mipsel-unknown-linux-musl install directory",247)248v(249    "musl-root-mips64",250    "target.mips64-unknown-linux-muslabi64.musl-root",251    "mips64-unknown-linux-muslabi64 install directory",252)253v(254    "musl-root-mips64el",255    "target.mips64el-unknown-linux-muslabi64.musl-root",256    "mips64el-unknown-linux-muslabi64 install directory",257)258v(259    "musl-root-powerpc64",260    "target.powerpc64-unknown-linux-musl.musl-root",261    "powerpc64-unknown-linux-musl install directory",262)263v(264    "musl-root-powerpc64le",265    "target.powerpc64le-unknown-linux-musl.musl-root",266    "powerpc64le-unknown-linux-musl install directory",267)268v(269    "musl-root-riscv32gc",270    "target.riscv32gc-unknown-linux-musl.musl-root",271    "riscv32gc-unknown-linux-musl install directory",272)273v(274    "musl-root-riscv64gc",275    "target.riscv64gc-unknown-linux-musl.musl-root",276    "riscv64gc-unknown-linux-musl install directory",277)278v(279    "musl-root-loongarch64",280    "target.loongarch64-unknown-linux-musl.musl-root",281    "loongarch64-unknown-linux-musl install directory",282)283v(284    "musl-root-wali-wasm32",285    "target.wasm32-wali-linux-musl.musl-root",286    "wasm32-wali-linux-musl install directory",287)288v(289    "qemu-armhf-rootfs",290    "target.arm-unknown-linux-gnueabihf.qemu-rootfs",291    "rootfs in qemu testing, you probably don't want to use this",292)293v(294    "qemu-aarch64-rootfs",295    "target.aarch64-unknown-linux-gnu.qemu-rootfs",296    "rootfs in qemu testing, you probably don't want to use this",297)298v(299    "qemu-riscv64-rootfs",300    "target.riscv64gc-unknown-linux-gnu.qemu-rootfs",301    "rootfs in qemu testing, you probably don't want to use this",302)303v(304    "experimental-targets",305    "llvm.experimental-targets",306    "experimental LLVM targets to build",307)308v("release-channel", "rust.channel", "the name of the release channel to build")309v(310    "release-description",311    "build.description",312    "optional descriptive string for version output",313)314v("dist-compression-formats", None, "List of compression formats to use")315316# Used on systems where "cc" is unavailable317v("default-linker", "rust.default-linker", "the default linker")318319# Many of these are saved below during the "writing configuration" step320# (others are conditionally saved).321o("manage-submodules", "build.submodules", "let the build manage the git submodules")322o(323    "full-bootstrap",324    "build.full-bootstrap",325    "build three compilers instead of two (not recommended except for testing reproducible builds)",326)327o("extended", "build.extended", "build an extended rust tool set")328329v("bootstrap-cache-path", None, "use provided path for the bootstrap cache")330v("tools", None, "List of extended tools will be installed")331v("codegen-backends", None, "List of codegen backends to build")332v("build", "build.build", "GNUs ./configure syntax LLVM build triple")333v("host", None, "List of GNUs ./configure syntax LLVM host triples")334v("target", None, "List of GNUs ./configure syntax LLVM target triples")335336# Options specific to this configure script337o(338    "option-checking",339    None,340    "complain about unrecognized options in this configure script",341)342o(343    "verbose-configure",344    None,345    "don't truncate options when printing them in this configure script",346)347v("set", None, "set arbitrary key/value pairs in TOML configuration")348v(349    "parallel-frontend-threads",350    "rust.parallel-frontend-threads",351    "number of parallel threads for rustc compilation",352)353354355def p(msg):356    print("configure: " + msg)357358359def err(msg):360    print("\nconfigure: ERROR: " + msg + "\n")361    sys.exit(1)362363364def is_value_list(key):365    for option in options:366        if option.name == key and option.desc.startswith("List of"):367            return True368    return False369370371if "--help" in sys.argv or "-h" in sys.argv:372    print("Usage: ./configure [options]")373    print("")374    print("Options")375    for option in options:376        if "android" in option.name:377            # no one needs to know about these obscure options378            continue379        if option.value:380            print("\t{:30} {}".format("--{}=VAL".format(option.name), option.desc))381        else:382            print("\t--enable-{:25} OR --disable-{}".format(option.name, option.name))383            print("\t\t" + option.desc)384    print("")385    print("This configure script is a thin configuration shim over the true")386    print("configuration system, `bootstrap.toml`. You can explore the comments")387    print("in `bootstrap.example.toml` next to this configure script to see")388    print("more information about what each option is. Additionally you can")389    print("pass `--set` as an argument to set arbitrary key/value pairs")390    print("in the TOML configuration if desired")391    print("")392    print("Also note that all options which take `--enable` can similarly")393    print("be passed with `--disable-foo` to forcibly disable the option")394    sys.exit(0)395396VERBOSE = False397398399# Parse all command line arguments into one of these three lists, handling400# boolean and value-based options separately401def parse_args(args):402    unknown_args = []403    need_value_args = []404    known_args = {}405406    i = 0407    while i < len(args):408        arg = args[i]409        i += 1410        if not arg.startswith("--"):411            unknown_args.append(arg)412            continue413414        found = False415        for option in options:416            value = None417            if option.value:418                keyval = arg[2:].split("=", 1)419                key = keyval[0]420                if option.name != key:421                    continue422423                if len(keyval) > 1:424                    value = keyval[1]425                elif i < len(args):426                    value = args[i]427                    i += 1428                else:429                    need_value_args.append(arg)430                    continue431            else:432                if arg[2:] == "enable-" + option.name:433                    value = True434                elif arg[2:] == "disable-" + option.name:435                    value = False436                else:437                    continue438439            found = True440            if option.name not in known_args:441                known_args[option.name] = []442            known_args[option.name].append((option, value))443            break444445        if not found:446            unknown_args.append(arg)447448    # NOTE: here and a few other places, we use [-1] to apply the *last* value449    # passed.  But if option-checking is enabled, then the known_args loop will450    # also assert that options are only passed once.451    option_checking = (452        "option-checking" not in known_args or known_args["option-checking"][-1][1]453    )454    if option_checking:455        if len(unknown_args) > 0:456            err("Option '" + unknown_args[0] + "' is not recognized")457        if len(need_value_args) > 0:458            err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0]))459460    global VERBOSE461    VERBOSE = "verbose-configure" in known_args462463    config = {}464465    set("build.configure-args", args, config)466    apply_args(known_args, option_checking, config)467    return parse_example_config(known_args, config)468469470def build(known_args):471    if "build" in known_args:472        return known_args["build"][-1][1]473    return bootstrap.default_build_triple(verbose=False)474475476def set(key, value, config):477    if isinstance(value, list):478        # Remove empty values, which value.split(',') tends to generate and479        # replace single quotes for double quotes to ensure correct parsing.480        value = [v.replace("'", '"') for v in value if v]481482    s = "{:20} := {}".format(key, value)483    if len(s) < 70 or VERBOSE:484        p(s)485    else:486        p(s[:70] + " ...")487488    arr = config489490    # Split `key` on periods using shell semantics.491    lexer = shlex.shlex(key, posix=True)492    lexer.whitespace = "."493    lexer.wordchars += "-"494    parts = list(lexer)495496    for i, part in enumerate(parts):497        if i == len(parts) - 1:498            if is_value_list(part) and isinstance(value, str):499                value = value.split(",")500            arr[part] = value501        else:502            if part not in arr:503                arr[part] = {}504            arr = arr[part]505506507def apply_args(known_args, option_checking, config):508    for key in known_args:509        # The `set` option is special and can be passed a bunch of times510        if key == "set":511            for _option, value in known_args[key]:512                keyval = value.split("=", 1)513                if len(keyval) == 1 or keyval[1] == "true":514                    value = True515                elif keyval[1] == "false":516                    value = False517                else:518                    value = keyval[1]519                set(keyval[0], value, config)520            continue521522        # Ensure each option is only passed once523        arr = known_args[key]524        if option_checking and len(arr) > 1:525            err("Option '{}' provided more than once".format(key))526        option, value = arr[-1]527528        # If we have a clear avenue to set our value in rustbuild, do so529        if option.rustbuild is not None:530            set(option.rustbuild, value, config)531            continue532533        # Otherwise we're a "special" option and need some extra handling, so do534        # that here.535        build_triple = build(known_args)536537        if option.name == "sccache":538            set("build.ccache", "sccache", config)539        elif option.name == "local-rust":540            for path in os.environ["PATH"].split(os.pathsep):541                if os.path.exists(path + "/rustc"):542                    set("build.rustc", path + "/rustc", config)543                    break544            for path in os.environ["PATH"].split(os.pathsep):545                if os.path.exists(path + "/cargo"):546                    set("build.cargo", path + "/cargo", config)547                    break548        elif option.name == "local-rust-root":549            set("build.rustc", value + "/bin/rustc", config)550            set("build.cargo", value + "/bin/cargo", config)551        elif option.name == "llvm-root":552            set(553                "target.{}.llvm-config".format(build_triple),554                value + "/bin/llvm-config",555                config,556            )557        elif option.name == "llvm-config":558            set("target.{}.llvm-config".format(build_triple), value, config)559        elif option.name == "llvm-filecheck":560            set("target.{}.llvm-filecheck".format(build_triple), value, config)561        elif option.name == "tools":562            set("build.tools", value.split(","), config)563        elif option.name == "bootstrap-cache-path":564            set("build.bootstrap-cache-path", value, config)565        elif option.name == "codegen-backends":566            set("rust.codegen-backends", value.split(","), config)567        elif option.name == "host":568            set("build.host", value.split(","), config)569        elif option.name == "target":570            set("build.target", value.split(","), config)571        elif option.name == "full-tools":572            set("rust.codegen-backends", ["llvm"], config)573            set("rust.lld", True, config)574            set("rust.llvm-tools", True, config)575            set("rust.llvm-bitcode-linker", True, config)576            set("build.extended", True, config)577        elif option.name in ["option-checking", "verbose-configure"]:578            # this was handled above579            pass580        elif option.name == "dist-compression-formats":581            set("dist.compression-formats", value.split(","), config)582        else:583            raise RuntimeError("unhandled option {}".format(option.name))584585586# "Parse" the `bootstrap.example.toml` file into the various sections, and we'll587# use this as a template of a `bootstrap.toml` to write out which preserves588# all the various comments and whatnot.589#590# Note that the `target` section is handled separately as we'll duplicate it591# per configured target, so there's a bit of special handling for that here.592def parse_example_config(known_args, config):593    sections = {}594    cur_section = None595    sections[None] = []596    section_order = [None]597    targets = {}598    top_level_keys = []599    comment_lines = []600601    with open(rust_dir + "/bootstrap.example.toml", encoding="utf-8") as example_config:602        example_lines = example_config.read().split("\n")603    for line in example_lines:604        if line.count("=") >= 1 and not line.startswith("# "):605            key = line.split("=")[0]606            key = key.strip(" #")607            parts = key.split(".")608            if len(parts) > 1:609                cur_section = parts[0]610                if cur_section not in sections:611                    sections[cur_section] = ["[" + cur_section + "]"]612                    section_order.append(cur_section)613            elif cur_section is None:614                top_level_keys.append(key)615            # put the comment lines within the start of616            # a new section, not outside it.617            sections[cur_section] += comment_lines618            comment_lines = []619            # remove just the `section.` part from the line, if present.620            sections[cur_section].append(621                re.sub("(#?)([a-zA-Z_-]+\\.)?(.*)", "\\1\\3", line)622            )623        elif line.startswith("["):624            cur_section = line[1:-1]625            if cur_section.startswith("target"):626                cur_section = "target"627            elif "." in cur_section:628                raise RuntimeError(629                    "don't know how to deal with section: {}".format(cur_section)630                )631            sections[cur_section] = [line]632            section_order.append(cur_section)633        else:634            comment_lines.append(line)635636    sections[cur_section] += comment_lines637    # Fill out the `targets` array by giving all configured targets a copy of the638    # `target` section we just loaded from the example config639    configured_targets = [build(known_args)]640    if "build" in config:641        if "host" in config["build"]:642            configured_targets += config["build"]["host"]643        if "target" in config["build"]:644            configured_targets += config["build"]["target"]645    if "target" in config:646        for target in config["target"]:647            configured_targets.append(target)648    for target in configured_targets:649        targets[target] = sections["target"][:]650        # For `.` to be valid TOML, it needs to be quoted. But `bootstrap.py` doesn't use a proper TOML parser and fails to parse the target.651        # Avoid using quotes unless it's necessary.652        targets[target][0] = targets[target][0].replace(653            "x86_64-unknown-linux-gnu",654            "'{}'".format(target) if "." in target else target,655        )656657    if "profile" not in config:658        set("profile", "dist", config)659    configure_file(sections, top_level_keys, targets, config)660    return section_order, sections, targets661662663def is_number(value):664    try:665        float(value)666        return True667    except ValueError:668        return False669670671# Here we walk through the constructed configuration we have from the parsed672# command line arguments. We then apply each piece of configuration by673# basically just doing a `sed` to change the various configuration line to what674# we've got configure.675def to_toml(value):676    if isinstance(value, bool):677        if value:678            return "true"679        else:680            return "false"681    elif isinstance(value, list):682        return "[" + ", ".join(map(to_toml, value)) + "]"683    elif isinstance(value, str):684        # Don't put quotes around numeric values685        if is_number(value):686            return value687        else:688            return "'" + value + "'"689    elif isinstance(value, dict):690        return (691            "{"692            + ", ".join(693                map(694                    lambda a: "{} = {}".format(to_toml(a[0]), to_toml(a[1])),695                    value.items(),696                )697            )698            + "}"699        )700    else:701        raise RuntimeError("no toml")702703704def configure_section(lines, config):705    for key in config:706        value = config[key]707        found = False708        for i, line in enumerate(lines):709            if not line.startswith("#" + key + " = "):710                continue711            found = True712            lines[i] = "{} = {}".format(key, to_toml(value))713            break714        if not found:715            # These are used by rpm, but aren't accepted by x.py.716            # Give a warning that they're ignored, but not a hard error.717            if key in ["infodir", "localstatedir"]:718                print("WARNING: {} will be ignored".format(key))719            else:720                raise RuntimeError("failed to find config line for {}".format(key))721722723def configure_top_level_key(lines, top_level_key, value):724    for i, line in enumerate(lines):725        if line.startswith("#" + top_level_key + " = ") or line.startswith(726            top_level_key + " = "727        ):728            lines[i] = "{} = {}".format(top_level_key, to_toml(value))729            return730731    raise RuntimeError("failed to find config line for {}".format(top_level_key))732733734# Modify `sections` to reflect the parsed arguments and example configs.735def configure_file(sections, top_level_keys, targets, config):736    for section_key, section_config in config.items():737        if section_key not in sections and section_key not in top_level_keys:738            raise RuntimeError(739                "config key {} not in sections or top_level_keys".format(section_key)740            )741        if section_key in top_level_keys:742            configure_top_level_key(sections[None], section_key, section_config)743744        elif section_key == "target":745            for target in section_config:746                configure_section(targets[target], section_config[target])747        else:748            configure_section(sections[section_key], section_config)749750751def write_uncommented(target, f):752    """Writes each block in 'target' that is not composed entirely of comments to 'f'.753754    A block is a sequence of non-empty lines separated by empty lines.755    """756    block = []757758    def flush(last):759        # If the block is entirely made of comments, ignore it760        entire_block_comments = all(ln.startswith("#") or ln == "" for ln in block)761        if not entire_block_comments and len(block) > 0:762            for line in block:763                f.write(line + "\n")764            # Required to output a newline before the start of a new section765            if last:766                f.write("\n")767        block.clear()768769    for line in target:770        block.append(line)771        if len(line) == 0:772            flush(last=False)773774    flush(last=True)775    return f776777778def write_config_toml(writer, section_order, targets, sections):779    for section in section_order:780        if section == "target":781            for target in targets:782                writer = write_uncommented(targets[target], writer)783        else:784            writer = write_uncommented(sections[section], writer)785786787def quit_if_file_exists(file):788    if os.path.isfile(file):789        msg = "Existing '{}' detected. Exiting".format(file)790791        # If the output object directory isn't empty, we can get these errors792        host_objdir = os.environ.get("OBJDIR_ON_HOST")793        if host_objdir is not None:794            msg += "\nIs objdir '{}' clean?".format(host_objdir)795796        err(msg)797798799if __name__ == "__main__":800    # If 'bootstrap.toml' already exists, exit the script at this point801    quit_if_file_exists("bootstrap.toml")802803    if "GITHUB_ACTIONS" in os.environ:804        print("::group::Configure the build")805    p("processing command line")806    # Parse all known arguments into a configuration structure that reflects the807    # TOML we're going to write out808    p("")809    section_order, sections, targets = parse_args(sys.argv[1:])810811    # Now that we've built up our `bootstrap.toml`, write it all out in the same812    # order that we read it in.813    p("")814    p("writing `bootstrap.toml` in current directory")815    with bootstrap.output("bootstrap.toml") as f:816        write_config_toml(f, section_order, targets, sections)817818    with bootstrap.output("Makefile") as f:819        contents = os.path.join(rust_dir, "src", "bootstrap", "mk", "Makefile.in")820        contents = open(contents).read()821        contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + "/")822        contents = contents.replace("$(CFG_PYTHON)", sys.executable)823        f.write(contents)824825    p("")826    p("run `{} {}/x.py --help`".format(os.path.basename(sys.executable), rust_dir))827    if "GITHUB_ACTIONS" in os.environ:828        print("::endgroup::")

Code quality findings 48

Ensure functions have docstrings for documentation
missing-docstring
def o(*args):
Ensure functions have docstrings for documentation
missing-docstring
def v(*args):
Ensure functions have docstrings for documentation
missing-docstring
def p(msg):
Use logging module for better control and configurability
print-statement
print("configure: " + msg)
Ensure functions have docstrings for documentation
missing-docstring
def err(msg):
Use logging module for better control and configurability
print-statement
print("\nconfigure: ERROR: " + msg + "\n")
Ensure functions have docstrings for documentation
missing-docstring
def is_value_list(key):
Use logging module for better control and configurability
print-statement
print("Usage: ./configure [options]")
Use logging module for better control and configurability
print-statement
print("")
Use logging module for better control and configurability
print-statement
print("Options")
Use logging module for better control and configurability
print-statement
print("\t{:30} {}".format("--{}=VAL".format(option.name), option.desc))
Use logging module for better control and configurability
print-statement
print("\t--enable-{:25} OR --disable-{}".format(option.name, option.name))
Use logging module for better control and configurability
print-statement
print("\t\t" + option.desc)
Use logging module for better control and configurability
print-statement
print("")
Use logging module for better control and configurability
print-statement
print("This configure script is a thin configuration shim over the true")
Use logging module for better control and configurability
print-statement
print("configuration system, `bootstrap.toml`. You can explore the comments")
Use logging module for better control and configurability
print-statement
print("in `bootstrap.example.toml` next to this configure script to see")
Use logging module for better control and configurability
print-statement
print("more information about what each option is. Additionally you can")
Use logging module for better control and configurability
print-statement
print("pass `--set` as an argument to set arbitrary key/value pairs")
Use logging module for better control and configurability
print-statement
print("in the TOML configuration if desired")
Use logging module for better control and configurability
print-statement
print("")
Use logging module for better control and configurability
print-statement
print("Also note that all options which take `--enable` can similarly")
Use logging module for better control and configurability
print-statement
print("be passed with `--disable-foo` to forcibly disable the option")
Ensure functions have docstrings for documentation
missing-docstring
def parse_args(args):
Avoid global variables; use function parameters or class attributes for better scope management
global-variable
global VERBOSE
Ensure functions have docstrings for documentation
missing-docstring
def build(known_args):
Ensure functions have docstrings for documentation
missing-docstring
def set(key, value, config):
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
if isinstance(value, list):
Avoid unnecessary list conversions; use generators where possible
unnecessary-list
parts = list(lexer)
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
if is_value_list(part) and isinstance(value, str):
Ensure functions have docstrings for documentation
missing-docstring
def apply_args(known_args, option_checking, config):
Ensure functions have docstrings for documentation
missing-docstring
def parse_example_config(known_args, config):
Ensure functions have docstrings for documentation
missing-docstring
def is_number(value):
Ensure functions have docstrings for documentation
missing-docstring
def to_toml(value):
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
if isinstance(value, bool):
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
elif isinstance(value, list):
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
elif isinstance(value, str):
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
elif isinstance(value, dict):
Ensure functions have docstrings for documentation
missing-docstring
def configure_section(lines, config):
Use logging module for better control and configurability
print-statement
print("WARNING: {} will be ignored".format(key))
Ensure functions have docstrings for documentation
missing-docstring
def configure_top_level_key(lines, top_level_key, value):
Ensure functions have docstrings for documentation
missing-docstring
def configure_file(sections, top_level_keys, targets, config):
Ensure functions have docstrings for documentation
missing-docstring
def flush(last):
Ensure functions have docstrings for documentation
missing-docstring
def write_config_toml(writer, section_order, targets, sections):
Ensure functions have docstrings for documentation
missing-docstring
def quit_if_file_exists(file):
Use logging module for better control and configurability
print-statement
print("::group::Configure the build")
Use logging module for better control and configurability
print-statement
print("::endgroup::")
Avoid complex 'lambda' functions; prefer named functions for clarity and debugging
info maintainability complex-lambda
lambda a: "{} = {}".format(to_toml(a[0]), to_toml(a[1])),

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.