# Non-Cargo Based Projects

rust-analyzer does not require Cargo. However, if you use some other
build system, you’ll have to describe the structure of your project for
rust-analyzer in the `rust-project.json` format:

```typescript
interface ProjectJson {
    /// Path to the sysroot directory.
    ///
    /// The sysroot is where rustc looks for the
    /// crates that are built-in to rust, such as
    /// std.
    ///
    /// https://doc.rust-lang.org/rustc/command-line-arguments.html#--sysroot-override-the-system-root
    ///
    /// To see the current value of sysroot, you
    /// can query rustc:
    ///
    /// ```
    /// $ rustc --print sysroot
    /// /Users/yourname/.rustup/toolchains/stable-x86_64-apple-darwin
    /// ```
    sysroot?: string;
    /// Path to the directory with *source code* of
    /// sysroot crates.
    ///
    /// By default, this is `lib/rustlib/src/rust/library`
    /// relative to the sysroot.
    ///
    /// It should point to the directory where std,
    /// core, and friends can be found:
    ///
    /// https://github.com/rust-lang/rust/tree/HEAD/library.
    ///
    /// If provided, rust-analyzer automatically adds
    /// dependencies on sysroot crates. Conversely,
    /// if you omit this path, you can specify sysroot
    /// dependencies yourself and, for example, have
    /// several different "sysroots" in one graph of
    /// crates.
    sysroot_src?: string;
    /// A ProjectJson describing the crates of the sysroot.
    sysroot_project?: ProjectJson;

    /// List of groups of common cfg values, to allow
    /// sharing them between crates.
    ///
    /// Maps from group name to its cfgs. Cfg follow
    /// the same format as `Crate.cfg`.
    cfg_groups?: { [key: string]: string[]; };
    /// The set of crates comprising the current
    /// project. Must include all transitive
    /// dependencies as well as sysroot crate (libstd,
    /// libcore and such).
    crates: Crate[];
    /// Configuration for CLI commands.
    ///
    /// These are used for running and debugging binaries
    /// and tests without encoding build system-specific
    /// knowledge into rust-analyzer.
    ///
    /// # Example
    ///
    /// Below is an example of a test runnable. `{label}` and `{test_id}`
    /// are explained in `Runnable::args`'s documentation below.
    ///
    /// ```json
    /// {
    ///     "program": "buck",
    ///     "args": [
    ///         "test",
    ///          "{label}",
    ///          "--",
    ///          "{test_id}",
    ///          "--print-passing-details"
    ///     ],
    ///     "cwd": "/home/user/repo-root/",
    ///     "kind": "testOne"
    /// }
    /// ```
    runnables?: Runnable[];
}

interface Crate {
    /// Optional crate name used for display purposes,
    /// without affecting semantics. See the `deps`
    /// key for semantically-significant crate names.
    display_name?: string;
    /// Path to the root module of the crate.
    root_module: string;
    /// Edition of the crate.
    edition: '2015' | '2018' | '2021' | '2024';
    /// The version of the crate. Used for calculating
    /// the correct docs.rs URL.
    version?: string;
    /// Dependencies
    deps: Dep[];
    /// Should this crate be treated as a member of
    /// current "workspace".
    ///
    /// By default, inferred from the `root_module`
    /// (members are the crates which reside inside
    /// the directory opened in the editor).
    ///
    /// Set this to `false` for things like standard
    /// library and 3rd party crates to enable
    /// performance optimizations (rust-analyzer
    /// assumes that non-member crates don't change).
    is_workspace_member?: boolean;
    /// Optionally specify the (super)set of `.rs`
    /// files comprising this crate.
    ///
    /// By default, rust-analyzer assumes that only
    /// files under `root_module.parent` can belong
    /// to a crate. `include_dirs` are included
    /// recursively, unless a subdirectory is in
    /// `exclude_dirs`.
    ///
    /// Different crates can share the same `source`.
    ///
    /// If two crates share an `.rs` file in common,
    /// they *must* have the same `source`.
    /// rust-analyzer assumes that files from one
    /// source can't refer to files in another source.
    source?: {
        include_dirs: string[];
        exclude_dirs: string[];
    };
    /// List of cfg groups this crate inherits.
    ///
    /// All cfg in these groups will be concatenated to
    /// `cfg`. It is impossible to replace a value from
    /// the groups.
    cfg_groups?: string[];
    /// The set of cfgs activated for a given crate, like
    /// `["unix", "feature=\"foo\"", "feature=\"bar\""]`.
    cfg: string[];
    /// Target tuple for this Crate.
    ///
    /// Used when running `rustc --print cfg`
    /// to get target-specific cfgs.
    target?: string;
    /// Environment variables, used for
    /// the `env!` macro
    env: { [key: string]: string; };
    /// Extra crate-level attributes applied to this crate.
    ///
    /// rust-analyzer will behave as if these attributes
    /// were present before the first source line of the
    /// crate root.
    ///
    /// Each string should contain the contents of a `#![...]`
    /// crate-level attribute, without the surrounding `#![]`.
    crate_attrs?: string[];

    /// Whether the crate is a proc-macro crate.
    is_proc_macro: boolean;
    /// For proc-macro crates, path to compiled
    /// proc-macro (.so file).
    proc_macro_dylib_path?: string;

    /// Repository, matching the URL that would be used
    /// in Cargo.toml.
    repository?: string;

    /// Build-specific data about this crate.
    build?: BuildInfo;
}

interface Dep {
    /// Index of a crate in the `crates` array.
    crate: number;
    /// Name as should appear in the (implicit)
    /// `extern crate name` declaration.
    name: string;
}

interface BuildInfo {
    /// The name associated with this crate.
    ///
    /// This is determined by the build system that produced
    /// the `rust-project.json` in question. For instance, if buck were used,
    /// the label might be something like `//ide/rust/rust-analyzer:rust-analyzer`.
    ///
    /// Do not attempt to parse the contents of this string; it is a build system-specific
    /// identifier similar to `Crate::display_name`.
    label: string;
    /// Path corresponding to the build system-specific file defining the crate.
    build_file: string;
    /// The kind of target.
    ///
    /// This information is used to determine what sort
    /// of runnable codelens to provide, if any.
    target_kind: 'bin' | 'lib' | 'test';
}

interface Runnable {
    /// The program invoked by the runnable.
    ///
    /// For example, this might be `cargo`, `buck`, or `bazel`.
    program: string;
    /// The arguments passed to `program`.
    args: string[];
    /// The current working directory of the runnable.
    cwd: string;
    /// Used to decide what code lens to offer.
    ///
    /// `testOne`: This runnable will be used when the user clicks the 'Run Test'
    /// CodeLens above a test.
    ///
    /// The args for testOne can contain two template strings:
    /// `{label}` and `{test_id}`. `{label}` will be replaced
    /// with the `Build::label` and `{test_id}` will be replaced
    /// with the test name.
    kind: 'testOne' | string;
}
```

This format is provisional and subject to change. Specifically, the
`roots` setup will be different eventually.

There are three ways to feed `rust-project.json` to rust-analyzer:

-   Place `rust-project.json` file at the root of the project, and
    rust-analyzer will discover it.

-   Specify
    `"rust-analyzer.linkedProjects": [ "path/to/rust-project.json" ]` in
    the settings (and make sure that your LSP client sends settings as a
    part of initialize request).

-   Specify
    `"rust-analyzer.linkedProjects": [ { "roots": […​], "crates": […​] }]`
    inline.

Relative paths are interpreted relative to `rust-project.json` file
location or (for inline JSON) relative to `rootUri`.

You can set the `RA_LOG` environment variable to `rust_analyzer=info` to
inspect how rust-analyzer handles config and project loading.

Note that calls to `cargo check` are disabled when using
`rust-project.json` by default, so compilation errors and warnings will
no longer be sent to your LSP client. To enable these compilation errors
you will need to specify explicitly what command rust-analyzer should
run to perform the checks using the
`rust-analyzer.check.overrideCommand` configuration. As an example, the
following configuration explicitly sets `cargo check` as the `check`
command.

    { "rust-analyzer.check.overrideCommand": ["cargo", "check", "--message-format=json"] }

`check.overrideCommand` requires the command specified to output json
error messages for rust-analyzer to consume. The `--message-format=json`
flag does this for `cargo check` so whichever command you use must also
output errors in this format. See the [Configuration](#_configuration)
section for more information.
