Before starting we need a very quick setup. You will need to install some software:
If anything is missing or if you have the commands for other distros send me a DM on discord (;
#For Arch
sudo pacman -S docker grub qemu-system-x86
#For Ubuntu/Debian
sudo apt install grub2 qemu-system-x86
curl -fsSL get.docker.com | bash
Explained:
sudo ---> This means we are using root (superuser) privilege, always be careful when using a command with sudo!
You need to start the docker service.
sudo systemctl start docker.service
Lets download and enter the Docker-LFN
sudo docker run -it maplecircuit/lfn
If ever you get locked out of your Docker-LFN.
#(get the id)
sudo docker ps -a
sudo docker start 4a8954d9ddf1
sudo docker exec -it 4a8954d9ddf1 bash
Lastly, if you need to delete Docker-LFN:
#(get the id)
sudo docker ps -a
sudo docker rm 4a8954d9ddf1
Docker-LFN provides an directory tree and the programs needed for us to create our LFN.
Here is the directory tree that is created:
This all happens in Docker-LFN
Glibc is the base of all library, it allows us to load dynamic libs through /lib64/ld-linux-x86-64.so.2 and gives us an implementation of the standard C lib (libc.so.6)
cd LFN
cd temp
wget https://ftp.gnu.org/gnu/glibc/glibc-2.41.tar.gz
tar -xf glibc-2.41.tar.gz
mkdir build-glibc
cd build-glibc
../glibc-2.41/configure --without-selinux --libdir=/usr/lib --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Explained:
cd LFN ---> Change Directory.
wget https://ftp.gnu.org/gnu/glibc/glibc-2.41.tar.gz ---> Download the archive for Glibc
tar -xf glibc-2.41.tar.gz ---> Uncompress the archive.
mkdir build-glibc ---> Create directory: build-glibc
../glibc-2.41/configure ---> Configure script is a standard across GNU software, it allows to configure the software before compiling.
--without-selinux ---> Removes selinux support. Not in LFN.
--libdir=/usr/lib ---> Set where ld-linux will search for dir, by default we have /usr/lib64 but we also want /usr/lib.
--prefix=/usr ---> By default, most software is installed in /usr/local/... we want to install it in the right place for us to use it, which is /usr. KEEP IN MIND a lot of software will have hard-coded paths, we cannot directly put /LFN/root/usr here.
make -j8 ---> Compile the software that we just configured.
make install ---> Make install makes the software deploys itself on the system.
DESTDIR=/LFN/root ---> Set the new / of the make install. Instead of putting things in /usr it will put things in /LFN/root/usr
Ncurses is a library that allows program to make TUIs(Terminal User interfaces). Ncurses' libs allows bash (and more) to work, we also need to compile the wide character version which has its libs end in 'w'. (get the latest here: https://ftp.gnu.org/gnu/ncurses/ )
wget https://ftp.gnu.org/gnu/ncurses/ncurses-6.5.tar.gz
tar -xf ncurses-6.5.tar.gz
mkdir build-ncurses
cd build-ncurses
CFLAGS='-std=gnu17' ../ncurses-6.5/configure --with-shared --with-termlib --enable-widec --with-versioned-syms --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
ln -s libncursesw.so.6 /LFN/root/usr/lib/libncurses.so.6
ln -s libformw.so.6 /LFN/root/usr/lib/libform.so.6
ln -s libpanelw.so.6 /LFN/root/usr/lib/libpanel.so.6
ln -s libmenuw.so.6 /LFN/root/usr/lib/libmenu.so.6
ln -s libtinfow.so.6 /LFN/root/usr/lib/libtinfo.so.6
cd ..
Explained:
CFLAGS='-std=gnu17' ---> Ncurse is kinda broken and needs us to compile using the gnu17 standard of C.
--with-shared ---> Creates libs(.so files)
--with-termlib ---> Creates libtinfow.so.6 (used by bash)
--enable-widec ---> Makes sure that ncurses is compatible with wide characters. This will also make all the libs end in w (libncurses.so.6 => libncursesw.so.6)
--with-versioned-syms ---> By default ncurses omits putting a version on the libs. This will make some software unable to use them.
ln -s libncursesw.so.6 /LFN/root/usr/lib/libncurses.so.6 ---> Some software will still search for the non w libs. We can fix this with a symlink to the w lib from the non w lib.
We need a shell in order to interact with our kernel.
wget https://ftp.gnu.org/gnu/bash/bash-5.3.tar.gz
tar -xf bash-5.3.tar.gz
mkdir build-bash
cd build-bash
../bash-5.3/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
ln -s bash /LFN/root/bin/sh
Explained:
ln -s bash /LFN/root/bin/sh ---> Most software won't assume bash but will assume sh for the shell, making a symlink is a standard.
We need core utilities like cat ,cp, rm...
wget https://ftp.gnu.org/gnu/coreutils/coreutils-9.7.tar.xz
tar -xf coreutils-9.7.tar.xz
mkdir build-coreutils
cd build-coreutils
FORCE_UNSAFE_CONFIGURE=1 ../coreutils-9.7/configure --without-selinux --without-included-regex --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Explained:
FORCE_UNSAFE_CONFIGURE=1 ---> Our docker is running as root an coreutils has a protection against it, this is a bypass.
--without-included-regex ---> Removes regex support. PCRE2 (which is needed for this feature) is not yet in LFN (but will be).
Gives us a bunch of Linux tools like mount.
wget https://www.kernel.org/pub/linux/utils/util-linux/v2.41/util-linux-2.41.tar.xz
tar -xf util-linux-2.41.tar.xz
mkdir build-util
cd build-util
../util-linux-2.41/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Nano a very simple text editor.
wget https://www.nano-editor.org/dist/v8/nano-8.5.tar.xz
tar -xf nano-8.5.tar.xz
mkdir build-nano
cd build-nano
../nano-8.5/configure --enable-tiny --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Explained:
--enable-tiny ---> Disables all extra features. Ensure compatibility.
Lets download and config the kernel.
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.16.tar.xz
tar -xf linux-6.16.tar.xz
cd linux-6.16
make tinyconfig
make menuconfig
Explained:
git clone https://github.com/torvalds/linux ---> Clone the latest kernel.
--depth 1 ---> Doesn't clone the whole git history. We don't plan to go into any other version so it isn't needed.
make tinyconfig ---> Makes the smallest possible kernel that can be compiled.
make menuconfig ---> Opens the menu for us to config the kernel.
There is a few thing that we want to achieve with the kernel.
/ Here is how you should set the kernel /
General setup --->
----[ ] Configure standard kernel features (expert users)
[*] 64-bit kernel
Processor type and features --->
----[*] Symmetric multi-processing support
----[*] Linux guest support --->
--------[*] Enable paravirtualization code
----(8) Maximum number of CPUs
Power management and ACPI options --->
----[*] ACPI (Advanced Configuration and Power Interface) Support
General architecture-dependent options --->
----[*] Provide system calls for 32-bit time_t
Executable file formats --->
----[*] Kernel support for ELF binaries
----[*] Kernel support for scripts starting with #!
[*] Networking support --->
----Networking options --->
--------[*] Packet socket
--------[*] Unix domain sockets
--------[*] TCP/IP networking
--------[*] DNS Resolver support (needs the other option ↓ to be shown)
Security options --->
----[*] Enable access key retention support
Device Drivers --->
----[*] PCI support
----Generic Driver Options --->
--------[*] Maintain a devtmpfs filesystem to mount at /dev
--------[*] Automount devtmpfs at /dev, after the kernel mounted the rootfs
----SCSI device support --->
--------[*] SCSI disk support (this will unlock after serial ATA)
----[*] Serial ATA and Parallel ATA drivers (libata) --->
--------[*] Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support
----[*] Network device support --->
--------[*] Ethernet driver support (NEW) ---> (THIS IS ALREADY MARKED)
------------[*] Intel(R) PRO/1000 Gigabit Ethernet support
----Character devices --->
--------Serial drivers --->
------------[*] 8250/16550 and compatible serial support
------------[*] Console on 8250/16550 and compatible serial port
----Graphics support --->
--------Frame buffer Devices --->
------------[*] Support for frame buffer device drivers --->
---------------[*] VESA VGA graphics support
--------Console display driver support --->
------------[*] Framebuffer Console support
File systems --->
----[*] The Extended 4 (ext4) filesystem
----[*] Inotify support for userspace
Compile and dump our kernel in the boot dir of LFN, we also take the time to copy the .config we did. We won't have to do it again. (;
make -j8
mv arch/x86/boot/bzImage /LFN/root/boot/
cp .config /LFN/root/boot/
cd ..
Explained:
mv arch/x86/boot/bzImage /LFN/root/boot/ ---> Moves the file bzImage to the boot dir.
ld-linux-x86-64.so.2 can detect libs in 2 ways:
Lets generate that cache!
cd ..
cd root
nano etc/ld.so.conf
First time running nano, nano allows to edit and create files.
Content of the file (save and exit using Ctrl-x and than y, than Enter).
/usr/lib
/usr/lib64
Update the ld.so.cache .
ldconfig -v -r ./
Now lets make the init, it can be placed in /, /bin or /sbin, always need to be called "init" and be executable.
The init is the first thing to boot from the userspace by the kernel, it allows us to direct what we want our LFN to do as it boots.
nano sbin/init
Content of the file (exit using Ctrl-x and than y, than Enter).
#!/bin/bash
mount -t proc none /proc
mount -t sysfs none /sys
exec /bin/bash
Explained:
#!/bin/bash ---> This is called a shebang, it is used to indicate to the kernel that it should open the script using bash.
mount -t proc none /proc ---> Mounts the Proc FS (will be populated by the kernel).
mount -t sysfs none /sys ---> Mounts the Sys FS (will be populated by the kernel).
exec /bin/bash ---> Executes bash for us to use the shell.
Make it executable.
chmod +x sbin/init
Grub is a bootloader, it is opened by the BIOS to boot the kernel. Grub is a big beast with a lot of feature while being fairly easy to configure.
Now lets create the boot entry.
nano boot/grub/grub.cfg
Content of the file (exit using Ctrl-x and than y, than Enter).
menuentry 'LFN' {
gfxpayload=1920x1080
set root='(hd0,1)'
linux /boot/bzImage root=/dev/sda1 rw
}
Explained:
menuentry 'LFN' { ---> We have a menuentry called LFN. You could have multiple and the name isn't important.
gfxpayload=1920x1080 ---> Allows us to boot the kernel with a given screen size, you can edit to your preferred size.
set root='(hd0,1)' ---> Sets the disk we are booting from, hd0 means first disk and ,1 means first partition.
linux /boot/bzImage ---> Grub will attempt to boot a linux kernel stored in /boot/bzImage.
root=/dev/sda1 rw ---> Mount /dev/sda1 as Read-Write.
We need to create a disk (in our case 1GB).
(CTRL+D)
mkdir LFN
cd LFN
dd if=/dev/zero of=disk.img bs=1M count=1024
fdisk disk.img
n - p - 1 - (leave default 2048 sectors) - (leave default xxxx sectors)
a
w
Explained:
(CTRL+D) ---> On you keyboard doing CTRL+D quits the session that you are in, this will make you exit docker.
dd if=/dev/zero of=disk.img bs=1M count=1024 ---> Will create an empty 1GB disk.img file.
fdisk disk.img ---> Will format our disk using the msdos standard. Also create a bootable partition.
Mounting our disk using losetup, it will find the next available /dev/loop# and give us access to the partitions at /dev/loop#p#. it will also tell us which loop# it chose.
sudo losetup -fP --show disk.img
You can now format the partition to the FS of your choice, given that it was configured into your kernel. if you followed this tutorial without change, you will be using EXT4.
sudo mkfs.ext4 /dev/loop#p1
This will be the last thing you have to do to mount an not-new image. don't stop the tutorial if its new (; .
sudo mount /dev/loop#p1 /mnt
We will find our docker ID and copy the data out of docker into our image (/mnt).
sudo docker ps -a
sudo docker cp 4a8954d9ddf1:/LFN/root/. /mnt/
We need a bootloader to tell our system what to do at boot, Grub is a complete, battle-harden bootloader and you will learn to use it. Lets get it onto our drive!
sudo grub-install --target=i386-pc --root-directory=/mnt --no-floppy --modules="normal part_msdos ext2 multiboot" /dev/loop#
Explained:
--target=i386-pc ---> Grub will set itself to boot from a msdos pc, it is universal and works well with QEMU.
--root-directory=/mnt ---> Grub will install itself in /mnt.
--no-floppy ---> Wont scan for a floppy.
--modules="normal part_msdos ext2 multiboot" ---> Will add modules for ext4 and msdos partitioning.
/dev/loop# ---> Will modify the partition table.
sudo umount /mnt
sudo losetup -d /dev/loop#
Explained:
sudo umount /mnt ---> Unmount /mnt
sudo losetup -d /dev/loop# ---> Removes our loopback device.
You can now follow #Running LFN to test your creation!
Here is the basic command:
qemu-system-x86_64 disk.img
There is some options that you can add to better your experience.
By default, QEMU gives you 128MB, not alot...
-m 4G
You can change 4G for the amount that you want, but at least 4GB.
By default, QEMU gives you 1 core.
-smp 8
Here we have 8 core, you can change it for the needed amount. (and yes cursed amounts like 7 work)
KVM will harness the power of virtualization provided by the hardware and it is wayyyy faster, the host kernel needs to have it enabled and bios too but they are both default now....
-enable-kvm -cpu host
The simplest way to get network on QEMU is (but it should be enabled by default):
-net nic -net user
We are going to install all that is necessary for us to compile from LFN (Without Docker-LFN).
Get back in your Docker-LFN instance:
sudo systemctl start docker.service
sudo docker ps -a
sudo docker start 4a8954d9ddf1
sudo docker exec -it 4a8954d9ddf1 bash
#Now inside docker, get to the right Dir
cd LFN
cd temp
Explained:
sudo systemctl start docker.service ---> If you have rebooted your machine since last tutorial, docker may not be started.
sudo docker ps -a ---> Prints all docker on the system, allows you to get the ID of your LFN docker.
sudo docker start 4a8954d9ddf1 ---> Start your docker instance. Choose the right id. (;
sudo docker exec -it 4a8954d9ddf1 bash ---> Gets into your docker instance using bash.
Contains Assembler and a bunch of tools used by the compiler.
wget https://sourceware.org/pub/binutils/releases/binutils-2.44.tar.gz
tar -xf binutils-2.44.tar.gz
mkdir build-binutils
cd build-binutils
../binutils-2.44/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
This Linux kernel header file, you can think of them as the connection that any program we compile will use to connect to the kernel.
#If you deleted the linux dir...
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.16.tar.xz
tar -xf linux-6.16.tar.xz
cd linux-6.16
make headers
cp -r usr/include/* /LFN/root/usr/include/
cd ..
Explained:
make headers ---> Will generate the Linux Headers.
The basic Gnu C Compiler and its c++ libs. Probably the most technical part of LFN.
wget https://ftp.gnu.org/gnu/gcc/gcc-15.1.0/gcc-15.1.0.tar.xz
tar -xf gcc-15.1.0.tar.xz
cd gcc-15.1.0
./contrib/download_prerequisites
cd ..
mkdir build-gcc
cd build-gcc
../gcc-15.1.0/configure --with-build-sysroot=/LFN/root --disable-nls --disable-multilib --disable-bootstrap --disable-fixincludes --enable-languages=c,c++ --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Explained:
./contrib/download_prerequisites ---> Allows to download some of the libs needed to compile GCC. We will also be using some of the libs right after to install on LFN.
--with-build-sysroot=/LFN/root ---> Will build against the headers and libs that we have in our LFN.
--disable-nls ---> Disable Multi-Lingual support.
--disable-multilib ---> 32 bit support, Not needed.
--disable-bootstrap ---> GCC normally compile a compiler and then compile itself with it, skip that step.
--disable-fixincludes ---> GCC normally runs a scripts that scans and modify the headers on the system for better compatibility, this probably won't break anything but it is unnecessary on anything modern.
--enable-languages=c,c++ ---> GCC allows to compile a LOT of languages, only go with C and C++.
GNU Multiple Precision Arithmetic Library. Used to compile.
mkdir build-gmp
cd build-gmp
../gcc-15.1.0/gmp/configure --host=none-linux-gnu --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Explained:
--host=none-linux-gnu ---> GMP will attempt to scan the host architecture at compile time and 99% fail, this fixes it.
The MPFR library is a C library for multiple-precision floating-point computations with _correct rounding_.
mkdir build-mpfr
cd build-mpfr
../gcc-15.1.0/mpfr/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
make install
cd ..
Explained:
make install ---> This is not a mistake, to be able to compile MPC for LFN we will need to install it on docker.
Multiprecision, is an extention of MPFR.
mkdir build-mpc
cd build-mpc
../gcc-15.1.0/mpc/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Used to make program multi-lingual.
mkdir build-gettext
cd build-gettext
../gcc-15.1.0/gettext/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Make, we all know what it is by now.
wget https://ftp.gnu.org/gnu/make/make-4.4.1.tar.gz
tar -xf make-4.4.1.tar.gz
mkdir build-make
cd build-make
../make-4.4.1/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Macros M4 is a macro processor. You can think of it as a powerful and scriptable find and replace. It is used by autoconf (the tool that produce configure).
wget https://ftp.gnu.org/gnu/m4/m4-1.4.20.tar.xz
tar -xf m4-1.4.20.tar.xz
mkdir build-m4
cd build-m4
../m4-1.4.20/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Provides diff and cmp needed broadly across GNU software.
wget https://ftp.gnu.org/gnu/diffutils/diffutils-3.12.tar.xz
tar -xf diffutils-3.12.tar.xz
mkdir build-diffutils
cd build-diffutils
../diffutils-3.12/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Needed by perl
wget https://ftp.gnu.org/gnu/gawk/gawk-5.3.2.tar.gz
tar -xf gawk-5.3.2.tar.gz
mkdir build-gawk
cd build-gawk
../gawk-5.3.2/configure --without-readline --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Explained:
--without-readline ---> We don't have readline yet, we need to disable it.
Provides find.
wget https://ftp.gnu.org/gnu/findutils/findutils-4.10.0.tar.xz
tar -xf findutils-4.10.0.tar.xz
mkdir build-findutils
cd build-findutils
../findutils-4.10.0/configure --without-selinux --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Grep allows you to search for terms in text or files. Used with Make.
wget https://ftp.gnu.org/gnu/grep/grep-3.12.tar.gz
tar -xf grep-3.12.tar.gz
mkdir build-grep
cd build-grep
../grep-3.12/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
The PCRE2 lib implements regular expression pattern matching. Integrates with grep and others.
wget https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.45/pcre2-10.45.tar.gz
tar -xf pcre2-10.45.tar.gz
mkdir build-pcre2
cd build-pcre2
../pcre2-10.45/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Very simple find and replace. Used with Make.
wget https://ftp.gnu.org/gnu/sed/sed-4.9.tar.gz
tar -xf sed-4.9.tar.gz
mkdir build-sed
cd build-sed
../sed-4.9/configure --without-selinux --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Used to apply patches that were created using diff. Used with Make.
wget https://ftp.gnu.org/gnu/patch/patch-2.8.tar.xz
tar -xf patch-2.8.tar.xz
mkdir build-patch
cd build-patch
../patch-2.8/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
ElfUtils will provide libelf and simple elf editing tools. Most executable on linux are elf binaries.
wget https://sourceware.org/elfutils/ftp/0.193/elfutils-0.193.tar.bz2
tar -xf elfutils-0.193.tar.bz2
mkdir build-elfutils
cd build-elfutils
../elfutils-0.193/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
> [!NOTE] Detailed explanation on what is (F)lex
> Flex allows you to generate lexers. Lexers allow you to do lexing, the act of parsing a stream of text info tokens. follow the link for Examples.
FLEX allows you to generate scanners (Will generate the C code for a scanner to find a specific pattern). Used by the kernel, libcap and others.
wget https://github.com/westes/flex/releases/download/v2.6.4/flex-2.6.4.tar.gz
tar -xf flex-2.6.4.tar.gz
mkdir build-flex
cd build-flex
../flex-2.6.4/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Allows us to unpack and pack archives. We will need alot!
wget https://ftp.gnu.org/gnu/tar/tar-1.35.tar.gz
tar -xf tar-1.35.tar.gz
mkdir build-tar
cd build-tar
FORCE_UNSAFE_CONFIGURE=1 ../tar-1.35/configure --without-selinux --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
GZ compression. We will need with Tar.
wget https://ftp.gnu.org/gnu/gzip/gzip-1.14.tar.gz
tar -xf gzip-1.14.tar.gz
mkdir build-gzip
cd build-gzip
../gzip-1.14/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
XZ compression. We will need with Tar.
wget https://github.com/tukaani-project/xz/releases/download/v5.8.1/xz-5.8.1.tar.xz
tar -xf xz-5.8.1.tar.xz
mkdir build-xz
cd build-xz
../xz-5.8.1/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Zlib is a compression lib, it provides libz.
wget https://zlib.net/zlib-1.3.1.tar.gz
tar -xf zlib-1.3.1.tar.gz
mkdir build-zlib
cd build-zlib
../zlib-1.3.1/configure --prefix=/usr
make -j8
make DESTDIR=/LFN/root install
cd ..
Zstd is a compression lib/program that can produce and decode .zst .gz .xz .lz4 . Provides libzstd.
wget https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz
tar -xf zstd-1.5.7.tar.gz
cd zstd-1.5.7
make -j8
make DESTDIR=/LFN/root prefix=/usr install
cd ..
Explained:
make DESTDIR=/LFN/root prefix=/usr install ---> Zstd doesn't have a configure so we set the prefix with make install.
Bzip2 is a compression lib, it provides libbz2.
wget https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz
tar -xf bzip2-1.0.8.tar.gz
cd bzip2-1.0.8
make -f Makefile-libbz2_so
make -j8
make PREFIX=/LFN/root install
cp libbz2.so.* /LFN/root/lib
cd ..
Explained:
make -f Makefile-libbz2_so ---> Bzip2 doesn't generate .so libs by default, lets force it to do so (and copy them).
We will download a few program that we will compile now and in part 3.
cd ..
cd root
#mkdir LFN <--- automated by docker-LFN
cd LFN
wget http://ftp.astron.com/pub/file/file-5.46.tar.gz
wget https://git.kernel.org/pub/scm/libs/libcap/libcap.git/snapshot/libcap-cap/v1.2.76.tar.gz
mv v1.2.76.tar.gz libcap-v1.2.76.tar.gz
wget https://distfiles.dereferenced.org/pkgconf/pkgconf-1.1.0.tar.xz
wget https://ftp.gnu.org/gnu/bison/bison-3.8.2.tar.xz
wget https://mirrors.edge.kernel.org/pub/linux/utils/net/iproute2/iproute2-6.15.0.tar.xz
wget https://github.com/openssl/openssl/releases/download/openssl-3.5.1/openssl-3.5.1.tar.gz
wget https://www.cpan.org/src/5.0/perl-5.42.0.tar.gz
wget https://ftp.gnu.org/gnu/wget/wget-1.25.0.tar.gz
wget https://thekelleys.org.uk/dnsmasq/dnsmasq-2.91.tar.gz
cd ..
ldconfig -v -r ./
Now lets fix the init.
nano sbin/init
Content of the file (exit using Ctrl-x and than y, than Enter).
#!/bin/bash
mount -t proc none /proc
mount -t sysfs none /sys
export CC=/usr/bin/gcc
export GCC_EXEC_PREFIX=/usr/libexec/gcc/
export LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/15.1.0/
exec /bin/bash
Explained:
export ---> Sets a variable.
export CC=/usr/bin/gcc ---> Some programs like there compiler to be defined.
export GCC_EXEC_PREFIX=/usr/libexec/gcc/ ---> Tells GCC where to find internal components (cc1).
export LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/15.1.0/ ---> ells GCC where to find some internal libs.
If you are watching the vids and you just want to skip to this point, make sure that you start your docker-LFN and run:
LFN-install
It will do all the steps above. You may have to answer some question when it comes to compiling the kernel, just press enter and it will set the default.
DO NOT DO IF YOU ALREADY INSTALLED ANYTHING IT WON'T WORK/BRICK THING UP.
Now out of docker:
We need to create a disk (in our case 1GB).
(CTRL+D)
#Make sure you are in the right dir
cd LFN
rm disk.img
qemu-img create -f qcow2 disk.img 100G
sudo modprobe nbd max_part=8
sudo qemu-nbd -c /dev/nbd0 disk.img
sudo fdisk /dev/nbd0
n - p - 1 - (leave default 2048 sectors) - (default 209715199)
a
w
Explained:
rm disk.img ---> Removes disk.img.
qemu-img create -f qcow2 disk.img 100G ---> Creates a Qcow2 image of size 100G. This image is compressed so it won't take a lot of place and it is optimized for QEMU.
sudo modprobe nbd max_part=8 ---> Enable nbd in the kernel.
sudo qemu-nbd -c /dev/nbd0 disk.img ---> Mount disk.img to /dev/nbd0.
You can now format the partition to the FS of your choice, given that it was configured into your kernel. if you followed this tutorial without change, you will be using EXT4.
sudo mkfs.ext4 /dev/nbd0p1
This will be the last thing you have to do to mount an not-new image. don't stop the tutorial if its new (; .
sudo mount /dev/nbd0p1 /mnt
We will find our docker ID and copy the data out of docker into our image (/mnt).
sudo docker ps -a
sudo docker cp 4a8954d9ddf1:/LFN/root/. /mnt/
We need a bootloader to tell our system what to do at boot, Grub is a complete, battle-harden bootloader and you will learn to use it. Lets get it onto our drive!
sudo grub-install --target=i386-pc --root-directory=/mnt --no-floppy --modules="normal part_msdos ext2 multiboot" /dev/nbd0
sudo umount /mnt
sudo qemu-nbd -d /dev/nbd0
Explained:
sudo qemu-nbd -d /dev/nbd0 ---> Removes our NBD device.
You can now follow #Running LFN to test your creation!
File allows us to know what a specific file is.
cd LFN
tar -xf file-5.46.tar.gz
mkdir build-file
cd build-file
../file-5.46/configure --prefix=/usr
make -j8
make install
cd ..
You can now test (and celebrate) the file command with any file of your choosing!
Keep in mind that our LFN doesn't have any way to shutdown correctly, make sure to do:
sync
before closing QEMU/LFN as to make sure that everything that needs to be written to the disk is.
Lets get LFN on the internet.
PKGconf is used by some config script to detect compatible features. PKGconf searches /usr/lib/pkgconfig for .pc files that shows the information about installed programs. It is a replacement to pkg-config which is not as well maintained and contains weird dependencies (Glib).
cd /LFN
tar -xf pkgconf-1.1.0.tar.xz
mkdir build-pkgconf
cd build-pkgconf
../pkgconf-1.1.0/configure --with-system-libdir=/usr/lib:/usr/lib64 --with-system-includedir=/usr/include --prefix=/usr
make -j8
make install
ln -s pkgconf /usr/bin/pkg-config
ln -s /usr/lib/pkgconfig /usr/lib64/pkgconfig
cd ..
Explained:
ln -sf pkgconf /usr/bin/pkg-config ---> We need to symlink to pkg-config for us to use is in scripts.
ln -s /usr/lib/pkgconfig /usr/lib64/pkgconfig ---> We need to symlink lib64/pkgconfig to lib/pkgconfig to make it detectable.
LibCap is a library that allows to limit the reach of the superuser. For example, you might not want to pass the right to change permissions on files to a program that shouldn't do that, even if it does need superuser. This Library allows you to do just that by making the kernel function available to the user.
tar -xf libcap-v1.2.76.tar.gz
cd libcap-cap
cd v1.2.76
make -j8
make install
cd ..
cd ..
Bison allows you to generate C parsers, often used with #FLEX (to sanitise what you input into bison).
Needed by the kernel and GNU software.
tar -xf bison-3.8.2.tar.xz
mkdir build-bison
cd build-bison
../bison-3.8.2/configure --prefix=/usr
make -j8
make install
cd ..
Iproute2 is the default network tool for linux, and with it, we will be connection our LFN to the network.
tar -xf iproute2-6.15.0.tar.xz
cd iproute2-6.15.0
./configure --prefix=/usr
make -j8
make install
cd ..
Perl is a high-level language (like python...) that fell out of favour, it's needed everywhere... and Openssl.
ln -s gcc /bin/cc
tar -xf perl-5.42.0.tar.gz
cd perl-5.42.0
./Configure -d
make -j8
make install
cd ..
Explained:
ln -s gcc /bin/cc ---> Perl will use cc instead of gcc, we can bridge this with a symlink.
./Configure -d ---> Perl is a bit fancy in their configure script, -d is for default as you will need to answer 1000 things otherwise. When it asks you a question just press enter.
We need a library that will manage ours certificates for SSL,TLS,HTTPS. OpenSSL is the standard for that.
tar -xf openssl-3.5.1.tar.gz
mkdir build-openssl
cd build-openssl
../openssl-3.5.1/Configure --prefix=/usr
make -j8
make install
cd ..
Wget will allow us to start downloading thing.
tar -xf wget-1.25.0.tar.gz
mkdir build-wget
cd build-wget
../wget-1.25.0/configure --with-ssl=openssl --prefix=/usr
make -j8
make install
cd ..
Explained:
--with-ssl=openssl ---> Use OpenSSL instead of GnuTLS.
DNSMasq is a small DNS server, it can be used for a bunch of other things and it was more widely used before systemd was the solution to everything (; .
tar -xf dnsmasq-2.91.tar.gz
cd dnsmasq-2.91
make -j8
make install
cd ..
We need a bit more setup in order to get DNSMasq to work, we need to create our first user, root:
nano /etc/passwd
Content of the file
root:x:0:0:root:/root:/bin/bash
here is what it means:
mkdir /root
mkdir /var/run
While we are making files lets create /etc/resolv.conf. This file is looked at when it comes time to choose a DNS, we will be choosing the one from cloudflare.
nano /etc/resolv.conf
Content of /etc/resolv.conf:
nameserver 1.1.1.1
Lets add ip/DNSMasq to our init.
nano /sbin/init
This is the content:
#!/bin/bash
mount -t proc none /proc
mount -t sysfs none /sys
export CC=/usr/bin/gcc
export GCC_EXEC_PREFIX=/usr/libexec/gcc/
export LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/15.1.0/
ip link set up eth0
ip addr add 10.0.2.15/24 dev eth0
ip route add 10.0.2.2 dev eth0
ip route add 0/0 via 10.0.2.2 dev eth0
dnsmasq -uroot
exec /bin/bash
Explained:
ip link set up eth0 ---> Default network connector eth0 set to up (enabled).
ip addr add 10.0.2.15/24 dev eth0 ---> Default guest (local) ip address for QEMU, applied to eth0.
ip route add 10.0.2.2 dev eth0 ---> Opens a route through 10.0.2.2 which is the QEMU gateway, applied to eth0.
ip route add 0/0 via 10.0.2.2 dev eth0 ---> Push all network traffic (0/0) via 10.0.2.2, applied to eth0.
dnsmasq -uroot ---> Start dnsmasq using the root user.
Lets Sync and reboot.
sync
Once we boot it back up, our LFN should be able to go online.
We still need a certificate for us to accept https connections.
mkdir -p /etc/ssl/certs
cd /etc/ssl/certs
wget --no-check-certificate https://curl.se/ca/cacert.pem
mv cacert.pem ca-certificates.crt
Explained:
mkdir -p /etc/ssl/certs ---> the -p allows all dirs that are not yet created to be created, so here we will be creating both /etc/ssl and /etc/ssl/certs
wget https://curl.se/ca/cacert.pem ---> wget allow to download from the internet, here we are downloading the CA root certificate.
--no-check-certificate ---> Ignores the fact that we cannot verify the https (as the root cert isn't installed yet).
mv cacert.pem ca-certificates.crt ---> Some program needs the cert to be of a specific name.
Lets edit the init again:
nano /sbin/init
This is the content:
#!/bin/bash
mount -t proc none /proc
mount -t sysfs none /sys
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
export CC=/usr/bin/gcc
export GCC_EXEC_PREFIX=/usr/libexec/gcc/
export LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/15.1.0/
ip link set up eth0
ip addr add 10.0.2.15/24 dev eth0
ip route add 10.0.2.2 dev eth0
ip route add 0/0 via 10.0.2.2 dev eth0
dnsmasq -uroot
exec /bin/bash
Explained:
SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt ---> This is the default variable and placement for a certificate.
Lets Sync and reboot to test it!
sync
You can now use wget as much as you want!
Lets get python with pip working on LFN along with Ninja and Meson which are used to compile some software.
Python is an essential tool for any modern system, used for everything from system administration scripts to running complex applications. We will install Python 3 from source, ensuring it's linked correctly with the libraries we've already built.
Before we can build Python, we need one more library: libffi. The Foreign Function Interface library provides a way for a program written in one language to call code written in another. Python uses it for its powerful ctypes module.
cd /LFN
wget https://github.com/libffi/libffi/releases/download/v3.5.2/libffi-3.5.2.tar.gz
tar -xf libffi-3.5.2.tar.gz
mkdir build-libffi
cd build-libffi
../libffi-3.5.2/configure --prefix=/usr
make -j8
make install
cd ..
With the prerequisite installed, we can now build Python itself. We'll use several configuration flags to make sure our Python build is optimized and can find the libraries we've already installed, like OpenSSL and libffi.
wget https://www.python.org/ftp/python/3.13.5/Python-3.13.5.tar.xz
tar -xf Python-3.13.5.tar.xz
mkdir build-python
cd build-python
../Python-3.13.5/configure --with-openssl=/usr --prefix=/usr
make -j8
make install
ln -s python3 /usr/bin/python
ln -s pip3 /usr/bin/pip
pip install setuptools
cd ..
Explained:
--with-openssl=/usr ---> Explicitly tells Python where to find the OpenSSL headers and libraries. This enables the ssl module.
ln -s python3 /usr/bin/python ---> Both python and pip symlink need to be created to their 3 equivalent.
pip install setuptools ---> pip is a python package manager and it allows us to install setuptools which is needed by meson.
Meson is a build system, but it relies on a "backend" to do the actual compiling. The most common backend is Ninja, a small and extremely fast build tool. We'll need to install both.
Ninja is written in C++ and has a very straightforward build process.
wget https://github.com/ninja-build/ninja/archive/refs/tags/v1.13.1.tar.gz
mv v1.13.1.tar.gz ninja-v1.13.1.tar.gz
tar -xf ninja-v1.13.1.tar.gz
cd ninja-1.13.1
./configure.py --bootstrap --verbose
cp ninja /usr/bin/
cd ..
Explained:
./configure.py --bootstrap ---> Ninja is unique in that it can build itself. This command uses Python to create a minimal build.ninja file and then uses a pre-compiled version of itself (or a C++ compiler) to build the final binary.
--verbose ---> Will crash if we don't, we are probably missing something but couldn't diag the issue XD.
cp ninja /usr/bin/ ---> We manually copy the single ninja executable into /usr/bin so it can be found by Meson.
Meson is a Python application, so we don't need to compile it in the traditional sense. We just need to download it and run its installation script.
wget https://github.com/mesonbuild/meson/releases/download/1.8.3/meson-1.8.3.tar.gz
tar -xf meson-1.8.3.tar.gz
cd meson-1.8.3
python setup.py install
cd ..
Explained:
python setup.py install ---> This is a standard way to install Python packages from source. It will place the meson executable in /usr/bin and its library files in the correct Python site-packages directory.
We still need to edit the top line of meson as it won't correctly detect python:
nano /usr/bin/meson
This is the what the first line should look like:
#!/usr/bin/python
Lets Sync and reboot to test it!
sync
You now have a working Python, pip, Ninja Meson setup inside LFN!
Now that we have a basic system, let's create a non-root user for our daily tasks and install sudo to grant administrative privileges when needed. This is a crucial step for system security.
We need to install libxcrypt to provide the crypt() function required by the shadow utilities for password management.
cd /LFN
wget https://github.com/besser82/libxcrypt/releases/download/v4.4.38/libxcrypt-4.4.38.tar.xz
tar -xf libxcrypt-4.4.38.tar.xz
mkdir build-libxcrypt
cd build-libxcrypt
../libxcrypt-4.4.38/configure --enable-obsolete-api=no --prefix=/usr
make -j8
make install
cd ..
Explained:
--enable-obsolete-api=no ---> Disable obsolete api, which isn't needed for a modern kernel.
Libxml2 is an XML toolkit implemented in C. Needed to compile Linux-PAM.
wget https://download.gnome.org/sources/libxml2/2.14/libxml2-2.14.0.tar.xz
tar -xf libxml2-2.14.0.tar.xz
mkdir build-libxml2
cd build-libxml2
../libxml2-2.14.0/configure --prefix=/usr
make -j8
make install
ln -s libxml2.so /usr/lib/libxml2.so.2
cd ..
Explained:
ln -s libxml2.so /usr/lib/libxml2.so.2 ---> Some programs we have compiled requires us to have the lib named that way.
Pluggable Authentication Modules for Linux is a crucial system component that provides a flexible framework for applications to authenticate users.
wget https://github.com/linux-pam/linux-pam/releases/download/v1.7.1/Linux-PAM-1.7.1.tar.xz
tar -xf Linux-PAM-1.7.1.tar.xz
cd Linux-PAM-1.7.1
mkdir build
cd build
wget http://docbook.org/xml/5.0/rng/docbookxi.rng
meson setup .. --prefix=/usr -Ddocbook-rng=/LFN/Linux-PAM-1.7.1/build/docbookxi.rng
meson compile
meson install
cd ..
cd ..
Explained:
wget http://docbook.org/xml/5.0/rng/docbookxi.rng ---> we need to bypass an internal test so it doesn't fail.
meson setup .. --prefix=/usr ---> The meson equivalent to ./configure.
-Ddocbook-rng=/LFN/Linux-PAM-1.7.1/build/docbookxi.rng ---> Same as wget...
meson compile ---> The meson equivalent to make.
meson install ---> The meson equivalent to make install.
We need to do some extra setup for PAM to work:
mkdir /etc/pam.d
nano /etc/pam.d/other
Here is the content:
# Begin /etc/pam.d/other
auth required pam_unix.so nullok
account required pam_unix.so
session required pam_unix.so
password required pam_unix.so nullok
# End /etc/pam.d/other
The file sets default rules for the four main PAM management groups, each handled by the standard pam_unix.so module, which provides traditional Unix-style authentication based on files like /etc/passwd and /etc/shadow
Shadow - Utilities for managing accounts and shadow password files Shadow is a suite of tools that includes useradd, groupadd, passwd, and other essential utilities for managing user accounts.
wget https://github.com/shadow-maint/shadow/releases/download/4.18.0/shadow-4.18.0.tar.xz
tar -xf shadow-4.18.0.tar.xz
mkdir build-shadow
cd build-shadow
../shadow-4.18.0/configure --without-libbsd --prefix=/usr
make -j8
make install
cd ..
Explained:
--without-libbsd ---> Do not use the readpassphrase function from libbsd which is not in LFN. Use the internal copy instead.
Now, let's create a user and a password for us.
useradd -m -s /bin/bash your_username
passwd your_username
touch /etc/shadow
passwd root
Explained:
useradd ---> Creates a new user.
-m ---> Creates a home directory for the user at
/home/your_username. -s /bin/bash ---> Sets the default shell for this user to be bash.
passwd ---> Allows you to set a password for the new user and root (might be useful).
touch /etc/shadow ---> Needed to change root password
Sudo allows a permitted user to execute a command as the superuser or another user, as specified by the security policy.
wget https://www.sudo.ws/dist/sudo-1.9.17.tar.gz
tar -xf sudo-1.9.17.tar.gz
mkdir build-sudo
cd build-sudo
../sudo-1.9.17/configure --with-editor=/usr/bin/nano --prefix=/usr
make -j8
make install
cd ..
Explained:
--with-editor=/usr/bin/nano ---> Set the default text editor as nano (for visudo).
To allow our new user to use sudo, we need to edit the sudoers file. The visudo command is the recommended way to do this, as it prevents syntax errors.
visudo
Uncomment the following line at end of file.
%wheel ALL=(ALL:ALL) ALL
Now lets add our user to wheel group to have access to sudo.
groupadd wheel
usermod -aG wheel your_username
Let's modify our init script to log in as our new user automatically.
nano /sbin/init
New content:
#!/bin/bash
mount -t proc none /proc
mount -t sysfs none /sys
mkdir /dev/pts
mount -t devpts devpts /dev/pts
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
export CC=/usr/bin/gcc
export GCC_EXEC_PREFIX=/usr/libexec/gcc/
export LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/15.1.0/
ip link set up eth0
ip addr add 10.0.2.15/24 dev eth0
ip route add 10.0.2.2 dev eth0
ip route add 0/0 via 10.0.2.2 dev eth0
dnsmasq -uroot
while true; do
/sbin/agetty --noclear tty1
sleep 1
done
Explained:
mkdir /dev/pts ---> Creates the mount point /dev/pts.
mount -t devpts devpts /dev/pts ---> Mounts a Unix98 Pseudo terminal (PTY). Is used by sudo.
while true; do ---> Infinite loop.
/sbin/agetty --noclear tty1 ---> agetty will connect us to a terminal (tty1) and ask for a user+password. Once entered it will issues /bin/login to the user we selected letting us control of the terminal.
sleep 1 ---> Sleep (wait) for 1 second.
done ---> End to our loop.
This allows us to leave our session and enter another without kernel panic. you can do that by doing (CTRL+D)
/tmp needs to have specific permissions:
chmod 1777 /tmp
Explained:
chmod ---> Used to change the permission of a file/dir.
1777 ---> 777 Means that everybody will be able to write to the dir. the 1 is the sticky bit that only allows the owner of the dir (root) to edit it, meaning that only root can remove /tmp.
/etc/nsswitch.conf governs where/how a program should check for a ressource.
nano /etc/nsswitch.conf
Here is the content:
passwd: files
group: files
shadow: files
hosts: files dns
networks: files
protocols: files
services: files
ethers: files
rpc: files
Sync your changes and reboot in your new user.
sync
Once reboot, we need to make a .bashrc file for our variables to be declared.
nano .bashrc
Here is the content:
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
export CC=/usr/bin/gcc
export GCC_EXEC_PREFIX=/usr/libexec/gcc/
export LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/15.1.0/
alias sudo='sudo -S'
Explained:
alias sudo='sudo -S' ---> When we do sudo it will instead use sudo -S. This is necessary as we need to get the password from standard input.
We also need to create .bash_profile:
nano .bash_profile
Here is the content:
if [[ $- == *i* && -f ~/.bashrc ]]; then
. ~/.bashrc
fi
Explained:
If the shell is interactive and .bashrc exists, get the aliases and functions.
Sync your changes and reboot.
sync
You should be able to log yourself in as your user or root with a working sudo.
We have meson, lets get yet another build system script generator.
wget https://github.com/Kitware/CMake/releases/download/v4.1.0/cmake-4.1.0.tar.gz
tar -xf cmake-4.1.0.tar.gz
mkdir build-cmake
cd build-cmake
../cmake-4.1.0/configure --prefix=/usr
make -j8
sudo make install
cd ..
Allows to create makefiles.
wget https://ftp.gnu.org/gnu/autoconf/autoconf-2.72.tar.xz
tar -xf autoconf-2.72.tar.xz
mkdir build-autoconf
cd build-autoconf
../autoconf-2.72/configure --prefix=/usr
make -j8
sudo make install
cd ..
Used to download everything... and Git. If you have a program, it will most likely use curl to download things.
wget https://github.com/curl/curl/releases/download/curl-8_15_0/curl-8.15.0.tar.xz
tar -xf curl-8.15.0.tar.xz
mkdir build-curl
cd build-curl
../curl-8.15.0/configure --with-openssl --without-libpsl --prefix=/usr
make -j8
sudo make install
cd ..
Explained:
--with-openssl ---> Using OpenSSL as the SSL provider.
--without-libpsl ---> We don't have libpsl. Lets disable it.
Git, we all know what it is by now.
wget https://github.com/git/git/archive/refs/tags/v2.50.1.tar.gz
mv v2.50.1.tar.gz git-v2.50.1.tar.gz
tar -xf git-v2.50.1.tar.gz
cd git-2.50.1
make configure
./configure --prefix=/usr
make -j8
sudo make install
cd ..
Explained:
make configure ---> Will allow up to generate a configure script.
./configure --prefix=/usr ---> git is special as the configure script cannot be used outside of its directory.
It's time to move beyond the console and lay the groundwork for a graphical user interface with the X Window System (Xorg).
We will now be expecting to use the new user (in /home/your_user) we have created, do not run everything as root.
The Xorg server is the core of the X Window System, providing the basic framework for a GUI environment. Installing it involves compiling the server itself and several required libraries. This is a significant step and will involve compiling multiple packages.
Allows to render fonts.
wget https://download.savannah.gnu.org/releases/freetype/freetype-2.13.3.tar.xz
tar -xf freetype-2.13.3.tar.xz
mkdir build-freetype
cd build-freetype
../freetype-2.13.3/configure --prefix=/usr
make -j8
sudo make install
cd ..
GNU gperf is a perfect hash function generator. Needed by Fontconfig.
wget http://ftp.gnu.org/pub/gnu/gperf/gperf-3.3.tar.gz
tar -xf gperf-3.3.tar.gz
mkdir build-gperf
cd build-gperf
../gperf-3.3/configure --prefix=/usr
make -j8
sudo make install
cd ..
Fontconfig is a library for configuring and customizing font access.
wget https://www.freedesktop.org/software/fontconfig/release/fontconfig-2.16.0.tar.xz
tar -xf fontconfig-2.16.0.tar.xz
mkdir build-fontconfig
cd build-fontconfig
../fontconfig-2.16.0/configure --enable-libxml2 --prefix=/usr
make -j8
sudo make install
cd ..
Explained:
--enable-libxml2 ---> Fontconfig need an xml parser, the default is expat but we already have libxml2.
Contains the headers needed by other xorg component.
wget https://www.x.org/releases/individual/proto/xorgproto-2024.1.tar.xz
tar -xf xorgproto-2024.1.tar.xz
mkdir build-xorgproto
cd build-xorgproto
../xorgproto-2024.1/configure --prefix=/usr
make -j8
sudo make install
cd ..
wget https://www.x.org/archive/individual/lib/libXau-1.0.12.tar.gz
tar -xf libXau-1.0.12.tar.gz
mkdir build-libxau
cd build-libxau
../libXau-1.0.12/configure --prefix=/usr
make -j8
sudo make install
cd ..
Explained:
wget ... ---> You can write the start of a command and do PAGE_UP for it to autocomplete the last command you have used, this can be very useful.
The X protocol C-language Binding (XCB). Allows the client side to be implemented. We will need to install the xcb-proto then libxcb.
wget https://xcb.freedesktop.org/dist/xcb-proto-1.17.0.tar.xz
tar -xf xcb-proto-1.17.0.tar.xz
mkdir build-xcb-proto
cd build-xcb-proto
../xcb-proto-1.17.0/configure --prefix=/usr
make -j8
sudo make install
cd ..
wget https://xcb.freedesktop.org/dist/libxcb-1.17.0.tar.xz
tar -xf libxcb-1.17.0.tar.xz
mkdir build-libxcb
cd build-libxcb
../libxcb-1.17.0/configure --prefix=/usr
make -j8
sudo make install
cd ..
X Transport Interface. API that govern all Xorg component.
wget https://www.x.org/releases/individual/lib/xtrans-1.6.0.tar.xz
tar -xf xtrans-1.6.0.tar.xz
mkdir build-xtrans
cd build-xtrans
../xtrans-1.6.0/configure --prefix=/usr
make -j8
sudo make install
cd ..
Core X11 Library.
wget https://www.x.org/releases/individual/lib/libX11-1.8.12.tar.xz
tar -xf libX11-1.8.12.tar.xz
mkdir build-libX11
cd build-libX11
../libX11-1.8.12/configure --prefix=/usr
make -j8
sudo make install
cd ..
libxkbfile is used by the X servers and utilities to parse the XKB configuration data files.
wget https://www.x.org/releases/individual/lib/libxkbfile-1.1.3.tar.xz
tar -xf libxkbfile-1.1.3.tar.xz
mkdir build-libxkb
cd build-libxkb
../libxkbfile-1.1.3/configure --prefix=/usr
make -j8
sudo make install
cd ..
X Keyboard Extension.
wget https://www.x.org/releases/individual/app/xkbcomp-1.4.7.tar.xz
tar -xf xkbcomp-1.4.7.tar.xz
mkdir build-xkbcomp
cd build-xkbcomp
../xkbcomp-1.4.7/configure --prefix=/usr
make -j8
sudo make install
cd ..
Pixman is a low-level software library for pixel manipulation, providing features such as image compositing and trapezoid rasterization.
wget https://www.x.org/releases/individual/lib/pixman-0.46.4.tar.xz
tar -xf pixman-0.46.4.tar.xz
cd pixman-0.46.4
mkdir build
cd build
meson setup .. --prefix=/usr
meson compile
sudo meson install
cd ..
cd ..
libdrm is a userspace library for accessing the DRM(Direct Rendering Manager). Made by Mesa.
wget https://dri.freedesktop.org/libdrm/libdrm-2.4.125.tar.xz
tar -xf libdrm-2.4.125.tar.xz
cd libdrm-2.4.125
mkdir build
cd build
meson setup .. --prefix=/usr
meson compile
sudo meson install
cd ..
cd ..
GLSLang is the official reference front-end compiler and validator for the OpenGL ES, OpenGL, and Vulkan shading languages, particularly GLSL (OpenGL Shading Language). Required by Mesa.
wget https://github.com/KhronosGroup/glslang/archive/refs/tags/15.4.0.tar.gz
mv 15.4.0.tar.gz glslang-15.4.0.tar.gz
tar -xf glslang-15.4.0.tar.gz
cd glslang-15.4.0
python update_glslang_sources.py
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr
make -j8
make install
cd ..
cd ..
Explained:
cmake .. ---> Just like meson setup .. but for cmake.
-DCMAKE_INSTALL_PREFIX=/usr ---> just like --prefix=/usr but for cmake.
Mesa is the base for most graphic driver on linux.
sudo pip install packaging
sudo pip install Mako
wget https://archive.mesa3d.org/mesa-25.1.7.tar.xz
tar -xf mesa-25.1.7.tar.xz
cd mesa-25.1.7
mkdir build
cd build
meson setup .. --buildtype=release -Dplatforms=x11,wayland -Dgallium-drivers=auto -Dvulkan-drivers=auto -Dvalgrind=disabled -Dvideo-codecs=all -Dlibunwind=disabled --prefix=/usr
meson compile
sudo meson install
cd ..
cd ..
Explained:
packaging Mako ---> Dependencies to compile mesa
--buildtype=release ---> Will create an optimized version. The compiled size will be far smaller.
-Dplatforms=x11,wayland ---> Compile for both X11 and Wayland.
-Dgallium-drivers=auto ---> Compile all possible gallium (Standard API for GPU drivers) drivers.
-Dvulkan-drivers=auto ---> Compile all possible Vulkan drivers
-Dvalgrind=disabled ---> Debugging tool that we don't have.
-Dvideo-codecs=all ---> Include all codecs.
-Dlibunwind=disabled ---> We don't have Libunwind so we disable it.
The big man.
wget https://www.x.org/releases/individual/xserver/xorg-server-21.1.18.tar.xz
tar -xf xorg-server-21.1.18.tar.xz
mkdir build-xorg-server
cd build-xorg-server
../xorg-server-21.1.18/configure --prefix=/usr --enable-xorg???
make -j8
sudo make install
cd ..
Explained:
--enable-xorg ---> This enables the building of the Xorg server.
We need a driver that will connect to our graphic card.
wget https://www.x.org/releases/individual/driver/xf86-video-vesa-2.6.0.tar.xz
tar -xf xf86-video-vesa-2.6.0.tar.xz
mkdir build-xf86-video-vesa
cd build-xf86-video-vesa
../xf86-video-vesa-2.6.0/configure --prefix=/usr
make -j8
sudo make install
cd ..
wget https://www.x.org/releases/individual/app/xinit-1.4.2.tar.xz
tar -xf xinit-1.4.2.tar.xz
mkdir build-xinit
cd build-xinit
../xinit-1.4.2/configure --prefix=/usr
make -j8
sudo make install
cd ..
Now, to start our graphical environment, we will use the startx command. Let's create a basic .xinitrc file in our user's home directory.
nano ~/.xinitrc
Add the following content:
#!/bin/bash
xterm
Make it executable:
chmod +x ~/.xinitrc
After a reboot, you can try running startx. You should see a blank screen with a single xterm window. Congratulations, you have a graphical environment! To exit, type exit in the xterm window.
With Xorg installed, we can now build a basic but functional desktop environment. We'll install a tiling window manager, a terminal emulator, and an application launcher.
i3 - a tiling window manager i3 is a popular, lightweight, and highly configurable tiling window manager.
# First, we need some dependencies for i3
wget https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz
wget https://github.com/yshui/picom/archive/refs/tags/v9.1.tar.gz
mv v9.1.tar.gz picom-9.1.tar.gz
wget https://github.com/i3/i3/archive/refs/tags/4.23.tar.gz
mv 4.23.tar.gz i3-4.23.tar.gz
# libevent
tar -xf libevent-2.1.12-stable.tar.gz
mkdir build-libevent
cd build-libevent
../libevent-2.1.12-stable/configure --prefix=/usr
make -j8
sudo make install
cd ..
# picom (a compositor for transparency and effects) .... nnnaaaahhh
tar -xf picom-9.1.tar.gz
cd picom-9.1
# Picom uses meson, so we need that first
pip install meson
meson setup build --prefix=/usr
ninja -C build
sudo ninja -C build install
cd ..
# i3
tar -xf i3-4.23.tar.gz
cd i3-4.23
mkdir build
cd build
meson --prefix=/usr ..
ninja
sudo ninja install
cd ../..
dmenu - dynamic menu dmenu is a fast and lightweight dynamic menu for X, often used with i3 to launch applications.
wget https://dl.suckless.org/tools/dmenu-5.2.tar.gz
tar -xf dmenu-5.2.tar.gz
cd dmenu-5.2
make
sudo make install
cd ..
Now, let's update our ~/.xinitrc to start i3.
nano ~/.xinitrc
Replace the content with:
#!/bin/bash
exec i3
After a reboot and running startx, you will be greeted with the i3 initial configuration dialog. You can accept the defaults. You now have a tiling window manager! You can open a terminal by pressing Mod+Enter (the Mod key is usually the Windows key). You can launch applications by pressing Mod+d to open dmenu.