├── .gitignore ├── smoketest ├── src │ └── main.rs ├── Cargo.toml └── Cargo.lock ├── scripts ├── _fix_symlinks.sh └── _debootstrap.sh ├── README.md └── Dockerfile /.gitignore: -------------------------------------------------------------------------------- 1 | smoketest/target/ 2 | sysroot-* 3 | -------------------------------------------------------------------------------- /smoketest/src/main.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | fn main() { 4 | let f = libm::hypot(1_f64, 1_f64); 5 | unsafe { libc::dlopen(b"libc" as *const _ as _, 0); } 6 | println!("Hello, world! {f}"); 7 | } 8 | -------------------------------------------------------------------------------- /smoketest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "smoketest" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | libc = "0" 10 | libm = "0" 11 | -------------------------------------------------------------------------------- /scripts/_fix_symlinks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | 4 | # Make all the symlinks in the sysroot relative, with the exception of /dev/ and /proc. 5 | find /sysroot -not \( -path "/sysroot/dev/*" -prune \) -not \( -path "/sysroot/proc/*" -prune \) -lname '/*' | while read l; do 6 | target="$(readlink "$l")" 7 | ls -ld $l 8 | ln -svnrif "/sysroot/$target" "$l" 9 | ls -ld $l 10 | done 11 | -------------------------------------------------------------------------------- /smoketest/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "libc" 7 | version = "0.2.154" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" 10 | 11 | [[package]] 12 | name = "libm" 13 | version = "0.2.8" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" 16 | 17 | [[package]] 18 | name = "smoketest" 19 | version = "0.1.0" 20 | dependencies = [ 21 | "libc", 22 | "libm", 23 | ] 24 | -------------------------------------------------------------------------------- /scripts/_debootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | 4 | # This script runs inside of the docker container to build a pristine sysroot. 5 | 6 | DISTRO=bionic 7 | 8 | # Note: for earlier versions of Ubuntu "aarch64" is considered a port and requires a different package 9 | # source. This may change for future distros. 10 | declare -A DISTRO_SOURCES=( 11 | ["aarch64"]=http://ports.ubuntu.com/ 12 | ["x86_64"]=http://azure.archive.ubuntu.com/ubuntu 13 | ) 14 | ARCH=$(uname -m) 15 | DISTRO_SOURCE="${DISTRO_SOURCES[${ARCH}]}" 16 | 17 | echo "Building ${ARCH} sysroot from ${DISTRO} at ${DISTRO_SOURCE}..." 18 | 19 | # Note that this can fail if you have Rosetta enabled on Apple Silicon 20 | # This can be disabled from "Features in Development" page 21 | debootstrap \ 22 | --include=ca-certificates,curl,file,libc6-dev,make \ 23 | --no-merged-usr --variant=buildd $DISTRO /sysroot \ 24 | $DISTRO_SOURCE || ( 25 | cat /sysroot/debootstrap/debootstrap.log && 26 | echo "deboostrap failed. If building on Apple Silicon, make sure Rosetta is disabled." && 27 | exit 1 28 | ) 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # deno_sysroot_build 2 | 3 | Deno for Linux sysroot build. 4 | 5 | This allows `deno` executables to link against older versions of glibc. The 6 | sysroot itself is only there to provide appropriately-versioned `.a` files to a 7 | linker running on the main system. 8 | 9 | We don't actually build `deno` in a sysroot or chroot with this project. 10 | Instead, it allows us to pass `-L` and `--sysroot` flags to the linker which 11 | redirect the link phase from the system libraries (which would tie us to a much 12 | later version of GLIBC) to the sysroot libraries (which are taken from a much 13 | older version of Ubuntu). 14 | 15 | ## Supported architectures 16 | 17 | - aarch64 18 | - x86_64 19 | 20 | To add a new architecture, add the appropriate Ubuntu mirror in 21 | [_debootstrap.sh](scripts/_debootstrap.sh) and add the appropriate target to 22 | `./build.sh`. Note that this requires support for the platform in your local 23 | docker instance and at the time of writing, only these two platforms are 24 | supported. 25 | 26 | ## Rebuilding 27 | 28 | 1. Run `build.sh` on a system with Docker. If building on Apple Silicon, you may 29 | need to disable Rosetta from the Docker settings. 30 | 2. Upload the `sysroot-*.tar.xz` files as releases. 31 | 3. Update `deno` build scripts to point at new `sysroot` release 32 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu 2 | # Various tools we need to build and test the sysroot 3 | RUN apt update && apt install -y debootstrap xz-utils symlinks curl build-essential 4 | 5 | # Run the appropriate debootstrap steps 6 | COPY scripts/_debootstrap.sh /scripts/ 7 | RUN /scripts/_debootstrap.sh 8 | 9 | # Clean the noisiest parts of the sysroot 10 | RUN rm -rf /sysroot/var/cache 11 | RUN rm -rf /sysroot/var/lib/dpkg 12 | RUN rm -rf /sysroot/usr/share/man 13 | RUN rm -rf /sysroot/usr/share/doc 14 | 15 | # Fix relative symlinks 16 | COPY scripts/_fix_symlinks.sh /scripts/ 17 | RUN /scripts/_fix_symlinks.sh 18 | 19 | # Provide a /sysroot/.env that sets up the appropriate Rust and C flags 20 | RUN echo "# Compiler flags" > /sysroot/.env 21 | RUN echo export RUSTFLAGS=\"-C link-arg=-L/sysroot/lib/`uname -m`-linux-gnu -C link-arg=-L/sysroot/usr/lib/`uname -m`-linux-gnu -C link-arg=--sysroot=/sysroot $RUSTFLAGS\" >> /sysroot/.env 22 | RUN echo export CFLAGS=\"-L/sysroot/lib/`uname -m`-linux-gnu -L/sysroot/usr/lib/`uname -m`-linux-gnu --sysroot=/sysroot $CFLAGS\" >> /sysroot/.env 23 | 24 | # Test the sysroot by building a Rust program that uses various bits of libc/libm/libdl and trying 25 | # to run it in a chroot /sysroot. 26 | RUN curl https://sh.rustup.rs -sSf > /tmp/rustup-init.sh && sh /tmp/rustup-init.sh -y 27 | COPY smoketest/ /tmp/smoketest/ 28 | WORKDIR /tmp/smoketest 29 | RUN . /sysroot/.env && PATH=/root/.cargo/bin:$PATH cargo -vv build 30 | RUN cp /tmp/smoketest/target/debug/smoketest /sysroot 31 | RUN chroot "/sysroot" /smoketest 32 | RUN rm /sysroot/smoketest 33 | WORKDIR / 34 | 35 | # Build and compress the sysroot, excluding the contents of /dev and /proc. Use 36 | # the recommended flags from https://reproducible-builds.org/docs/archives/ to make 37 | # the sysroot reproducible. 38 | RUN tar \ 39 | --exclude='/sysroot/dev/*' \ 40 | --exclude='/sysroot/proc/*' \ 41 | --sort=name \ 42 | --mtime="@0" \ 43 | --owner=0 --group=0 --numeric-owner \ 44 | --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime \ 45 | -cv sysroot/ > /tmp/sysroot.tar 46 | # RUN xz -0 -z /tmp/sysroot.tar 47 | RUN xz -9 -e -z /tmp/sysroot.tar 48 | RUN mv /tmp/sysroot.tar.xz /tmp/sysroot-`uname -m`.tar.xz 49 | RUN ls -l /tmp/sysroot-`uname -m`.tar.xz 50 | --------------------------------------------------------------------------------