Building a Linux distro from scratch has been one of the most tasking projects I've attempted. There are two phases: the frustration phase, and the tedious phase. Bootstrapping it is an incredibly frustrating process - I restarted from scratch 5 times before any attempt ever got to the tedious phase. The tedious phase never ends. You have to make hundreds of packages to get to a usable desktop system. I've made 407 packages and I still don't have a desktop to show for it (I'm hoping to get sway working tomorrow, I think I have about 30 packages left).
Still, I've finally gotten to a somewhat practical self-hosting system. My laptop runs it on the metal and all of the infrastructure (website, bugzilla, git hosting, mirrors) is on a server running my distro too. It's taken almost a year of frustration, but it's very rewarding.
I'm just curious: In what way is it rewarding? Just for educational purpose? Or anything else? Or is it just a hobby? I mean, you are probably investing a lot of time into this. This time you could spend on other things instead.
I see the educational purpose. Although you probably get similar experience/understanding/education if you use something like Gentoo and you would have to invest much less time because all the nasty corner cases are already taken care of.
It's rewarding because I finally have a Linux distro that's designed the way I want. I started making this because I wasn't satisfied with anyone else's offerings.
Can you say what is different in your distro than in any other distro? And you think that no other distro could have been extended/fixed to get what you want? Do you consider that this is useful for anyone else? In that case, you really should publish your work and write about it.
> invest much less time because all the nasty corner cases are already taken care of
I'm certain (because I learned with Slackware before there was Gentoo) that those nasty corner cases are actually where the rewarding part is. The progression of distros for me was, ZipSlack (fit on a 100MB Zip Disk), Red Hat, Mandrake, then back to Slackware once I actually had a real decent internet connection, and I can say for sure that dealing with those naturally occurring corner cases was a lot more fun than dealing with those "it's packaged, but for a different version of RedHat, so it won't work on your Mandrake install"
Eventually I switched to Debian and was able to just stop caring about that stuff for the most part until something was too fresh to find a package.
(I'd run Unstable, and everything was either packaged already or the vast majority of the dependencies were already packaged.)
I don't know if there was any tangible reward from learning to build Enlightenment, and a full stack of graphical libraries underneath, but at least I did get Enlightenment from it. (!!)
Good for you for sticking with it. I've started in that direction a few times, but it really is amazing just how necessary all those hacky distro-maintained build scripts and patches are. It's tempting to think that they're just tweaking things to fit their conventions and handling edge cases, but they're often just getting it to not explode by default.
I've made several compromises so far. I've been making a note of them with the expectation (or hope) that I'll get to them, or a bright eyed new contributor might (I have some of those :D).
Or even a blog post or something talking about it. I understand that sharing your experiences with the rest of the world might not be top priority while you're hammering away at sorting out these packages so I don't expect you to stop what you're doing purely to satisfy us on HN! But if you've already got something I'd love to see it :-)
Amazing - I had no idea you were the person behind KnightOS, I've previously read a few of your posts and thoroughly enjoyed them (the one about the US election particularly hit home). Thanks so much
I really wondered what's so special about this project that aims to achieve what probably more projects aimed to achieved than there are lines of code in the kernel.
It's not the goal, it's not the OS. But the documentation is a sight to behold! Very clear, detailed, interesting writing style, and it puts together quite a few frustrating topics in a simple, structured matter. Wow and kudos! Keep on writing docs, please!
Your kind words are much appreciated. Many people seem to indeed be missing the point. I wasn't trying to create a new distro, I'm just trying to teach people in a way so that it would just take a few hours of your time.
Both this and LFS reminds me that Linux makes sense until you get the DEs involved. At that point shit just sprawls all over the place as there are no longer any notion of layers.
Back in 2002 I ran LFS for a semester and a half. Then I got tired of saving all my ./configure flags and switch to Redhat and gained a respect for package management. :-P Eventually I started using Gentoo.
Still, I'm really glad I built and ran an LFS for nearly a year. It helped me build a really in-dept knowledge of Linux that's helped me as I later moved into embedded development.
Today I still use Gentoo (which feels like LFS with package management) and Void and would recommend either for Linux devs.
I did exactly the same in 2005. I even wrote my own init scripts, so I really understood a lot what's going on at startup time. Linux was quite simple at that time. I could write my own init, if I wanted. Unfortunately now this knowledge is obsolete. Systemd is a complex beast which uses a lot of arcane techniques, I'm hardly understanding it. chroot was a really simple concept, but nowadays people use containers, and they are much more complex than chroot. Logging is complicated. In the past I could try to load and then mount partition from livecd or another OS and read logs, now I don't know how to do it. Init scripts were simple bash scripts. They were verbose, may be buggy, but after all they were just bash scripts and every Linux user knows bash, so every Linux user could write or modify init script. Now systemd uses its own format, I'm spending hours every time I need to write new service or timer for RedHat. SELinux is just so complex. I know about UNIX permissions. They are so simple and elegant. I'm using them everywhere, when I need security. I could explain them in 2 minutes. SELinux has books. I have those books in bookmarks, may be I'll read them sometimes. But until then, I just use copy-pasta from internets to solve my tasks, like allow ssh to listen at non-standard port. I don't think that it's good, that I have to run some random strings on my computer from root without fully understanding what they are doing. SELinux has binary compiled configurations and some encrypted logs for tools to decipher them, what a mess! Sometimes I just disable it to get things done.
Don't get me wrong. I think that Linux looks more professional, more robust, especially for system administrators, who can devote their lives to learn about those systems. But for hobbyists, who doesn't have a lot of time, Linux became much less transparent.
May be if I didn't have that prior knowledge, it would be easier to learn those things from scratch. But I doubt it.
I've had to learn apparmour, which isn't too bad and a lot easier than SELinux (maybe not as powerful).
Systemd is a religious argument at this point, but if you want simplicity check out Void. It uses runit and I love it. It's incredibly simple. Startup files are often less than 4 lines. I don't really like systemd either, but I will admit, as a package maintainer, it does make packaging a lot easier/universal. It'd be nice if there were drop in replacements for systemd that uses the target files for services and trashed everything else. UselessD was a cool project that attempted it, but it became to difficult to maintain. :(
I currently work at a docker shop and I will say, containers are pretty nice. They're better isolated chroots with a lot of cool versioning support. There are pluses and minuses, but overall, I think docker is a nice evolution from chroots. Now all the eco-systems around docker: kubernets, DC/OS/marathon, nomad .. all totally different, proprietary and over-complicated.
The nosh toolset can of course import systemd socket, service, and target units into its native daemontools-encore-superset form; which can then be used on a BSD, on things like UbuntuBSD or Debian kFreeBSD, or (in theory) on Debian Hurd; as well as on Linux operating systems.
What is that legal term again, "Different in degree, not kind"?
The more i find out about systemd and surrounding projects, the more i feel they should stop branding anything using it as Linux.
It seems to be heading into Android territory, where it may have the kernel in common with classic (GNU?) Linux, but beyond that it is a whole new beast.
Use funding to keep keep the 'cool things' purposefully incompatible, GPL'ed, and controlled via influence by well-staffed and funded corporate sponsors..
This keeps the IT people from getting too powerful w/r/t the managers...
Maybe you should give FreeBSD a go. I've migrated to it from GNU/Linux for my everyday dev laptop, and haven't looked back. It's a lot like Linux used to be.
Same here. After 20 years of using Linux I'm again a Linux newbie. I have given up, I just install Ubuntu. It's true that Linux works better than before but I feel it's just because there is so much more muscle behind not because of better design. I'm getting old I suppose.
I am of two minds about package managers after having used Gobolinux for some years.
Because once i got familiar with Gobolinux and how it handles things, i can't shake the feel that most package managers introduce as many problems as they solve.
The biggest is that while _nix have sonames to handle multiple lib versions installed at the same time, most package managers balk at there being more than one package of a given name installed at the same time (Debian apparently works around this by including soname-like info in the package names).
They balk because there's usually only one major version of a package that's still receiving security updates upstream.
Thus, a package being able to depend on an old version of another package, is basically morally equivalent to depending on an unmaintained package. Which, if the packge author is gonna do that, they might as well just vendor the dependency.
The "version numbers in package names" thing is basically to indicate exceptions to this: cases where there are secondary living packages, with either upstream-tracking or distro-backported security updates.
Ideally, there'd be a way to do the same thing just using pure semver heuristics—but any major-version release-stream can just peter out at any time and dependent packages will be none the wiser. So you sort of need your package manager's notion of a package's major-version release streams to be something equivalent to their own "packages" anyway, so that you can have somewhere to put package-alike metadata, e.g. "depending on this is deprecated", when the release-stream for said version gets EOLed upstream.
> If upstream wants people to stick with the latest and "greatest" then they need to stop breaking APIs and ABIs at the drop of a hat.
"Upstream" usually doesn't care about that. Upstreams—developers who write things that get packaged—almost always have a philosophy of "eh, just vendor it." Which is where things like Docker images come from.
Instead, it's the distros that care about being able to update a package's deps out from under it; because this lets them have one copy of e.g. OpenSSL on the system and fix everything that depends on that package, whenever there's a new vuln discovered in it, by just updating that package. They're the ones trying to eat a cake and have it—even as the upstream devs take the view that you should just eat their ingredients directly and never bother baking a cake in the first place. :)
---
As a tangent: I'm almost beginning to agree with the Golang philosophy: a "package" is its ABI. New ABI = new package with a separate identifier, that everyone has to explicitly update to.
Doing this has two incentive-system effects:
1. It makes package-authors much more reluctant to make breaking changes to their ABIs, which in turn encourages them to think through their ABI before their initial release;
2. The semantics of a semver major version are transferred entirely to the package identifier itself. Almost nobody uses semver major-versions correctly; but if you collapse those semantics up a level, the package-manager can enforce the semantics. So you, as a downstream consumer, can actually be sure there are no breaking ABI changes as long as you're tracking the same package identifier.
"They balk because there's usually only one major version of a package that's still receiving security updates upstream."
This is not entirely true, because this one version usually can be configured to produce a lot of slightly different versions of that one version. For example, even simply swapping glibc with musl gets you two different versions of the same version of every package. There are a lot more issues though, nix's paper explains some.
Package management is a huge mess at this point, docker even managed to capitalize on that.
Ah, sure, I'm sort of treating the concept of "package" as being equivalent to "ports-system build formula" here. In pretty much all modern package managers, `pkgmgr install foo` can have any of N prebuilt binary versions of a package like foo-1.0.3 laying around on the package repo server, one of which might be used to satisfy the formula if they match the installation options you passed.
The non-BSD-inspired distros, rather than having a separate concept of build artifacts, tend to put the options to match in the "build" part of a package's version string—making them technically separate releases. But it does the same thing in the end.
But that's a separate thing from a distro keeping multiple forks of the package itself, with separate release cadences—which mostly only happens as a way to keep individual efforts to create releases from upstream major-versions, or backport to dead upstream major-versions, distinct from one-another.
Package managers are like vehicle transmissions. They are designed a certain way, and if you misuse them, they break. Some are more or less annoying, depending on the perspective of the user and how they use it.
Most package managers are some form of automatic transmission. Some provide paddle shifting, some are CVT, some have two clutches and 9 gears, and some just basic four speed boxes of swirling fluid. Almost all of them are a nightmare for a regular person to maintain.
That's part of why I use Slackware, which uses Pkgtool. It doesn't track dependencies. It doesn't resolve conflicts. It doesn't roll back changes. It doesn't do much of anything. And it's absolutely wonderful. The only time it ever gets in your way is if you intentionally break it. Of course, i'm on the extreme end of a "power user", but the damn thing is so simple that even a total newbie can grok how it works and the potential for catastrophe if they misuse it (like a manual in a car).
Of the ~8 package managers I've used, RPM is the closest to a simple, coherent, complete system. It's still not great, though.
Exherbo and Gentoo both solve this problem with something called "slots". Namely, you can install various slots of a package, you can depend on a slot, etc.
In Exherbo you can tell optionally one package to runtime-depend on the slot of another package that you built it with.
I love slots. The Gentoo eselect system is way ahead of etc-alternatives or some of the other package select tools I've seen. Slotted binaries are easier though; slotted libraries can get complicated and get into some crazy dependency hell.
One of the nice things about Exherbos take on slots is that you won't get breakage with library upgrades because you won't be able to uninstall the old version until all packages declared to build with that ABI (or more specifically that slot was installed and built against) are rebuilt against the new library.
ABI breakages are far less painful than on gentoo.
Have you tried out Exherbo? In many ways it is an improvement over Gentoo (disclaimer: I used to be a Gentoo developer ~10 years ago, still am an Exherbo dev). It might feel familiar because the package manager, paludis, also works as a package manager for Gentoo.
But the package format has numerous additional features and the distribution does as well.
I ran LFS too, probably around the same time, ran it until I moved to Debian of all things, probably for a few years even.
I remember at the time writing a series of very intricate build scripts to download and update the kernel on my desktop with every single release, specifically with the ac-sources patches that Alan Cox was maintaining at the time. Probably one of the first non-trivial programming projects I did.
I'm running i3, polybar, connman and rofi as my Linux desktop environment and its very productive, configurable, lightweight and reliable. My only worry is that one day I'll be forced to move to something akin to what you describe. I blame object-oriented programmers.
Its about how you have the kernel, the userland and then whatever you want to run on top, with the upper layers not caring much about whats is beyond its nearest neighbors.
Thus you can switch out what makes up the various layers as you see fit.
The problem is described perfectly with the name: desktop environment.
The very goal of a desktop environment is to create an entire environment, rather than using the one that is already there.
Desktop environments like GNOME and MADE have so many worthless parts that are tightly coupled dependencies, they end up becoming the same bloated mess that Windows and OS X are.
If a desktop environment focused on creating separate packages that played well with the underlying system, they would not have this problem.
A similar process is building a custom kernel and rootfs for an ARM device such as the beaglebone. Olimex actually has a good tutorial for their device: https://www.olimex.com/wiki/AM335x
This is only slightly more complicated due to the need to cross-build but I found it fairly easy with qemu-static-arm and prebuilt cross toolchain packages for Ubuntu/ Debian.
The benefit is that you can develop for a target device that is not your PC, so no worry about messing up the bootloader and leaving your PC in a state where you need a recovery CD to fix it and boot. Just get a USB-serial cable :)
You can also try buildroot or yocto, although I had no interest in building every package manually versus relying on Debian's repos.
Actually LFS teaches you about the whole GNU Userland, getting a kernel up and running with busybox is much easier. This project does just that - teaching you the bare minimum.
The embedded version of CLFS (Cross-Compiled Linux From Scratch) covers building a musl + busybox system: http://clfs.org/view/clfs-embedded/x86/
But the more resources available on this kind of thing the better IMHO, there's not really a one size fits all :)
It's supposed to be a lot shorter and simpler. Which means many important things were left out for the sake of brevity. I also think LFS doesn't always explain why we are doing certain things a certain way or how things work. Sure you get a working system but it's often assumed you know why it's working. I'm not sure if I did a better job though.
I see this project as the next logical step beyond LFS. LFS will help you get one up and running from start to finish, but once you do that, you might want to try it a bit more free-form. That's where this project seems to fit in.
Certainly you mean the other way around? This project gets you busybox and a kernel, which barely qualifies as "up and running from start to finish", whereas following this doesn't even get you a compiler in the target system.
I have a question related to this article, though not directly. If building completely from scratch turns out too cumbersome and time-consuming, what would be the easiest way of building a minimal, fast starting distro with graphical user interface and networking whose only purpose is to run one application on x86 hardware in kiosk mode?
NixOS is awesome for stuff like this. Very easy to define your own "base image" and layer whatever you want on top of it. Binary packages by default, but you can override the compilation flags for any any package, Gentoo-style. Configuration files are also packages, which frees you from the cruft that systems like Chef or Puppet tend to accumulate.
Oh, and NixOps is awesome for managing multiple machines. And it can automagically set up VMs corresponding to your production network.
SUSE Studio has a nice GUI and is easy to get started with, but AFAIK it doesn't have a nice story for configuration management, or managing the systems after they've been deployed.
Sure there is LFS. I suppose arch could give you a fairly minimal installation. Really when you think of it harddisc usage is hardly the problem here so even though it might seem silly having a 10GB installation, it will cost you nothing and save you time.
But if you want it quick install debian or arch or whatever and simply start only X11 and whatever application you want to run. If there is no window manager or an extremely limited mode, you got kiosk mode.
Following this guide will get you something very close to a base Alpine Linuxwith busybox. Alpine is fairly minimal out of the box and even eschews grub for syslinux.
The upside with Alpine is if you need features and packages they are an install away. But if the purpose is to learn about compiling the kernel and how the system initalizes this is a decent start.
Huge fang on Linux From Scratch myself, after reading this I wonder if someone has tried the same with FreeBSD! Or the Darwin sources released for OSX (.. not talking about dormant PureDarwin project)
This is awesome. I've been building almost the exact same project, along almost the same timeline (based on the commit history). Mostly an excuse to learn more advanced Bash, and Linux Internals/Features I've never had a good excuse to explore. Gonna release next week. Hope I get as warm a reception. Kudos on an awesome project!
I am following this guide to build a kernel. But it seems like that instead of getting the headers from the kernel source they are using a github repository which only contains the headers to save downloading time. All fine and dandy if the latest commit to this repo wasn't from 3 years ago!!
This is an awesome write-up. did not know losetup can do what kpartx does now with the option -P, I did similar things in the past but this is a good update for me.
LFS is infinitely more involved and am not sure for good reasons. I don't like to say it because it's someone else project but I feel important parts are missing, format is wrong, and without BLFS the goal is only half realized.
Still, I've finally gotten to a somewhat practical self-hosting system. My laptop runs it on the metal and all of the infrastructure (website, bugzilla, git hosting, mirrors) is on a server running my distro too. It's taken almost a year of frustration, but it's very rewarding.