Skip to content

Add Cargo post-build scripts #1777

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

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions text/0000-cargo-post-build-scripts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
- Feature Name: post_build
- Start Date: 2016-10-26
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)

# Summary
[summary]: #summary

This will add the ability for an extra build script to be run *after* the build completes.

This is a similar concept current build script concept but rather than processing files beforehand,
this script would perform tasks _after_ the crate has completed compilation.

# Motivation
[motivation]: #motivation

This feature will give Rust programmers more flexibility when compiling their crates.

Pre-build scripts as we have today are very useful for performing tasks before the
crate is compiled, such as for compiling C/C++ sources or generating bindings. It
is not currently possible to do anything _after_ Cargo finishes.

## Use cases

On most platforms, once linking is done there is no longer any work to do. This
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another common use case for embedded systems is to display the binary size information (e.g. arm-none-eabi-size the_binary) after each build.

differs on some systems, such as AVR (which requires linked ELF binaries to be
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be better handled by a Cargo subcommand. The rationale is that even if Cargo would produce a raw binary blob as its final artifact you'll still need to call a second tool to flash that into a device. So, IMO, we could leave things as they are (final artifact = ELF) and have a Cargo subcommand, say cargo flash, that does the ELF -> binary file part and then flashes that binary into the device.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be better handled by a Cargo subcommand

That's a good idea, I like it

converted into raw binary blobs).

Currently this would require something like a Makefile which internally
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate on this? It seems to if the Makefile uses Cargo then there are crates within the repository / project directory and those crates can be published to crates.io.

calls `cargo`, which prohibits the crate being published to `crates.io`.

In another case, we could use post-build scripts to generate mountable disk
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For development, a Cargo subcommand like the one I mentioned above could fit the bill. cargo qemu could string executables together into a .iso file and then spawn a QEMU instance that boots that disk.

For deployments, I think that's very likely that one will need to use shell scripts or Makefiles to produce the final tarball, checksum it, sign it, upload it, etc. so I don't see much gain from having Cargo help with an extra step of doing the executable -> .iso file part.

images for an operating system kernel written in Rust. Again, this is something
that would require an external build system today.

# Detailed design
[design]: #detailed-design

The crate manifest `[package]` table will support another textual field `post-build`.

A normal manifest would look something like this:

```toml
[package]
name = "foobar"

build = "pre-build.rs"
post-build = "post-build.rs"
```

Once `cargo build` finishes compiling a crate, it will check if there is a `post-build` script
configured, and it will compile and run it similarly to the current build script setup.

A post-build script looks like this:

```rust
use std::process::Command;

fn main() {
let out_dir = env::var("OUT_DIR").unwrap();

Command::new("avr-objcopy")
.arg(&format!("-i elf32 -o binary {}/myobject {}/mybinary", out_dir, out_dir))
.spawn();
}
```

If the build script returns an error code, Cargo should report compilation as failed.

# Drawbacks
[drawbacks]: #drawbacks

* More complexity in the Cargo source
* A corner case that won't be used very often

# Alternatives
[alternatives]: #alternatives

* Use a Makefile-like build system which calls into Cargo
* Expect users to do post-processing manually

If Cargo will not support something given crate authors this ability, people will
be forced to stray-away from the crates ecosystem and use something more custom.

# Unresolved questions
[unresolved]: #unresolved-questions

* What should "crate compilation finished" mean in this regard?
* Should `cargo doc` run the post-build script?