GALES LINUX BUILD GUIDE J. Welsh July 2017 - July 2019 This document takes the form of a recipe, intended to guide the literate reader through a reliable process for building the Gales Linux installation media -- completely from source and, in principle, starting from any reasonably Unix-like host system. While thorough, it is not intended to be cut-and-pasted; you are expected to read and comprehend the commands and fill in a few gaps based on the details of your own environment. As there are numerous ways for things to go wrong, it is recommended you do your first build "by the book", including the exact package versions. This accomplished, if you wish to customize you can go back and see what can be bent and in what direction. CONTENTS 0. Prerequisites 1. Define a clean build environment 2. Populate the build tree and build basic utilities 2.1. Arrange in-tree sources into the build tree 2.2. Compile basic build-time tools using the host toolchain 2.3. Verify and unpack out-of-tree sources to the build tree 3. Build a cross toolchain and environment using the host toolchain 3.1. Prepare toolchain sources 3.2. Build cross binutils 3.3. Build a minimal C cross compiler for building libc 3.4. Cross compile musl libc, installed to the compiler's sysroot 3.5. Build the full cross compilers 3.6. Install the kernel userspace API headers 4. Cross compile the kernel 5. Cross compile the base userland 5.1. BusyBox 5.2. Non-BusyBox Unix utilities 5.3. Linux specific utilities 5.4. Init and process supervision system 5.5. Bootloader 5.5.1. Lilo (x86) 6. Cross compile a native toolchain in the sysroot 7. Make symlinks to activate the installed versions 8. Pack distribution archives 9. Create a bootable install medium, if desired Appendices: A1. Helpful resources A2. Reproducible builds A3. Hacks for building from an OpenBSD host A4. ARM notes 0. Prerequisites A copy of this repository Upstream sources as listed in base/src.sha512 (see the gports/gales-util/gales-mirror-sync script - described at http://jfxpt.com/2019/gales-linux-initial-release/ - for how to obtain these) ISO C90 compiler (probably needs to be gcc 2.95+) /bin/sh (bash or ksh required for the brace expansions below. BusyBox ash as of 1.24.2 is known to fail on binutils and musl configure scripts; dash 0.5.9.1 works) GNU make (3.80+ for gcc) ncurses (for Linux/BusyBox menuconfig) bc (for Linux build) Standard utilities Full list of required commands (derived by doing the full build with a restricted PATH variable so should be fairly complete, but something may have been missed e.g. if it was invoked by absolute path or failed quietly): ar basename bc cat cc chmod cmp cp cut date dd diff dirname echo egrep env expr find gcc grep head install ln ls make mkdir mktemp mv od printf pwd ranlib rm rmdir sh sleep sort tail touch tr true uname uniq wc xargs 1. Define a clean build environment The build tree can be anywhere, but for reproducibility the standard is /var/build/gales. It'll need ~3GB of disk space. (Your mileage may vary, e.g. based on host compiler; one reviewer reports closer to 10GB being required.) Under this we will be creating three subdirectories: build -- where package sources are extracted, patched and compiled tools -- where the cross toolchain and any other build-time utilities are installed root -- where the final system tree is iteratively assembled (known as "sysroot" in the context of cross compiling: where the toolchain searches for target headers and libc) Note that root access is not required at any point in the build process (though you will presumably need it to create bootable media). Create the top level of the build tree and enter it as necessary: cd /var/build mkdir gales cd gales The following steps start a new subshell to define runtime aspects of the build environment. To maximize reproducibility, the technique of enumerating goodness is used to define a known set of shell and environment variables. If you exit this shell midway through the build, you will need to repeat these steps prior to resuming. You will need to make some adjustments based on the details of your host environment, namely: 1. Replace "bash --norc" as needed for your shell; in particular, from building on an existing Gales system, simply use "ksh" (but note that additional variables may be introduced by way of your ~/.kshrc file). 2. Set GALES_REPO as the absolute path to your copy of this repository (containing this BUILD file, sources, patches, gports and so on). 3. Set S as the absolute path to your copy of the Gales mirror (containing the upstream sources as listed in base/src.sha512). 4. Set J=-jN where N is your desired limit on the number of parallel "make" jobs. A rule of thumb is one greater than your CPU core count, while available RAM imposes a hard constraint. The most conservative choice is 1, though this will make for a slow build. 5. Set BUILD and TGT based on the CPU architecture the resulting system is to target. (Presently only x86_64 is supported so no change is needed here.) env -i TERM=$TERM HOME=$HOME USER=$USER LC_ALL=C PATH=$PWD/tools/bin:$PATH bash --norc PS1="(build) $PS1" export GALES=$PWD GALES_REPO=/path/to/repo # to be set appropriately S=/path/to/sources # to be set appropriately P=$GALES_REPO/base/patches TOOLS=$PWD/tools ROOT=$PWD/root BUILD=x86_64-unknown-linux-gnu # mostly just needs to differ from TGT TGT=x86_64-gales-linux-musl J=-j3 2. Populate the build tree and build basic utilities 2.1. Arrange in-tree sources into the build tree cd $GALES mkdir build root mkdir -m 1755 root/package mkdir -m 1755 root/package/admin cp -r $GALES_REPO/base/* build/ mv build/daemontools root/package/admin/daemontools-0.76 2.2. Compile basic build-time tools using the host toolchain To reduce host environment dependencies and better control the bootstrap process, we will be using the BusyBox/Gales versions of some basic tools such as tar, gzip, awk, sed, patch, and stat, shadowing whatever system versions may be in the PATH. You could think of these as part of an extended cross toolchain. cd build/busybox cp $GALES_REPO/kconfig/busybox-1.24-build-tools.config .config make $J mkdir -p $TOOLS/bin mv busybox $TOOLS/bin/ $TOOLS/bin/busybox --install $TOOLS/bin 2.3. Verify and unpack out-of-tree sources to the build tree Ensure the following "sha512sum" output reads all OK before proceeding! cd $S sha512sum -c $GALES_REPO/base/src.sha512 cd $GALES/build tar xzf $S/bin86-0.16.17.tar.gz tar xjf $S/binutils-2.24.tar.bz2 tar xJf $S/e2fsprogs-1.43.4.tar.xz tar xjf $S/gcc-4.7.4.tar.bz2 tar xJf $S/gmp-6.0.0a.tar.xz tar xzf $S/lilo-24.0.tar.gz tar xJf $S/linux-4.9.tar.xz tar xjf $S/make-4.2.1.tar.bz2 tar xzf $S/mpc-1.0.3.tar.gz tar xJf $S/mpfr-3.1.5.tar.xz 3. Build a cross toolchain and environment using the host toolchain 3.1. Prepare toolchain sources "libiberty" is a library providing portability and other common routines used by the different subprojects of the GNU toolchain (binutils, gcc and gdb). These projects share the code by way of copying it whole-hog. To reverse this proliferation, we will use only the slightly newer version from binutils and symlink it into the gcc source tree. Both trees include optional components in subdirectories that are either not relevant to our present needs, not working, or not desirable. We will ensure that the build system ignores them by pruning ahead of time. Note that "libssp" is not necessary for using -fstack-protector as musl provides a considerably cleaner implementation of the runtime parts (initialization and __stack_chk_fail). mkdir build-{binutils,gcc} cd binutils-2.24 rm -r intl gold include/xregex2.h libiberty/regex.c patch -p1 < $P/binutils-2.24-system-regex.patch patch -p1 < $P/binutils-2.24-ld-kill-sneaky-plugins.patch patch -p1 < $P/binutils-2.24-bounded-stack.patch patch -p1 < $P/binutils-2.24-format-nonliteral.patch # Bypass spurious post-patch info generation to avoid makeinfo dependency. # (This "hypertext must be precompiled" thing is dumb.) (cd bfd/doc && touch archive.texi bfdt.texi bfd.texinfo bfd.info) cd .. cd gcc-4.7.4 rm -r boehm-gc gnattools intl libmudflap libssp libada libffi libgfortran libgo libjava libobjc lto-plugin libiberty include/xregex* patch -p1 < $P/gcc-4.7.4-musl.patch patch -p1 < $P/gcc-4.7.4-58385-fold-const-side-effect.patch patch -p1 < $P/gcc-4.7.4-49008-59545-genautomata.patch patch -p1 < $P/gcc-4.7.4-31798-arm-static-libs.patch patch -p1 < $P/gcc-4.7.4-55003-constexpr-no-initializer.patch patch -p1 < $P/gcc-4.7.4-kill-fixincludes.patch patch -p1 < $P/gcc-4.7.4-hardening.patch patch -p1 < $P/gcc-4.7.4-libgcc-bounded-stack.patch patch -p1 < $P/gcc-4.7.4-libcpp-format-nonliteral.patch patch -p1 < $P/gcc-4.7.4-demangler-amputation.patch ln -s ../binutils-2.24/libiberty . ln -s ../../binutils-2.24/include/xregex.h include/ ln -s ../gmp-6.0.0 gmp ln -s ../mpfr-3.1.5 mpfr ln -s ../mpc-1.0.3 mpc cd .. cd gmp-6.0.0 patch -p1 < $P/gmp-6.0.0-no-asm.patch patch -p1 < $P/gmp-6.0.0-format-nonliteral.patch cd .. cd mpfr-3.1.5 patch -p1 < $P/mpfr-3.1.5-bounded-stack.patch patch -p1 < $P/mpfr-3.1.5-format-nonliteral.patch cd .. 3.2. Build cross binutils Here and following, the -std=gnu89 option is given, despite already being the default language standard in GCC 4.7, for compatibility with newer host compilers that broke the build by changing it. cd build-binutils CFLAGS="-std=gnu89 -O0" ../binutils-2.24/configure --build=$BUILD --host=$BUILD --target=$TGT --prefix=$TOOLS --with-sysroot=$ROOT --disable-{nls,shared,werror} --enable-deterministic-archives make $J make install rm -rf * # ^ -f is needed because BLD-POTFILES and SRC-POTFILES generated in bfd/po/ are stripped of write permission (and apparently --disable-nls isn't as strong as I would like) cd .. 3.3. Build a minimal C cross compiler for building libc cd build-gcc CFLAGS="-std=gnu89 -O0" ../gcc-4.7.4/configure --build=$BUILD --host=$BUILD --target=$TGT --prefix=$TOOLS --with-sysroot=$ROOT --with-newlib --without-headers --with-local-prefix=$TOOLS --with-native-system-header-dir=/include --with-mpfr-include=$PWD/../gcc-4.7.4/mpfr/src --with-mpfr-lib=$PWD/mpfr/src/.libs --disable-{bootstrap,decimal-float,fixincludes,libgcc,libgomp,libmudflap,libquadmath,libssp,lto,multilib,nls,shared,threads,werror} --enable-languages=c make $J make install rm -r * cd .. 3.4. Cross compile musl libc, installed to the compiler's sysroot cd musl ./configure --build=$BUILD --host=$TGT --prefix= --disable-shared --enable-debug --enable-warnings CFLAGS=-O1 make $J install DESTDIR=$ROOT cd .. 3.5. Build the full cross compilers You can adjust CFLAGS to -O0 as above to disable (some) optimization. This roughly halves gcc build time and doubles subsequent cross compiles; probably not a speed win, but could make for a good reproducibility data point. (libgcc is still built optimized; looks like that's controlled by TARGET_CFLAGS.) This double build is unpleasant, but is more or less the official way to do it as some pieces (e.g. C++ threads support) require an installed target libc. If you won't be needing g++ on the target system, or you prefer to build it after installation, you can probably get away without this step (though you may want to keep optimization enabled in section 3.3). We don't build libstdc++ here as there are no C++ programs in the base system, but the cross g++ frontend will be needed to build it for the native toolchain in step 5. cd build-gcc CFLAGS="-std=gnu89 -O2" ../gcc-4.7.4/configure --build=$BUILD --host=$BUILD --target=$TGT --prefix=$TOOLS --with-sysroot=$ROOT --with-local-prefix=$TOOLS --with-native-system-header-dir=/include --with-mpfr-include=$PWD/../gcc-4.7.4/mpfr/src --with-mpfr-lib=$PWD/mpfr/src/.libs --disable-{bootstrap,decimal-float,fixincludes,libgomp,libitm,libmudflap,libquadmath,libssp,libstdc++-v3,lto,multilib,nls,shared,werror} --enable-{threads=posix,__cxa_atexit} --enable-languages=c,c++ make $J # on my Core 2 this takes 15m user time make install rm -r * cd .. 3.6. Install the kernel userspace API headers For reproducible builds, these should be installed from the base release of a given branch, before applying the current patch. (Changes to these are few and minor; conventional distros often ship headers even from an older branch than the running kernel.) Don't use INSTALL_HDR_PATH to install directly: it can delete existing headers that don't belong to the kernel (in particular scsi/*.h)! cd linux-4.9 patch -p1 < $P/linux-4.9-portable-build.patch make headers_install find usr/include -name '.*install*' -exec rm {} + cp -r usr/include $ROOT cd .. 4. Cross compile the kernel Configuring a Linux kernel is non-trivial and will not be explained here. While laborious, tailoring it to your particular hardware and needs can yield substantial size, build time, and boot time savings compared to a generic distribution kernel, as well as a better understanding of your system and likely reduced security exposure. Make sure to enable initramfs (CONFIG_BLK_DEV_INITRD) with gzip compression (CONFIG_RD_GZIP) support, unless you intend to bypass the included installer construction scripts. A partial indicator of success is that the "usr/gen_init_cpio" program gets built in the kernel tree. Example configurations may be available upon request. cd linux-4.9 gzip -dc .../patch-4.9.X.gz | patch -p1 # to be set appropriately # You can switch to a new patch release by first reversing the old patch: # gzip -dc .../patch-4.9.X.gz | patch -p1 -R Install an existing .config, make oldconfig, make menuconfig, etc. rm -f .version make KBUILD_BUILD_TIMESTAMP=@0 KBUILD_BUILD_USER=build KBUILD_BUILD_HOST=localhost CROSS_COMPILE=$TGT- $J cp arch/x86/boot/bzImage $GALES/bzImage-4.9.X # to be named appropriately If you enabled loadable modules (though this is not The Gales Way): make modules_install INSTALL_MOD_PATH=$ROOT rm $ROOT/lib/modules/*/{build,source} cd .. 5. Cross compile the base userland 5.1. BusyBox cd busybox make clean cp $GALES_REPO/kconfig/busybox-1.24.config .config make CROSS_COMPILE=$TGT- $J mkdir -p $ROOT/bin mv busybox $ROOT/bin/ cd .. The included .config was hand-crafted as follows: make allnoconfig # enumerating goodness make menuconfig Busybox Settings: General Configuration: Show applet usage messages: y Support --install: y Don't use /usr: y Support for --long-options: y Use the devpts filesystem for Unix98 PTYs: y Path to BusyBox executable: /bin/busybox Build Options: Build BusyBox as a static binary: y Build with Large File Support: y Additional CFLAGS: -O1 Debugging Options: Build BusyBox with extra Debugging symbols: y Disable compiler optimizations: y Busybox Library Tuning: Command line editing: y Use clock_gettime(CLOCK_MONOTONIC) syscall: y Archival utilities: gunzip bunzip2 unxz bzip2 gzip tar Make tar, ... understand .xz/bz2/gz data: y Trade memory for gzip speed: 2 Coreutils: basename cat date dd id groups shuf sync test touch tr truncate unlink base64 cal catv chgrp chmod chown chroot cksum comm cp cut df dirname du echo env expand expr false fold head install ln logname ls md5sum mkdir mkfifo mknod mv nice nohup od printenv printf pwd readlink rm rmdir seq sha1sum sha256sum sha512sum sha3sum sleep sort split stat stty sum tac tail tee true tty uname unexpand uniq wc whoami yes Support verbose options (usually -v): y Console Utilities: chvt clear loadfont loadkmap openvt reset resize setfont Debian utilities: mktemp which Editors: awk cmp diff ed patch sed vi Use 'tell me cursor position' ESC sequence to measure window: n Finding Utilities: find grep xargs Init Utilities: poweroff, halt, and reboot: y Call telinit on shutdown and reboot: n Login/Password Management Utilities: adduser addgroup deluser delgroup getty login passwd su sulogin Support for shadow passwords: y Use internal crypt functions: y Default password encryption method: sha512 Linux Module Utilities: insmod rmmod lsmod modprobe depmod Linux System Utilities: blockdev fallocate fstrim mount rev dmesg fbset fdisk flock mkfs_vfat hexdump hwclock ipcrm ipcs losetup lspci lsusb mkswap more script scriptreplay swaponoff switch_root umount Support specifying devices by label or UUID: n Support GPT disklabels: y Misc Utilities: setserial beep eject hdparm setsid time timeout readahead: n Networking Utilities: nc ping wget arp arping brctl hostname ifconfig netstat route tcpsvd tftp tftpd traceroute udhcpc udpsvd Try to connect to HTTPS using ...: n Support for RFC3397 domain search: n Support for 802.1Q VLAN paramteters: n Absolute path to config script: /etc/udhcpc/default.script Process Utilities: iostat lsof pmap pstree top uptime free fuser kill killall killall5 pgrep pidof pkill ps sysctl watch System Logging Utilities: logger 5.2. Non-BusyBox Unix utilities cd gksh make CROSS_COMPILE=$TGT- $J DEST=$ROOT/gales/pkg/gksh-0.0-99K mkdir -p $DEST/{bin,man/man1} cp ksh $DEST/bin/ cp ksh.1 $DEST/man/man1/ cd .. cd make-4.2.1 CFLAGS=-O1 ./configure --build=$BUILD --host=$TGT --prefix=/gales/pkg/make-0.0-4.2.1 --datarootdir='${prefix}' --disable-nls make $J make install DESTDIR=$ROOT cd .. 5.3. Linux specific utilities cd makedev make install CC=$TGT-gcc DESTDIR=$ROOT sbindir=/gales/pkg/MAKEDEV-0.0-3.23/bin mandir=/gales/pkg/MAKEDEV-0.0-3.23/man cd .. cd e2fsprogs-1.43.4 patch -p1 < $P/e2fsprogs-1.43.4-really-unbreak-cross.patch rm -r doc CFLAGS=-O1 ./configure --build=$BUILD --host=$TGT --prefix=/gales/pkg/e2fsprogs-0.0-1.43.4 --datarootdir='${prefix}' --sysconfdir=/etc --disable-{e2initrd-helper,nls,uuidd} --enable-{libuuid,libblkid,symlink-install} make $J install DESTDIR=$ROOT cd $ROOT/etc mkdir examples mv makedev.d examples/ sed -e '/enable_periodic_fsck/ s/0/1/' mke2fs.conf > examples/mke2fs.conf rm mke2fs.conf cd $GALES/build 5.4. Init and process supervision system cd init make install CC=$TGT-gcc DESTDIR=$ROOT cd $ROOT/package/admin/daemontools-0.76 CHOST=$TGT- package/install rm -rf compile cd $GALES/build 5.5. Bootloader 5.5.1. Lilo (x86) cd bin86-0.16.17 patch -p1 < $P/bin86-0.16.17-int32.patch patch -p1 < $P/bin86-0.16.17-install.patch make $J PREFIX=$TOOLS CFLAGS=-D_POSIX_SOURCE install cd .. cd lilo-24.0 patch -p1 < $P/lilo-24.0-musl-v2.patch patch -p1 < $P/lilo-24.0-cross.patch patch -p1 < $P/lilo-24.0-kill-format-juggling-and-devfs.patch patch -p1 < $P/lilo-24.0-blkext.patch cd src make all CROSS_COMPILE=$TGT- $J DEST=$ROOT/gales/pkg/lilo-0.0-24.0 mkdir -p $DEST/{bin,man/man{5,8}} cp lilo $DEST/bin/ cd ../man cp lilo.8 $DEST/man/man8/ cp lilo.conf.5 $DEST/man/man5/ cp $GALES_REPO/conf/lilo*.conf $ROOT/etc/examples/ cd ../.. 6. Cross compile a native toolchain in the sysroot GCC refers to this as "Canadian cross" even if host == target. Among target libraries, the OpenMP runtime libgomp remains disabled due to an even dumber than usual configure script (copy-pasted, perhaps from libitm; forces -Werror in violation of --disable-werror). You could also disable libitm and libquadmath as before if you have no applications that need them. Multilib (e.g. -m32 on x86_64) is a special case of cross compiling and likely not worth the added complexity. For example, musl doesn't support 32-bit and 64-bit headers in the same include tree, but as far as I've found gcc can't use different include paths based on the multilib flag. Instead, you can do static builds using a full cross compiler or chroot. cd build-binutils ../binutils-2.24/configure --build=$BUILD --host=$TGT --target=$TGT --prefix=/gales/pkg/binutils-0.0-2.24 --disable-{nls,shared,werror} --enable-deterministic-archives make $J STRIPPROG=$TGT-strip make install-strip DESTDIR=$ROOT # ^ binutils bug? uses the correct strip for most but not all executables rm -rf * cd .. cd build-gcc ../gcc-4.7.4/configure --build=$BUILD --host=$TGT --target=$TGT --prefix=/gales/pkg/gcc-0.0-4.7.4 --with-local-prefix=/local --with-native-system-header-dir=/include --with-mpfr-include=$PWD/../gcc-4.7.4/mpfr/src --with-mpfr-lib=$PWD/mpfr/src/.libs --disable-{bootstrap,fixincludes,libgomp,libmudflap,libssp,libstdcxx-pch,lto,multilib,nls,shared,werror} --enable-{threads=posix,__cxa_atexit} --enable-languages=c,c++ make $J make install-strip DESTDIR=$ROOT rm -r * cd .. GCC info and man pages are generated from a number of .texi files and included in the distribution tarball in case makeinfo or perl are unavailable. For reasons not entirely understood, gcc/Makefile fails not only to rebuild but to install prefab for some docs in this case. So we install manually, and in a simpler path: cd gcc-4.7.4/gcc/doc DEST=$ROOT/gales/pkg/gcc-0.0-4.7.4 mkdir -p $DEST/{info,man/man1} cp {cpp,cppinternals,gcc,gccinstall,gccint}.info* $DEST/info/ cp {cpp,g++,gcc,gcov}.1 $DEST/man/man1/ cd $DEST mv share/info/lib{itm,quadmath}.info* info/ Remove ~useless junk: rm -r share/{info,man} rm lib*/*.la # ^ there used to be a libiberty.a to remove here, apparently no longer installed but unsure why rm bin/*gcc-* rm libexec/gcc/*/*/lto-wrapper Move binutils docs for consistency and remove ~useless junk: cd ../binutils-0.0-2.24 mv share/{info,man} . rmdir share rm -r lib 7. Make symlinks to activate the installed versions cd $ROOT/gales mkdir command info man cd pkg for p in MAKEDEV binutils e2fsprogs gcc gksh init lilo make ; do ln -s $p-*-* $p ; done cd ../command ln -s ../pkg/{MAKEDEV,binutils,e2fsprogs,gcc,lilo,make}/bin/* . ln -s ../pkg/e2fsprogs/sbin/* . ln -s ../pkg/gcc/bin/gcc cc cd ../info ln -s ../pkg/{binutils,gcc,make}/info/*.info* . cd ../man for p in MAKEDEV binutils e2fsprogs gcc gksh init lilo make ; do ln -s ../pkg/$p/man $p ; done cd $ROOT/bin ln -s ../gales/pkg/init/bin/init . ln -s ../gales/pkg/gksh/bin/ksh . ln -s ../gales/pkg/gksh/bin/ksh sh 8. Pack distribution archives The "tar --sterilize" option is a Gales feature that removes nondeterminism and ensures proper root ownership of installed files by zeroing out the unwanted metadata fields for modification time, owner and group. Thus you must follow section 2.2 to build the necessary "tar". An area for future work is to extend this option - or even the standard "tar" functioning - to sort directory entries, as file discovery presently proceeds in the unspecified and unstable filesystem order. cd $GALES $TGT-strip root/bin/* root/gales/command/* export DATE=`date +%Y%m%d` tar -czf base-$DATE.tar.gz --sterilize -C root . cd $GALES_REPO ./mkskeleton > $GALES/skeleton-$DATE.sh The Gales installation and rescue environment is implemented as a Linux initramfs, with contents controlled by the installer/initramfs.list.sh template. Now that the payloads are all in place, build it; the DATE setting from above is still required. This script also builds the gales-util package to facilitate building gports once the system is installed. This step, unlike the rest, writes to the repository rather than the build tree, an area for possible future improvement. ./mkinstaller 9. Create a bootable install medium, if desired # To be written (still)... for now, see conf/lilo-external.conf A1. Helpful resources http://jwrd.net/ http://jfxpt.com/category/gales-linux/ http://www.musl-libc.org/doc/1.0.0/manual.html http://www.musl-libc.org/faq.html http://gcc.gnu.org/install/configure.html http://www.linuxfromscratch.org/lfs/view/7.3/ A2. Reproducible builds In principle, anyone following the exact process should end up with bitwise identical results independent of their initial environment, even Unix flavor and CPU architecture. In practice, this can be a challenge as software is rarely built with this in mind, some even deliberately "coloring the bits" through build timestamps and the like. Some approaches to dealing with sources of variance: * Eliminate: Modify sources and build scripts to remove things like embedded timestamps (or fake them), seed pseudorandom algorithms, etc. * Normalize: Where there are multiple equivalent representations of the same information, coerce it into a canonical one. Example: sorting the order of files in an archive. * Standardize: When all else fails, mandate certain conditions on the build environment. Example: build paths, which are embedded in debug info. A3. Hacks for building from an OpenBSD host * tar doesn't auto-decompress: use "tar xzf", "tar xjf", or "xz -dc ... | tar xf -" * alias make=gmake * The kernel requires Linux-specific headers for some build tools: copy elf.h, byteswap.h and features.h from "include" in the musl sources to /usr/include * daemontools: my "ifdef CHOST" needs GNU make, but the compile script runs plain make. Delete it (src/Makefile +260), leaving just the stub echo. A4. ARM notes * Cortex-A8 is an ARMv7-A (32-bit, hardware float, optional NEON SIMD). musl-cross says to use "musleabi". So, using the target tuple: armv7a-gales-linux-musleabi (But does this imply HF?) * For Linux kernel: export ARCH=arm; make defconfig; make menuconfig * Kernel builds to arch/arm/boot/zImage