In this post I will show you how to compile a statically linked transmission-daemon in transmision 4.0.5 with buildah, you should be able to build other components as well. The process should be roughly the same but your mileages may vary, as I am doing some dirty hacks to make it work.

The build_tranmission-daemon.sh script

# build_tranmission-daemon.sh
#!/bin/bash

export TRANSMISSION_VERSION="4.0.5"
buildah bud -f Containerfile.transmission --iidfile out/transmission-${TRANSMISSION_VERSION}.iid

export iid=$(cat out/transmission-${TRANSMISSION_VERSION}.iid | cut -d ':' -f2)
export container=$(buildah from ${iid})

copy_script="copy_artifacts.sh"
cat << 'EOF' >> $copy_script
#!/bin/sh
mnt=$(buildah mount $container)
cp $mnt/$1 ./out/$2
buildah umount $container
EOF
chmod a+x $copy_script
buildah unshare ./$copy_script transmission-${TRANSMISSION_VERSION}-obj/daemon/transmission-daemon transmission-daemon-4.0.5
rm ./$copy_script
buildah rm $container

The script is pretty simple, it builds the container with the Containerfile.transmission and then copy the artifacts out of the container. The copy_artifacts.sh script is a helper script to copy the artifacts out of the container.

The script outputs the image ID (iid) of the newly created image into a file. Then it creates a new container(container=$(buildah from ${iid}) ) from the image and copy the artifacts out of the container. The container is then removed.

The Containerfile.transmission dockerfile

FROM alpine:latest
LABEL maintainer="gitub.com/deamen"

ENV TRANSMISSION_VERSION="4.0.5"

RUN apk update && apk --no-cache add sudo vim \
    build-base curl-static curl-dev brotli-static brotli-dev nghttp2-static \
    zlib-static zlib-dev c-ares-static linux-headers libunistring-static libunistring-dev \
    openssl-libs-static libevent-static libidn2-static libidn2-dev libevent-dev xz ninja cmake \
    gettext-dev

RUN wget -c https://github.com/transmission/transmission/releases/download/${TRANSMISSION_VERSION}/transmission-${TRANSMISSION_VERSION}.tar.xz
RUN tar -xf transmission-${TRANSMISSION_VERSION}.tar.xz

RUN   cmake \
        -S transmission-${TRANSMISSION_VERSION} \
        -B transmission-${TRANSMISSION_VERSION}-obj \
        -G Ninja \
        -DCMAKE_BUILD_TYPE=Release \
        -DENABLE_DAEMON=ON \
        -DENABLE_CLI=OFF \
        -DENABLE_GTK=OFF \
        -DENABLE_QT=OFF \
        -DENABLE_UTILS=OFF \
        -DENABLE_TESTS=OFF \
        -DBUILD_SHARED_LIBS=OFF \
        -DENABLE_NLS=OFF \
        -DCMAKE_EXE_LINKER_FLAGS="-static" \
        -DCURL_LIBRARY_RELEASE=/usr/lib/libcurl.a \
        -DEVENT2_LIBRARY=/usr/lib/libevent.a \
        -DOPENSSL_USE_STATIC_LIBS=TRUE

RUN cmake --build transmission-${TRANSMISSION_VERSION}-obj --config Release ; \
      cd transmission-${TRANSMISSION_VERSION}-obj && \
      /usr/bin/c++ -O2 -g -DNDEBUG -static \
      daemon/CMakeFiles/transmission-daemon.dir/daemon.cc.o \
      daemon/CMakeFiles/transmission-daemon.dir/daemon-posix.cc.o \
      -o daemon/transmission-daemon \
      libtransmission/libtransmission.a \
      /usr/lib/libevent.a \
      third-party/libdeflate.bld/pfx/lib/libdeflate.a \
      /usr/lib/libssl.a \
      /usr/lib/libcrypto.a \
      -ldl \
      /usr/lib/libcurl.a \
      /usr/lib/libbrotlidec.a \
      /usr/lib/libnghttp2.a \
      /usr/lib/libcares.a \
      /usr/lib/libidn2.a \
      /usr/lib/libunistring.a \
      /usr/lib/libssl.a \
      /lib/libz.a \
      /usr/lib/libcrypto.a \
      /usr/lib/libbrotlicommon.a \
      third-party/libpsl.bld/pfx/lib/libpsl.a  \
      third-party/libnatpmp.bld/pfx/lib/libnatpmp.a  \
      third-party/miniupnpc.bld/pfx/lib/libminiupnpc.a  \
      third-party/dht.bld/pfx/lib/libdht.a \
      third-party/libutp.bld/libutp.a \
      third-party/libb64.bld/src/libb64.a \
      -lm  third-party/jsonsl/libjsonsl.a  third-party/wildmat/libwildmat.a

The Containerfile.transmission is a dockerfile that installs the dependencies and then builds the transmission-daemon statically linked. The hack I have to do here is to manually link the libraries with the daemon. The libcurl and libevent static libraries are not properly set by the cmake, so I have to do it manually.

For libevent there is no existing switch to set it to static, so I have to manually point it to the static library file with -DEVENT2_LIBRARY=/usr/lib/libevent.a during the configuration stage.

For libcurl, there is no existing switch too, so I have to use -DCURL_LIBRARY_RELEASE=/usr/lib/libcurl.a during the configuration stage. But since libcurl has a lot of dependencies, it still fails at the link step, I have to figure out the dependencies and ink them to the link command manually. So if you are compling on other platforms, you may have to spend sometime to track down the dependencies of libcurl.

Conclusion

The compiled transmission-daemon is statically linked and can be run on any linux system without the need to install any dependencies. The process is pretty simple, but you may have to spend some time to figure out the dependencies of the libraries. The process should be roughly the same for other components, but your mileages may vary.

The proper way to do it should be to patch the CMAKEList.txt of the transmission project to properly set the static libraries, we probably need to add switches for setting libcurl and libevent to static libraries. And an option to add library dependencies for libcurl. But I don’t know how to do it yet, I may spend some time to figure it out in the future.