bevy
bevy copied to clipboard
Add information on releasing Bevy games
For relative newcomers to Rust, we should start a section on Releasing Bevy games, to go along with our advice on fast compilations.
This should include:
- maximizing the optimization level (#4586)
- using relative rather than absolute paths
- how to build executables for different platforms
- eventually, links to concrete advice on releasing the game on various distribution platforms like Steam and itch.io
This information likely deserves its own page, but should be linked on the Bevy website, perhaps near the section on fast compilation.
This Bevy game template is another great source of inspiration for tricks to draw from.
* using relative rather than absolute paths
This is about privacy-sensitive paths in the compiled executable, right? Reading through the relevant rust issues (e.g. https://github.com/rust-lang/rust/issues/40552) it does not sound like there is an actual fix or an easy workaround for now. Several people wrote that the mentioned solutions do not work (and I did not see anything about "relative rather than absolute paths").
The way to avoid leaking paths at the moment seems to be not distributing executables compiled on your private machine.
I would propose recommending to only publish builds from CI/CD e.g. GitHub workflows in the new "Releasing Bevy games" section.
This is about privacy-sensitive paths in the compiled executable, right?
Correct. I think your proposal is sensible then; it's a shame there's no local machine workaround.
it's a shame there's no local machine workaround.
Probably building in docker or similar would work... but I would recommend setting up CI anyway
Probably building in docker or similar would work... but I would recommend setting up CI anyway
I think CI makes the most sense for most people, but if someone's project isn't open-source, then CI could cost money.
Maybe we should focus on CI on the website, but also link to some documentation on local alternatives like Docker, chroot jails, etc.?
Just noticed some of our dependencies have licenses that needs to be mentioned when releasing a game made with Bevy. For example wgpu with MPL-2.0 see https://github.com/bevyengine/bevy/pull/2101#discussion_r626193647 (and https://github.com/bevyengine/bevy/pull/2101#discussion_r626194330 for wgpu)
I just left some thoughts on that here: https://github.com/bevyengine/bevy/pull/2101#discussion_r626193647
We could also consider getting "cute" here by doing something like include_bytes!("uber_license_file") by default (with a way to opt out for people who want slimmer binaries and have other compliance plans), but thats not really in the spirit of these licenses and might not even hold up in court.
The file produced by https://crates.io/crates/cargo-bom for Bevy is 568KB
Maybe we can compress it by removing redundant license boilerplate? no clue if that is valid.
Another option would be to gzip (or any common method) compress it and add a header that describes in plain text that the following bytes are the gzipped license text. A function to get the license text at runtime could transparently decompress it.
I dig that. We could have a bevy_license_compliance plugin that include_bytes!() the gzipped license, adds support for a command line: --print-bevy-licenses argument, and provides a function to get the full text at runtime.
And then (depending on the size) we could include it by default.
I've been starting to do a bit of poking around on this topic and could use some advice. I'm fairly new to Bevy (and machine languages more generally) and been struggling to make a Debian package file for my example application. When I build the application, I'm unable to directly run the binary due to missing shared libraries. Is the entire target/release/deps folder required in the linker path in order to run the Bevy app? Is there existing best practice on how to bundle up all of these shared libraries? Can some of these dynamically linked libraries be statically linked instead?
If you aren't using --features bevy/dynamic all shared libraries necessary are native dependencies. See https://github.com/bevyengine/bevy/blob/main/docs/linux_dependencies.md for all dependencies.
Egg on my face; thank you @bjorn3. I forget that all of my child crates had been using the dynamic linking feature.
Using cargo-about for crate license credits
In addition to cargo-bom mentioned in https://github.com/bevyengine/bevy/issues/1885#issuecomment-832363439 I thought I'd mention https://github.com/EmbarkStudios/cargo-about/ as an option which I recently used to produce about dialog crate credits.
This particular app used egui directly for the UI rather than via the Bevy integration but my plan is to get to that point eventually. :D
Display template flexibility
After cargo-about has collected the list of licenses used by your dependencies, you can customize the display of the list of crate licenses using a (handlebars-style) template like this which provides a reasonable degree of display flexibility:
-
Click to display an example template for `cargo-about` license display.
This template is a modified version of one shipped with
cargo-about.## Third Party Licenses List of the licenses of the Rust projects used in "Button Up Community". ### Overview of licenses {{#each overview}} * {{{name}}} ({{{count}}}) {{/each}} ### All license text {{#each licenses}} #### {{{name}}} ##### Used by {{#each used_by}} * {{{crate.name}}} {{{crate.version}}} -- {{#if crate.repository}}{{{crate.repository}}}{{else}}https://crates.io/crates/{{{crate.name}}}{{/if}} {{/each}} {{{text}}} {{/each}}
Final license display output
Here's some examples of the result:
-
Click to show initial dialog view with multiple terms/license sections
This part of the UI was created manually...

Click to show generated summary of crate licenses

Click to show further example license summary display
As you can tell from the scrollbar this is followed by many more pages. :D

Related observations
A couple of observations:
-
Even after de-duplication, in the case of this app there's about 260KB of license text!
-
I'm not 100% certain what the implications of license text de-duplication are in terms of explicit copyright date & project copyright holder details when specified in the text. But when you start wondering about this you discover that there's seemingly many instances where people haven't actually modified the license file to contain this information!
Anyway, hope this might be a helpful pointer/experience to have shared.
@follower How big is the license text after compression? I would assume that it compresses very well.
@bjorn3 Yeah, it's a bit under 20KB with random right-click compression action applied.
So it'd be interesting to see what sort of trade-offs make sense in terms of size+compression+ease of use.
(And, for a GUI app at least, it feels like its probably primarily an amusing situation rather than a major issue. :) )
One thing I've not seen mentioned yet is around building portable executables when distributing for Linux.
My understanding is that building with the x86_64-unknown-linux-gnu target dynamically links to GLIBC, but there's issues with backwards compatibility. E.g. if you build your app using v2.38, it won't run on any machines using earlier GLIBC versions.
A solution to this is to build using MUSL instead e.g.
cargo build --target x86_64-unknown-linux-musl
This produces a static binary which should just work on any Linux machine.
I've tried the above but I'm getting pkg_config errors whilst compiling the alsa-sys crate (open issue for this: https://github.com/diwic/alsa-sys/issues/10) - not sure if there's a workaround for now.
Regardless, using MUSL then has its own issue in that its memory allocator performs relatively poorly in multi-threaded workloads. To resolve this, a different memory allocator would need to be used.
This recent blog post covers 2 ways of using the MiMalloc allocator - the easiest approach seems to be just using this crate: https://github.com/purpleprotocol/mimalloc_rust
This post gives a bit more context to the above, and also found that using a MUSL + MiMalloc combination can outperform GLIBC.
It might be worth running the stress tests whilst using MiMalloc (on Windows or Linux) and see if that grants an easy performance boost?
This produces a static binary which should just work on any Linux machine.
You can't statically link a program that needs to use the GPU. The userspace part of the graphics driver has to be dynamically linked. If you were to statically link it, you wouldn't be able to use any future gpu's with the game, nor be able to use nvidia's graphics driver (which doesn't have a stable syscall abi). If you are dynamically linking, using glibc instead of musl is a much better option. Most distros use glibc and thus compile the graphics driver against it. And the main musl based distro that I know of (Alpine linux) has a glibc compatibility shim.
My understanding is that building with the x86_64-unknown-linux-gnu target dynamically links to GLIBC, but there's issues with backwards compatibility. E.g. if you build your app using v2.38, it won't run on any machines using earlier GLIBC versions.
There are three options:
- Compile the game on an older distro.
- Use steam's runtime which includes glibc and graphics drivers. (IMHO best option for games on steam)
- Use flatpak with and the
org.freedesktop.Platformruntime for glibc and the rightorg.freedesktop.Platform.GL.*runtime extension for the graphics driver. (IMHO best option otherwise)
Ah okay, thanks for your reply @bjorn3 - I've learnt something new today!
Will have a look into Steam's runtime/Flatpak and see what I can get working
Probably good to mention one should include the following in one's Cargo.toml:
log = { version = "0.4", features = ["max_level_debug", "release_max_level_warn"] }
See https://github.com/bevyengine/bevy/issues/14116