Can dependencies use nightly if my compiler is stable?

I have some code which compiles and passes all tests on my local machine, but fails on CI with the error

> error[E0599]: no method named `is_terminal` found for struct `Stderr` in the current scope
>   --> src/output/fmt.rs:88:45
>    |
> 88 |         Stream::Stderr => std::io::stderr().is_terminal(),
>    |                                             ^^^^^^^^^^^ method not found in `Stderr`
>

when compiling the dependency clap 4.0.29 (after having upgraded from 3.2.22).

I'm using Nix to nail down the exact versions on everything, so, in theory, the versions used on CI and my local machine should be identical. Consequently, I'm perplexed that there could be a difference between the two environments: this is the whole point of Nix!

I see that std::io::Stderr.is_terminal() is nightly-only. I don't use nightly myself directly.

Can dependencies use nightly features even if my compiler is stable?

Where could the difference in the two environments be lurking?

No, but there are some crates that pull shenanigans like attempting to detect if they are being compiled by a nightly compiler, and enabling nightly-only code in that case. Misfires of that logic can happen — or the case where the feature has been stabilized (and thus the feature gate deleted), so compiling on nightly fails because #![feature(whatever)] now must be omitted.

However, I don't think this is a nightly issue. Look at a wider scope of the code you referred to:

    use is_terminal::IsTerminal;
    match stream {
        Stream::Stdout => std::io::stdout().is_terminal(),
        Stream::Stderr => std::io::stderr().is_terminal(),
    }

It's importing a trait from the library is_terminal, which is supposed to supply that method, but evidently the trait isn't being implemented for Stderr. Taking a look at that library's source, it seems like the conditional compilation it uses might be failing — it has conditions for cfg(unix) and cfg(windows) and cfg(target_os = "unknown"), but it doesn't attempt to have any fallback for “none of the above”.

Is your CI environment somehow none of the above? That seems odd, but in any case, the thing you need to nail down here for identical builds is to make sure that the cfg is the same for both. You may find rustc --print=cfg helpful for troubleshooting.

3 Likes

My CI is running in the very spartan environment provided (by design) by nix build.

I've managed to reproduce the problem locally, thereby getting to see the beginning of the compilation errors:

Building src/lib.rs (clap)
Running rustc --crate-name clap src/lib.rs --out-dir target/lib -L dependency=target/deps --cap-lints allow -C opt-level=3 -C codegen-units=1 --remap-path-prefix=/build=/ --extern bitflags=/nix/store/ibx98nakn980n626999q0yjs0x795iqk-rust_bitflags-1.3.2-lib/lib/libbitflags-25edeaf30b.rlib --extern clap_lex=/nix/store/fkkrmi8z3jfq0fh76xz7n7navsnvryp2-rust_clap_lex-0.3.0-lib/lib/libclap_lex-24b3a0b2a5.rlib --cfg feature="color" --cfg feature="default" --cfg feature="derive" --cfg feature="error-context" --cfg feature="help" --cfg feature="std" --cfg feature="suggestions" --cfg feature="usage" --edition 2021 -C metadata=22befacdfd -C extra-filename=-22befacdfd --crate-type lib --color always
error[E0432]: unresolved import `clap_derive`
   --> src/lib.rs:119:9
    |
119 | pub use clap_derive::{self, *};
    |         ^^^^^^^^^^^ use of undeclared crate or module `clap_derive`

error[E0432]: unresolved import `once_cell`
   --> src/lib.rs:136:13
    |
136 |     pub use once_cell;
    |             ^^^^^^^^^ no external crate `once_cell`

error[E0432]: unresolved import `termcolor`
   --> src/builder/styled_str.rs:198:13
    |
198 |         use termcolor::WriteColor;
    |             ^^^^^^^^^ use of undeclared crate or module `termcolor`

error[E0432]: unresolved import `termcolor`
  --> src/output/fmt.rs:37:13
   |
37 |         use termcolor::{BufferWriter, ColorChoice as DepColorChoice};
   |             ^^^^^^^^^ use of undeclared crate or module `termcolor`

error[E0432]: unresolved import `is_terminal`
  --> src/output/fmt.rs:85:9
   |
85 |     use is_terminal::IsTerminal;
   |         ^^^^^^^^^^^ use of undeclared crate or module `is_terminal`

... and so on.

So it seems that it's not recognizing any of the dependencies of clap.

So it seems that it's not recognizing any of the dependencies of clap .

bitflags and clap_lex are present in the command line:

It's not that all dependencies are missing, but that all the optional dependencies are missing. The derive and color features have been specified in cfg but their dependencies are missing, so the compilation fails. The build tool you are using is not correctly translating the Cargo.toml into compilation options.

2 Likes