rustc Command Line Arguments

Purpose and Scope

This page explains how to read the rustc command line as both a user-facing interface and a source-level contract inside the Rust repository. rustc is the Rust compiler executable: it takes a crate root, applies compilation configuration, resolves dependencies and native libraries, emits artifacts or printed metadata, and may invoke backend or linker commands as part of the build. Most Rust programmers reach this interface through Cargo, but the rustc book documents the flags directly so build-system authors, compiler contributors, and advanced users can understand what Cargo is ultimately asking the compiler to do.

The repository separates the public explanation of flags from implementation helpers that build and test command invocations. The rustc documentation page lists stable command-line arguments such as help, configuration, library search paths, and native library linkage. A separate print-options page documents information queries routed through --print. Related command wrappers in codegen, bootstrap support, and run-make tests show why command-line shape matters after parsing: arguments may become linker invocations, response-file inputs, or test subprocesses whose success and output must be checked. Sources: src/doc/rustc/src/command-line-arguments.md, src/doc/rustc/src/command-line-arguments/print-options.md, compiler/rustc_codegen_ssa/src/back/command.rs, src/build_helper/src/arg_file_command.rs, src/tools/run-make-support/src/command.rs

A useful mental model is that rustc accepts one crate root plus options that describe the environment in which that crate is compiled. The official rustc documentation emphasizes that users do not pass every module file to rustc; module declarations in the crate root lead the compiler to the rest of the crate. Command-line flags therefore configure the translation unit, not a list of independent source files in the C compiler sense. That model explains why flags like --cfg, --check-cfg, -L, and -l are about the compilation environment and final linkage rather than per-file compilation tasks.

Relevant Source Files

  • src/doc/rustc/src/command-line-arguments.md — user-facing rustc book chapter for stable command-line arguments such as -h, --cfg, --check-cfg, -L, and -l.
  • src/doc/rustc/src/command-line-arguments/print-options.md — rustc book reference for --print information kinds, output ordering, stdout versus file output, and examples such as crate-name, sysroot, cfg, and target queries.
  • src/doc/rustdoc/src/command-line-arguments.md — companion rustdoc command-line reference showing shared option concepts, including --cfg, --check-cfg, dependency search paths, and --extern.
  • compiler/rustc_codegen_ssa/src/back/command.rs — backend command wrapper that records arguments and environment changes before spawning linker-like tools, including normal programs, Windows batch scripts, and LLD invocations.
  • src/build_helper/src/arg_file_command.rs — bootstrap/build helper wrapper that switches long command lines to argument files when OS limits are likely to be exceeded.
  • src/tools/run-make-support/src/command.rs — test-support command wrapper used by run-make tests to enforce that commands are executed and that exit status and captured output are checked.

Public Command-Line Surface

The stable rustc command-line reference begins with basic discovery and configuration flags. -h and --help print built-in help, which is the fastest way to inspect the compiler installed on the local toolchain. --cfg activates conditional compilation settings. It accepts either a single identifier, such as verbose, or a key-value form such as feature="serde"; those values correspond directly to #[cfg(verbose)] and #[cfg(feature = "serde")] in source. This flag changes what code is considered active during compilation, so it is a build input just like the crate root. Sources: src/doc/rustc/src/command-line-arguments.md

--check-cfg is intentionally different from --cfg. Where --cfg activates a configuration, --check-cfg defines the expected configuration names and values that should be accepted when reachable #[cfg] attributes are checked. This is a diagnostics-oriented option: it helps catch stale conditions, misspelled names, and unexpected values without itself enabling the condition. The rustc book examples use forms such as cfg(verbose) and cfg(feature, values("serde")), making the expected set explicit. For build systems, this means generated invocations should not treat --cfg and --check-cfg as interchangeable switches.

Library discovery and native linkage are represented by -L and -l. The -L flag appends directories to the search path for external crates and native libraries, with an optional kind prefix such as dependency, crate, native, framework, or all. The -l flag specifies a native library to link, using syntax that can include a kind, modifiers, the library name, and an optional rename. The rustc book calls out dynamic libraries, static libraries, and macOS frameworks, and it also documents command-line overrides for names declared in #[link] attributes. These flags bridge Rust compilation and platform linkers. Sources: src/doc/rustc/src/command-line-arguments.md

A compact first-use sequence looks like this:

rustc -h
rustc --cfg 'feature="serde"' main.rs
rustc --check-cfg 'cfg(feature, values("serde"))' main.rs
rustc -L dependency=target/debug/deps main.rs
rustc -l static:+whole-archive=mylib main.rs

These commands illustrate the main categories rather than a complete build recipe. Help is introspection, --cfg is environment activation, --check-cfg is environment validation, -L is search-path configuration, and -l is native library linkage. In practice, Cargo usually constructs these invocations for ordinary packages, but seeing them directly is useful when debugging verbose Cargo output or integrating Rust compilation into a non-Cargo build system.

The --print flag turns rustc into an information query tool. The print-options documentation states that multiple print kinds can be specified, and output is produced in the order requested. Specifying a print option usually disables the normal --emit step and prints the requested information instead. A print request can also be redirected to a file with the form --print KIND=PATH, mirroring the --emit style of associating an output kind with a destination. This makes --print useful for build-system probing without requiring the caller to parse generated artifacts. Sources: src/doc/rustc/src/command-line-arguments/print-options.md

Several print kinds describe naming and installation layout. crate-name prints the crate name selected from a crate attribute, the --crate-name flag, or the input filename. file-names reports the files produced by link emission. sysroot returns the absolute path to the compiler sysroot, while target-libdir returns the target-specific library directory. host-tuple reports the host compiler target tuple and remains the host tuple even when a different --target is passed. These options help tooling discover where the compiler and libraries live without hard-coding rustup or distribution paths.

Other print kinds describe compilation target capabilities. cfg prints the active configuration values for the selected target, including entries such as target architecture, endian, operating system, panic strategy, atomic widths, and target features. target-list enumerates known targets, while target-cpus and target-features expose target-specific tuning choices. relocation-models, code-models, and tls-models enumerate lower-level code generation selections tied to -C or -Z options. Because some of these values are target-dependent, build scripts and external systems should pass the same target-related arguments they intend to use for compilation when probing. Sources: src/doc/rustc/src/command-line-arguments/print-options.md

A representative probing session might look like this:

rustc --print crate-name --crate-name my_crate a.rs
rustc --print sysroot a.rs
rustc --print cfg --target x86_64-unknown-linux-gnu a.rs
rustc --print target-list
rustc --print target-features --target x86_64-unknown-linux-gnu a.rs

The important operational detail is that these commands are not merely human-readable help pages. They are part of the compiler interface that tools can call to learn names, paths, targets, and capability lists. When a caller redirects a print kind to a path, it should treat the result as a generated output of the compiler process, even if no object code or executable is emitted.

System-to-Code Mapping

The documentation files describe the public option vocabulary, while command wrapper modules show how the repository preserves and manipulates process arguments after option selection. In code generation, compiler/rustc_codegen_ssa/src/back/command.rs defines a thin wrapper around std::process::Command that stores the program, argument vector, environment additions, removed variables, and an environment-clear flag. It supports normal programs, Windows batch scripts, and LLD invocations, with the LLD variant automatically adding -flavor and the selected flavor description. Sources: compiler/rustc_codegen_ssa/src/back/command.rs

That codegen wrapper matters because compiler command-line behavior does not stop at parsing rustc flags. Some rustc options eventually influence backend and linker subprocesses. The wrapper exposes arg, args, env, env_remove, env_clear, output, and command, plus extensions such as get_args and take_args. Those extensions are specifically useful because the wrapper can inspect the built-up argument list before spawning. The implementation also contains logic for estimating whether a command is very likely to exceed OS spawn limits, which connects directly to the repository’s broader response-file strategy.

Bootstrap and build tooling use a related but separate helper, ArgFileCommand, in src/build_helper/src/arg_file_command.rs. This wrapper roughly follows the std::process::Command API while holding arguments until build is called. On Windows it uses a threshold around thirty kilobytes to stay below the hard command-line limit; on Unix it derives a threshold from ARG_MAX or defaults to one megabyte. If the accumulated arguments are short enough, it passes them normally. If they exceed the threshold, it writes one argument per line to a temporary file and invokes the program with an @path argument. Sources: src/build_helper/src/arg_file_command.rs

The argument-file helper also documents constraints that command producers must respect. Arguments written to the file must be valid UTF-8 and may not contain newlines; otherwise build returns an error. The helper deliberately avoids response files when the command is not close to the operating-system limit because response files make debugging more complicated. This is a concrete implementation tradeoff behind long rustc, linker, or test commands: reliability across platforms is balanced against the need for invocations to remain easy to inspect.

Relationship to rustdoc and Other Tool Commands

The rustdoc command-line reference is not the rustc reference, but it is useful context because rustdoc accepts several concepts with the same meaning. The rustdoc page documents -h and --help, --crate-name, -L and --library-path, --cfg, --check-cfg, and --extern. It also explains rustdoc-specific behavior such as output directory selection and documenting private items. The shared flags reinforce that Rust tools often need the same crate-configuration and dependency-location inputs, even when the tool output is documentation rather than object code or an executable. Sources: src/doc/rustdoc/src/command-line-arguments.md

For developers writing automation around Rust tools, this means command construction should be explicit rather than stringly typed. A wrapper should preserve argument boundaries, pass repeated flags in the order intended by the tool, and avoid shell-dependent quoting assumptions. The repository’s command wrappers do exactly that by storing OsString arguments and passing them to std::process::Command as a vector. When documentation examples show shell quoting around --cfg 'feature="serde"', the quote characters belong to the shell example; an API caller should pass the cfg expression as a single argument value, not as a pre-split shell command line.

Testing and Operational Signals

The run-make support command wrapper in src/tools/run-make-support/src/command.rs shows how compiler command behavior is validated in repository tests. It wraps std::process::Command with a runtime-enforced linear-use discipline: a command is armed with a drop bomb when constructed, and execution methods defuse it. If a test constructs a command and never runs it, the drop bomb causes a panic. This prevents tests from silently giving confidence without actually invoking the process they intended to check. Sources: src/tools/run-make-support/src/command.rs

The same test wrapper also tracks standard input, output, and error configuration, supports a convenience stdin buffer, carries contextual error messages, and exposes environment manipulation. That design is especially relevant for command-line documentation because command behavior is observable through process status and streams. A test that runs rustc --print cfg, for example, needs to assert on stdout and success; a test that expects a bad flag or invalid argument-file content should assert on failure and diagnostics. The wrapper’s purpose is to make those expectations explicit in tests rather than relying on incidental process execution.

When debugging command-line behavior in this repository, start from the user-facing documentation to identify the intended stable contract, then inspect command construction code only for the phase you are investigating. For flag meaning, use src/doc/rustc/src/command-line-arguments.md and src/doc/rustc/src/command-line-arguments/print-options.md. For backend or linker process construction, use compiler/rustc_codegen_ssa/src/back/command.rs. For bootstrap or long-command failures, use src/build_helper/src/arg_file_command.rs. For run-make test behavior, use src/tools/run-make-support/src/command.rs.