Skip to content

Commit

Permalink
CentOS 7 build (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
mlin authored Jan 5, 2021
1 parent b9ca880 commit bf8ce0a
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 55 deletions.
47 changes: 32 additions & 15 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ env:
APT_DEPS: libzstd-dev samtools tabix libhts-dev pigz python3-pip
BREW_DEPS: python@3.8 sqlite zstd samtools pigz coreutils
PIP_DEPS: pytest pytest-xdist
SQLITE_VERSION: 3340000

jobs:

Expand Down Expand Up @@ -59,7 +60,7 @@ jobs:
- name: test
run: env -C build ctest -V

linux-so:
linux-x86-64-so:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
Expand All @@ -70,18 +71,25 @@ jobs:
sudo apt-get -qq update
sudo apt-get install -y $APT_DEPS
sudo pip3 install --system $PIP_DEPS
cmake -DCMAKE_BUILD_TYPE=Release -B build . && cmake --build build -j $(nproc)
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS='-D_GLIBCXX_USE_CXX11_ABI=0' -B build . && cmake --build build -j $(nproc)
rm build/libgenomicsqlite.so
sudo apt-get remove -y libzstd-dev # should be linked into libgenomicsqlite.so
- name: build portable .so in docker
run: docker build -t genomicsqlite . && docker run -v $(pwd):/mnt --rm genomicsqlite cp build/libgenomicsqlite.so /mnt/build/
- name: ldd
run: docker build --build-arg "SQLITE_VERSION=${SQLITE_VERSION}" -t genomicsqlite . && docker run -v $(pwd):/mnt --rm genomicsqlite cp /usr/local/lib/{libgenomicsqlite.so,libsqlite3.so.0} /mnt/build/
- name: symbols & digests
run: |
docker run genomicsqlite ldd -v -r build/libgenomicsqlite.so
readelf -d build/libgenomicsqlite.so
ldd -r build/libgenomicsqlite.so
echo "----"
ldd -v -r build/libgenomicsqlite.so
echo "libgenomicsqlite.so GLIBC version requirements:"
objdump -t build/libgenomicsqlite.so | grep -o 'GLIBC_.*' | sort -Vr | head -n1
objdump -t build/libgenomicsqlite.so | grep -o 'GLIBCXX_.*' | sort -Vr | head -n1
echo "libsqlite3.so.0 GLIBC version requirements:"
objdump -t build/libsqlite3.so.0 | grep -o 'GLIBC_.*' | sort -Vr | head -n1
echo "----"
sha256sum build/libgenomicsqlite.so
sha256sum build/libgenomicsqlite.so build/libsqlite3.so.0
sudo cp build/libsqlite3.so.0 /usr/local/lib
sudo ldconfig
- name: rust toolchain
uses: actions-rs/toolchain@v1
with:
Expand All @@ -96,13 +104,17 @@ jobs:
bindings/rust/cargo test --release
bindings/rust/cargo package --list | grep libgenomicsqlite.so
- name: prepare artifacts
run: cp build/libgenomicsqlite.so include/genomicsqlite.h .
run: cp build/{libgenomicsqlite.so,libsqlite3.so.0} .
- uses: actions/upload-artifact@v2
with:
name: libgenomicsqlite.so
path: libgenomicsqlite.so
- uses: actions/upload-artifact@v2
with:
name: libsqlite3.so.0
path: libsqlite3.so.0

macOS-dylib:
macOS-x86-64-dylib:
runs-on: macOS-10.15
steps:
- uses: actions/checkout@v2
Expand All @@ -111,9 +123,10 @@ jobs:
- name: dependencies
run: |
rm -f /usr/local/bin/2to3 # https://github.com/pypa/pipenv/issues/3831
brew update
brew upgrade
brew install $BREW_DEPS
brew update || (sleep 2; brew update)
for dep in $BREW_DEPS ; do
brew install $dep || brew upgrade $dep
done
/usr/local/bin/pip3 install $PIP_DEPS
- name: rust toolchain
uses: actions-rs/toolchain@v1
Expand All @@ -136,7 +149,7 @@ jobs:
-DCMAKE_PREFIX_PATH=$(brew --prefix)/opt/sqlite \
-B build .
cmake --build build -j 4
- name: otool
- name: symbols & digests
run: |
otool -L build/libgenomicsqlite.dylib
sha256sum build/libgenomicsqlite.dylib
Expand All @@ -160,13 +173,17 @@ jobs:

artifacts:
runs-on: ubuntu-20.04
needs: [linux-so, macOS-dylib]
needs: [linux-x86-64-so, macOS-x86-64-dylib]
steps:
- uses: actions/checkout@v2
- name: fetch libgenomicsqlite.so
uses: actions/download-artifact@v2
with:
name: libgenomicsqlite.so
- name: fetch libsqlite3.so.0
uses: actions/download-artifact@v2
with:
name: libsqlite3.so.0
- name: fetch libgenomicsqlite.dylib
uses: actions/download-artifact@v2
with:
Expand All @@ -188,7 +205,7 @@ jobs:
cp libgenomicsqlite.so libgenomicsqlite.dylib bindings/jdbc/genomicsqlite-jdbc/src/main/resources/
mvn deploy -Drevision=${{ env.GIT_REVISION }} -B -f bindings/jdbc/genomicsqlite-jdbc/pom.xml
- name: digests
run: sha256sum *genomicsqlite* bindings/jdbc/genomicsqlite-jdbc/target/genomicsqlite*.jar
run: sha256sum *genomicsqlite* bindings/jdbc/genomicsqlite-jdbc/target/genomicsqlite*.jar libsqlite3.so.0
- uses: actions/upload-artifact@v2
with:
name: genomicsqlite-jdbc-${{ env.GIT_REVISION }}
Expand Down
129 changes: 111 additions & 18 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
# Builds libgenomicsqlite.so in old ubuntu (16.04) to maximize portability. Also bakes in Zstandard.
# This recipe works on 14.04 too, but there are C++ symbol differences before & after g++ 5.1:
# https://gcc.gnu.org/onlinedocs/gcc-5.2.0/libstdc++/manual/manual/using_dual_abi.html
FROM ubuntu:16.04
# Builds libgenomicsqlite.so in CentOS 7 (+ devtoolset-8) to maximize compatibility. Bakes in
# Zstandard, and also builds a compatible libsqlite3.so.0 for users unable/unwilling to upgrade
# their host's.
FROM centos:7 as builder

ARG CMAKE_VERSION=3.17.3
ARG SQLITE_VERSION=3310000
ARG ZSTD_VERSION=1.4.7
ARG CPU_ARCH=haswell

ARG SQLITE_VERSION=3340000
ARG ZSTD_VERSION=1.4.8
ARG CPU_ARCH=ivybridge
ENV CFLAGS="-march=${CPU_ARCH} -O3"
ENV CXXFLAGS=${CFLAGS}
# https://www.sqlite.org/compile.html
ENV SQLITE_CFLAGS="\
-DSQLITE_ENABLE_LOAD_EXTENSION \
-DSQLITE_USE_URI \
-DSQLITE_DQS=0 \
-DSQLITE_LIKE_DOESNT_MATCH_BLOBS \
-DSQLITE_DEFAULT_MEMSTATUS=0 \
-DSQLITE_MAX_EXPR_DEPTH=0 \
-DSQLITE_ENABLE_NULL_TRIM \
-DSQLITE_USE_ALLOCA \
-DSQLITE_HAVE_ISNAN \
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT \
-DSQLITE_ENABLE_COLUMN_METADATA \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_PREUPDATE_HOOK \
-DSQLITE_ENABLE_SESSION \
"

# apt
RUN apt-get -qq update && DEBIAN_FRONTEND=noninteractive apt-get -qq install -y \
build-essential wget zip rsync git-core
RUN yum install -y -q wget unzip rsync git centos-release-scl
RUN yum install -y -q devtoolset-8-gcc devtoolset-8-gcc-c++ devtoolset-8-make

RUN mkdir -p /work/GenomicSQLite

Expand All @@ -22,16 +39,16 @@ WORKDIR /work
RUN wget -nv https://www.sqlite.org/2020/sqlite-amalgamation-${SQLITE_VERSION}.zip \
&& unzip -o sqlite-amalgamation-${SQLITE_VERSION}.zip
WORKDIR /work/sqlite-amalgamation-${SQLITE_VERSION}
RUN gcc -shared -o libsqlite3.so.0 -fPIC -shared -Wl,-soname,libsqlite3.so.0 -g ${CFLAGS} sqlite3.c
RUN gcc -o sqlite3 -g ${CFLAGS} sqlite3.c shell.c -lpthread -ldl
RUN bash -c "scl enable devtoolset-8 'gcc -shared -o libsqlite3.so.0 -fPIC -shared -Wl,-soname,libsqlite3.so.0 -g ${CFLAGS} ${SQLITE_CFLAGS} sqlite3.c' & pid=$? \
scl enable devtoolset-8 'gcc -o sqlite3 -g ${CFLAGS} ${SQLITE_CFLAGS} sqlite3.c shell.c -lpthread -ldl -lm' && wait $pid"
RUN cp libsqlite3.so.0 /usr/local/lib && cp *.h /usr/local/include && cp sqlite3 /usr/local/bin
RUN ln -s /usr/local/lib/libsqlite3.so.0 /usr/local/lib/libsqlite3.so

# Zstandard -- hacked with -fPIC for use with ZSTD_WHOLE_ARCHIVE
WORKDIR /work
RUN wget -nv -O - https://github.com/facebook/zstd/releases/download/v${ZSTD_VERSION}/zstd-${ZSTD_VERSION}.tar.gz | tar zx
WORKDIR /work/zstd-${ZSTD_VERSION}
RUN CFLAGS="${CFLAGS} -fPIC" make install -j $(nproc)
RUN scl enable devtoolset-8 "CFLAGS='${CFLAGS} -fPIC' make install -j $(nproc)"

# CMake
WORKDIR /work
Expand All @@ -44,7 +61,83 @@ RUN ldconfig
# libgenomicsqlite.so
ADD . /work/GenomicSQLite
WORKDIR /work/GenomicSQLite
RUN rm -rf build && cmake -DCMAKE_BUILD_TYPE=Release -DZSTD_WHOLE_ARCHIVE=true -B build . && cmake --build build --target genomicsqlite -j $(nproc)
RUN ldd -v -r build/libgenomicsqlite.so
RUN sqlite3 -cmd '.load build/libgenomicsqlite.so' :memory: 'select genomicsqlite_version()'
RUN sha256sum build/libgenomicsqlite.so
RUN rm -rf build
RUN scl enable devtoolset-8 "cmake -DCMAKE_BUILD_TYPE=Release -DZSTD_WHOLE_ARCHIVE=true -B build . && cmake --build build --target genomicsqlite -j $(nproc)"
RUN sqlite3 -cmd '.load build/libgenomicsqlite.so' :memory: 'select sqlite_version(); select genomicsqlite_version()'




###################################################################################################
# Run-up in fresh centos:7, to confirm no dependencies crept into the .so's

FROM centos:7

COPY --from=builder /usr/local/bin/sqlite3 /usr/local/bin/
COPY --from=builder /usr/local/include/sqlite3.h /usr/local/include/

# NOTE: /usr/local/lib is NOT a default ld path in CentOS -- https://unix.stackexchange.com/q/356624
RUN mkdir -p /work/lib
WORKDIR /work
COPY --from=builder /usr/local/lib/libsqlite3.so.0 ./lib/
COPY --from=builder /work/GenomicSQLite/build/libgenomicsqlite.so ./
# the following approximates how bindings will usually load the extension at runtime:
# - libsqlite3.so.0 in the ld search path (if not already resident in the process)
# - given absolute path to libgenomicsqlite3.so
RUN LD_LIBRARY_PATH=$(pwd)/lib sqlite3 -cmd ".load $(pwd)/libgenomicsqlite.so" :memory: 'select sqlite_version(); select genomicsqlite_version()'
# if troubleshooting that: set LD_DEBUG=libs for extremely detailed dlopen() logs

# now try capi_smoke_test, with some hoops to ensure it's not dependent on implicit RPATHs
RUN yum install -y -q gcc && gcc -v
RUN mv libgenomicsqlite.so lib/ && ln -s libsqlite3.so.0 lib/libsqlite3.so
ADD ./test/capi_smoke_test.c ./include/genomicsqlite.h ./
RUN gcc -o genomicsqlite_capi_smoke_test ${CFLAGS} -L$(pwd)/lib -Wl,-rpath,\$ORIGIN -Wl,-z,origin \
capi_smoke_test.c -lgenomicsqlite -lsqlite3 \
&& readelf -d genomicsqlite_capi_smoke_test
RUN mv lib/{libgenomicsqlite.so,libsqlite3.so.0} . && rm -rf lib
RUN ./genomicsqlite_capi_smoke_test
# ^ we didn't need LD_LIBRARY_PATH even though the .so's aren't at their linktime locations

# test rust bindings too
FROM centos:7

RUN yum install -y -q gcc git
ADD https://sh.rustup.rs /usr/local/bin/rustup-init.sh
RUN chmod +x /usr/local/bin/rustup-init.sh && rustup-init.sh -y
ENV PATH=${PATH}:/root/.cargo/bin

RUN mkdir -p /work/lib
WORKDIR /work
COPY --from=builder /usr/local/lib/libsqlite3.so.0 ./lib/
RUN ln -s libsqlite3.so.0 lib/libsqlite3.so
ADD ./.git ./.git
ADD ./bindings/rust ./rust
COPY --from=builder /work/GenomicSQLite/build/libgenomicsqlite.so ./rust/
RUN LD_LIBRARY_PATH=$(pwd)/lib LIBRARY_PATH=$(pwd)/lib rust/cargo test --release

###################################################################################################
# Run-up in ubuntu 16.04

FROM ubuntu:16.04

COPY --from=builder /usr/local/bin/sqlite3 /usr/local/bin/
COPY --from=builder /usr/local/include/sqlite3.h /usr/local/include/
COPY --from=builder /usr/local/lib/libsqlite3.so.0 /work/GenomicSQLite/build/libgenomicsqlite.so /usr/local/lib/
RUN ln -s libsqlite3.so.0 /usr/local/lib/libsqlite3.so

RUN sqlite3 -cmd '.load /usr/local/lib/libgenomicsqlite.so' :memory: 'select sqlite_version(); select genomicsqlite_version()'

RUN mkdir /work
WORKDIR /work

RUN apt-get -qq update && apt-get install -qq -y build-essential && gcc -v
ADD ./test/capi_smoke_test.c ./include/genomicsqlite.h /work/
RUN gcc -o genomicsqlite_capi_smoke_test ${CFLAGS} capi_smoke_test.c -lgenomicsqlite -lsqlite3
RUN ./genomicsqlite_capi_smoke_test

# display dependencies & digests in docker build log
RUN ldd -v -r /usr/local/lib/libgenomicsqlite.so
RUN objdump -t /usr/local/lib/libgenomicsqlite.so | grep -o 'GLIBC_.*' | sort -Vr | head -n1
RUN objdump -t /usr/local/lib/libgenomicsqlite.so | grep -o 'GLIBCXX_.*' | sort -Vr | head -n1
RUN objdump -t /usr/local/lib/libsqlite3.so.0 | grep -o 'GLIBC_.*' | sort -Vr | head -n1
RUN sha256sum /usr/local/lib/libgenomicsqlite.so /usr/local/lib/libsqlite3.so.0
7 changes: 7 additions & 0 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ The Genomics Extension integrates with your programming language's existing SQLi
Link the program to `sqlite3` and `genomicsqlite` libraries; optionally,
[SQLiteCpp](https://github.com/SRombauts/SQLiteCpp).

GNU/Linux: to link the prebuilt `libgenomicsqlite.so` distributed from our GitHub Releases, you
may have to compile your source with `CXXFLAGS=-D_GLIBCXX_USE_CXX11_ABI=0`. This is because the
library is built against an old libstdc++ version to improve runtime compatibility. The
function of this flag is explained in the libstdc++ docs on
[Dual ABI](https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html). If you build
`libgenomicsqlite.so` from source, then the flag will not be needed.

General note: GenomicSQLite C++ routines are liable to throw exceptions.

=== "C"
Expand Down
10 changes: 9 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ Our **[Colab notebook](https://colab.research.google.com/drive/1OlHPOcRQBhDmEnS1

**To use the Genomics Extension you might first need to upgrade SQLite itself.** The host program must link [SQLite version 3.31.0 (2020-01-22)](https://www.sqlite.org/releaselog/3_31_0.html) or newer. In your shell, `sqlite3 --version` displays the version installed with your OS, which is probably what your programs use; if in doubt, cause a program to report the result of `SELECT sqlite_version()`.

If this is too old, then upgrade SQLite3 using your preferred binary package manager (e.g. apt, yum, conda, brew), if possible. Otherwise, modify your program's linking step or runtime environment to cause it to use an up-to-date version, for example by setting rpath or LD_LIBRARY_PATH to the location of an up-to-date shared library file. Resources:
If this is too old, then upgrade SQLite3 using your preferred binary package manager (e.g. apt, yum, conda, brew), if possible. Otherwise, modify your program's linking step or runtime environment to cause it to use an up-to-date version, for example by setting rpath or `LD_LIBRARY_PATH` to the location of an up-to-date shared library file. Resources:

* [How To Compile SQLite](https://www.sqlite.org/howtocompile.html)
* [DreamHost Knowledge Base - Installing a custom version of SQLite3](https://help.dreamhost.com/hc/en-us/articles/360028047592-Installing-a-custom-version-of-SQLite3)
* [Rpmfind: libsqlite3](https://rpmfind.net/linux/rpm2html/search.php?query=libsqlite3&submit=Search+...&system=&arch=)
* [Sqlite :: Anaconda Cloud](https://anaconda.org/anaconda/sqlite)
* Homebrew [formula/sqlite](https://formulae.brew.sh/formula/sqlite), [formula-linux/sqlite](https://formulae.brew.sh/formula-linux/sqlite)
* As a last resort for GNU/Linux, our [GitHub Releases](https://github.com/mlin/GenomicSQLite/releases) include a `libsqlite3.so.0` that should be compatible with modern (2016+) hosts.

You can always `SELECT sqlite_version()` to verify the upgrade in your program.

Expand Down Expand Up @@ -82,6 +83,13 @@ It's usually easiest to obtain the extension as a pre-compiled shared library (L

Recommendation: *also* install the Python package, which includes a useful command-line shell and smoke-test script.

GNU/Linux: to link the prebuilt `libgenomicsqlite.so` distributed from our GitHub Releases, you
may have to compile your source with `CXXFLAGS=-D_GLIBCXX_USE_CXX11_ABI=0`. This is because the
library is built against an old libstdc++ version to improve runtime compatibility. The
function of this flag is explained in the libstdc++ docs on
[Dual ABI](https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html). If you build
`libgenomicsqlite.so` from source, then the flag will not be needed.

See our [GitHub README](https://github.com/mlin/GenomicSQLite) for the source build procedure, if needed.

We welcome community contributions to the available language bindings; see the Language Bindings Guide if interested.
Expand Down
Loading

0 comments on commit bf8ce0a

Please sign in to comment.