~fincham/static-binary-zoo

92133cf24670bb439827262bfc1bdb1893fe5f2a — Michael Fincham 2 months ago c04fe7b
Add remaining hashes for downloads, improve README a little
M Dockerfile.busybox-1.33.1 => Dockerfile.busybox-1.33.1 +3 -5
@@ 2,13 2,11 @@ ARG MUSL_TARGET=x86_64-linux-musl
FROM musl-cross-make-${MUSL_TARGET}
ARG MUSL_TARGET

RUN cd /build && \
wget -O source.tar.bz2 https://busybox.net/downloads/busybox-1.33.1.tar.bz2 && \
tar xf source.tar.bz2

WORKDIR /build
RUN download https://busybox.net/downloads/busybox-1.33.1.tar.bz2 source.tar.bz2 12cec6bd2b16d8a9446dd16130f2b92982f1819f6e1c5f5887b6db03f5660d28 && tar xf source.tar.bz2
RUN export PATH=/build/cross/bin:$PATH && \
mkdir -p /output/bin && \
cd /build/busybox-* && \
cd busybox-* && \
export CFLAGS="-frandom-seed=pulse -I/output/include" && \
export LDFLAGS="--static -L/output/lib" && \
make defconfig && \

M Dockerfile.fuse-2.9.9 => Dockerfile.fuse-2.9.9 +3 -4
@@ 2,12 2,11 @@ ARG MUSL_TARGET=x86_64-linux-musl
FROM musl-cross-make-${MUSL_TARGET}
ARG MUSL_TARGET

RUN cd /build && \
wget -O source.tar.gz https://github.com/libfuse/libfuse/releases/download/fuse-2.9.9/fuse-2.9.9.tar.gz && \
tar xf source.tar.gz

WORKDIR /build
RUN download https://github.com/libfuse/libfuse/releases/download/fuse-2.9.9/fuse-2.9.9.tar.gz source.tar.gz d0e69d5d608cc22ff4843791ad097f554dd32540ddc9bed7638cc6fea7c1b4b5 && tar xf source.tar.gz
RUN export PATH=/build/cross/bin:$PATH && \
cd /build/fuse-* && \
cd fuse-* && \
CC="$MUSL_TARGET-gcc" \
CFLAGS="-static -frandom-seed=pulse -I/output/include" \
LDFLAGS="-L/output/lib" \

M Dockerfile.libpcap-1.10.1 => Dockerfile.libpcap-1.10.1 +3 -5
@@ 2,12 2,10 @@ ARG MUSL_TARGET=x86_64-linux-musl
FROM musl-cross-make-$MUSL_TARGET
ARG MUSL_TARGET

RUN cd /build && \
wget -O source.tar.gz https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz && \
tar xf source.tar.gz

WORKDIR /build
RUN download https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz source.tar.gz ed285f4accaf05344f90975757b3dbfe772ba41d1c401c2648b7fa45b711bdd4 && tar xf source.tar.gz
RUN export PATH=/build/cross/bin:$PATH && \
cd /build/libpcap-* && \
cd libpcap-* && \
CC="$MUSL_TARGET-gcc" \
CFLAGS="-static -frandom-seed=pulse" \
./configure \ 

M Dockerfile.libxml2-2.9.12 => Dockerfile.libxml2-2.9.12 +3 -4
@@ 2,12 2,11 @@ ARG MUSL_TARGET=x86_64-linux-musl
FROM musl-cross-make-$MUSL_TARGET
ARG MUSL_TARGET

RUN cd /build && \
wget -O source.tar.gz ftp://xmlsoft.org/libxml2/libxml2-2.9.12.tar.gz && \
tar xf source.tar.gz

WORKDIR /build
RUN download ftp://xmlsoft.org/libxml2/libxml2-2.9.12.tar.gz source.tar.gz c8d6681e38c56f172892c85ddc0852e1fd4b53b4209e7f4ebf17f7e2eae71d92 && tar xf source.tar.gz
RUN export PATH=/build/cross/bin:$PATH && \
cd /build/libxml2-* && \
cd libxml2-* && \
CC="$MUSL_TARGET-gcc" \
CFLAGS="-static -frandom-seed=pulse" \
./configure \

M Dockerfile.loggedfs-0.9 => Dockerfile.loggedfs-0.9 +3 -5
@@ 9,12 9,10 @@ COPY --from=fuse /output /output
COPY --from=libxml2 /output /output
COPY --from=pcre /output /output

RUN cd /build && \
wget -O source.tar.gz https://github.com/rflament/loggedfs/archive/refs/tags/loggedfs-0.9.tar.gz && \
tar xf source.tar.gz

WORKDIR /build
RUN download https://github.com/rflament/loggedfs/archive/refs/tags/loggedfs-0.9.tar.gz source.tar.gz 10cd007782c6b91a154758dabac0c3b41e580ca0f9496cab411054219ef52b22 && tar xf source.tar.gz
RUN export PATH=/build/cross/bin:/output/bin:$PATH && \
cd /build/loggedfs-* && \
cd loggedfs-* && \
sed -e 's/^CC=/CC?=/' -e 's/^CFLAGS=/CFLAGS+=/' -e 's/^LDFLAGS=/LDFLAGS+=/' -i Makefile && \
CC="${MUSL_TARGET}-g++ -static -static-libstdc++" \
CFLAGS="-frandom-seed=pulse -I/output/include" \

M Dockerfile.musl-cross-make => Dockerfile.musl-cross-make +5 -7
@@ 2,20 2,18 @@ ARG MUSL_TARGET=x86_64-linux-musl
FROM debian:bullseye
ARG MUSL_TARGET

ADD ./download /usr/local/bin

RUN mkdir /output && \
export DEBIAN_FRONTEND=noninteractive && \
sed -e 's/http:\/\/[^/]*/http:\/\/mirror.fsmg.org.nz/g' -i /etc/apt/sources.list && \
apt-get update && \
apt-get -y dist-upgrade && \
apt-get -y autoremove && \
apt-get install -y --no-install-recommends build-essential ca-certificates wget unzip flex bison autoconf file && \
apt-get install -y --no-install-recommends build-essential ca-certificates wget unzip flex bison autoconf file python3 && \
apt-get clean
RUN wget -O /tmp/musl-cross-make.zip https://github.com/richfelker/musl-cross-make/archive/refs/tags/v0.9.9.zip && \
sha256sum /tmp/musl-cross-make.zip && \
if [ "$(sha256sum /tmp/musl-cross-make.zip)" != "6cbe2f6ce92e7f8f3973786aaf0b990d0db380c0e0fc419a7d516df5bb03c891  /tmp/musl-cross-make.zip" ]; then \
    echo "Invalid checksum of musl-cross-make.zip, giving up."; \
exit 1; fi
RUN mkdir /build && \
RUN download https://github.com/richfelker/musl-cross-make/archive/refs/tags/v0.9.9.zip /tmp/musl-cross-make.zip 6cbe2f6ce92e7f8f3973786aaf0b990d0db380c0e0fc419a7d516df5bb03c891 && \
mkdir /build && \
cd /build && \
unzip /tmp/musl-cross-make.zip && \
cd musl-cross-make-* && \

M Dockerfile.ncurses-6.2 => Dockerfile.ncurses-6.2 +3 -5
@@ 2,12 2,10 @@ ARG MUSL_TARGET=x86_64-linux-musl
FROM musl-cross-make-$MUSL_TARGET
ARG MUSL_TARGET

RUN cd /build && \
wget -O source.tar.gz https://invisible-mirror.net/archives/ncurses/ncurses-6.2.tar.gz && \
tar xf source.tar.gz

WORKDIR /build
RUN download https://invisible-mirror.net/archives/ncurses/ncurses-6.2.tar.gz source.tar.gz 30306e0c76e0f9f1f0de987cf1c82a5c21e1ce6568b9227f7da5b71cbea86c9d && tar xf source.tar.gz
RUN export PATH=/build/cross/bin:$PATH && \
cd /build/ncurses-* && \
cd ncurses-* && \
CC="$MUSL_TARGET-gcc" \
./configure \
--prefix=/output \

M Dockerfile.nmap-7.90 => Dockerfile.nmap-7.90 +3 -5
@@ 7,12 7,10 @@ ARG MUSL_TARGET
COPY --from=libpcap /output /output
COPY --from=openssl /output /output

RUN cd /build && \
wget -O source.tar.gz https://nmap.org/dist/nmap-7.92.tgz && \
tar xf source.tar.gz

WORKDIR /build
RUN download https://nmap.org/dist/nmap-7.92.tgz source.tar.gz 064183ea642dc4c12b1ab3b5358ce1cef7d2e7e11ffa2849f16d339f5b717117 && tar xf source.tar.gz
RUN export PATH=/build/cross/bin:$PATH && \
cd /build/nmap-* && \
cd nmap-* && \
CC="${MUSL_TARGET}-gcc -static -fPIC" \
CXX="${MUSL_TARGET}-g++ -static -fPIC -static-libstdc++" \
CFLAGS="-frandom-seed=pulse -I/output/include" \

M Dockerfile.openssl-0.9.8zh => Dockerfile.openssl-0.9.8zh +3 -6
@@ 5,14 5,11 @@ ARG MUSL_TARGET

COPY --from=zlib /output /output

RUN cd /build && \
wget -O source.tar.gz https://ftp.openssl.org/source/old/0.9.x/openssl-0.9.8zh.tar.gz && \
tar xf source.tar.gz

WORKDIR /build
RUN download https://ftp.openssl.org/source/old/0.9.x/openssl-0.9.8zh.tar.gz source.tar.gz f1d9f3ed1b85a82ecf80d0e2d389e1fda3fca9a4dba0bf07adbf231e1a5e2fd6 && tar xf source.tar.gz
COPY patches/openssl-0.9.8zh /build/patches

RUN export PATH=/build/cross/bin:$PATH && \
cd /build/openssl-* && \
cd openssl-* && \
find /build/patches -type f -exec patch -p1 -i {} \; && \
CC="$MUSL_TARGET-gcc -frandom-seed=pulse -I/output/include -L/output/lib" \
./Configure \

M Dockerfile.openssl-1.1.1k => Dockerfile.openssl-1.1.1k +3 -5
@@ 5,12 5,10 @@ ARG MUSL_TARGET

COPY --from=zlib /output /output

RUN cd /build && \
wget -O source.tar.gz https://www.openssl.org/source/openssl-1.1.1k.tar.gz && \
tar xf source.tar.gz

WORKDIR /build
RUN download https://www.openssl.org/source/openssl-1.1.1k.tar.gz source.tar.gz 892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5 && tar xf source.tar.gz
RUN export PATH=/build/cross/bin:$PATH && \
cd /build/openssl-* && \
cd openssl-* && \
CC="gcc" \
CFLAGS="-static -frandom-seed=pulse -I/output/include" \
LDFLAGS="-L/output/lib" \

M Dockerfile.pcre-8.45 => Dockerfile.pcre-8.45 +3 -5
@@ 2,12 2,10 @@ ARG MUSL_TARGET=x86_64-linux-musl
FROM musl-cross-make-$MUSL_TARGET
ARG MUSL_TARGET

RUN cd /build && \
wget -O source.tar.gz https://ftp.pcre.org/pub/pcre/pcre-8.45.tar.gz && \
tar xf source.tar.gz

WORKDIR /build
RUN download https://ftp.pcre.org/pub/pcre/pcre-8.45.tar.gz source.tar.gz 4e6ce03e0336e8b4a3d6c2b70b1c5e18590a5673a98186da90d4f33c23defc09 && tar xf source.tar.gz
RUN export PATH=/build/cross/bin:$PATH && \
cd /build/pcre-* && \
cd pcre-* && \
CC="$MUSL_TARGET-gcc" \
CFLAGS="-fPIC -static -frandom-seed=pulse" \
./configure \

M Dockerfile.readline-8.1 => Dockerfile.readline-8.1 +3 -5
@@ 5,12 5,10 @@ ARG MUSL_TARGET

COPY --from=ncurses /output /output

RUN cd /build && \
wget -O source.tar.gz ftp://ftp.cwru.edu/pub/bash/readline-8.1.tar.gz && \
tar xf source.tar.gz

WORKDIR /build
RUN download ftp://ftp.cwru.edu/pub/bash/readline-8.1.tar.gz source.tar.gz f8ceb4ee131e3232226a17f51b164afc46cd0b9e6cef344be87c65962cb82b02 && tar xf source.tar.gz
RUN export PATH=/build/cross/bin:$PATH && \
cd /build/readline-* && \
cd readline-* && \
CC="$MUSL_TARGET-gcc" \
./configure \
--prefix=/output \

M Dockerfile.socat-1.7.4.1 => Dockerfile.socat-1.7.4.1 +3 -5
@@ 9,12 9,10 @@ COPY --from=openssl /output /output
COPY --from=readline /output /output
COPY --from=zlib /output /output

RUN cd /build && \
wget -O source.tar.gz http://www.dest-unreach.org/socat/download/socat-1.7.4.1.tar.gz && \
tar xf source.tar.gz

WORKDIR /build
RUN download http://www.dest-unreach.org/socat/download/socat-1.7.4.1.tar.gz source.tar.gz 0c7e635070af1b9037fd96869fc45eacf9845cb54547681de9d885044538736d && tar xf source.tar.gz
RUN export PATH=/build/cross/bin:$PATH && \
cd /build/socat-* && \
cd socat-* && \
CC="${MUSL_TARGET}-gcc" \
CPPFLAGS="-static -frandom-seed=pulse -I/output/include" \
LDFLAGS="-L/output/lib" \

M Dockerfile.tcpdump-4.99.1 => Dockerfile.tcpdump-4.99.1 +3 -5
@@ 5,12 5,10 @@ ARG MUSL_TARGET

COPY --from=libpcap /output /output

RUN cd /build && \
wget -O source.tar.gz https://www.tcpdump.org/release/tcpdump-4.99.1.tar.gz && \
tar xf source.tar.gz

WORKDIR /build
RUN download https://www.tcpdump.org/release/tcpdump-4.99.1.tar.gz source.tar.gz 79b36985fb2703146618d87c4acde3e068b91c553fb93f021a337f175fd10ebe && tar xf source.tar.gz
RUN export PATH=/build/cross/bin:$PATH && \
cd /build/tcpdump-* && \ 
cd tcpdump-* && \ 
CC="${MUSL_TARGET}-gcc" \
CFLAGS="-static -frandom-seed=pulse -I/output/include" \
LDFLAGS="-L/output/lib" \

M Dockerfile.zlib-1.2.11 => Dockerfile.zlib-1.2.11 +3 -5
@@ 2,12 2,10 @@ ARG MUSL_TARGET=x86_64-linux-musl
FROM musl-cross-make-$MUSL_TARGET
ARG MUSL_TARGET

RUN cd /build && \
wget -O source.tar.gz https://zlib.net/zlib-1.2.11.tar.gz && \
tar xf source.tar.gz

WORKDIR /build
RUN download https://zlib.net/zlib-1.2.11.tar.gz source.tar.gz c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 && tar xf source.tar.gz
RUN export PATH=/build/cross/bin:$PATH && \
cd /build/zlib-* && \
cd zlib-* && \
CC="$MUSL_TARGET-gcc" \
CFLAGS="-static -frandom-seed=pulse" \
./configure \

M README.md => README.md +9 -9
@@ 8,10 8,11 @@ Run `make MUSL_TARGET=some_target_tuple` to compile everything. Tested targets s

* x86_64-linux-musl
* mips-linux-muslsf
* mipsel-linux-muslsf

But others are very likely to work. Building everything currently needs about 2GB per target and it helps to have a big Ryzen machine with NVMe storage and plenty of RAM and so on.
But others are very likely to work. Building everything currently needs about 2GB of disk per target and it helps to have a big machine with NVMe storage and plenty of RAM. A complete build for a single architecture currently takes about 15 minutes on a Ryzen 4750U.

You can build individual binaries by specifying it as an argument to `make` and the dependencies will be worked out for you. At the moment there are recipes for these tools:
You can build individual binaries by specifying the recipe name as an argument to `make`. Dependency resolution will be handled automatically. These recipes are included at the moment:

* `busybox-1.33.1`
* `loggedfs-0.9`


@@ 23,24 24,23 @@ You can build individual binaries by specifying it as an argument to `make` and 

More tools and documentation will be added over time.

To validate that all your binaries came out right, run `make check`. If everything is fine then nothing will be listed.
To validate that all your binaries came out right, run `make check`. This will list any binariesin the `output` directory which don't seem to have been statically linked.

## Rationale

There are numerous projects and approaches to building static tool binaries, but this one is mine. Sometimes you just find yourself on a little endian softfloat MIPS box and you really need that nmap.
There are numerous projects and approaches for building static tool binaries, but this one is mine. Sometimes you just find yourself on a little-endian softfloat MIPS box and you really need a specific tool!

Some goals of the project:

* Re-use dependencies and earlier build stages where possible.
* Ensure that only necessary modifications are made to packages to get them to build and be useful.
* Up to date versions of things.
* Re-use dependencies between recipes where possible.
* Ensure that only the necessary modifications are made to packages to get them to build and be useful.
* Up-to-date versions.
* Try and make things builds relatively quickly and efficiently (e.g. auto-detect number of cores, skip unhelpful build stages etc)
* Build tools with useful features enabled (e.g. socat has OpenSSL)
* Build tools with useful features enabled (e.g. `socat` has `OpenSSL`)

And yet to be added:

* Update notification feature (this may involve switching package sources to come from Debian).
* More pinned hashes for dependencies.

## Feedback? Questions?


A download => download +51 -0
@@ 0,0 1,51 @@
#!/usr/bin/python3 -u

"""
Download a file from a URL and validate the SHA256 checksum while downloading.

Michael Fincham <michael@hotplate.co.nz> 2021-08-20
"""

import sys
import os
import argparse
import hashlib
import urllib.request
import tempfile

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        "url", help="URL to download from"
    )
    parser.add_argument(
        "destination",
        help="destination file"
    )
    parser.add_argument(
        "sha256sum",
        help="SHA256 checksum to match again"
    )
    args = parser.parse_args()

    block_size = 1024 * 1024
    checksum = hashlib.sha256()
    response = urllib.request.urlopen(args.url)
    return_code = 0
    sha256sum = args.sha256sum.lower()
    print("Downloading '%s'..." % args.url)
    with tempfile.NamedTemporaryFile() as f:
        while True:
            block = response.read(block_size)
            if not block:
                break
            f.write(block)
            checksum.update(block)
            print(".", end="")
        print("")
        if checksum.hexdigest() == sha256sum:
            os.link(f.name, args.destination)
        else:
            sys.stderr.write("error: checksum didn't match for '%s', not saving file. got %s and expected %s.\n" % (args.url, checksum.hexdigest(), sha256sum))
            return_code = 1
    sys.exit(return_code)