I often need to do something to or with the binary I've just build, and would find it useful if cargo provided an easy way to find and access the location of the built binary, regardless of whether it has actually been built.
Possible Solution
In a way, the command would be like cargo run without actually running the
executable. It would just output the (by default absolute or relative, whichever
wins the bikeshed) path for the binary in plaintext format. For example,
cargo binpath
->
/home/hellouser/projects/hello/target/debug/hello
The command would accept the arguments that affect the build location, similar
to cargo run, such as:
--releaseor--profile ...--target ...--target-dir ...
No binary would be built, allowing the command to run blazingly fast quickly.
Rationale
Using the compiled binary directly has some advantages over cargo run.
Manual development tasks:
- Profile or benchmark the executable without noise from cargo.
hyperfine --warmup 3 target/release/my_bin_nameflamegraph target/release-with-debuginfo/my_bin_name
- Run the binary with a debugger.
rust-gdb target/debug/my_bin_name
It's inconvenient to type target/the_target_platform/the_profile_that_was_used/the_name_of_the_binary:
- It's many keypresses, even when using autocompletion.
- At worst, you have to remember or look up the profile, target triplet, and actual name of the binary.
- You have to remember the structure that the path follows, i.e. the order of the above things.
- The fact that
cargo runalready knows everything whereas you need to figure it out is frustrating.
Automation:
- Handling or poking the binary in the CI, e.g.
- Copying it somewhere else or packaging it into an archive
cp target/x86_64-unknown-linux-gnu/different-profile/my_bin_name my_bin_dirzip myzip.zip target/x86_64-unknown-linux-gnu/different-profile/my_bin_name
- Using various tools output debug information on the file
file target/x86_64-unknown-linux-gnu/different/try_bin_nameldd target/x86_64-unknown-linux-gnu/different/try_bin_namestrings target/x86_64-unknown-linux-gnu/different/try_bin_name | grep company_secret
- Copying it somewhere else or packaging it into an archive
- Local automation in a
Makefileor similar
Problems:
- Hardcoding the same binary name into many places leads to changes to many places later.
- The path, especially when repeated often, is verbose. It's also in an
"encoded" (although easy-to-understand) format that's more difficult to look
up than command-line parameters to
cargo.
Current Workarounds
In my opinion, this is already stretching it, but you can get to the root of the target directory with:
cargo metadata --format-version=1 --no-deps | jq '.target_directory'
cargo metadata doesn't support --release, --profile, or --target. If you
want to use those, you need to add them manually. Either way, you also need to
add the binary name.
Alternatively, you can tell cargo to build and provide the output as json with
--message-format json. Then, use jq:
cargo build --profile different --target x86_64-unknown-linux-gnu --message-format json | jq -s '.[0].executable'
The downside here is that the command will do the build.
Instead of jq, others tools such as grep could be used.
It all feels brittle and doesn't scale well when more advanced cargo configuration, workspaces etc. are used.
There's also the unstable --artifact-dir
option which could solve the problem at least partway.