Skip to content

Commit

Permalink
Musl support for htslib 1.10.2 (#193)
Browse files Browse the repository at this point in the history
* Add alternative strategy (local dependencies install) to get musl support shipped into rust-htslib

* Tweaking toolchain further for rust-htslib-musl and its dependencies

* Circumvent Makefile openssl bug in openssl/openssl#11362 and many other compile time gotchas

* Add newly docker baked image with the whole toolchain built statically with and for musl

* Bypass unneeded CI steps for now to focus on musl

* Tell openssl-sys crate where is our custom musl-openssl cross compiled directory...

* It is possible that https://github.com/rust-bio/rust-htslib/pull/193/checks?check_run_id=518233498#step:5:253 is just a binutils bug according to https://bbs.archlinux.org/viewtopic.php?id=242682 and other sites...

* Revert linting/formatting steps, those are done (and needed) anyway for the PR...

* Nasty hack with ld, tell musl that its own includes are available via CPPFLAGS and hopefully bypass clang/llvm errors?

* LDFLAGS and CPPFLAGS need to be passed to hts-sys, plus need to be surrounded by quotes since there are spaces in the variables

* Be a bit more careful with env variables when clippy is running

* A bit more classy to pass clippy?

* Temporarily try to bypass formatting/linting again, not helping focus on musl

* Passing clang_arg() to bindgen to compile the wrapper with -I/usr/local/musl/x86_64-linux-musl/include does not seem to help :/

* Hardcoded include path works for both musl and GNU bindgen building, removing .cargo/config, not necessary

* Re-enabling formatting and linting Github action phases after green build on MUSL testing :)

* hfile_s3.o is only included on libhts.a when ./configure is run previously according to James and Rob from the htslib team

* Make sure we are in htslib directory, otherwise configure.ac and .in will not be found

* Fix up redundant imports according to clippy, switch to alpine linux container, way more lightweight and less messy build process, also includes MUSL as base compiler

* Explicitly cross-compile passing the right ./configure --host flag, to be generalized later

* LDFLAGS was being pointed to CPPFLAGS, copy&paste hell. Also make cargo clippy happy

* More clippy

* Puzzled as of why this clippy error was not detected locally... also htslib compiles fine locally as well, no cross, just cargo

* CPPFLAGS as an argument to make is causing trouble on Linux but not on OSX...

* This include does not affect any build and it is crucial for MUSL ones

* Back to non-alpine container, not sure why cargo is not being found

* Disabling --no-default-features building for now, clang-sys not needed, suppress cppflags warnings

* Following @pmarks advice on libz-sys, bump up both libc anb libz-sys while at it

* Enable no-default-features back

* Make clippy happy with libz

* libz-sys should not be optional, thanks @pmarks

* Cleaning up flags, trying to have libz as static to avoid //usr/lib64/libz.so.1: error adding symbols: DSO missing from command line, linking errors, thansk @wezm for the tips

* Figured out next steps: need to incorporate static compilation features to both bzip2-sys and lzma-sys, otherwise MUSL will have DSO linker issues. Will implement alexcrichton/xz2-rs#62 and alexcrichton/bzip2-rs#56 next

* Add missing static flag to lzma-sys, getting rid of the need to export the env variable, closing into the core of the issue: rust-htslib's build.rs needs a feature-flag revamp as well... in addition to env variables, it should be able to use cfg Cargo features as well... and not sed-modify htslib's makefile if it's a static build

* Remove openssl-sys crate in favor of curl-sys, which already includes a vendored openssl-sys (hopefully more static-friendly)

* Temporarily comment out sed modifications against htslib's makefile, focusing on static compilation

* Semver + suffix on curl is not needed

* make -B, that flag was the current culprit on static compilation, bizarre since it does not seem to be related at all to the libssl errors: https://www.gnu.org/software/make/manual/html_node/Options-Summary.html

* Make extra sure that -fPIC flag is passed during all compile phases

* Passing println(cargo:rustc-link-lib=static=hts), works, finally :)

* Cleanup cflgags_patterns mess

* Works locally, migrating to docker/cross builds, MUSL has regressions after build.rs changes, regular GNU toolchain works though

* Cleanup build.rs

* Add clux/muslrust Dockerfile example, as referred on https://users.rust-lang.org/t/musl-cross-compilation-how-to-reuse-curl-sys-libz-sys-bzip2-sys-lzma-sys-and-other-dependency-includes-under-target/42817/4

* Revert .github workflow minor changes because 'remote rejected] musl_support -> musl_support (refusing to allow an OAuth App to create or update workflow  without  scope)'

* Adding rust workflow from master...

* Remove GitHub actions workflows for now since they are blocking my progress

* Thanks @wezm for feedback on MUSL dockerfiles and https://github.com/fornwall/rust-static-builder pointer

* Finally compiles MUSL, passing CFLAGS=-I/usr/local/musl/include and using build.env cross to passthrough that var

* Reintroducing the GitHub actions workflow... will I be able to push it now?

* Nope, pushes are still blocked by '[remote rejected] musl_support -> musl_support (refusing to allow an OAuth App to create or update workflow...'

* Cleanup and update README with the required cross commands. Also cleanup the different Dockerfiles tested but no longer needed. build.rs now runs make clean before reconfiguring htslib for better reproducible builds

* Add back github workflow, now that I am a project collab/admin

* Make sure MUSL builds find zlib.h et al

* Sans quotes and let others concatenate CFLAGS

* Remove clux rust container references and stray -j40 make flag

Co-authored-by: Roman Valls Guimera <[email protected]>
  • Loading branch information
brainstorm and brainstorm authored Jun 2, 2020
1 parent 3a2ff4e commit 8107160
Show file tree
Hide file tree
Showing 15 changed files with 233 additions and 61 deletions.
12 changes: 1 addition & 11 deletions .cargo/config
Original file line number Diff line number Diff line change
@@ -1,12 +1,2 @@
[target.x86_64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]

[target.x86_64-unknown-linux-musl]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]
linker = "x86_64-linux-musl-gcc"
linker = "x86_64-linux-musl-gcc"
31 changes: 18 additions & 13 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,21 @@ jobs:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./lcov.info

# - name: Test musl build without default features
# uses: actions-rs/cargo@v1
# with:
# use-cross: true
# command: build
# args: --target x86_64-unknown-linux-musl --no-default-features
#
# - name: Test musl build with all features
# uses: actions-rs/cargo@v1
# with:
# use-cross: true
# command: build
# args: --target x86_64-unknown-linux-musl --all-features
- name: Test musl build without default features
env:
CFLAGS: -I/usr/local/musl/include
uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --target x86_64-unknown-linux-musl --no-default-features

- name: Test musl build with all features
env:
CFLAGS: -I/usr/local/musl/include
uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --target x86_64-unknown-linux-musl --all-features

7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ tag-message = "Version {{version}} of Rust-HTSlib."

[dependencies]
libc = "0.2"
itertools = "0.8"
itertools = "0.9.0"
newtype_derive = "0.1"
custom_derive = "0.1"
url = "2.1"
Expand All @@ -29,16 +29,17 @@ linear-map = "1.2"
serde_base = { version = "^1", optional = true, package = "serde" }
serde_bytes = { version = "0.11", optional = true }
bio-types = ">=0.6"
snafu = ">= 0.5.0, <= 0.6.0"
snafu = "0.6.8"
hts-sys = { version = "^1.10", path = "hts-sys", default-features = false }

[features]
default = ["bzip2", "lzma", "curl"]
bzip2 = ["hts-sys/bzip2"]
lzma = ["hts-sys/lzma"]
curl = ["hts-sys/curl"]
openssl = ["hts-sys/openssl"]
#openssl = ["hts-sys/openssl"]
serde = ["serde_base", "serde_bytes"]
static = []

[dev-dependencies]
tempdir = "0.3"
Expand Down
10 changes: 9 additions & 1 deletion Cross.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
[build.env]
passthrough = [
"RUST_DEBUG",
"RUST_BACKTRACE",
"CFLAGS"
]


[target.x86_64-unknown-linux-musl]
image = "brainstorm/rust_musl_docker:stable-latest-libcurl"
image = "brainstorm/cross-x86_64-unknown-linux-musl:latest"
[target.x86_64-unknown-linux-gnu]
image = "brainstorm/cross-x86_64-unknown-linux-gnu:libcurl-openssl"
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,30 @@ This library provides HTSlib bindings and a high level Rust API for reading and

To clone this repository, issue

```
git clone --recursive https://github.com/rust-bio/rust-htslib.git
```shell
$ git clone --recursive https://github.com/rust-bio/rust-htslib.git
```

ensuring that the HTSlib submodule is fetched, too.
If you only want to use the library, there is no need to clone the repository. Go on to the **Usage** section in this case.

## Requirements

To compile this crate you need the development headers of zlib, bzip2 and xz. For instance, in Debian systems one needs the following dependencies:
To compile this crate you need docker and cross:

```shell
$ cargo install cross
$ cross build # will build with GNU toolchain
```

If you want to run rust-htslib code on AWS lambda, you'll need to statically compile it with MUSL as follows:

```shell
$ export CFLAGS="-I/usr/local/musl/include"
$ cross build --target x86_64-unknown-linux-musl # will build with MUSL toolchain
```

Alternatively, you can also install it locally by installing the development headers of zlib, bzip2 and xz. For instance, in Debian systems one needs the following dependencies:

```shell
$ sudo apt-get install zlib1g-dev libbz2-dev liblzma-dev clang pkg-config
Expand Down
11 changes: 6 additions & 5 deletions docker/Dockerfile.gnu
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
FROM rustembedded/cross:x86_64-unknown-linux-gnu

ENV LIBCLANG_PATH /usr/lib/x86_64-linux-gnu
#ENV LIBCLANG_PATH /usr/lib/x86_64-linux-musl
ENV LIBCLANG_PATH /usr/lib/llvm-10/lib
ENV LLVM_CONFIG_PATH /usr/bin
RUN apt-get update && \
apt-get install -y libcurl4-openssl-dev zlib1g-dev libbz2-dev liblzma-dev clang-8 && \
ln -sf /usr/bin/llvm-config-8 /usr/bin/llvm-config && \
ln -sf /usr/lib/x86_64-linux-gnu/libclang-8.so.1 /usr/lib/x86_64-linux-gnu/libclang.so.1
RUN apt-get update
RUN apt-get install -y wget gnupg lsb-release software-properties-common apt-transport-https ca-certificates # Otherwise LLVM bump below fails
RUN bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
RUN apt-get install -y libssl-dev libcurl4-openssl-dev zlib1g-dev libbz2-dev liblzma-dev # htslib deps
120 changes: 117 additions & 3 deletions docker/Dockerfile.musl
Original file line number Diff line number Diff line change
@@ -1,7 +1,121 @@
FROM rustembedded/cross:x86_64-unknown-linux-musl

ENV MUSL_CROSS_MAKE_VERSION 0.9.9
ENV PKG_CONFIG_ALLOW_CROSS 1
ENV OPENSSL_LIB_DIR /usr/lib/x86_64-linux-gnu
ENV OPENSSL_INCLUDE_DIR /usr/include/openssl
ENV LZMA_VERSION 5.2.5
ENV ZLIB_VERSION 1.2.11
ENV OPENSSL_VERSION 1_1_1g
ENV CURL_VERSION 7.70.0

ENV LIBCLANG_PATH /usr/lib/llvm-10/lib
ENV LLVM_CONFIG_PATH /usr/bin


# The default includes and packages from the Ubuntu distro that cross uses will generate all sorts of linux-headers related include errors, see:
# https://github.com/rust-bio/rust-htslib/pull/184#commitcomment-37496651
# Those are the packages installed, hopefully someone will find a good way to use the distro ones instead of compiling everything under /usr/local :/
# apt-get install -y libssl-dev libcurl4-openssl-dev zlib1g-dev libbz2-dev liblzma-dev musl musl-dev musl-tools linux-libc-dev linux-headers-4.15.0-20-generic

# Install basics to locally compile htslib dependencies
RUN apt-get update && \
apt-get install -y libssl-dev libcurl4-openssl-dev zlib1g-dev libbz2-dev liblzma-dev musl musl-dev musl-tools linux-libc-dev linux-headers-4.15.0-20-generic
apt-get install -y build-essential autoconf automake autotools-dev git wget

# Otherwise LLVM bump below fails
RUN apt-get install -y wget gnupg lsb-release software-properties-common apt-transport-https ca-certificates

# Autodetect and fetch latest LLVM repos for the current distro, avoids LLVM warnings and other issues, might generate slower builds for now though, see:
# https://www.phoronix.com/scan.php?page=news_item&px=Rust-Hurt-On-LLVM-10
RUN bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
#RUN apt-get install -y libssl-dev libcurl4-openssl-dev zlib1g-dev libbz2-dev liblzma-dev musl musl-dev musl-tools # htslib deps

# Remove pre-installed musl, to avoid cross-musl-make interference
RUN apt-get remove -y musl

# For now we'll have to go nuts and not only build musl-1.2.0 from scratch but all the other libs too...
# Updated musl-cross toolchain that does not fail on OpenSSL: https://github.com/openssl/openssl/issues/7207
WORKDIR /root
RUN wget https://github.com/richfelker/musl-cross-make/archive/v$MUSL_CROSS_MAKE_VERSION.tar.gz \
&& tar xvfz v$MUSL_CROSS_MAKE_VERSION.tar.gz
WORKDIR /root/musl-cross-make-$MUSL_CROSS_MAKE_VERSION
COPY config-musl-cross-make.mak config.mak
RUN make -j40 install

# Now we assume we have a properly configured musl-cross...
ENV PATH "/usr/local/musl/bin:$PATH"
ENV CFLAGS "-fPIC"
ENV CROSS_COMPILE x86_64-linux-musl-
ENV CC ${CROSS_COMPILE}cc
ENV AR ${CROSS_COMPILE}ar
ENV RANLIB ${CROSS_COMPILE}ranlib
ENV CXX ${CROSS_COMPILE}g++
ENV CPPFLAGS "-I/usr/local/musl/include -I/usr/local/include"
ENV LDFLAGS "-L/usr/local/musl/lib -L/usr/local/lib"

# .. and carry on with the htslib deps
RUN wget https://www.zlib.net/zlib-$ZLIB_VERSION.tar.gz \
&& tar xvfz zlib-$ZLIB_VERSION.tar.gz \
&& cd zlib-$ZLIB_VERSION \
&& ./configure --static --prefix=/usr/local/musl \
&& make -j40 install
WORKDIR /root
RUN git clone git://sourceware.org/git/bzip2 \
&& cd bzip2 \
#&& make -j40 CC=$CC AR=$AR RANLIB=$RANLIB CFLAGS=$CFLAGS bzip2 \
&& make PREFIX=/usr/local/musl -j40 bzip2 \
&& make -j40 install
WORKDIR /root
RUN wget https://tukaani.org/xz/xz-$LZMA_VERSION.tar.bz2 \
&& tar xvfj xz-$LZMA_VERSION.tar.bz2 \
&& cd xz-$LZMA_VERSION \
&& ./configure --prefix=/usr/local/musl --enable-static --disable-shared --host x86_64-unknown-linux-musl \
&& make -j40 install
WORKDIR /root

# A few gems from: https://wiki.openssl.org/index.php/Compilation_and_Installation
# "OpenSSL has been around a long time, and it carries around a lot of cruft"
# "SSLv2 is completely broken, and you should disable it during configuration"
# "You should specify both --prefix and --openssldir to ensure make install works as expected."
#
# And also this:
# https://github.com/openssl/openssl/issues/11362
#
# And having to redefine AR,CC & RANLIB because otherwise, this:
#
# make[1]: x86_64-linux-musl-x86_64-linux-musl-ar: Command not found
RUN wget https://github.com/openssl/openssl/archive/OpenSSL_$OPENSSL_VERSION.tar.gz \
&& tar xvfz OpenSSL_$OPENSSL_VERSION.tar.gz && cd openssl-OpenSSL_$OPENSSL_VERSION \
&& ./Configure --prefix=/usr/local/musl --openssldir=/usr/local/musl \
--with-zlib-lib=/usr/local/lib/zlib-$ZLIB_VERSION linux-x86_64 \
no-shared no-dso no-gost no-engine no-ssl2 no-srp no-srtp no-tests zlib \
no-weak-ssl-ciphers \
&& make AR=x86_64-linux-musl-ar \
CC=x86_64-linux-musl-cc \
-j40 \
&& make RANLIB=x86_64-linux-musl-ranlib -j40 install

WORKDIR /root
RUN wget https://curl.haxx.se/download/curl-$CURL_VERSION.tar.gz \
&& tar xvfz curl-$CURL_VERSION.tar.gz && cd curl-$CURL_VERSION \
&& ./configure --prefix=/usr/local/musl --host x86_64-linux-musl \
--with-ssl=/usr/local/musl --with-zlib=/usr/local/musl --enable-static \
--disable-dict --disable-file --disable-ftp --disable-gopher --disable-imap \
--disable-pop3 --disable-rtsp --disable-smb --disable-smtp --disable-telnet \
--disable-tftp --disable-ntlm --disable-ldap \
&& make -j40 install

# To cater Rust's openssl-sys needs...
#ENV OPENSSL_DIR /usr/local/openssl
ENV OPENSSL_DIR /usr/local/musl

# Hack to force ld stick to musl on the hts-sys/build.rs side, otherwise:
# = note: /usr/bin/ld: /target/debug/deps/liblibloading-689161fea10b6234.rlib(global_static.o): unable to initialize decompress status for section .debug_info
RUN rm /usr/bin/ld && ln -sf /usr/local/musl/bin/x86_64-linux-musl-ld /usr/bin/ld

# Prepare rustup and toolchain locally for easy manual intervention in this container
#RUN wget https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init \
# && chmod +x rustup-init \
# && ./rustup-init -y \
# && . $HOME/.cargo/env \
# && rustup target add x86_64-unknown-linux-musl

CMD ["bash"]
2 changes: 1 addition & 1 deletion docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ $ docker build -t brainstorm/cross-x86_64-unknown-linux-musl:libcurl-openssl . -
$ docker build -t brainstorm/cross-x86_64-unknown-linux-gnu:libcurl-openssl . -f Dockerfile.gnu
```

Then to build and test rust-htslib with the above containers, proceed as you would with `cargo`, using `cross` instead, i.e:
Then, to build and test rust-htslib with the above containers, proceed as you would with `cargo`, using `cross` instead, i.e:

```shell
$ cross build --target x86_64-unknown-linux-musl
Expand Down
4 changes: 4 additions & 0 deletions docker/config-musl-cross-make.mak
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
TARGET = x86_64-linux-musl
OUTPUT = /usr/local/musl
GCC_VER = 9.2.0
BINUTILS_VER = 2.33.1
20 changes: 10 additions & 10 deletions hts-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@ pre-release-commit-message = "release version {{version}}"
tag-message = "Version {{version}} of Rust-HTSlib."

[dependencies]
libc = "0.2"
libz-sys = "1.0"
bzip2-sys = { version = "0.1", optional = true }
lzma-sys = { version = "0.1", optional = true }
curl-sys = { version = "0.4.26", optional = true }
openssl-sys = { version = "0.9.54", optional = true }
libz-sys = { version = "1.0.25", features = ["static"] }
# https://github.com/alexcrichton/bzip2-rs/issues/56
bzip2-sys = { version = "0.1.8", optional = true }
lzma-sys = { version = "0.1.16", optional = true, features = ["static"] }
curl-sys = { version = "0.4.31", optional = true, features = ["static-curl", "static-ssl"] }

[features]
default = ["bzip2", "lzma", "curl"]
default = ["bzip2", "lzma"]
bzip2 = ["bzip2-sys"]
lzma = ["lzma-sys"]
openssl = ["openssl-sys"]
#openssl = ["openssl-sys"]
curl = ["curl-sys"]
static = []

[build-dependencies]
fs-utils = "1.1"
bindgen = { version = "0.53.1", default-features = false, features = ["runtime"] }
bindgen = { version = "0.53.2", default-features = false, features = ["runtime"] }
cc = "1.0"
glob = "0.3.0"
glob = "0.3.0"
Loading

0 comments on commit 8107160

Please sign in to comment.