[GH-ISSUE #64] Release Binaries #953

Closed
opened 2026-03-14 12:38:34 +03:00 by kerem · 4 comments
Owner

Originally created by @braheezy on GitHub (Jul 24, 2022).
Original GitHub issue: https://github.com/aome510/spotify-player/issues/64

Originally assigned to: @aome510 on GitHub.

The current install for this program (if using Cargo) looks something like:

  • Install Rust language support
  • Install system library dependencies (openssl, alsa-lib, libdbus)
  • Install spotify_player using Cargo
    • Bunch of crates are downloaded
    • Bunch of crates are compiled
    • If you're missing a system library, this is when you find out. Restart Cargo build after you've fixed any issues
  • Add ~/.cargo/bin to $PATH

This process may be long for users that have never used Rust before (20 min? Unacceptable! 😁). I thought I'd look into how things might be improved.

I found out the binary in the Docker image you provide "just works" and doesn't need all the crates installed. The first easy step could be to add that binary as a Release artifact. But...I know 100% statically linked binaries are a thing in languages like Go. Could things be even easier here?

I found this statement online:

By default, Rust will statically link all Rust code. However, if you use the standard library, it will dynamically link to the system's libc implementation.

And that's confirmed with the binary obtained from the Docker image:

$ file spotify_player
spotify_player: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8614a73108df435bc93ac676acd49b907f730034, for GNU/Linux 3.2.0, with debug_info, not stripped

$ ldd spotify_player
        linux-vdso.so.1 (0x00007ffcd1df9000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007faa06fbe000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007faa06f9c000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007faa06e58000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007faa06e52000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007faa06c8d000)
        /lib64/ld-linux-x86-64.so.2 (0x00007faa07edf000)

With a few edits to the Dockerfile and spotify_player/Config.toml, a 100% statically-linked binary is possible:

$ file /tmp/spotify_player
/tmp/spotify_player: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), static-pie linked, BuildID[sha1]=7289f836bdf693be7dc24b6bb26cb8e448311ffe, with debug_info, not stripped

$ ldd /tmp/spotify_player
	statically linked

Cool. As a test, I dropped the binary in a vanilla Ubuntu container to see if it would run:

$ docker run --rm -it -v /tmp:/app ubuntu

root@699340233eb9:/# /app/spotify_player --help
spotify-player 0.9.3
Thang Pham <phamducthang1234@gmail>
A command driven spotify player

USAGE:
    spotify_player [OPTIONS]

OPTIONS:
    -c, --config-folder <FOLDER>
            Path to the application's config folder (default: $HOME/.config/spotify-player)

    -C, --cache-folder <FOLDER>
            Path to the application's cache folder (default: $HOME/.cache/spotify-player)

    -h, --help
            Print help information

    -t, --theme <THEME>
            Application theme (default: dracula)

    -V, --version
            Print version information

Even cooler!

Summary of changes:

  • Dockerfile:
    • Add musl library support to build container
    • Use rustup to enable building for musl targets
    • Configure environment such that musl libraries are used during the build
  • Config.toml

I don't know anything about Rust or single line of your program but what you made is pretty sweet. Making it dead-simple to install can help more people enjoy it! I'd love to help with these type of Packaging/Release/Distribution challenges.

Originally created by @braheezy on GitHub (Jul 24, 2022). Original GitHub issue: https://github.com/aome510/spotify-player/issues/64 Originally assigned to: @aome510 on GitHub. The current install for this program (if using Cargo) looks something like: - Install Rust language support - Install system library dependencies (`openssl`, `alsa-lib`, `libdbus`) - Install `spotify_player` using Cargo - Bunch of crates are downloaded - Bunch of crates are compiled - If you're missing a system library, this is when you find out. Restart Cargo build after you've fixed any issues - Add `~/.cargo/bin` to `$PATH` This process may be long for users that have never used Rust before (20 min? Unacceptable! :grin:). I thought I'd look into how things might be improved. I found out the binary in the Docker image you provide "just works" and doesn't need all the crates installed. The **first easy step** could be to add that binary as a Release artifact. But...I know 100% statically linked binaries are a thing in languages like Go. Could things be even easier here? I found this statement [online](https://doc.bccnsoft.com/docs/rust-1.36.0-docs-html/edition-guide/rust-2018/platform-and-target-support/musl-support-for-fully-static-binaries.html): > By default, Rust will statically link all Rust code. However, if you use the standard library, it will dynamically link to the system's `libc` implementation. And that's confirmed with the binary obtained from the Docker image: ```console $ file spotify_player spotify_player: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8614a73108df435bc93ac676acd49b907f730034, for GNU/Linux 3.2.0, with debug_info, not stripped $ ldd spotify_player linux-vdso.so.1 (0x00007ffcd1df9000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007faa06fbe000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007faa06f9c000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007faa06e58000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007faa06e52000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007faa06c8d000) /lib64/ld-linux-x86-64.so.2 (0x00007faa07edf000) ``` With a few edits to the `Dockerfile` and `spotify_player/Config.toml`, a 100% statically-linked binary is possible: ```console $ file /tmp/spotify_player /tmp/spotify_player: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), static-pie linked, BuildID[sha1]=7289f836bdf693be7dc24b6bb26cb8e448311ffe, with debug_info, not stripped $ ldd /tmp/spotify_player statically linked ``` Cool. As a test, I dropped the binary in a vanilla Ubuntu container to see if it would run: ```console $ docker run --rm -it -v /tmp:/app ubuntu root@699340233eb9:/# /app/spotify_player --help spotify-player 0.9.3 Thang Pham <phamducthang1234@gmail> A command driven spotify player USAGE: spotify_player [OPTIONS] OPTIONS: -c, --config-folder <FOLDER> Path to the application's config folder (default: $HOME/.config/spotify-player) -C, --cache-folder <FOLDER> Path to the application's cache folder (default: $HOME/.cache/spotify-player) -h, --help Print help information -t, --theme <THEME> Application theme (default: dracula) -V, --version Print version information ``` Even cooler! Summary of changes: - `Dockerfile`: - Add `musl` library support to build container - Use `rustup` to enable building for `musl` targets - Configure environment such that `musl` libraries are used during the build - `Config.toml` - Use OpenSSL crate, which has a [magic "vendored" setting to support static linking](https://docs.rs/openssl/0.10.41/openssl/#vendored) I don't know anything about Rust or single line of your program but what you made is pretty sweet. Making it dead-simple to install can help more people enjoy it! I'd love to help with these type of Packaging/Release/Distribution challenges.
kerem 2026-03-14 12:38:34 +03:00
Author
Owner

@aome510 commented on GitHub (Jul 24, 2022):

Thanks @braheezy for an amazing finding.

The first easy step could be to add that binary as a Release artifact. But...I know 100% statically linked binaries are a thing in languages like Go. Could things be even easier here?

Adding binaries to release was mentioned a few times, I did look into this briefly before. However, as you already mention, it's not fully statically linked, so things may not work.

And that's confirmed with the binary obtained from the Docker image:

$ file spotify_player
spotify_player: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8614a73108df435bc93ac676acd49b907f730034, for GNU/Linux 3.2.0, with debug_info, not stripped

$ ldd spotify_player
        linux-vdso.so.1 (0x00007ffcd1df9000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007faa06fbe000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007faa06f9c000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007faa06e58000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007faa06e52000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007faa06c8d000)
        /lib64/ld-linux-x86-64.so.2 (0x00007faa07edf000)

Summary of changes:

  • Dockerfile:
    • Add musl library support to build container
    • Use rustup to enable building for musl targets
    • Configure environment such that musl libraries are used during the build
  • Config.toml

Dynamically link the binary provided in the docker image is simpler than dynamically linking the actual application because by default, the binary docker image doesn't include all the features (streaming, image, media-control, etc). With docker version, libc and openssl can be worked around to use the static link counterparts. I'm not too sure about the state of other dependencies when enabling all the default features.

That said, it's still better to provide any kinds of "just work, easy-to-install" binaries and not require people to install Rust/cargo to install the applications. I'll take a deeper look into how to improve these things. Will keep you updated.

Anyway, really appreciate your effort put into this 🙇.

<!-- gh-comment-id:1193338674 --> @aome510 commented on GitHub (Jul 24, 2022): Thanks @braheezy for an amazing finding. > The first easy step could be to add that binary as a Release artifact. But...I know 100% statically linked binaries are a thing in languages like Go. Could things be even easier here? Adding binaries to release was mentioned a few times, I did look into this briefly before. However, as you already mention, it's not fully statically linked, so things may not work. > And that's confirmed with the binary obtained from the Docker image: > ```console > $ file spotify_player > spotify_player: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8614a73108df435bc93ac676acd49b907f730034, for GNU/Linux 3.2.0, with debug_info, not stripped > > $ ldd spotify_player > linux-vdso.so.1 (0x00007ffcd1df9000) > libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007faa06fbe000) > libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007faa06f9c000) > libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007faa06e58000) > libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007faa06e52000) > libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007faa06c8d000) > /lib64/ld-linux-x86-64.so.2 (0x00007faa07edf000) > ``` > Summary of changes: > - `Dockerfile`: > - Add `musl` library support to build container > - Use `rustup` to enable building for `musl` targets > - Configure environment such that `musl` libraries are used during the build > - `Config.toml` > - Use OpenSSL crate, which has a [magic "vendored" setting to support static linking](https://docs.rs/openssl/0.10.41/openssl/#vendored) Dynamically link the binary provided in the docker image is simpler than dynamically linking the actual application because by default, the binary docker image doesn't include all the features (`streaming`, `image`, `media-control`, etc). With docker version, `libc` and `openssl` can be worked around to use the static link counterparts. I'm not too sure about the state of other dependencies when enabling all the default features. That said, it's still better to provide any kinds of "just work, easy-to-install" binaries and not require people to install **Rust/cargo** to install the applications. I'll take a deeper look into how to improve these things. Will keep you updated. Anyway, really appreciate your effort put into this :bow:.
Author
Owner

@braheezy commented on GitHub (Jul 24, 2022):

Dynamically link the binary provided in the docker image is simpler than dynamically linking the actual application because by default, the binary docker image doesn't include all the features (streaming, image, media-control, etc)

Ahh. This is my lack of Rust showing. I see the language has all that built-in support for conditionally compiling. That might explain your --no-default-features flag in the Dockerfile(?). I might explore with building all features.

That said, it's still better to provide any kinds of "just work, easy-to-install" binaries and not require people to install Rust/cargo to install the application.

Exactly it's all about having multiple choices. I've been taking inspiration from how bat provides targets. I was delighted to find out it was also a Rust project. I got some of the musl ideas from there.

<!-- gh-comment-id:1193420227 --> @braheezy commented on GitHub (Jul 24, 2022): > Dynamically link the binary provided in the docker image is simpler than dynamically linking the actual application because by default, the binary docker image doesn't include all the features (streaming, image, media-control, etc) Ahh. This is my lack of Rust showing. I see the language has all that built-in support for conditionally compiling. That might explain your `--no-default-features` flag in the Dockerfile(?). I might explore with building all features. > That said, it's still better to provide any kinds of "just work, easy-to-install" binaries and not require people to install Rust/cargo to install the application. Exactly it's all about having multiple choices. I've been taking inspiration from how [bat provides targets](https://github.com/sharkdp/bat/releases). I was delighted to find out it was also a Rust project. I got some of the `musl` ideas from there.
Author
Owner

@braheezy commented on GitHub (Jul 29, 2022):

I think a 100% static binary is off the table.

A few functions ultimately depend on dynamic linking because of the nature of what the functions do. This post sums it up.

Functions:

  • getgrouplist
  • initgroups
  • getgrgid_r
  • getgrnam_r
  • getpwnam_r
  • getpwuid_r
  • getaddrinfo
  • gethostbyname

The main warning during build:

Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

Any code rewrites to support this are surely not worth it.

<!-- gh-comment-id:1198842978 --> @braheezy commented on GitHub (Jul 29, 2022): I think a 100% static binary is off the table. A few functions ultimately depend on dynamic linking because of the nature of what the functions do. [This post](https://stackoverflow.com/questions/15165306/compile-a-static-binary-which-code-there-a-function-gethostbyname/15165424#15165424) sums it up. Functions: - getgrouplist - initgroups - getgrgid_r - getgrnam_r - getpwnam_r - getpwuid_r - getaddrinfo - gethostbyname The main warning during build: ``` Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking ``` Any code rewrites to support this are surely not worth it.
Author
Owner

@aome510 commented on GitHub (Jul 29, 2022):

Hey @braheezy,

I think a 100% static binary is off the table.

That's sad to hear :<. I planned to play around with musl after release v0.9.4. Thanks for the investigation, it did save me time then =).

Also, FYI, I added a CD workflow that will publish binaries whenever I release new version. You can find the prebuilt binaries in the release page (e.g v0.9.4). Please lmk if those binaries don't work. I only tested briefly on my Ubuntu. Note that you still need to install the dynamic dependencies (openssl, alsa-lib, libdbus, etc).

In the meantime, I'll close this issue for now. Feel free to reopen if you encounter any issues.

<!-- gh-comment-id:1198853860 --> @aome510 commented on GitHub (Jul 29, 2022): Hey @braheezy, > I think a 100% static binary is off the table. That's sad to hear :<. I planned to play around with `musl` after release [v0.9.4](https://github.com/aome510/spotify-player/releases/tag/v0.9.4). Thanks for the investigation, it did save me time then =). Also, FYI, I added a `CD` workflow that will publish binaries whenever I release new version. You can find the prebuilt binaries in the release page (e.g [v0.9.4](https://github.com/aome510/spotify-player/releases/tag/v0.9.4)). Please lmk if those binaries don't work. I only tested briefly on my Ubuntu. **Note** that you still need to install the dynamic dependencies (openssl, alsa-lib, libdbus, etc). In the meantime, I'll close this issue for now. Feel free to reopen if you encounter any issues.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/spotify-player#953
No description provided.