CLion[1] is a fantastic IDE. And I say this as a lifelong emacs[2] evangelist, so you know it pains me to say that. On top of being a fantastic IDE, it also has first-class support for Rust, so it's my daily driver these days.
There has been one minor issue I've experienced though - in my AVR projects code insight and some features (like detecting which `#[cfg(...)]` directives are enabled) don't work properly from CLion. With the invaluable help of Anna at JetBrains[3] I've managed to work out what the problem is, and a workaround.
The problem is fundamentally a bug in Rust, rather than with CLion per se. CLion uses the `cargo rustc --print cfg` command to identify the current build configuration for a project. Unfortunately, when you use a custom JSON target specification, like this in `.cargo/config.toml`...
[build] target = "target-specs/avr-atmega4809.json"
...that `cargo rustc --print cfg` command fails, like so:
timwa% cargo rustc -Z unstable-options --print cfg error: Error loading target specification: Could not find specification for target "avr-atmega4809". Run `rustc --print target-list` for a list of built-in targets
It seems the `--print cfg` command doesn't properly parse our config file.
Fortunately, there is a workaround. If we set the `RUST_TARGET_PATH` to the directory containing our target JSON file, then it will work:
timwa% setenv RUST_TARGET_PATH target-specs timwa% cargo rustc -Z unstable-options --print cfg debug_assertions panic="unwind" target_abi="" target_arch="avr" target_endian="little" target_env="" target_has_atomic_equal_alignment="8" target_has_atomic_load_store="8" target_os="unknown" target_pointer_width="16" target_vendor="unknown"
Of course, now that we know the workaround, we want a way to set that environment variable on a per-project basis (not all my projects use a custom target.json, and even if they did it might not always be in the same place...)
Looking at the documentation for `.cargo/config.toml` might suggest we can use an `[env]` section. Unfortunately, that doesn't work for some reason (the documented environment variable substitution doesn't seem to take place when `rustc` is invoked directly with `cargo rustc`.)
What does work though is providing a small wrapper-script that will wrap the `rustc` invocation.
Modify your `.cargo/config.toml` like so:
[build] target = "target-specs/avr-atmega4809.json" rustc-wrapper = "./rustc-wrapper.sh"
Create a wrapper script that looks something like this:
#!/bin/sh # rustc-wrapper # # Use this script in the `[build]`,`rustc-wrapper` section of your # `.cargo/config.toml` configuration file to correctly set the # `RUST_TARGET_PATH` environment variable before running rustc. # # This is to workaround a bug whereby `rustc --print cfg` fails when you # use a custom `target.json` file, unless `RUST_TARGET_PATH` is set to the # directory containing the target description. # `cargo` passes "rustc " as the first parameter to the wrapper; pop it off shift # Extract the target config JSON from the `config.toml` # # NOTE: We assume that this wrapper script is in the root of your project, and # that the `build.target` value is relative to the location of the same. # TARGET_JSON_FILE=$(cargo config -Z unstable-options get --format json-value build.target 2>/dev/null || echo "") if [ ! -z "${TARGET_JSON_FILE}" ]; then TARGET_JSON_DIR=$(dirname "${TARGET_JSON_FILE//\"/}") # Work out where we are and which rustup we're wrapping BASEDIR=$(dirname "$0") # Set the env variable export RUST_TARGET_PATH="${BASEDIR}/${TARGET_JSON_DIR}" fi RUSTC=$(rustup which rustc) # Now let rustc do its thing "${RUSTC}" $@
And, hey presto - working code insights in CLion :-).
1: https://www.jetbrains.com/clion/
2: https://www.gnu.org/software/emacs/
3: https://toolbox-support.jetbrains.com/hc/en-us/profiles/1283061991-Anna-Filippova
--------------------