207 lines
8.9 KiB
Plaintext
207 lines
8.9 KiB
Plaintext
mkroot - simple linux system builder
|
|
|
|
Compiles a toybox-based root filesystem and kernel that can boot under qemu.
|
|
|
|
Prebuilt binaries available from http://landley.net/bin/mkroot/latest
|
|
launched via ./run-qemu.sh (which assumes you have QEMU installed, KVM
|
|
works in a pinch), and then run "exit" to shut down the emulated system.
|
|
|
|
This project is a successor to https://landley.net/aboriginal/about.html
|
|
and shares most of the same goals, with a much simpler implementation.
|
|
|
|
--- Quick Start
|
|
|
|
To install the build prerequisites: download toybox source, linux kernel source,
|
|
and one or more musl cross compiler toolchain(s) in the "ccc" directory:
|
|
|
|
$ cd toybox
|
|
$ git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
|
|
$ wget https://landley.net/bin/toolchains/latest/i686-linux-musl-cross.tar.xz
|
|
$ mkdir ccc
|
|
$ tar xvJCf ccc i686-linux-musl-cross-tar.xz
|
|
|
|
Then invoke mkroot like:
|
|
|
|
$ mkroot/mkroot.sh CROSS=i686 LINUX=linux
|
|
$ root/i686/run-qemu.sh
|
|
|
|
This project is a successor to https://landley.net/aboriginal/about.html
|
|
and shares most of the same goals, with a much simpler implementation.
|
|
|
|
--- Building without a cross compiler (warning: glibc sucks)
|
|
|
|
Running ./mkroot.sh with no arguments and no $CROSS_COMPILE environment
|
|
variable builds a statically linked root filesystem with the host's compiler.
|
|
|
|
$ mkroot/mkroot.sh
|
|
|
|
You can then chroot into it like this:
|
|
|
|
$ sudo chroot output/host/root /init
|
|
$ ls -l
|
|
$ exit
|
|
|
|
Unfortunately, glibc doesn't properly support static linking, so if your host
|
|
Linux uses glibc the build will spit out a bunch of warnings indicating
|
|
all sorts of glibc features won't work (DNS lookups always fail, ls -l can't
|
|
read names out of /etc/password, etc). This is a known problem with glibc,
|
|
because ex-maintainer Ulrich Drepper had a strong personal dislike of static
|
|
linking and actively sabotaged it.
|
|
|
|
If building on a non-glibc system, such as Alpine Linux, you're fine.
|
|
Otherwise, you'll probably want to cross compile with a musl-libc toolchain
|
|
to avoid glibc's very long list of static linking bugs. (The resulting root
|
|
filesystem is also significantly smaller: a stripped statically linked
|
|
"hello world" binary for x86-64 is 5420 bytes with musl-libc, and 682,696 bytes
|
|
with glibc.)</p>
|
|
|
|
--- Building with a cross compiler.
|
|
|
|
The variable $CROSS_COMPILE indicates the toolchain prefix to apply to
|
|
commands such as "cc" and "ld". Since prefixed cross compiler names tend
|
|
to look like "armv5l-cc" this prefix tends to end with a dash.
|
|
|
|
$ mkroot/mkroot.sh CROSS_COMPILE=armv5l-
|
|
|
|
If you haven't added the cross compiler to your $PATH, you can specify
|
|
a path as part of the prefix:
|
|
|
|
$ mkroot/mkroot.sh CROSS_COMPILE=~/x86_64-linux-musl-cross/bin/x86_64-linux-musl-cross-
|
|
|
|
Don't forget the trailing dash.
|
|
|
|
Alternately, the variable $CROSS (as used in the Quick Start above) tells
|
|
mkroot to look in the "ccc" directory for a cross compiler starting with
|
|
a short name:
|
|
|
|
$ mkroot/mkroot.sh CROSS=s390x
|
|
|
|
That would look (using wildcards) for ccc/s390x-*cross/bin/s390x*-cc and
|
|
if found, work out the appropriate $CROSS_COMPILER prefix to use for the
|
|
corresponding other tools. Use "CROSS=help" to see the list of cross compilers
|
|
currently available in the ccc directory.
|
|
|
|
You only need to set one of $CROSS or $CROSS_COMPILE, the other gets derived
|
|
from the one you provided.
|
|
|
|
The downloadable toolchains were built with toybox's scripts/mcm-buildall.sh
|
|
running in a fresh checkout of https://github.com/richfelker/musl-cross-make
|
|
and are available as prebuilt binaries from https://landley.net/bin/toolchains
|
|
(The "native" compilers run _on_ the target system, as well as producing
|
|
binaries for them. Those are packaged as squashfs filesystems, to be loopback
|
|
mounted within qemu.)
|
|
|
|
--- Adding a kernel
|
|
|
|
On the mkroot command line add LINUX= pointing to a kernel source directory:
|
|
|
|
$ mkroot/mkroot.sh CROSS=sh4 LINUX=~/linux
|
|
|
|
This will build a kernel for the appropriate target, package the filesystem
|
|
as cpio.gz for use by initramfs, and create a run-qemu.sh script to invoke
|
|
qemu. This results in the following files under root/$CROSS:
|
|
|
|
initramfs.cpio.gz - the "fs" dir packaged for initramfs, plus any $MODULES
|
|
linux-kernel - the compiled kernel
|
|
linux.dtb - The device tree binary (if this target requires one)
|
|
run-qemu.sh - the qemu invocation to run it all
|
|
|
|
And also:
|
|
|
|
fs/ - the generated root filesystem (you can chroot here)
|
|
docs/ - Additional information not needed to run qemu.
|
|
|
|
The run-qemu.sh script will connect together the appropriate -kernel, -initrd,
|
|
and -dtb arguments to consume the provided files, as well as -m board and
|
|
-append "kernel command line arguments". The KARGS environment variable is
|
|
added to the kernel command line arguments, and any additional arguments
|
|
provided to the script are passed through to qemu, so you can do:
|
|
|
|
$ KARGS="rdinit=/bin/sh" ./run-qemu.sh -hda blah.img
|
|
|
|
Running the script should boot the kernel to a command prompt, with the
|
|
serial console connected to stdin and stdout of the qemu process so you can
|
|
just type into it and see the output. The generated kernel config should
|
|
provide basic NAT network support (as if behind a router) and block device
|
|
support.
|
|
|
|
--- Environment variables
|
|
|
|
Any "name=value" argument provided on the mkroot.sh command line will set
|
|
an environment variable, and any string that without an = indicates a package
|
|
script to run before building toybox (explained below). This is why CROSS=
|
|
CROSS_COMPILE= and LINUX= were all set on the command line above.
|
|
|
|
For portability reasons, mkroot.sh clears all environment variables at the
|
|
start of its run, with the following exceptions:
|
|
|
|
LINUX - Linux kernel source directory.
|
|
CROSS_COMPILE - Cross compiler prefix (sets $CROSS from prefix before first -)
|
|
CROSS - Short target name (sets $CROSS_COMPILE from ccc)
|
|
HOME - Absolute path to user's home directory.
|
|
PATH - Executable path to find binaries.
|
|
NOCLEAR - Don't clear environment variables. (Can't set on command line.)
|
|
|
|
Other interesting variables to set on the command line include:
|
|
|
|
NOAIRLOCK - don't do a hermetic build, just use the $PATH's tools.
|
|
NOLOGPATH - don't use the command line recording wrapper
|
|
NOLOG - don't record build output to root/build/log/$CROSS.[yn]
|
|
NOTOYBOX - don't build toybox
|
|
PENDING - extra commands to enable out of toys/pending
|
|
KEXTRA - Additional kernel symbols to enable (in short CSV format)
|
|
MODULES - Kernel modules to build (in short CSV format)
|
|
|
|
--- Adding build modules
|
|
|
|
You can run additional build scripts from the mkroot/packages directory by
|
|
listing them on the command line:
|
|
|
|
$ mkroot/mkroot.sh dropbear overlay OVERLAY=~/blah
|
|
|
|
Any "name=value" argument provided on the command line will set an environment
|
|
variable in mkroot (explained above), and any string that without an =
|
|
indicates a package script to run before building toybox.
|
|
|
|
The provided build scripts mostly download source tarballs, cross compile them,
|
|
and install them into the root filesystem. Additional package build instructions
|
|
are available from the "Linux From Scratch" (http://linuxfromscratch.org/lfs)
|
|
and "Beyond Linux From Scratch" (http://linuxfromscratch.org/blfs) projects.
|
|
|
|
If you specify any packages, the "plumbing" package is automatically read first
|
|
to provide the download, setupfor, and cleanup shell functions to fetch and
|
|
manage source tarballs, and set the $DOWNLOAD variable (defaulting to store
|
|
downloaded tarballs in "./root_download").
|
|
|
|
The "overlay" script copies the $OVERLAY directory (default "./overlay")
|
|
into the root filesystem, so you can add arbitrary additional files.
|
|
|
|
The "dynamic" script attempts to copy dynamic libraries out of the
|
|
toolchain, to allow a dynamically linked root filesystem. It's a work in
|
|
progress. (A debian host toolchain can have multiple gigabytes of shared
|
|
libraries.)
|
|
|
|
The "tests" script copies the toybox test suite into the new filesystem,
|
|
downloads some test files, and adds some test modules to the kernel build.
|
|
|
|
--- Creating new build modules
|
|
|
|
Build scripts run after creating the directory layout and writing
|
|
the the init script and etc files (resolv.conf/passwd/group), but before
|
|
building toybox.
|
|
|
|
These scripts are sourced, not run, so environment variables you set remain
|
|
in force. The following variables can affect the remaining mkroot.sh build:
|
|
|
|
NOTOYBOX - if set, toybox will not be installed into the new root filesystem
|
|
KEXTRA - additional kernel symbols to enable (in same CSV format as $KCONF)
|
|
QEMU_MORE - Additional qemu command line arguments added to run-qemu.sh
|
|
|
|
To append instead of replacing (in case they're already set), you can use
|
|
QEMU_MORE="$QEMU_MORE --blah" and KEXTRA="${KEXTRA+$KEXTRA,}"BLAH,BLAH,BLAH
|
|
|
|
If you check your own build scripts into mkroot/packages without touching
|
|
any existing files, you should be able to "git pull --ff" to update your tree
|
|
without conflicts. Alternately, you can add your script directory to the start
|
|
of the $PATH and bash's "source" command will fall back to looking there next.
|