cargo
cargo copied to clipboard
Post-build script execution
Currently, cargo execute scrips before the build starts with the build field. I propose renaming build to pre_build and adding post_build (which would run after every successful build). It's useful for general postprocessing: running executable packers, zipping files, copying stuff, logging, etc.
This will likely happen as part of an implementation of cargo install, but cargo build is not meant to be a general purpose build system for these sorts of applications.
What about integration tests? For example, PNaCl modules can be run on the host machine, but they have to be translated into a NaCl beforehand and then run with sel_ldr (from the NaCl SDK).
@DiamondLovesYou, would https://github.com/rust-lang/cargo/issues/1411 work for the tests?
A "post_build" script would be useful for things like creating a MacOS bundle, rather than having a separate script to do that work separately. "install" could do this too, but maybe not as useful for testing there?
+1 For rust projects that linked dynamically from other languages being able to deploy(move) the .so after a successful build would be nice.
This would be useful for running
arm-none-eabi-objcopy -O binary ${TARGET}.elf ${TARGET}.gba
gbafix ${TARGET}.gba
To fix up the headers and such after building my project.
+1 for post build scripts
This will likely happen as part of an implementation of cargo install, but cargo build is not meant to be a general purpose build system for these sorts of applications.
It doesn't have to mean that cargo will be a general purpose build system. An example where a post-build action could be used for cargo is triggering a build of a crate in a sub-directory once the main crate has been built.
Crate B depends on crate A, and is in a sub-directory of crate A, and it automatically gets built every time crate A has been built.
But what if crate B also depends on sub crates C and D? Shouldn't the build of dependencies be caused by building the crate that depends on them in a "by need" manner? I would say the post build command should not involve building any related crates or calling cargo (can be easily enforced), only for post processing of the lib/exe that was just built. To keep it compartmentalized / clean.
This would be useful for embedded systems programming. I often run arm-none-eabi-size to verify my binary size with each build, and occasionally other utilities from binutils to verify symbol tables, etc...
Don't forget that there's nothing that says you have to use a non-Rust solution for these kinds of things; any "cargo-foo" executable on your $PATH works as "cargo foo", and can be written in any language, including Rust. Your custom command could invoke "cargo build" as a step first and then do anything.
On Oct 29, 2016, 13:35 -0400, Mike [email protected], wrote:
This would be useful for embedded systems programming. I often run arm-none-eabi-size to verify my binary size with each build, and occasionally other utilities from binutils to verify symbol tables, etc...
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub (https://github.com/rust-lang/cargo/issues/545#issuecomment-257104800), or mute the thread (https://github.com/notifications/unsubscribe-auth/AABsimputy3ucYbBxCoVRqmOdAF8GQPnks5q44P0gaJpZM4CgUcP).
Don't forget that there's nothing that says you have to use a non-Rust solution for these kinds of things; any "cargo-foo" executable on your $PATH works as "cargo foo", and can be written in any language, including Rust. Your custom command could invoke "cargo build" as a step first and then do anything.
Yes, that is what I, and probably others, are already doing. It would just be more convenient to integrate this into the already familiar cargo build.
Not to mention that, in my experience, if you try to enforce your will too strongly, you start to get behaviours similar to what has been standard in the home inkjet printer market for well over a decade now.
(Where the first thing you see when you open the box is a slip that warns you, in big letters, to never plug the printer in until after you've installed the software off their CD, because Microsoft's automated driver installation workflow doesn't allow them to install their fancy, tray-resident, bloated, talking print drivers and their official position is that, if Microsoft's installer has had a chance to run, your OS is now broken and must be repaired first.)
Better to have an official way to run a post-build script than to see everyone and their dog reinventing broken wheels... especially since, as a Stubborn Person™, I can easily foresee these horrors:
- Crates which bail out early and insist that, even if they're being used as a dependency, you must run their own special
cargo mybuildwrapper instead ofcargo build(possibly not as an inherent thing, but as a result of depending on something else by the same author which has that build requirement). - Developers recognizing the ugliness of the former situation and producing a "better" solution by hacking (subtly buggy) post-builds onto
cargo buildusing pre-build scripts which leave something running in the background to trigger the post-build using inotify or equivalent.
(Also, keep in mind that, as Rust sees more corporate uptake, we'll see more "I'm too busy to learn the 'proper' way, so I'll just hack something in" WTFs. That's just a basic rule of programming in general.)
In embedded development it's useful to run objcopy to produce hex file or something similar. Adding this to post-build script would be much cleaner than reinventing wheel with my own shell script.
This would be useful for stuff like
SignTool sign /v /s PrivateCertStore /n MyTestCrt /t http://timestamp.verisign.com/scripts/timstamp.dll driver.sys
when developing Windows drivers in Testmode.
This would be useful for packaging debian applications, especially when combined with configuration
Like a configuration deploy which builds the crate in release mode, then creates the folders needed for a package (control files, etc.) and runs dpkg on it.
cargo install touches files outside the current directory, so it doesn't feel like a proper post-build step. If I want to strip the built binary, would I have to work on a binary already copied to /bin?
Why not do this:
If there is a postbuild.rs file, it gets executed after build. (similar to the build.rs file before.)
It would make sense to execute the script also if the build failed. The build status can be passed to it in an env var.
@Boscop I like that idea but I worry that executing another binary every compilation might slow down iterative development. Maybe using postbuild-success.rs for only success, postbuild-failure.rs for only failure and postbuild.rs for both?
I think there won't really be a slowdown compared to having different scripts for success/failure because if your postbuid.rs script checks the build status first and then returns if it's not success/failure, it won't really slow things down. The postbuild.rs script won't have to be recompiled every time, only when it changes. So calling it will just incur the cost of starting an executable that immediately returns.
Having one postbuild.rs script follows the KISS principle, most projects won't even have a postbuild.rs script, and for those that will have one, I think having one script fulfills their needs.
If they notice a slowdown, we can always introduce the option to replace the postbuild.rs script by the other two later. But let's first have just the postbuild.rs and see if that's enough.
That sounds reasonable.
@Boscop idea of the postbuild.rs script sounds like a very good way of managing post build actions. Even though the general opinion seems to be split between this and avoiding to turn cargo into a general purpose make system, I feel that this won't hurt.
Not that I'm advocating for it per se, but Cargo already is a general purpose build system due to the cargo plugins (e.g. cargo tree) being able to do whatever they want. That that is merely a user-friendly(ish) facade for "random turing-complete script" doesn't diminish that in any way.
So the real question becomes: How ergonomic do we want to make this general-purpose build system?
Cargo is not a general purpose build system in the sense that e.g. cmake is.
But I see no reason why cargo can't be the best build system for Rust projects, and having post-build script execution would remove the need to wrap cargo build into another build system for projects that have post-build steps, which occurs more often than not.
Cargo is more restricted than e.g. CMake in the sense that there are assumptions about e.g. where to download dependencies, that each such dependency is a rust crate etc.
That doesn't mean it's not general purpose, since again each cargo "plugin" (AFAIK just some binary that masquerades as a part of Cargo) can do whatever it wants to, including downloading arbitrary projects (including non-rust ones), and mangling them in arbitrary ways, including building them.
That is why I view this as a discussion about ergonomicity rather than capability.
That is why I view this as a discussion about ergonomicity rather than capability.
Agreed. I won't restate my previous comment, but I highly recommend that anyone who hasn't seen/doesn't remember it should scroll up and read it.
There are a couple of ways in which I can very easily imagine people who "just need to get work done" foisting a a monstrosity of a bodge on the rest of us.
Just to make sure folks are aware, there are at least two Rust projects which make executing stuff in addition to cargo build simpler:
https://github.com/casey/just https://sagiegurari.github.io/cargo-make/
Especially cargo-make seems, at least for now, like the way to go if post-build steps are required.
The utility name is apt, as it looks like a cross-platform version of make with much more intuitive "Makefile" syntax, since makefiles are just TOML files.
While that is certainly a workable solution for a lot of projects, I still have to wonder if long-term we want to incorporate that kind of functionality directly into Cargo.
The problem with cargo-make is that cargo build on a package isn't aware of any cargo-make or just scripting in the dependencies, so it's only a solution for --bin crates, not library crates.
For example, suppose you want to build a Rust binary that depends on a cdylib-based dlopened plugin for one of its other dependencies (or just wants to automate installing some plugins via features) and that cdylib needs to do some post-processing on the generated .so/.dll/.dylib file.
The only solution, currently, is to manually build the cdylib separately, using cargo-make or what have you, and then copy it into the depending project.
Couldn't a build dependency on cargo-make in the cdylib project (assuming it's a Cargo project) help with that, even when building a binary that depends on that cdylib?
Even though Cargo may not be explicitly aware of cargo-make, it know does know about transitive build dependencies, doesn't it?