This repo provides dockerfiles to create docker images used for creating
fully-static D program binaries. It serves as an example of how to compile static Dlang
programs using alpine linux, musl-c
, and the ldc
compiler. It also
serves as an example of how to configure github actions to build a docker image,
push it to Dockerhub, and create a release draft that has the static binary
attached from the uploaded docker image. The created binary should work on
any x86_64 linux distribution.
The dlang/ldc.dockerfile
provides a base environment that can be used to create
static dlang binaries. An example D program can be found here: tests/test-app
.
If your program requires other shared libraries you will have to manipulate the
dub.json
file further. The dub.json
excerpt below example is taken from
another D program, fade:
"configurations":[
{
"name":"shared",
"targetType": "executable"
},
{
"name":"static-alpine",
"targetType": "executable",
"dflags-ldc": [
"-link-defaultlib-shared=false",
"-static",
"--linker=gold",
"-L-lz",
"-L-lbz2",
"-L-ldeflate",
"-L-llzma",
"-L-lcurl",
"-L-lssl",
"-L-lssh2",
"-L-lcrypto"
],
"sourceFiles": ["/usr/local/lib/mimalloc-2.0/mimalloc.o"]
}
]
The dflags
must be appended to include "-L-lcurl"
lines for neccessary libraries,
and these libraries will need to be present in the docker image in both shared and static
library forms. For example, many libraries in the htslib/Dockerfile
image had to be compiled
from source:
# compiling libdeflate
RUN wget https://github.com/ebiggers/libdeflate/archive/refs/tags/v$DEFLATE_VER.tar.gz \
&& tar -xf v$DEFLATE_VER.tar.gz \
&& cd libdeflate-$DEFLATE_VER \
&& make install -j 8 \
&& cd /home/ \
&& rm -r libdeflate-$DEFLATE_VER
Though if the alpine repositories have it in both static and shared forms you may be able to avoid compiling them:
RUN apk add --update --no-cache \
autoconf automake make cmake \
zlib zlib-dev zlib-static \
xz xz-dev \
bzip2 bzip2-dev bzip2-static
These libraries also must be installed into locations on the LD_LIBRARY_PATH and LIBRARY_PATH or those environment variables must be altered. These are defined in our images as such:
ENV LD_LIBRARY_PATH="/lib:/usr/local/lib:/usr/local/lib64:/usr/lib:$LD_LIBRARY_PATH"
ENV LIBRARY_PATH="$LD_LIBRARY_PATH"
Since many of our programs that rely on htslib are multi-threaded, we have also included this line:
"sourceFiles": ["/usr/local/lib/mimalloc-2.0/mimalloc.o"]
musl-c
's allocation performance is poor compared to mimalloc in multi-threaded situations:
https://www.linkedin.com/pulse/testing-alternative-c-memory-allocators-pt-2-musl-mystery-gomes.
Our htslib
image includes a compiled version of mimalloc
, including the prior line in our dub.json
ensures that mimalloc
is used for all allocation across our binary, even for libraries that weren't
compiled with mimalloc
.
If your docker image is uploaded to Dockerhub, you can use the github actions .github/workflows/build_and_release.yml
in this repo to have your docker image built and uploaded to Dockerhub via github actions. You will have to
set up a dockerhub API key. The github actions script will also pull the test app docker image from
Dockerhub, extract the static binary from it, and create a release draft with the binary attached, just
look at our v0.0.1
release.
The docker images built by our github actions are availiable through dockerhub:
docker pull blachlylab/dlang-ldc-static
docker pull blachlylab/dlang-htslib-static
or use with the FROM
docker syntax.