HiGFXback (History of graphics backends) is a Linux from scratch distribution designed to preserve and maintain historical graphics backends on Linux systems.
This Linux distribution has a set of characteristics that make it unique.
First, by its construction: HiGFXback is a fully source-based distribution (system built entirely from source code) that relies on the C library of your choice (glibc, musl, …).
Second, it is possible with HiGFXback to run components natively based on the following graphics backends:
Other characteristics specific to HiGFXback are also detailed in the installation and usage procedure that follows.
The initial steps consist of creating and booting a minimal system that provides a shell environment for ordinary Unix-like tasks, in particular downloading and compiling source code.
Current versions of the GNU C compiler are written in C++, which means that a C++ compiler (typically g++) is needed to build gcc from source. The GNU Compiler Collection GCC 4.7 is the last version that can be built with only a C compiler (even a simple one such as tcc, the Tiny C compiler), thus it is used in the bootstrap process.
On the host system, enter the bootstrap directory, and optionally set MAKEFLAGS environment variable to speed up compilation:
$ cd bootstrap
$ export MAKEFLAGS=-j$(nproc)
The host system is used to build a cross-toolchain for the target system:
$ make toolchain
A single cross-toolchain capable of supporting multiple C libraries (glibc, musl, …) and based on Binutils, GCC (C compiler only), the Linux headers, is generated in a staging directory.
The same cross-compiler is thus used to build the various C libraries, each placed in a dedicated directory within the staging directory:
. . .
| | |
|-- bin |-- glibc |-- musl
| |-- x86_64-unknown-linux-as |-- bin |-- bin
| |-- x86_64-unknown-linux-gcc | |-- getconf | |-- getconf
| |-- x86_64-unknown-linux-ld | |-- ldd | |-- ldd
| |-- ... | |-- ... | |-- ...
| | |
|-- include |-- include |-- include
| |-- asm | |-- math.h | |-- math.h
| |-- linux | |-- stdio.h | |-- stdio.h
| |-- ... | |-- ... | |-- ...
| | |
|-- lib |-- lib |-- lib
|-- gcc |-- crt1.o |-- crt1.o
|-- x86_64-unknown-linux |-- ld-linux-x86-64.so.2 |-- ld-musl-x86_64.so.1
|-- 4.7.4 |-- libc.so |-- libc.so
|-- cc1 |-- libc.so.6 |-- libc.so.6
|-- crtbegin.o |-- libpthread.so |-- libpthread.so
|-- crtend.o |-- ... |-- ...
|-- libgcc.a
|-- ...
|-- include
|-- float.h
|-- stddef.h
|-- ...
Selecting which C library the cross-compiler will use is done with the stow command, which makes the headers and libraries of the chosen C library appear in the sysroot directory of the toolchain.
With the toolchain in place, cross-compile a minimal set of software required for an ISO image and for the minimal system installed on the target hardware.
For a minimal glibc-based system:
$ make initrd-glibc
$ make rootfs-glibc
For a minimal musl-based system:
$ make initrd-musl
$ make rootfs-musl
The initrd serves as an installer (and optionally as a rescue disk) for the distribution, and is composed of:
- busybox, which combines lightweight versions of many Unix utilities
- syslinux, with its EXTLINUX bootloader
- the C library (glibc or musl), runtime files only (no development files)
The generated root filesystem contains only:
- linux, the operating system kernel
- busybox, providing the shell environment with standard Unix-like commands (same binary as in the initrd)
- binutils, providing, among other tools, the assembler and linker used by the C compiler
- gcc, the GNU C compiler
- pkg-config, a tool typically invoked when compiling applications and libraries, but whose usage is extended to manage packages and their dependencies on the system
- the C library (glibc or musl), both the runtime and development files
Since a common cross-compiler is used to build the source code regardless of the target C library, all binaries in the minimal system have the same dynamic linker/loader ld-linux.so.2 in the
PT_INTERP ELFsegment. But note that the compiler present in this minimal root filesystem, and used to build and install packages that will replace the initial minimal system binaries, compiles source code by setting thePT_INTERP ELFsegment to the dynamic linker/loader name corresponding to the selected C library (i.e. ld-linux.so.2 for glibc or ld-musl-x86_64.so.1 for musl).
Next, generate the ISO image used for installation:
$ make iso-glibc
or :
$ make iso-musl
The target machine can now boot from the ISO image.
To test it on a virtual machine with QEMU, first create a disk image, then boot the VM, for example from the glibc-based ISO image, by attaching the created disk image to an ATA disk over a SATA AHCI controller:
$ qemu-img create disk-glibc-x86_64.img 64G
$ qemu-system-x86_64 -boot d -cdrom bootstrap-glibc-x86_64.iso -device ahci -drive id=disk,file=disk-glibc-x86_64.img,format=raw,if=none -device ide-hd,drive=disk
Or from the musl-based ISO image:
$ qemu-img create disk-musl-x86_64.img 64G
$ qemu-system-x86_64 -boot d -cdrom bootstrap-musl-x86_64.iso -device ahci -drive id=disk,file=disk-musl-x86_64.img,format=raw,if=none -device ide-hd,drive=disk
Once the VM has started, perform the installation from the guest system’s shell prompt:
# setup
The VM can now boot on the freshly installed minimal system (located on the disk image).
The package installation process relies on a specific tool named pkg-build, which starts by downloading the package source code from the Internet (if it has not already been downloaded).
When testing with a QEMU virtual machine, set up a virtual network interface on the host system (a TAP interface) to allow the VM to connect to the real network:
$ sudo ip tuntap add dev tap0 mode tap
$ sudo ip addr add 192.168.0.1/24 dev tap0
$ sudo ip link set tap0 up
If the dnsmasq DHCP server is not installed on the host system, install it and edit its /etc/dnsmasq.conf configuration file to include the following settings, then restart dnsmasq:
port=5353
interface=tap0
dhcp-option=option:dns-server,8.8.8.8
dhcp-range=192.168.0.101,192.168.0.200
As a final step on the host system, enable IP forwarding and configure NAT so that traffic from the VM is passed to the Internet and replies from the Internet can reach the VM:
$ sudo sh -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'
$ sudo iptables -t nat -A POSTROUTING -o $(ip -o link show up | awk -F': ' '{print $2}' | grep -E '^(en|eth|wl)' | head -n1) -j MASQUERADE
With the host system network fully configured, launch the VM, for example, the glibc-based VM:
$ qemu-system-x86_64 -monitor stdio -enable-kvm -cpu host -smp 8 -m 8G -device ahci -drive id=disk,file=disk-glibc-x86_64.img,format=raw,if=none -device ide-hd,drive=disk -netdev tap,id=net0,ifname=tap0,script=no -device e1000,netdev=net0 -usb -device usb-tablet -device intel-hda -device hda-duplex
Or the musl-based VM:
$ qemu-system-x86_64 -monitor stdio -enable-kvm -cpu host -smp 8 -m 8G -device ahci -drive id=disk,file=disk-musl-x86_64.img,format=raw,if=none -device ide-hd,drive=disk -netdev tap,id=net0,ifname=tap0,script=no -device e1000,netdev=net0 -usb -device usb-tablet -device intel-hda -device hda-duplex
QEMU options used:
-monitor stdioto redirect the QEMU monitor to the host console.-enable-kvm -cpu hostto enable KVM acceleration with the host CPU exposed to the guest system.- `-smp 8 -m 8G_ to set 8 CPUs and 8 GiB of RAM.
-netdev tap,id=net0,ifname=tap0,script=no -device e1000,netdev=net0to add an Intel e1000 network device connected to the host networking via the TAP interface.-usb -device usb-tabletto add a USB controller with a USB tablet pointing device.-device intel-hda -device hda-duplexto add an Intel High Definition Audio controller with microphone and speakers devices.
The VM is by default launched with a VGA-compatible display device, allowing the vesafb guest driver to expose a Linux Framebuffer device interface (/dev/fb0).
To enable a KMS/DRM device interface (/dev/dri/card0), launch the VM with a VirtIO display device by adding the -device virtio-vga option to the QEMU command line, which is handled by the virtio_gpu guest driver.
Once the VM has started, run the DHCP client from the guest system’s shell prompt to automatically configure its network interface:
# udhcpc eth0
Then, enter the sources directory to begin installing packages, and optionally set the MAKEFLAGS environment variable to speed up compilations launched by the pkg-build tool:
# cd sources
# export MAKEFLAGS=-j$(nproc)
Most packages are built using a build system such as Autoconf, Meson, or CMake.
The Autoconf build system is partly written in the M4 and Perl languages, the perl package itself depending on the bzip2 and zlib compression libraries. The m4 package, as well as the bzip2 and zlib packages, are built using the make utility, which is therefore the first package added to the system:
# pkg-build make
Once make is available:
# pkg-build m4
# pkg-build bzip2 zlib
# pkg-build perl
# pkg-build autotools-wrappers-ac autotools-wrappers-am mawk autotools-wrappers-lt
Note that building autotools-wrappers-lt requires mawk, as an awk-based script named inline-source, involved in the generation of libtoolize, fails when executed with busybox awk.
It is often convenient to have mouse support in virtual consoles to allow copy-and-paste operations instead of typing everything by hand, which is provided by the gpm daemon:
# pkg-build byacc gpm
# gpm -m /dev/input/event2 -t usbtablet
The Meson build system is written in Python 3 language and relies by default on ninja, an utility written in C++ which controls the generation of non-source files from source files (like the make utility). If ninja is missing on the system, meson fallback to samurai, a ninja-compatible implementation written in C that is installed to avoid a dependancy with g++ and libstdc++ packages:
# pkg-build expat python3
# pkg-build samurai
# pkg-build meson
The CMake build system is written in C++ language so depends on the availibility of g++ and libstdc++ packages. These are not required for installing and starting core graphics components, but if C++ compiler is needed by other components:
# pkg-build gmp mpfr mpc g++ libstdc++
Then, if the CMake build system is required to build a package:
# pkg-build curl
# pkg-build expat lz4 xz zstd libarchive
# pkg-build libuv
# pkg-build rhash
# pkg-build jsoncpp cmake3
Note that the CMake build system has support for both make (used by default) and ninja/samurai as non-source files generators from source files.
If the C++ compiler is available on the system, ninja can easiy be installed to replace samurai:
# pkg-build ninja
When launching the VM with the default VGA-compatible display device, the guest can also expose a KMS/DRM device interface (/dev/dri/card0) if the Linux kernel includes support for the simpledrm driver.
Since the simpledrm driver is only available in Linux kernels requiring a gcc version newer than 4.7 (and therefore Linux kernels more recent than the one used in the bootstrap), this introduces an indirect dependency of the Linux kernel on g++ and libstdc++ packages. Assuming these packages are present, the following command can be used to update the Linux kernel:
# pkg-build byacc flex bison diffutils findutils elfutils openssl ncurses linux
Note that building linux requires diff command from diffutils package, as it is invoked with the
-Ioption, which is not supported by busybox diff, and find command from findutils package, as it is invoked with the-printfoption, which is not supported by busybox find.
For the Linux Framebuffer graphics backend:
# pkg-build byacc flex bison fbset
# pkg-build util-macros libfontenc freetype mkfontscale mkfontdir
# pkg-build ttf-bitstream-vera
# pkg-build fb/ft2tf fb/fbpad
For the KMS/DRM graphics backend graphics backend:
# pkg-build libdrm
# pkg-build byacc flex bison
# pkg-build util-macros xkeyboard-config libxkbcommon
# pkg-build libudev-zero libtsm kmscon
For the DirectFB graphics backend:
# pkg-build dfb/directfb2 dfb/directfb2-tools
# pkg-build dfb/lite dfb/dfbterm
For the X11 graphics backend:
# pkg-build util-macros x11/xproto x11/libxau
# pkg-build x11/xtrans
# pkg-build libfontenc freetype
# pkg-build x11/fontsproto x11/libxfont
# pkg-build x11/bigreqsproto x11/inputproto x11/kbproto x11/xcmiscproto
# pkg-build x11/renderproto x11/videoproto x11/xextproto x11/fixesproto x11/damageproto x11/randrproto
# pkg-build libmd pixman xkeyboard-config x11/libpciaccess x11/xorg-server
# pkg-build x11/xf86-video-fbdev x11/xf86-input-evdev
# pkg-build x11/libx11
# pkg-build x11/libxkbfile x11/xkbcomp
# pkg-build x11/libxext
# pkg-build x11/libxrender x11/xdpyinfo
# pkg-build util-linux x11/libice x11/libsm x11/libxt
# pkg-build x11/libxmu x11/twm
# pkg-build mkfontscale mkfontdir ttf-bitstream-vera
# pkg-build x11/libxpm x11/libxaw
# pkg-build expat fontconfig x11/libxft
# pkg-build ncurses x11/xterm
For the Wayland graphics backend:
# pkg-build libffi expat
# pkg-build wl/wayland wl/wayland-protocols
# pkg-build byacc flex bison
# pkg-build util-macros xkeyboard-config libxkbcommon
# pkg-build libevdev libudev-zero mtdev libinput
# pkg-build pcre util-linux python3 glib freetype fontconfig libpng pixman wl/cairo
# pkg-build jpeg wl/weston
