bevy icon indicating copy to clipboard operation
bevy copied to clipboard

Add information on releasing Bevy games

Open alice-i-cecile opened this issue 4 years ago • 22 comments
trafficstars

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.

alice-i-cecile avatar Apr 11 '21 16:04 alice-i-cecile

This Bevy game template is another great source of inspiration for tricks to draw from.

alice-i-cecile avatar Apr 11 '21 16:04 alice-i-cecile

* 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.

NiklasEi avatar Apr 11 '21 18:04 NiklasEi

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.

alice-i-cecile avatar Apr 11 '21 18:04 alice-i-cecile

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

mockersf avatar Apr 11 '21 19:04 mockersf

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.?

lberrymage avatar Apr 16 '21 02:04 lberrymage

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)

mockersf avatar May 05 '21 00:05 mockersf

I just left some thoughts on that here: https://github.com/bevyengine/bevy/pull/2101#discussion_r626193647

cart avatar May 05 '21 00:05 cart

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

mockersf avatar May 05 '21 01:05 mockersf

Maybe we can compress it by removing redundant license boilerplate? no clue if that is valid.

cart avatar May 05 '21 17:05 cart

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.

bjorn3 avatar May 05 '21 18:05 bjorn3

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.

cart avatar May 05 '21 19:05 cart

And then (depending on the size) we could include it by default.

cart avatar May 05 '21 19:05 cart

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?

Bekreth avatar May 08 '21 15:05 Bekreth

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.

bjorn3 avatar May 08 '21 16:05 bjorn3

Egg on my face; thank you @bjorn3. I forget that all of my child crates had been using the dynamic linking feature.

Bekreth avatar May 08 '21 16:05 Bekreth

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...

    eos-button-up-about-dialog--Screenshot from 2021-10-28 00 16 23

  • Click to show generated summary of crate licenses

    eos-button-up-about-dialog-crates-credits-Screenshot from 2021-10-28 00 17 40

  • Click to show further example license summary display

    As you can tell from the scrollbar this is followed by many more pages. :D

    eos-button-up-about-dialog-crate-credits-more-Screenshot from 2021-10-28 00 19 09

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 avatar Oct 27 '21 11:10 follower

@follower How big is the license text after compression? I would assume that it compresses very well.

bjorn3 avatar Oct 27 '21 12:10 bjorn3

@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. :) )

follower avatar Oct 27 '21 22:10 follower

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?

66OJ66 avatar Sep 14 '23 10:09 66OJ66

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.Platform runtime for glibc and the right org.freedesktop.Platform.GL.* runtime extension for the graphics driver. (IMHO best option otherwise)

bjorn3 avatar Sep 14 '23 11:09 bjorn3

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

66OJ66 avatar Sep 14 '23 17:09 66OJ66

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

janhohenheim avatar Jul 02 '24 23:07 janhohenheim