8

As of the time of asking, if you have a bin and a lib in the same cargo project and would like to build the bin and lib with specific rustc cfg options it doesn't work.

You can build one or the other with rustc cfg options, but not both. And if you try and build the lib then the bin when the bin is compiled it recompiled the lib without the rustc options.

Is there a way to do both and if not why? Am I doomed to have to create my own build script anyways? If so, what's the point of having cargo?

EDIT

ok so maybe i was being a little dramatic

Background/Expansion

Say I had something like:

src/lib.rs

pub mod mylib {

    #[cfg(not(dosomething))]
    pub use self::without_cfg::dosomething;

    #[cfg(dosomething)]
    pub use self::with_cfg::dosomething;


    mod with_cfg {
        pub fn dosomething() {
            println!("config option");
        }
    }

    mod without_cfg {
        pub fn dosomething() {
            println!("no config option");
        }
    }

} 

src/main.rs

extern crate modules;

use modules::mylib::dosomething;

fn main() {
    dosomething();
}

So that if I compiled with the cfg option of dosomething I would get one version of a function, but if I didn't have the config I would get the "default" behavior or whatever.

Now if I try and compile with cargo rustc I can never get a version of the bin with the cfg dosomething set in the lib.

The closest I've come to being able to do it all in cargo is:

cargo rustc -v --lib -- --cfg dosomething
cargo rustc -v --bin [bin name] -- --cfg dosomething

which the first command will compile the lib with the cfg but the second command with recompile the lib without the cfg in order to create the bin.

the only workaround I've come up with is to:

cargo rustc -v --bin [bin name] -- --cfg dosomething

copy what it spits out for the command to compile such as:

rustc src/main.rs --crate-name [bin name] --crate-type bin -g --cfg dosomething --out-dir [/path/to/project]/target/debug --emit=dep-info,link -L dependency=[/path/to/project]/target/debug -L dependency=[/path/to/project]/target/debug/deps --extern modules=[/path/to/project]/target/debug/libmodules.rlib`

then run:

cargo rustc -v --lib -- --cfg dosomething

and finally copy and paste the rustc command from earlier in order to compile the bin with the lib having the cfg option set.

Is that the only way? Why can't I somehow specify which libs/bins get the rustc cfg options I want, even if its in the Cargo.toml? Or can I and I don't realize it?

For those that asked...

Cargo.toml:

[package]
name = "[bin name]"
version = "0.1.0"
authors = ["[Me] <[my email]>"]

[lib]
name = "modules"
path = "src/lib.rs"

P.S. Thank you to all those who have worked on rust and cargo, all in all I find it a pleasant environment to work in and LOVE the language. Keep up the good work.

7
  • I noticed the pattern that if it comes to cargo questions, the usual result is: build without cargo. Some things in the rust/cargo infrastructure are not really finished yet. Commented May 23, 2015 at 16:40
  • Could you update your question with some specifics? Maybe include your Cargo.toml that shows the options you have? Commented May 23, 2015 at 16:56
  • 1
    If so, what's the point of having cargo? seems overly fatalistic. Many projects are using Cargo just fine, but it's certainly possible that not every use case that exists in the entire spectrum of programming is captured. It's rather like asking "If Rust doesn't garbage-collect my memory for me, what's the point of having Rust?" Commented May 23, 2015 at 16:59
  • 2
    You can have a binary and a library in the same Cargo project. I'm doing that myself. If you're trying to do that and something is not working, please show code/Cargo.toml and explain the problem in detail. Commented May 23, 2015 at 17:00
  • @shepmaster can you look at my edit? I hope it provides more insight into what I was trying to do. Thank you for your responses and apologies for my moment of anger/frustration. Commented May 25, 2015 at 21:36

1 Answer 1

7

If I understand you correctly, then Cargos features should help out here:

src/lib.rs

#[cfg(feature = "dosomething")]
pub use self::with_cfg::dosomething;

#[cfg(not(feature = "dosomething"))]
pub use self::without_cfg::dosomething;

#[cfg(feature = "dosomething")]
mod with_cfg {
    pub fn dosomething() {
        println!("config option");
    }
}

#[cfg(not(feature = "dosomething"))]
mod without_cfg {
    pub fn dosomething() {
        println!("no config option");
    }
}

src/main.rs

extern crate what;

use what::dosomething;

fn main() {
    dosomething();
}

Cargo.toml

[package]
name = "what"
version = "0.1.0"
authors = ["An Devloper <[email protected]>"]

[features]
dosomething = []

Now, when I can compile or run in either mode:

$ cargo run
   Compiling what v0.1.0 (file:///private/tmp/what)
     Running `target/debug/what`
no config option

$ cargo run --features dosomething
   Compiling what v0.1.0 (file:///private/tmp/what)
     Running `target/debug/what`
config option
Sign up to request clarification or add additional context in comments.

3 Comments

what if the cfg was more like dosomething="value" ? could I still use features? Thanks for the quick response!
Also something I just stumbled upon is that cargo can take a build script. I think I'll look further into that (doc.crates.io/build-script.html)
@sbditto85 I don't believe so. Features are implemented as --cfg feature="dosomething", so they are already the parameter. However, you should be able to flatten the namespace. Instead of dosomething(1), you can have dosomething-1.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.