1

I'm starting on a command-line tool in Rust, and hitting a wall right from the get-go. I can parse command-line arguments using StructOpt if the Opt struct is defined in main.rs, but since I want to be able to pass the Opt struct into the library code, I'm defining it in its own file so that other parts of the library know what it's all about.

Here's the version of the code that's dumping the fewest errors, although I concede that it's largely cobbled together by trying things suggested by the compiler and some random SO suggestions, so it may be completely wrong.

The build error I'm getting is:

$ cargo run
   Compiling basic v0.1.0 (/home/mpalmer/src/action-validator/blobble)
error[E0433]: failed to resolve: maybe a missing crate `structopt`?
 --> src/opt.rs:8:5
  |
8 |     /// Activate debug mode
  |     ^^^^^^^^^^^^^^^^^^^^^^^ not found in `structopt::clap`
  |
help: consider importing this struct
  |
3 | use opt::structopt::clap::Arg;
  |

For more information about this error, try `rustc --explain E0433`.
error: could not compile `basic` due to previous error
$ cargo --version
cargo 1.56.0 (4ed5d137b 2021-10-04)
$ rustc --version
rustc 1.56.0 (09c42c458 2021-10-18)

(Yes, I have tried adding use opt::structopt::clap::Arg;, just in case, but the error doesn't go away and I get a warning about an unused import -- while still being told to try adding the same use that is unused, which is amusing)

Cargo.toml

[package]
name = "basic"
version = "0.1.0"
authors = ["User"]

[dependencies]
structopt = "0.3"

src/main.rs

extern crate basic;
extern crate structopt;

use basic::Opt;
use structopt::StructOpt;

fn main() {
    let opt = Opt::from_args();
    println!("{:#?}", opt)
}

src/lib.rs

mod opt;

pub use crate::opt::Opt;

src/opt.ts

extern crate structopt;

use self::structopt::StructOpt;

#[derive(StructOpt, Debug)]
#[structopt(name = "basic")]
pub struct Opt {
    /// Activate debug mode
    #[structopt(short,long)]
    debug: bool,
}

Suggestions gratefully appreciated.

womble
  • 12,033
  • 5
  • 52
  • 66
  • 1
    `self::structopt` doesn't make sense, it should just be `structopt` since its a dependency – kmdreko Oct 25 '21 at 22:14
  • 1
    You'd think so, but changing that line to `use structopt::StructOpt;` produces a whole bunch more errors. As I said, this is a kludged-together minimal-errors version. If you can produce a version of `opt.rs` that compiles cleanly and parses my command-line arguments, post it as an answer and you'll get all the Internet Points I can award. – womble Oct 25 '21 at 22:17
  • 2
    I wonder if the structopt macros are somehow interacting poorly with the fact that your crate is implicitly in the 2015 edition, which has [significantly different behavior around paths and `use`](https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html). Try adding `edition = "2021"` to your `Cargo.toml`. (Then you will also be able to remove all of the `extern crate`s.) – Kevin Reid Oct 25 '21 at 22:52
  • Shouldn't there be an `extern crate structopt` in `lib.rs`? Or just switch to edition 2018 or 2021 as suggested by @KevinReid. – Jmb Oct 26 '21 at 06:26

1 Answers1

2

A working version is

Cargo.toml

[package]
name = "basic"
version = "0.1.0"
authors = ["User"]
edition = "2018"

[dependencies]
structopt = "0.3"

lib.rs

#[macro_use] extern crate structopt;
use structopt::StructOpt;

pub mod opt;

opt.rs

#[derive(StructOpt, Debug)]
#[structopt(name = "basic")]
pub struct Opt {
    /// Activate debug mode
    #[structopt(short,long)]
    debug: bool,
}

main.rs

#[macro_use] extern crate structopt;
use structopt::StructOpt;

fn main() {
    let opt = basic::opt::Opt::from_args();
    println!("{:#?}", opt);
}

You need to declare use structopt::StructOpt because from_args trait must be in the scope.

Zeppi
  • 1,175
  • 6
  • 11