rust-lang / rust-lang/rust-clippy

Lint for `cfg` usage which would provide a misleading result in a build script.

Open
#9,419 4 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

A-lint
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

What it does

Lints for uses of cfg!, #[cfg], #[cfg_attr] with keys which will have misleading[^1] values when used inside build scripts (e.g. build.rs files), such as windows, unix, and the ones that begin with target_*.

This is a restriction lint, as I'm assuming Clippy has no way of figuring out if we're in a build script on it's own (it seems completely impossible, as build scripts are just normal rust code).

The idea is that developers of build scripts that support cross compilation can add something like #![deny(clippy::misleading_cfg_in_build_script)].

[^1]: These will report the values for the host, not the target, e.g. cfg!(windows) is true when compiling on Windows, so will give the wrong answer if cross compiling. This is because build scripts run on the machine performing compilation, rather than on the target.

Lint Name

misleading_cfg_in_build_script

Category

restriction

Advantage

The recommended code produces the expected value even when cross-compiling.

Drawbacks

  • This is not a useful lint outside of build scripts. The advice it gives will be wrong in other environments.
  • Unlike with #[cfg], there may be no alternative for uses of #[cfg]/#[cfg_attr] (perhaps that code needs to not compile).
  • Even within a build scripts, it may be impossible or impractical to support cross compilation.
  • Even within build-scripts that support cross-compilation, you need to use cfg! to detect if you're cross-compiling.
  • The correct equivalent is significantly more complicated and much harder to write correctly.
  • It's an opt-in restriction lint, so the usefulness is inherently limited.

Example

The correct replacement is a bit tricky and has several cases, and IDK if Clippy should even suggest a replacement. Also, it's worth noting that none of these have any hope of working outside a build script.

Anyway, there are a few cases here:

For no-value cfgs, like cfg!(windows) or cfg!(unix)
if cfg!(windows) { ... }

Can be written as:

if std::env::var("CARGO_CFG_WINDOWS").is_ok() { ... }

For single-value cfgs, like cfg!(target_os = ...)
if cfg!(target_os = "macos") { ... }

Can be written as:

if std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default() == "macos" { ... }

For multi-value cfgs, like cfg!(target_feature = ...) or target_family

(This also works for single-value cfgs, but you can see why it's less desirable)

if cfg!(target_feature = "crt-static") { ... }

Can be written as:

if std::env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or_default().split(',').any(|f| f == "crt-static") { ... }

The complexity is caused by multi-value cfg being provided by cargo as comma-separated environment vars. This not a theoretical issue either (as crt-static is definitely useful for build scripts).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing how Clippy restriction lints recognize cfg!, #[cfg], and #[cfg_attr], with build.rs as the relevant entry point. Define coverage for host-versus-target keys and the no-value, single-value, and multi-value cases, then add tests showing that the lint reports misleading build-script usage without affecting other code.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
devtools, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.