Hacker News new | past | comments | ask | show | jobs | submit login
Oasis: a small statically-linked Linux system (github.com/oasislinux)
252 points by varbhat 52 days ago | hide | past | favorite | 160 comments



Would be cool to get a bit of a "why this matters" intro on repos like this. I clicked through the details, but left wondering if I have any potential use for this. Can I compile this onto a USB stick and use it as a throw-away boot Linux for maintenance tasks? Can I cross-compile this for embedded devices? What is the statically-linked advantage here? Not trying to minimize the effort, I would actually love to see more such things, but felt a bit left out as I couldn't figure out why exactly it exists.


It seems like your definition of "why this matters" is "how can this pick me up as a user" but for some projects "why this matters" is "to see if this works as well as we think it could" or similar more abstract goals. If the goal of the project is to try to be as small and simple of a Linux distro as possible by trying a different take and seeing how it pans out (which it seems like this is) then it's accomplishing it's goals whether or not it tells you how you could use such a distro were it to pan out.


I don't think you're disagreeing with each other - a bit of intro text especially helps if the project is abstract.


The description of "I built this to try something cool, but maybe someone could find a use for it!" is just fine. But it would be great to know. Likewise: "We built at company Y this for use case x and intend to support it" also tells me what is going on.


As someone who uses linux casually, I often experience pain when I download a program, try to run it, and it fails because some dependency is not installed or is not the right version. So you try to figure out how to install it and it in turn needs a couple of things.

All of this works fine if whatever package manager your distro uses has the program you want, but the package managers don't have evertying!

So I'd love an ecosystem where things tend to be statically linked unless there is a good reason not to.


> So I'd love an ecosystem where things tend to be statically linked unless there is a good reason not to.

Well, every time there is a bug fix in one of your dependencies you/your distribution would have to recompile everything that depends on it. Which will use quite some resources.

So to actually use this you would have to reinstall (nearly) all programs once a week or so (no matter if source or binary distribution). While that is quite possible with modern internet connections, I am not sure if it solves all the problems you might think it solves. After all, even nowadays application authors could provide static packages, but many don't do it.

After using quite a few distributions over the years, I like Arch Linux best at the moment, as the combination of binary distribution, with frequent updates, and the source based AUR, with the very large amount of packages, suits my needs very good.


> every time there is a bug fix in one of your dependencies you/your distribution would have to recompile everything that depends on it

Back in the dark ages, some mainframe operating systems like MVS normally stored executables as object files, and would link the program every time you executed it.

Has the on-disk space savings and updateable libraries of dynamic linking, without most of the complexity. I believe the original motivation was to allow an executable to run at an arbitrary address on systems without virtual memory though.


It was for personal operating systems (and ancient mainframes) that had a multitasking OS but without any MMU support in the hardware. Relocatable executables were required so that you could load multiple executables at different addresses within the single address space of the memory. This is now called Position Independent Code[1].

Modern MMUs meant that the OS would define specific addresses for use by a program, so for example all ELF programs in a distribution would have the same starting address in memory hard coded into the executable (one virtual address within a process is mapped to a different physical memory address for each process by the MMU).

[1] https://en.wikipedia.org/wiki/Position-independent_code


There’s a difference. Position independent means you can move the executable anywhere and run it.

Relocatable means the binary has enough information to fix any absolute addresses in the code after that move. That’s extra work, and means you cannot have the same physical memory mapped to different virtual addresses in different processes, and that you have to either swap out the relocated memory, or repeat the relocation when you swap in the code again (I’m not aware of any OS doing the latter, and don’t see a nice way to do it, but it is a possibility).

https://en.wikipedia.org/wiki/Position-independent_code:

“In computing, position-independent code[1] (PIC[1]) or position-independent executable (PIE)[2] is a body of machine code that, being placed somewhere in the primary memory, executes properly regardless of its absolute address.”

https://en.wikipedia.org/wiki/Relocation_(computing):

“Relocation is the process of assigning load addresses for position-dependent code and data of a program and adjusting the code and data to reflect the assigned addresses.”


I would be surprised if there was not a way to take a dynamic executable, "add in" all the required libraries, and return a fat static executable


If you know of such a utility I'd like to see it, because I've looked and never found it. The closest I've seen are things like AppImage.


I have used exodus to do this in the past. https://github.com/intoli/exodus


> Exodus handles bundling all of the binary's dependencies, compiling a statically linked wrapper for the executable that invokes the relocated linker directly, and installing the bundle in ~/.exodus/ on the remote machine. You can see it in action here.

That isn't really what is being described, or at least not what I'm referring to. It's more like a self-extractor.


You are right. My mistake. I remembered it wrong.


It exists. I came across at least one such project last year, but I don't recall the name. :(


Shell scripting and ld tools should allow you to make that yourself.

EDIT: people are apparently entitled to solutions for their problems...

> Care to elaborate?

> Show us a script then! Your internet fame awaits.

I'm not interested in fame, or in reinventing the wheel.

Apparently, you are unfamiliar with this process, so TLDR: there are basically 2 approaches, in order of complexity: 1. working with ldtools or 2. running the executable to find the various parts then dumping a binary, (3 if you consider putting the libraries in a directory then run with LD_LIBRARY_PATH=/thisdir myexecutable)

Let me google some existing tools for you:

https://github.com/systems-nuts/dynamic_to_static

http://bitwagon.com/jumpstart/jumpstart.html

http://statifier.sourceforge.net/

https://www.ucc.asn.au/~dagobah/things/make-static.html

https://web.archive.org/web/20130114222319if_/http://dagobah... with patch and explanation on https://stackoverflow.com/questions/17390722/how-can-i-conve...

A better approach from 15 years ago is slinky, so that you can "update" the libraries if needed: https://www.usenix.org/legacy/publications/library/proceedin...

There's nothing fancy in there. It just requires some effort.


Care to elaborate? Because I'm not aware of any tool that could be used to combine a binary and all its .so dependencies (and all of theirs recursively) into a single statically-linked binary.


My admittedly poor understand of macOS application bundles, is that is basically how they work (modulo certain Frameworks in Library folders)


You won't have to recompile everything if you cache your build artifacts (e.g., object files); you'll only have to relink which is quite a lot better.


So long as I'm not the one building it, its fine. My internet can redownload everything. It also depends on what libraries are being used. musl does generate smaller binaries than glibc. and if you look at the massive project that is sqlite, building software should only take a couple of seconds. Of course, whether anyone actually goes to such lengths for easy compilation is another matter entirely.

https://sta.li/


Letting software have dependencies then making the user manage them in the off chance there is some bug in the foundational mostly frozen libraries should be an obviously bad decision at this point.

No other environment forces this kind of complexity on their users and almost no non-enthusiast user wants to deal with this structure.


>Well, every time there is a bug fix in one of your dependencies you/your distribution would have to recompile everything that depends on it

Well no, I could opt not to apply the bug fix if it isn't affecting me. This again is sort of serve mentality, where of course you want to get a bug fix in as quick as possible in case it is a security issue. A desktop user, maybe you don't.

>After all, even nowadays application authors could provide static packages, but many don't do it.

Right, and really what I would like is for application authors to just static link more, more often, on linux. Or at the least ship their programs with installers that apply the needed deps if they are not already there! That the OS itself is statically linked doesn't really matter, but perhaps it would inspire an ecosystem that does this.

> I like Arch Linux best at the moment

Probably suggest arch linux to someone complaining about having to track down dependencies does not make sense, since such a person is more interested in the OS just working rather than making the OS a bit of a hobby that that they want to customize.

Which, is why I mostly use windows.


> Probably suggest arch linux to someone complaining about having to track down dependencies does not make sense, since such a person is more interested in the OS just working rather than making the OS a bit of a hobby that that they want to customize.

Sure, in the beginning you have to spend some time to set it up, but due to the rolling releases it has a great longevity. And talking about application integration, I prefer the package management style (even through AUR) greatly to the chaotic download some binary and execute it way windows does it. Over time your windows always gets so messy because every device manufacturer seems to think that it is cool, to bundle his device driver with hundreds of megabytes of non-sense-ware (last weekend I installed some Logitech driver on Windows, because the default Windows driver didn't work (on Arch I didn't have to install anything extra, just saying... yes, anecdotal evidence)).


> Probably suggest arch linux to someone complaining about having to track down dependencies does not make sense, since such a person is more interested in the OS just working rather than making the OS a bit of a hobby that that they want to customize.

having used Red Hat, Mandrake, Ubuntu, Debian... Arch Linuxis by far the most "just works" distro I've used


Do you really mean Arch Linux or something based on it like Manjaro? Pretty sure Arch Linux doesn't even come with an installer.


there are plenty of installers of archlinux - I use https://anarchyinstaller.org/ for instance


But do any of those come with the ISO available at https://www.archlinux.org/download/? I don't see how you can say something "just works" if you have to go out of your way to choose an installer for it.


ArchLinux is not defined by the ArchLinux ISO ? it will be arch as long as it installs packages from the arch repos, which is what those installer do. So you just burn this iso to an usb and be happy: https://gitlab.com/anarchyinstaller/installer/-/releases


>Which, is why I mostly use windows.

Oh, Windows can have dependency hell. And even worse is when you have a WinSXS blowout and you're trying to figure out why that subdirectory is using up 80GB of space for an unknown reason.


DLLHell


> Probably suggest arch linux to someone complaining about having to track down dependencies does not make sense, since such a person is more interested in the OS just working rather than making the OS a bit of a hobby that that they want to customize.

Then recommend Manjaro, not an OS that “just” loads them down with ads, tracking, forced updates, and more unless — and to some extent still even after — they customize it.


At the risk of starting a distro war in the comments, I'll have to recommend Pop!_OS over Manjaro.

Pop has broken itself less often then Windows for me, while Manjaro has broken itself slightly more.


> Well, every time there is a bug fix in one of your dependencies you/your distribution would have to recompile everything that depends on it. Which will use quite some resources.

This is far for more clear cut. Often some dependency bugs, might not impact my program. Even worse, sometimes by fixing a bug my program does not care about, a dependency might break my program in some subtle way. The author of the program is the best qualified person to make the upgrade/not upgrade decision.


Hot take: A great tragedy of the GNU/Linux ecosystem is the fact that ABI+API is still not figured out, and the most common interface between programs is the C ABI, which is embarassingly primitive even by 80's/90's standards. Some people in the FOSS community just want to leave things as-is to hinder propiertary software, and it's the same story with device drivers. You can debate the merits rightfully so, but then there's still companies pushing out binary blobs which break every few kernel updates. As a FOSS developer it's an eternal fight between good and evil with no winner in sight, as a propiertary developer it's pain in the ass to maintain old and new software between all the permutation of Linux distros, and as a user I get to cry because of the lack of popular software and backwards compatibility. Snaps and flatpaks are an ugly hack, literal ductape around this very fundamental problem, and clearly not the solution. GNU/Linux should have adopted COM and/or an adequete proglang with stable ABI a long time ago, and should have tried to control wasted effort put into duplicate software ecosystems (KDE and Gnome).


That's a searing hot take, to be sure.

There is no alternative to the C ABI. If you look at stable ABIs in other programming languages, they're either identical to or thin shims around the C ABI! Even COM, with the caveat of calling convention on MSVC.

Regardless of ABI stability you also need software to have API stability for stable distribution. The two solutions to this problem are to statically link everything or package your shared objects with your software. Then to launch the software you need a shell script that overrides the loader search path and move on with your life.

The ultimate solution is the .app/.bundle paradigm of MacOS. Everything should copy that.

The other issues of packaging software like entitlements/capability based security and code signing are similarly orthogonal. If you're shipping big software today, it needs to have everything it needs and to ignore whatever is on the user's system unless they explicitly request an override.

The real tragedy of GNU is that the interchangeability of software was always possible, package managers just managed to make it accidental and explicit. Too many foot guns there.


> Then to launch the software you need a shell script that overrides the loader search path and move on with your life.

> The ultimate solution is the .app/.bundle paradigm of MacOS. Everything should copy that.

All ELF systems support the $ORIGIN RPATH macro. It lets you build and package an application exactly like, if not better than, you would a macOS bundle. Specifically, it let's you specify at compile time a library load path relative to the invoked binary. You'd specify it as $ORIGIN/../lib for the canonical bin/, lib/, etc layout.


Awesome tip, thanks! I didn't know this existed.


I haven't done native development professionally, but it seems to me like dynamic linking is a leftover from a time when memory and even disk space were precious, isn't it? Are the savings really still worth all the breakage? What is Docker but a way to force static linking on programs that were built for dynamic linking?


Example: GCC had been known that GNU worried to add plugin API.

https://lwn.net/Articles/301135/


Stable ABIs don't seem like a good solution though. It is preferable that the system running the code should make the decisions on how best execute it. Especially as hardware becomes more specialized and diverse. Additionally, guarantees of stability necessarily increase maintenance burdens, so they should be avoided whenever possible.

IMO, the best solution would be something like SPIR-V. That is, programs are shipped in an intermediate representation which a platform-specific compiler would reduce to the final program. That way no stable ABI is needed, there is less maintenance for distros and toolchains, and end users still get high quality binaries.

Of course there are issues with protecting the intermediate representations of programs from reverse engineering. But the combination of strong DRM with obfuscation should satisfy most software vendors. After all, most companies are comfortable shipping Java based programs.


I believe Apple sort of does this for iOS: developers submit LLVM IR to them and they compile it to send to end users


As a primarily Linux developer I'm super jealous of COM. It reminds me a lot of dbus with more legacy cruft but also a lot better designed.


As a former Windows developer, I am thankful that I never have to touch COM ever again.


Damn, guess the grass isn’t greener.


We should aim to not use Snap, please! :/


> So I'd love an ecosystem where things tend to be statically linked unless there is a good reason not to.

Me too, but I'm not sure this project brings us closer to that goal.

I don't need the base OS to be statically linked—in fact, that's where static vs dynamic linking matters least, because it all comes preinstalled. What I want is for everything else which I may want to install on top to be available as statically-linked binaries.


Check out kiss linux, another interesting project: k1ss.org/install

I'm considering trying it: having the simplest distribution baremetal, and keeping the complexity "outside" and "contained" (docker for servers, flatpack for desktops and laptops, etc.) makes sense to me


Since most common applications have moved to the web, and the biggest Linux end user deployment by far, Android, was created from fresh beginnings, the idea of the user being concerned with minutia of binaries is already far along a long road to the grave.


This right here is what's wrong with the application space. The idea that this could be true leads to terrible software design and slow, bloated applications. In the current landscape is it perfectly possible (and I'd say even usual) to do most of your work and processing on local system binaries (that aren't a browser or a browser with a different name).


It’s no one’s fault really. As long as people pirate software, it is economically Darwinian / inevitable that all commercial software will migrate to centrally controlled subscription gated servers. This includes open source software, if you correctly count how much of it is repackaged and sold to people this way.


It has nothing to do with pirating. That sort of predatory mercantile behaviour has happened basically ever since humanity invented money. It happens because unscrupulous people are allowed more power than they should have. Stop blaming everyone else for their bad decisions.


Eh, but if that was completely true I'd be using ChromeOS, or something similar. Perhaps some day I will—but as of 2020, I still find myself popping into a lot of native apps day-to-day.


99% of the apps I use aren't on the web at all


> Since most common applications have moved to the web

No, just please no!


This is true, though perhaps there is some performance benefit.


If you need exotic libraries, you install them into /usr/local/lib with GNU Stow for secondary package management. Then point your loader there first when starting programs that depend on them. Your distro stays pristine and the program runs so everything is good.


> So I'd love an ecosystem where things tend to be statically linked unless there is a good reason not to.

Security: a good distro provides security updates for shared libraries. With static linking it becomes too burdensome.


Actually that's one problem I've never had with Linux. Even using stuff that isn't in the default package manager seems to just work.


It's a joy to deploy. I loved the IBM Blue Gene/L. Like AWS Lambda, except instead of a zip you deployed a static linked binary.


Looks like the readme was updated 3 hours after your message, and does a great job of explaining the ideas/advantages.


This seems to "statically link" binaries in the sense that each program it ships with is a standalone binary. Does anyone know whether it's possible to truly statically link an entire Linux install, in the sense that the whole system is a single statically linked file including the kernel, display manager, web browser, etc so that link-time optimization can deduplicate code across the entire system?


Yes, I know that it's NOT possible. Anything that uses the same libraries, e.g. GTK+, will end up calling gtk_init() multiple times. Callback functions with the same names will collide at link-time.

Despite the madness of the code that would be generated if the compiler allowed it, since it doesn't, you can expect a list of linker errors so long, that you can go to bed and wake up in the morning and it's still spewing to stderr.


It could be done. Obviously you would only run one of the main functions (via a wrapper) per process invocation and you would need to rename conflicting global symbols at some point before the link step, but this is basically how tools like busybox work. If the application uses global constructors or init functions then those would require special handling since they bypass main—C tends to work better than C++ in this regard. Applying LTO to the resulting code for inter-application optimization would be an interesting twist.


It could be done if you heavily patched everything you linked in, or developed an entirely new compiler, or both, but as-is, no.


Apart from the global initializers, everything necessary could be accomplished with a reasonable-length shell script applying "objcopy --redefine-syms" to the object files between the compilation and linking steps to add application-specific prefixes to all external symbols defined in any of the application's object files, without any changes to the source code or the compiler. I'm not saying it would be trivial, but it wouldn't require writing an entirely new compiler.

Source: I've implemented programs similar to busybox before by merging programs originally intended to be compiled separately, albeit on a smaller scale than an entire Linux distribution.


You're asking for something similar to a Lisp machine, or perhaps even an Amiga. Everything runs in the same address space and has access to all available library functions; "processes", such as they are, are in no way isolated.


I am not sure what you mean.

The Linux kernel has dynamically loaded modules but you can build modules as statically part of the kernel. 'Y' instead of 'M' in the config.

It doesn't make sense to "statically link" a kernel to a program, or multiple programs together, which I read your comment to suggest. That would be a different thing than the term "statically link" refers to.


I think they might be referring to a unikernel.

https://en.m.wikipedia.org/wiki/Unikernel

In userspace, you can do what busybox does and link a bunch of programs together with a single main function that decides which program to actually run.


> It doesn't make sense to "statically link" a kernel to a program

That's kinda what a Unikernel is.


This is kind of the idea behind unikernels. There are experimental Linux-based unikernels, but the more mature unikernels are custom.


I don't know if this is what you are thinking of, but there is this concept in embedded systems sometimes refereed to as library operating systems [1]. My understanding is that in this model the operating system is implemented as a library and you your system would consider of one application that uses the os library to do tasks usually handled by the operating system.

[1]: https://en.wikipedia.org/wiki/Operating_system#Library


> Does anyone know whether it's possible to truly statically link an entire Linux install

I think if you give busybox enough time, it might happen.

That's if systemd doesn't get there first, of course...


The answer is probably downvoted because of the systemd comment but I think that busybox is statically linkable, is it not ?


It absolutely is; busybox is quite happy to be built into a single binary with no outside dependencies. Worked example: https://hub.docker.com/_/busybox


Does statically linking everything not lead to much higher disk usage, espcially when you have thousands of binaries? Drew Devault has an analysis[0] that appears to claim otherwise.

[0] https://drewdevault.com/dynlib.html


It might have been a concern long ago when space was a premium, but these days in the world of >=1TB drives you could probably build your entire software library in the most horrifying, space inefficient way, and it would still be completely and utterly dwarfed by the user's media library. Excepting games, I would bet most anyone's software library would likely comfortably fit under 128 GB. The photos, games, music, and video would be what necessitates more. And I suspect even then, a lot of people don't bother to store these things locally besides the games and photos.


The majority of a game's data usage comes from assets. The binary is a tiny fraction of the size of the application.


The game binary is generally completely worthless without its associated assets, though. Nobody would really want to install Skyrim without the master esm since the assets contained therein are essential to the experience. Maybe that's not particularly useful to the discussion, but my point is you could probably fit all your most commonly used programs in a static format + all your average assets like icons or config files, and run and use them in a pretty small amount of space. The games, FLAC music collection, high quality photo library, etc can very easily be much greater a storage requirement than an application library full of static binaries.


The idea with oasis is to choose smaller software with fewer dependencies that offsets the slightly higher disk usage, as well as to deliberately not have thousands of binaries.


Yes, I would think static linking would lead to higher disk usage for binaries.

That analysis doesn't really answer the question re: disk usage and doesn't really quantify how much sharing there is from shared libraries, just how many shared libraries don't get shared... basically "Do your installed programs share dynamic libraries" is answered as "not really" because there s a long tail of libraries that are not widely shared.

Drew's stats shows 80% of binaries link to libc (1.8MB on my system), which by itself could be "a lot" of extra storage. It wouldn't be 80% * 1.8MB per executable if unused symbols weren't linked, but still


The problem is not the size, but for Linux distributions to provide fast security updates for shared libraries instead of having to patch and recompile tons of packages.


That also depends on how the libraries are structured. As far as I know, if you were to successfully link in glibc, that would include the entirety of it, however musl libc is structured so only the parts (at function level?) are linked in.


I find the build system more interesting than the "statically linked" part. Incremental compilation across your whole system is something we should have nailed by now, I think. The best I've seen is something like openembedded, where you get per-package (but not per-file) dependency tracking across the whole system.

I was ever so slightly disappointed to see how manual the packaging is, with every .c file listed in each lua script. It looks quite maintenance-intensive. I was almost hoping for some kind of meta-build system which could parse automake etc. files and hoist the dependency graph into the main system build.


> I was ever so slightly disappointed to see how manual the packaging is, with every .c file listed in each lua script. It looks quite maintenance-intensive.

I was worried about this, too, but it turns out most of the cost in just the initial packaging. Packages do not tend to change their build system very much in between releases, so updating is usually just `git diff` between the version tags, sometimes adding/removing a couple source files to `gen.lua`, and regenerating `config.h`.

I'm just one person, but I've been able to keep these 100 or so packages up-to-date fairly easily, while still spending most of my time developing my own projects.

> I was almost hoping for some kind of meta-build system which could parse automake etc. files and hoist the dependency graph into the main system build.

This would be amazing, but I think it is too difficult a problem to solve, especially with the huge variety of build systems (which are sometimes used pretty creatively). For some packages I get part of the way there with scripts or command snippets to extract source lists from the upstream build system. Here's an example: https://github.com/oasislinux/oasis/blob/master/pkg/mpv/gens...

One of the main motivations for the oasis build system is that it is often very difficult to get the upstream build system to do what you want. It is very common for projects to ignore your CFLAGS or LDFLAGS, ignore special include/lib directories for dependencies, or have automagic dependencies (to borrow a term from gentoo) that can't be enabled/disabled explicitly with a configure switch. Also, most build systems don't work very well for building things statically. libtool will intercept your -static flag, hiding it from the compiler, and libraries which are dependencies of other libraries get left out from the linking command.


Honestly, DLL hell is currently only a solved problem by nix and guix and at this point onwards, I don’t see much point in not porting everything over to the nix way of maintaining packages.


Honestly, I'm team dynamic linking. I prefer to have things clearly separated in functionality and easily upgradeable.

Statically linking all the OS utilities to their dependency libraries, over and over again? Dear god that sounds awful.


There's no reason that there needs to be such extremes as either all statically linked or all dynamically linked. History has proven that dynamic linking causes a large number of headaches, and static linking has drawbacks as well. There is a reasonable middle ground: base system functionality that is utilized by most software (stdlib, cryptography, networking, gui, etc) should be dynamic and everything else should be static.

The problem is that Linux userspace has historically payed little attention to backwards compatibility and has no definition of "base system". Consequently, Linux distros tend to be their own little mutually-incompatible worlds where you either play with the package manager/repo combo you have or jump through hoops and dodge conflicts to try to get anything to work.

Oasis is interesting in this way: there are no conflicts, there is no package manager, and the binaries should work anywhere provided the arch is the same.


>>There is a reasonable middle ground: base system functionality that is utilized by most software (stdlib, cryptography, networking, gui, etc) should be dynamic and everything else should be static

I disagree, I tend to want the opposite. I want big, bloated libraries like Qt or Gtk or Boost to be dynamically linked, and OS facilities like libc to be statically linked.


> I want big, bloated libraries like Qt or Gtk or Boost to be dynamically linked

These fall under "GUI" in the "base system" category in my opinion.

> and OS facilities like libc to be statically linked.

If you're not being sarcastic right now, I'm really curious as to your reasoning.


I'm not OP but statically linking a compact libc like musl gets you just the parts of libc that you need and nothing more. This can be a lot more efficient than a dynamically linked program which has to bring in the entire bloated mess of glibc.

Whether this is a benefit when you're duplicating bits of libc across every executable in your entire system is unclear to me though.


libc is much smaller than other libraries, and as another has pointed out, compiling it statically will get you only the symbols you actually use, so it doesn't even equal the total size of libc. Which makes more sense? Bloating your executable with ~100+MiB of Qt crap, or bloating it with 100KiB of libc symbols?


This 'middle ground' you describe is essentially how macOS and Windows work, isn't it?


> There is a reasonable middle ground: base system functionality that is utilized by most software (stdlib, cryptography, networking, gui, etc) should be dynamic and everything else should be static.

But isn't this the exact opposite of what Oasis provides?


Oasis is just the opposite extreme of how most Linux distros work. That's interesting because no one else does it. I did not say it was the ideal.


> I prefer to have things clearly separated in functionality and easily upgradeable.

What is your thinking here? Are you talking about a use case where you have an application that uses a library and a bug fix is issued for that library, so you want to just get the new .so for the library and have the application use it? That feels like a niche use case to me. Maybe there is another benefit, or this use case is more common than I realize. I'd be interested in further opinions/info.


> That feels like a niche use case to me.

I wouldn't call it a niche use case at all, it's exactly how the software for all major Linux and BSD operating systems are packaged and built.

For example, when (not if) a vulnerability is found in OpenSSL, package maintainers just commit an update to the openssl package and users only have to download and install one package to patch their system against the vulnerability.

Contrast with a fully-static OS and applications: the maintainers would have to update the openssl package, rebuild it, and then also rebuild _every single other program_ that relies on it as well. On my system, that's 123 packages. I don't have all of those installed, but as a user, it means I would have to download new full copies of around a dozen packages to patch one flaw in one package.

And of course, the packages themselves are much _much_ larger too. Most software that I can install as a flatpack or appimage are at least an order of magnitude larger than the deb version, take longer to start, and also take up more valuable RAM when running.

Proponents of static linking have generally experienced the pain of dynamically-linked software either through container deployment or by accidentally messing up their system with third-party packages and repos and the like. I get it, I have been there too. But even through managing a dynamically linked system is certainly more complex, it brings a lot of benefits to the table.


> I wouldn't call it a niche use case at all, it's exactly how the software for all major Linux and BSD operating systems are packaged and built.

even though I'm typing this on a linux desktop, this is a niche use case. In Windows, macOS, iOS and Android, so 99.9% of all user-facing computing, all the libraries except the OS API are duplicated for each app.


I think the license for the Microsoft C runtime dll's precludes bundling although it does allow static linking. It used to cause me no end of problems because the silent install would often fail.


Updating OpenSSL or any other shared library is a "niche use case"?


Using OpenSSL is itself a niche on windows / macOS. And it's not about using shared libraries - it's about actually sharing them. I have at least two dozens apps using Qt on my windows desktop but they all use a slightly different or patched Qt version so exactly nothing is gained when compared to static linking


When you rebuild the binaries that depend on the upgraded library, you can also run their tests and run automated analysis tools. This improves reliability.

DLL loading is full of security risks. Static binaries are free of them.

DLLs are compiled separately from the binaries that load them. Compilers cannot optimize code that calls into a DLL. Compiler optimizers are amazing these days. Compared to a separately optimized binary + DLL, a completely optimized binary will consume less CPU, use less memory, and cause less heap pressure and fragmentation.

DLL's original purpose is reducing memory and disk usage. Since we have different needs now, DLLs are just technical debt.


I remember statically linked software on Linux (old one, such as Netscape, Soffice)... much faster on usage than LibreOffice today.

Also, on services you got a performance boost.


OK, that makes sense. I error in my head was imagining a situation where the user was responsible for knowing which openssl .so file to download and where to put it.


That is not at al a niche use case, at least on a general-purpose system. Shared libraries on Linux, like most modern OSes, are also shared in resident memory among programs using them. For very common libraries like TLS, readline, or GTK that can be a big savings.


> Statically linking all the OS utilities to their dependency libraries, over and over again? Dear god that sounds awful.

Just curious, why does that sound awful to you? Are you worried that it will take a long time to relink the binaries? The oasis build system is incremental, so updates to a library only involve relinking dependent binaries, which is quite fast. Even a full rebuild from scratch only takes a few minutes (assuming you have the sources downloaded already).

If it's just the idea of relinking all the dependencies over and over again, note that with dynamic linking you do this at runtime every time you execute a binary.


> Honestly, I'm team dynamic linking. I prefer to have things clearly separated in functionality and easily upgradeable.

This is awesome as long as no app you need requires an otherwise-useless yet big thing (with its own requirements) or insists on an obsolete version of a library you prefer to have a newer version of.


For a system I'm going to keep and use in multiple ways, dynamic linking is wonderful. Save time building and upgrading, and save memory using the various apps.

For a base image for VMs or containers I'm going to build automatically and throw away on demand anyway, a slightly longer build time to statically link things won't hurt. The memory utilization penalty should also be small, because those should only be running one application or a couple at most.


This makes me so happy!

If static linking was ubiquitous, we could have avoided the complex craziness of docker and the like.


Well, you'd also need to fix Python (, Go, Ruby, JS, ...) packaging and delivery too...


so it's a step in the right direction, then; bravo Oasis Linux!


>Go

Go is already static.


I might be mistaken, but is Oasis also somehow related to the suckless [1] community? (Edit: yes, the maintainer seems to be part of it.)

Another static distro by the suckless people is stali (static linux) [2].

1: http://suckless.org

2: https://sta.li


Ok maybe this is dumb question and is addressed somewhere: If a security problem is found, e.g. in muscl (the C lib), then is the user supposed to rebuild everything that statically linked it??


Yes, but with the oasis build system this is just a single command to do an incremental build that relinks your binaries and takes a matter of seconds.

The user experience is essentially the same as updating your system on a dynamically-linked system. There is no "partial build" where some binaries get relinked but not others.


Not a dumb question just there is always a catch: dynamical link saves you from rebuild only if the fix is carefully backported (by a distributor), which can introduce issues, too. The upstream has usually moved on in the meantime and the library isn't binary compatible.


Yep. And also because it's statically linked and optimised, which version of musl that ships in that binary may be obfuscated somewhat. And no, I don't get it either.


Yes, and this is why Linux distribution exist.

Good luck maintaining 100.000 statically linked libraries embedded in 10.000 applications.


That's the point, you need less than 100.

A browser, cloc, sbase, ubase, X/Arcan, mpv, youtube-dl, ffmpeg, mocp, lynx/link, bitlbee, irssi and not much more.

On games, mednafen can emulate well a huge stack of systems, slashem/nethack is highly replayable and chocolate-doom has tons of PWADs (maps, levels and total conversions). Not the most modern gaming, but these are options to almost never be bored.

For everything else you can spawn an x86 vm with tinyemu and forget maintenance.


oh no, LD_PRELOAD= hax won't work! LGPL is d00med!

Beyond that dynamic linking seems like a great solution to a problem posed by hardware constraints from 30 years ago. Like a lot of CS. Eg most uses of linked lists. (Can't wait for the abuse I'll cop for that).


I think it's awesome. This is likely another of those passion project that, might draw in some overzealous on-watchers, not really become anything usable in the end, but still be incredibly valuable for the greater ecosystem.

It points out how some things has gone unconsidered in the "status quo", but rather then just rant about it, shows how it can be different.

It might put some lesser known code bases into the public eye.

It might iron out compatibility issues with e.g. the linux kernel and "the good parts" of POSIX/unix-philosophy. Which is why I like Alpine and Voidlinux for being such complete systems, without hard dependencies on GNU-components (I think the GNU project, especially many of the individual code bases, are awesome as well).

And while there are benefits of both statically linked applications, an dynamic linking, I do find it for the best if that can be a realistic choice of the user, whatever program of library you want to use. And most big applications simplu can't be totally statically linked as of now.

It's a form of "greenfield project", but still leveraging existing components.


As an addition, I've been trying their qemu image, and similar to an older, similarly radical distro "rsld" (the old release which was graphical), it's usable in qemu, with kvm disabled, to get a snappy graphical environment that can even browse the web (with all the limitation those simple webbrowser have). Browsing HN (using netsurf), while checking memory usage in a st window uses 56MBs of memory. IIRC rsld, which used dillo on tinyxserver, used ~25MB on something like wikipedia.

Other notable "radical" linux systems are EasyOS, RancherOS, Bedrock linux, Gobolinux, NixOS and Guix.


I'll never use this but it's cool that it exists.


> No package manager.

> Instead, you configure a set of specifications of what files from which packages to include on your system

Isn't that a just a declarative package manager?


I suppose you could argue that, but it is not a package manager in the traditional sense.

My main point here is that once you build the system, there is no longer any notion of "package", just files that make up your root filesystem. There is no package database tracking which files came from which packages. Instead, if you want to add/remove/update a package, you rebuild the system with a different specification, and then sync the resulting tree it to /.


All README's should begin with some sort of mission statement. What is the goal or reason for the existence of this? I can imagine some, but I am not sure where this is heading.


It exists because I wanted a complete system where I could easily experiment with various minimal/alternative software. I wanted this so that I could easily understand and hack on any component without spending weeks/months familiarizing with massive code-bases and waiting for things to compile.

I made it for myself, and honestly that's all there is to it. I tried to describe the things that make oasis unique in the README, and I think some of those are pretty cool, but I'm not trying to market this to anyone. If it doesn't sound interesting to you, then feel free to disregard the project.


I definitely do not want to disregard. It think its cool. I just wanted to know what the target was and I think its helpful for README's to include their purpose.


Except that the README of this project answers all your questions. A list of distinctive features and a list of project's principles make up half of the README.


I read it. It does not say "why" anywhere.


Why care about "why" when there is "why not".


> Why care about "why" when there is "why not".

Life is short. As I've gotten older, I've seen the importance on focusing my time and attention on what matters.

So, personally, I'd want to know "why" so I could decide where the project ranks in my priorities.


Okay, how about this: Why are you on Hacker News? It clearly doesn't align well with your self-professed interests.


> netsurf instead of chromium or firefox

Great for the default but can we have a Firefox/Chromium/derivative as an alternative, for the sites which don't work in NetSurf?


Yep, you can install firefox via pkgsrc or nix. Due to the complexity of the modern web browser and all of its dependencies, it is unlikely to ever be part of oasis itself.


Is a self-sufficient static build of Chromium or Firefox an impossible thing?


As of now I think it is, but it should be fixable. Something like Oasis might spur interest (and possibly a framework) for such work.


It's tedious and cumbersome to do so with C++, and with QT is a nightmare.


For my purposes I've often found that static-binary+cgroups+chroot+permissions gives you 90% of the isolation benefit of various container systems (docker) with like 10% of the pain.

I'm also not happy with Ubuntu's move towards snaps which also seem to increase complexity and overhead with minimal benefit.

An app-as-directory setup, like the one that was used in NeXTSTEP and is still used in macOS, also seems to work OK.


build manifests generated by Lua scripts look so elegant and clean.


>Velox

Arcan would be interesting on this, too.


Is "velox" (mentioned in the article) a display server or a window manager?


As far as I understand it, that distinction doesn't really make sense with Wayland. The display server / compositor is also the "window manager".

Client applications have their own buffer they draw on, and they negotiate the details of its handling with the compositor which manages the composition of all client buffers (and other data, such as input events) to form the final result.

I suppose it's technically possible to write a protocol that involves a third client process (a "window manager") to draw something around another client's buffer and tell the compositor how to position things, but that sounds like a nightmare to synchronize.


A wayland window manager.


Window manager I think. Is based on https://github.com/michaelforney/swc that is a Wayland compositor


How does graphics drivers work on this distro?


There is rudimentary hardware acceleration for certain older GPUs that I own in wld (intel at https://github.com/michaelforney/wld/blob/master/intel.c and nouveau https://github.com/michaelforney/wld/blob/master/nouveau.c).

But, for everything else there is only software rendering via pixman. I started working on a new library called libblit that will support amdgpu, and I managed to draw some rectangles and textures, but there is still a ways to go on that: https://git.sr.ht/~mcf/libblit/tree/master/amdgpu


it's advertised as "small". how small is that? an Alpine minirootfs is ~2.5 MB tar.gz and ~6.0 MB on ext4 (4k overhead).


This looks like a desktop system, with a browser and window manager. So comparing it to the alpine minirootfs is apples to oranges


good stuff


Having grown up on a static linked world, where dynamic linking was a thing of big iron computers that we dreamt about being able to do in home computers this trend of static linked compiled stuff feels somehow a tragedy of some sort.

How bad have we gone, that is now trendy to return to the days of static compiled binaries and process IPC to achieve any sort of dynamism.


I think dynamic linking one of those ideas that looks neater on paper and therefore feels better but just fails in many ways in the real world (at least for statically compiled languages like C and C++).

Personally i think at least half the times i really tried to use Linux i always wanted a new shiny version of some program at some point, this usually devolved into a more or less broken system due to dependencies.

I do understand some people who really loves their package managers and knowing that their updated system will be secure, but many people are even more into shiny new things than me and if anything has held back Linux adoption on the desktop I'd probably point to this second to drivers and configuration troubles historically.

Am I alone in this? I doubt it if we consider the existence of Docker, Snap packages and similar things.


Containers fulfil other purpose, and have existence in some form on mainframes and big UNIXes, because just using UNIX permissions is not enough to actually secure a process.

They just happen to have been misused to workaround deficiencies on Linux software distributions.

The only areas where I see a failure of dynamic linking is security, given the possible exploits of the host process.

Even IPC comes to IPC hell if not everyone is speaking the same version.


Sorry for the late reply but my point was more about user and developer experience (the end result of the system in place) vs the traditional sysadmin/poweruser view of packages among Linux users/distros where the security and interop details of systems matters more but is kind of in conflict (as a loose reference, think of the conflicing requirement origins of why shadow-IT exists).

Like as a user i don't really need to care if my Chrome browser uses a newer version of the V8 JS engine or libpng for security than for example my VS Code IDE (because that IDE instance isn't active on the hostile internet visiting "random" webpages).

Sure the browser will be more secure and if it was dynamically linked I'd get the benefits of having both upgraded at the same time, however it'd also require breaking changes to an cutting-edge program like Chrome/Chromium to bring all dependencies forward, maybe breaking programs like VSCode that aren't updated as frequently but has more or less the same dependencies. (Like in practice it seems like Ubuntu even uses a dummy Chromium package that just forwards the user to a snap package).

The way forward i think would be to bring some variant of sem-ver to the C/C++ world with a unified strategy to package management, but i don't have hopes of that ever happening.


This would be 10x faster and smaller if they just built these components into Busybox.

Package management, library management, etc are solved problems when it comes to Linux distros. The only practical improvement you can make is containers (or similar).

Static binaries cannot deal with external dependencies, and many applications require external dependencies that cannot be compiled in. But even by trying to compile-in all the dependencies, you've only shifted the complexity from the filesystem to the build system, and you still have applications with incompatible features and interfaces across versions.


> Package management, library management, etc are solved problems when it comes to Linux distros. The only practical improvement you can make is containers (or similar).

To me this basically reads as "we added a bunch of complexity on top of the problem without actually solving it". Package managers are supposed to prevent conflicts and manage giant dependency graphs, but they're so shit at doing that while actually allowing people to use whatever software they want that we've invented containers to keep everything separate again.


> "we added a bunch of complexity on top of the problem without actually solving it"

It solved it as much as is possible within the current state of software design.

> Package managers are supposed to prevent conflicts and manage giant dependency graphs

Actually, they can't do that. They can look for the conflicts they're programmed to look for by packages, and they can walk dependency graphs that are generated by the packages in the repos maintained by a person. The root of the problem is that modern software architecture (even for trendy languages) cannot express the dependencies in the first place.

I wrote you an explanation, but it ran to 1,355 words, so I Gist'd it here https://gist.github.com/peterwwillis/e96854532f471c739983c0b...


Nix[1] is a package manager for linux and macos that solves this problem beautifully. You can have any variation (version, build options, dependencies, etc) of a package installed natively without conflicting with eachother because the filesystem path includes a hash of the build instructions. It works really, really well for reproducibility and eliminating the "works on my machine" problem. I've been using it exckusively for dev machines and servers for years.

[1] https://github.com/NixOS/nixpkgs


I worked for a company that built the same thing in the mid-2000s, and it did not solve all dependency issues, because there's multiple kinds of issues. They're actually kind of unsolveable. I list some of the reasons here https://gist.github.com/peterwwillis/e96854532f471c739983c0b...


Thanks for sharing. Agreed that runtime dependency conflicts are unavoidable for most programming languages. Your example of sqlite database format conflicts is also a good one.

I definitely won't claim that nix has solved runtime dependency conflicts, but it does decisively solve build-time conflicts.

Similar to containers like you describe, but reproducible and don't require storing and shipping opaque binary images around. Reproducibility is really the killer feature, IMO. I inherited a bunch of containers that don't build anymore because the build instructions weren't reproducible. Having an old container image that still runs is just tech debt if yiu can't edit the build instructions and genrrate a new one.


All versions of SQLite from 3.0.0 (2004-06-18) through 3.34.0 (the latest) use the same database file format. So if two applications use different versions of SQLite, it shouldn't matter. The database file will be the same.

Now, if one application uses a more recent version of SQLite and also makes use of some new feature (say, for example, generated columns which were added in release 3.31.0) then that might result in a database file that is unreadable by older versions since the older version won't be able to interpret the generated column syntax. But if you assume that all different versions of SQLite that you use have support for all of the features used in the database file (a reasonable assumption in most cases) then the database files are completely portable across versions. Different versions of SQLite can read/write the same database file concurrently. And newer versions of SQLite are always able to read/write databases created by older versions of SQLite, without exception or precondition.

So perhaps the "sqlite format conflict" example was not the best, in as much as it will always work as long as the package manager installs the most recent version of SQLite.

All of the above is also true for the API.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: