emk / rust-musl-builder

Docker images for compiling static Rust binaries using musl-libc and musl-gcc, with static versions of useful C libraries. Supports openssl and diesel crates.
Apache License 2.0
1.54k stars 193 forks source link

question: can't manage to make a static binary of my application #106

Closed emmanueltouzery closed 4 years ago

emmanueltouzery commented 4 years ago

Hello, I'm trying to use this docker image to make a static binary of my rust application (which depends on sqlcipher and therefore also, transitively, on openssl). For now I can't make it work.

I asked a question on stackoverflow with details. I'm aware this issue tracker is not a support forum, however I thought I would at least mention this here, feel free to close the issue. If you have some ideas though, I'd love to hear them...

Thank you for this tool!

https://stackoverflow.com/questions/64737810/rust-building-a-statically-linked-binary-including-external-c-libraries

Here is the question, just in case:


Here is my current docker file:

FROM ekidd/rust-musl-builder

# sqlcipher requirements
ENV TZ=Europe/Ljubljana
RUN sudo sh -c "ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone"
RUN sudo apt update
RUN sudo apt install tcl -y

# sqlcipher
RUN VERS=4.4.1 && \
    cd /home/rust/libs && \
    curl -LO https://github.com/sqlcipher/sqlcipher/archive/v$VERS.tar.gz && \
    tar xzf v$VERS.tar.gz && cd sqlcipher-$VERS && \
    CC=musl-gcc ./configure  --host=x86_64-pc-linux-gnu --target=x86_64-linux-musl --prefix=/usr/local/musl --disable-tcl --disable-shared --with-crypto-lib=none --enable-static=yes --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC -DSQLCIPHER_CRYPTO_OPENSSL -I/usr/include/x86_64-linux-musl -I/usr/local/musl/include -I/usr/local/musl/include/openssl" LDFLAGS=" /usr/local/musl/lib/libcrypto.a" && \
    make && sudo make install && \
    cd .. && rm -rf v$VERS.tar.gz sqlcipher-$VERS

# bring in my rust source
ADD --chown=rust:rust ./ .

# build my rust code
ENV RUSTFLAGS='-L/usr/local/musl/lib  -L/usr/lib/x86_64-linux-musl  -L/lib/x86_64-linux-musl -C linker=musl-gcc -Clink-arg=/usr/local/musl/lib/libcrypto.a -Clink-arg=/usr/local/musl/lib/libsqlcipher.a -C link-arg=/lib/ld-musl-x86_64.so.1 -Clink-arg=/usr/lib/x86_64-linux-musl/libc.a -Ctarget-feature=-crt-static -Clink-arg=-no-pie -C target-feature=+crt-static'
ENV PKG_CONFIG_ALLOW_CROSS=1
ENV PKG_CONFIG_ALL_STATIC=true
ENV OPENSSL_STATIC=true
ENV LIBZ_SYS_STATIC=1
CMD cargo build --target x86_64-unknown-linux-musl --release --bin projectpad-cli && cp /home/rust/src/target/x86_64-unknown-linux-musl/release/projectpad-cli /host

(my rust source is at https://github.com/emmanueltouzery/projectpad2)

This succeeds entirely and generates a binary, but it's not statically linked:

ldd projectpad-cli 
    /lib/ld-musl-x86_64.so.1 => /lib64/ld-linux-x86-64.so.2 (0x00007f56d6749000)
    linux-vdso.so.1 (0x00007fff301f7000)
file projectpad-cli
     projectpad-cli: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, with debug_info, not stripped

Attempting to run this binary crashes in malloc_usable_size () from /lib/ld-musl-x86_64.so.1.

I believe it's because my system doesn't have the MUSL linker and so it uses the glibc/gcc one, and this causes issues.

I'm thinking that if I could manage to produce a really static binary, that wouldn't have references to the linker, this would possibly work.

Any idea what I'm doing wrong? I experimented with some builder.rs printlns, but I currently don't have any.

emmanueltouzery commented 4 years ago

OK, I found it...

I'm pretty sure the problem was the -C link-arg=/lib/ld-musl-x86_64.so.1 flag. This more or less forced a dynamic executable I think. Removing it fixed the issue :-)

# -*- mode: dockerfile -*-
#
# An example Dockerfile showing how to add new static C libraries using
# musl-gcc.

FROM ekidd/rust-musl-builder

# https://rtfm.co.ua/en/docker-configure-tzdata-and-timezone-during-build/
ENV TZ=Europe/Ljubljana
RUN sudo sh -c "ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone"

RUN sudo apt update

RUN sudo apt install tcl -y

# Build a static copy of sqlcipher.
# https://github.com/sqlcipher/sqlcipher/issues/132#issuecomment-122908672 
# also related https://discuss.zetetic.net/t/cross-compile-sqlicipher-for-arm/2104/4
# https://github.com/sqlcipher/sqlcipher/issues/276
# https://github.com/rust-lang/rust/issues/40049
RUN VERS=4.4.1 && \
    cd /home/rust/libs && \
    curl -LO https://github.com/sqlcipher/sqlcipher/archive/v$VERS.tar.gz && \
    tar xzf v$VERS.tar.gz && cd sqlcipher-$VERS && \
    CC=musl-gcc ./configure  --host=x86_64-pc-linux-gnu --target=x86_64-linux-musl --prefix=/usr/local/musl --disable-tcl --disable-shared --with-crypto-lib=none --enable-static=yes --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC -DSQLCIPHER_CRYPTO_OPENSSL -I/usr/include/x86_64-linux-musl -I/usr/local/musl/include -I/usr/local/musl/include/openssl" LDFLAGS=" /usr/local/musl/lib/libcrypto.a" && \
    make && sudo make install && \
    cd .. && rm -rf v$VERS.tar.gz sqlcipher-$VERS

ADD --chown=rust:rust ./ .

# https://stackoverflow.com/questions/40695010/how-to-compile-a-static-musl-binary-of-a-rust-project-with-native-dependencies
# https://github.com/rust-lang/rust/issues/54243

ENV RUSTFLAGS='-L/usr/local/musl/lib  -L/usr/lib/x86_64-linux-musl  -L/lib/x86_64-linux-musl -C linker=musl-gcc -Clink-arg=/usr/local/musl/lib/libcrypto.a -Clink-arg=/usr/local/musl/lib/libsqlcipher.a -Clink-arg=/usr/lib/x86_64-linux-musl/libc.a'
ENV PKG_CONFIG_ALLOW_CROSS=1
ENV PKG_CONFIG_ALL_STATIC=true
ENV OPENSSL_STATIC=true
ENV LIBZ_SYS_STATIC=1
CMD cargo build --target x86_64-unknown-linux-musl --release --bin projectpad-cli && cp /home/rust/src/target/x86_64-unknown-linux-musl/release/projectpad-cli /host