Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Size issues (again?) #489

Closed
RandomInsano opened this issue Aug 21, 2021 · 6 comments
Closed

Size issues (again?) #489

RandomInsano opened this issue Aug 21, 2021 · 6 comments

Comments

@RandomInsano
Copy link

I've been playing around with getting my final binaries smaller and after finding #46 I'm somewhat confused about why structopts is the biggest contributor to my binary size after the standard library. What's a little funny is turning default features off grows the final binary so there's nowhere to go but up? This is all on Linux with 1.56.0-nightly but I see the same results in stable.

Here's some experiments:

-rwxrwxr-x 2 me me 3.5M Aug 21 01:27 target/release/test_opts (without structopt code)
-rwxrwxr-x 2 me me 4.1M Aug 21 01:29 target/release/test_opts
-rwxrwxr-x 2 me me 4.2M Aug 21 01:26 target/release/test_opts (after default-features = false)

The code for this:

use structopt::StructOpt;
use std::path::PathBuf;

#[derive(StructOpt, Debug)]
enum ProgramOptions {
    New {
        #[structopt(parse(from_os_str), help = "File path for new level")]
        filename: PathBuf,

        #[structopt(short, long, help = "Level name")]
        name: String,

        #[structopt(short, long, help = "Width for new level")]
        width: usize,

        #[structopt(short, long, help = "Height for new level")]
        height: usize,
    },
    Load {
        #[structopt(parse(from_os_str), help = "File path for new level")]
        filename: PathBuf,
    }
}

pub fn main() {
    // Comment this line out to compare and contrast sizes
    parse_args().unwrap();
}

pub fn parse_args() -> Result<(), &'static str> {
    let opts = ProgramOptions::from_args();

    match opts {
        ProgramOptions::New { ref filename, ref name, width, height } => {
            let filename = match filename.to_str() {
                Some(y) => y,
                None => return Err("Unable to parse filename into OS string".into()),
            };

            println!("Use some vars: {:?}, {}, {}, {}", filename, name, width, height);
        },
        ProgramOptions::Load { ref filename } => {
            let filename = match filename.to_str() {
                Some(y) => y,
                None => return Err("Unable to parse filename into OS string".into()),
            };

            println!("Use some vars: {:?}", filename);
        }
    }
    
    Ok(())
}
@RandomInsano
Copy link
Author

RandomInsano commented Aug 21, 2021

I built a simple script to test sizes over time. Nothing terribly exciting. Without specifying options, the size changes very little. Output below shows only size changes and removed any failed builds. Tested between v0.1.4 and v0.3.22 which was output from git tag

Build 0.3.5 size is	4196 target/release/test_opts
Build 0.3.22 size is	4200 target/release/test_opts
...didn't include latest from git tags somehow?!

Disabling default features has about the same effect

Build 0.3.5 size is	4220 target/release/test_opts
Build 0.3.22 size is	4224 target/release/test_opts
#!/usr/bin/env bash
BIN_NAME=test_opts

function build() {
        cp Cargo.template Cargo.toml
        rm -f Cargo.lock
        echo "structopt = {version =\"=$1\", default-features=false}" >> Cargo.toml

        echo -n "Build $1 size is       "
        if `cargo build --release -q 2>/dev/null`; then
                ls -s target/release/$BIN_NAME
        else
                echo "unknown (build failed)"
        fi
}

for version in `cat versions | sort -V`; do
        build $version
done

@TeXitoi
Copy link
Owner

TeXitoi commented Aug 26, 2021

Strange, no idea after a quick look at the code, the features seems well forwarded to clap. Do you see the same behavior if using only clap?

@TeXitoi
Copy link
Owner

TeXitoi commented Aug 30, 2021

cargo bloat with default-features:

 File  .text     Size Crate
 7.8%  54.6% 297.7KiB clap
 6.0%  41.9% 228.3KiB std
 0.1%   0.5%   3.0KiB strsim
 0.1%   0.5%   3.0KiB ansi_term
 0.0%   0.3%   1.7KiB textwrap
 0.0%   0.2%   1.1KiB test_rs
 0.0%   0.0%     213B [Unknown]
 0.0%   0.0%      28B atty
14.2% 100.0% 545.2KiB .text section size, the file size is 3.7MiB

with default-features = false:

 File  .text     Size Crate
 8.0%  55.8% 309.6KiB clap
 6.0%  41.7% 231.1KiB std
 0.0%   0.3%   1.7KiB textwrap
 0.0%   0.2%   1.1KiB test_rs
 0.0%   0.0%     213B [Unknown]
14.4% 100.0% 554.5KiB .text section size, the file size is 3.8MiB

Everything seems fine. The features don't really minimize the binary size.

@TeXitoi TeXitoi closed this as completed Aug 30, 2021
@RandomInsano
Copy link
Author

RandomInsano commented Aug 31, 2021

Default features being off results in a 0.1MiB increase in your test despite things like ansi_term not being included. I've moved to argh for now which isn't as featureful.

@TeXitoi
Copy link
Owner

TeXitoi commented Aug 31, 2021

Clap v2 is not really size optimized, so the code used in place of the external library is not a size gain. Nothing structopt can do.

You can also try clap master (future v3) than embeds directly structopt.

The clap features came at a size cost.

Sorry to see you leaving structopt, but there is alternatives because there is different needs :-)

@RandomInsano
Copy link
Author

RandomInsano commented Aug 31, 2021 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants