[HN Gopher] Oasis - a small, statically-linked Linux system
       ___________________________________________________________________
        
       Oasis - a small, statically-linked Linux system
        
       Author : smartmic
       Score  : 355 points
       Date   : 2024-01-26 14:11 UTC (8 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | __s wrote:
       | michaelforney was also who did the wayland port of st:
       | https://github.com/michaelforney/st
       | 
       | oasis's predecessor would be
       | https://dl.suckless.org/htmlout/sta.li
        
         | sigsev_251 wrote:
         | Michaelforney has also built croc [1], a qbe based C compiler.
         | Really impressive!
         | 
         | [1]: https://github.com/michaelforney/cproc
        
           | Koshkin wrote:
           | Not as "impressive" as TCC, I'd say. Why? TCC has its own
           | backend, and it has the preprocessor built in. (But QBE is
           | indeed impressive.)
        
       | hkt wrote:
       | This is very very cool. I love the bloat free nature of the
       | thing, especially velox (the WM). Samurai (build system) also
       | looks pretty interesting. I've not managed to work out quite how
       | samurai works, or truthfully, why it differs from ninja, but this
       | project is exactly the kind of brain food I intend on learning a
       | lot from.
       | 
       | Many, many props to Michael Forney.
        
       | dijit wrote:
       | I cant speak much about the system, it just works, but the
       | community was really nice when I interacted with them over IRC
       | 
       | I had the plan to build oasis with bazel for some immutable OS
       | images that could run as kubernetes nodes. I succeeded with a
       | little pointing.
        
         | gravypod wrote:
         | Have you shared your BUILD files upstream?
        
           | dijit wrote:
           | No, they were quite happy with Samurai
        
         | malux85 wrote:
         | Thats a cool idea! Will you open source it or make it available
         | somehow? I would like to play with it for running Atomic T
        
         | public_void wrote:
         | Why did you need to use bazel?
        
           | dijit wrote:
           | I didnt need to use bazel, I like bazel and want to learn
           | more about it.
           | 
           | I also have a small, but burning, passion for reproducible
           | builds, distributed compilation and distributed caching.
           | 
           | Being able to build an entire OS and essentially anything I
           | want on top in a reproducible and relatively organic way
           | (with incremental compilation) is pretty dope.
        
             | i-use-nixos-btw wrote:
             | You sound like the perfect Nix cult memb... erm, user. It's
             | everything you describe and more (plus the language is
             | incredibly powerful compared with starlark).
             | 
             | But you speak from sufficient experience that I presume Nix
             | is a "been there, done that" thing for you. What gives?
        
               | chaxor wrote:
               | Nix has decentralized caching and memorizing?
        
               | IshKebab wrote:
               | Nix isn't as fine-grained as Bazel as I understand it? I
               | don't think it's incremental within a package, which is
               | presumably what dijit achieved.
        
         | MuffinFlavored wrote:
         | > I cant speak much about the system, it just works,
         | 
         | What systems don't just work by this criteria?
         | 
         | Just because something is statically linked vs dynamically
         | linked, as long as you are within "normal expected operating
         | conditions", does it really make a "just works vs doesn't work"
         | quality difference?
        
           | Koshkin wrote:
           | Read after the comma:
           | 
           | > _it just works, but..._
        
       | eterps wrote:
       | Interesting choices, finally something that isn't just another
       | Linux distribution.
        
       | nightowl_games wrote:
       | Can someone explain a couple use cases for something like this?
        
         | ekianjo wrote:
         | immutable images
        
         | ghotli wrote:
         | I routinely get embedded linux devices at $dayjob that need my
         | time and attention and they basically never have the tooling I
         | need to get my job done. I'm a pro at looking at how Alpine
         | builds a tool and then just making my own statically linked /
         | minimal size tool to drop in place on the device. The allure of
         | something like this is that I can just potentially grab a drop-
         | in binary and get on with my day. I simply don't attempt to
         | link to libraries already on the device since they're all built
         | in wildly different ways, old tools, old compilers.
         | 
         | Hopefully that's helpful context. Overall since I did linux
         | from scratch half a lifetime ago I've always wondered why
         | something like Oasis hasn't gotten more traction. It's got some
         | ambitious ideas in the README so maybe others have other nice
         | use-cases atop all that. I just see small, statically linked
         | and think 'oh boy if i never have to build my own tools again
         | for some weird board'. If so, I'm here for it.
        
           | 8organicbits wrote:
           | > grab a drop-in binary
           | 
           | This is a cool approach on Docker as well.
           | FROM some:thing AS bins         FROM debian:latest
           | COPY --from=bins /bin/foo /bin/
        
             | ghotli wrote:
             | Agreed, if the binary is statically linked. If you run
             | `file` on the output from that and it shows 'dynamically
             | linked' then you're playing games with porting over
             | libraries, changing the library loading path, or just going
             | full chroot like linux from scratch does with the
             | bootstrapping part of the install. I find static binaries
             | simplest to work with in that context but agreed I use that
             | pattern too with docker and generally build ad-hoc tools
             | within containers like that. If only these devices could
             | run docker but I'm left to my own tooling to figure out per
             | device.
        
               | 8organicbits wrote:
               | Agreed, dynamically linked binaries don't drop in well.
        
               | lloeki wrote:
               | In a way, that's what Nix sets out to do, isolating even
               | dynamically linked libraries: if two derivations depend
               | on the same shared lib derivation then it's reused, if
               | not then they don't conflict. Each leaf derivation can be
               | handled completely independently of the others, and
               | independently of the original system+.
               | 
               | And then when Nix+ is not an option at runtime,
               | dockerTools++ can build a Docker image to do the
               | minimisation+isolation.
               | 
               | That said, Nix might also be completely overkill in some
               | scenarios where static linking would be just fine and
               | very practical. The practical simplicity of a single
               | binary should not be overlooked.
               | 
               | + nixpkgs is sufficient, a full nixos is not needed
               | 
               | ++ https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-
               | dockerTool...
        
               | vacuity wrote:
               | So Nix keeps track of different versions of shared
               | libraries?
        
               | sporeray wrote:
               | Yeah, each package/lib is stored in a unified directory
               | by it's hash https://zero-to-nix.com/concepts/nix-store.
               | Different variation different hash.
        
         | pjmlp wrote:
         | You miss UNIX developer experience until mid-1980's, before
         | shared objects came to be.
        
           | mech422 wrote:
           | Heh...rebuilding gcc on slackware to enable shared libs was
           | an adventure - but that wasn't till the late 90s(??). I think
           | I spent like a week bootstrapping the new gcc, rebuilding
           | glibc and rebuilding all the stuff I used.
        
             | pjmlp wrote:
             | UNIX System V 4.0 was the one that kind of uniformized
             | existing parallel solutions from UNIX variants, alongside
             | ELF in the late 1980's.
        
         | enriquto wrote:
         | > Can someone explain a couple use cases for something like
         | this?
         | 
         | At this point, it would be more useful if someone explained a
         | couple of use cases for dynamic linking.
        
           | pjmlp wrote:
           | Plugins, unless you want to have one process per plugin.
           | 
           | Which in the days of running Kubernetes clusters on laptops
           | maybe isn't a big deal.
        
             | enriquto wrote:
             | You can still call dlopen from your static binary, if you
             | really want to.
        
               | pjmlp wrote:
               | Sure lets go back to 1980's UNIX, it was such a great
               | experience.
        
               | mappu wrote:
               | I tried to do this recently at $DAYJOB, but when you
               | statically link a binary with musl, the dlopen() you get
               | is a no-op:
               | 
               | https://github.com/bpowers/musl/blob/master/src/ldso/dlop
               | en....
               | 
               | I tried to hack in a copy of the musl's dynamic loader
               | (and also from old uclibc). But it took a few hours and
               | my only result was segfaults.
               | 
               | Do you have any pointers on making this work?
        
       | sluongng wrote:
       | What is the comparison between using musl and traditional glibc?
       | 
       | Is there performance differences between the two?
       | 
       | I have been seeing musl used more and more in both Rust and Zig
       | ecosystems lately.
        
         | znpy wrote:
         | > What is the comparison between using musl and traditional
         | glibc?
         | 
         | you get weird bugs and failures that don't happen with glibc
         | (like the incomplete dns resolving routines that would fail
         | under some conditions) but you can brag about saving 30-40 mb
         | of disk space.
         | 
         | this project seems to be compromising on quality overall, in
         | the name of having smaller size.
         | 
         | Even BearSSL, by their own website is beta-quality: "Current
         | version is 0.6. It is now considered beta-quality software"
         | (from https://bearssl.org/).
        
           | ghotli wrote:
           | https://musl.libc.org/releases.html
           | 
           | I maintain a large codebase, widely deployed, cross compiled
           | to many cpu architecures that's built atop musl. You're right
           | that historically in the context of people blindly using
           | alpine for their container base that sort of thing might be
           | the case. The newest version of musl solves the thing you're
           | describing and in general most of the complaints about malloc
           | perf or otherwise have been addressed. Avoiding musl to me
           | seems like an outdated trope, but there was a time wherein
           | that take was valid indeed.
        
             | NewJazz wrote:
             | malloc performance is still sub-par IMO. It is not nearly
             | as terrible as it was, but scudo, memalloc, and glibc's
             | malloc are better.
        
           | raesene9 wrote:
           | A small point on that last bit. The bearssl authors are
           | pretty conservative when it comes to development milestones,
           | I'd guess that their 0.6 would be pretty solid :)
        
             | znpy wrote:
             | > I'd guess that their 0.6 would be pretty solid :)
             | 
             | Would you accept that kind of reasoning for software
             | running on your pacemaker, or on your insuline pump?
             | 
             | I think we should respect the developers here: they're not
             | claiming production quality level (they're claiming beta-
             | quality level) so it's not correct to use that library in
             | any kind of product and claim any kind of production-level
             | quality.
        
               | ComputerGuru wrote:
               | I would run away from using glibc on an insulin pump or
               | pacemaker, so I'm not sure what point you're trying to
               | make.
        
               | foul wrote:
               | > Would you accept that kind of reasoning for software
               | running on your pacemaker, or on your insuline pump?
               | 
               | God helps me I wouldn't implant anything so fundamental
               | in my body with hard dependencies on encrypted
               | communication to a remote agent elsewhere, no matter the
               | advantage.
        
           | electroly wrote:
           | > incomplete dns resolving routines
           | 
           | They eventually did fix this, as of musl 1.2.4.
        
             | o11c wrote:
             | While not an issue for musl-centric distros if they keep
             | updated, note that e.g. Debian stable doesn't have that
             | version yet, so good luck testing.
        
               | electroly wrote:
               | At least we have light at the end of the tunnel now. This
               | is a tremendous improvement from the previous status quo
               | of the musl maintainers not even agreeing that it's a
               | problem.
        
               | znpy wrote:
               | This alone "musl maintainers not even agreeing it's a
               | problem" should be a good reason to avoid musl imho
        
               | electroly wrote:
               | What's a better option for static linking? glibc is
               | religiously against it; they have far worse dogmatic
               | beliefs than this musl DNS thing. I'd be happy to choose
               | a better alternative if one exists, but if one does not,
               | I have to live with the options at hand. From where I'm
               | standing, musl seems like the only game in town. uClibc
               | doesn't seem like it's appropriate for general purpose
               | Linux applications on desktop computers (maybe I'm
               | wrong?).
        
               | o11c wrote:
               | Static linking doesn't actually solve any problem. Just
               | use dynamic linking with (probably relative) rpath, and
               | compile against a sufficiently old libc.
               | 
               | There's some common FUD about rpath being insecure, but
               | that only applies if the binary is setuid (or otherwise
               | privileged) _and_ the rpath is writable by someone other
               | than the binary 's owner (all relative rpaths are
               | writable since you can use symlinks; absolute rpaths are
               | writable if they point to /tmp/ or a similar directory,
               | which used to be common on buildbots).
               | 
               | This is really not hard; working around all static
               | linking's quirks is harder.
        
               | schemescape wrote:
               | What are the quirks of static linking you need to work
               | around (in general, not for glibc)?
        
               | o11c wrote:
               | You have to know the internals of your dependencies so
               | you can link them explicitly, recursively. (admittedly,
               | pkg-config helps a ton, but not all libraries ship (good)
               | .pc files)
               | 
               | Global constructors no longer reliably fire unless you
               | are _extremely_ careful with your build system, nor do
               | they run in a predictable order (e.g. you can call a
               | library before it is actually initialized, unlike dynamic
               | linking where only preinit - which nobody uses - is
               | weird), nor can you defer them until dlopen time if you
               | want (which is, admittedly, overdone).
               | 
               | It's possible to link to _parts_ of multiple versions of
               | a library (remember, you have to recurse into your
               | dependencies), as opposed to dynamic libraries where at
               | least you 're guaranteed all-or-nothing (which is much
               | easier to detect).
               | 
               | Linking is slower since it always has to be redone from
               | scratch.
               | 
               | Not resilent against system changes. For example, old
               | versions of `bash-static` (grab them from e.g. Debian
               | snapshot and extract them manually; don't install them)
               | are no longer runnable on modern systems since certain
               | system files have changed formats, whereas the
               | dynamically-linked `bash` packages still run just fine.
               | 
               | It also encourages bad stability habits, leading to the
               | equivalent of NPM hell, which is far worse than DLL hell
               | ever was.
               | 
               | You can't use LD_PRELOAD or other dynamic interception
               | tools.
               | 
               | There are probably more reasons to avoid static linking,
               | but I'm trying to ignore the handful from the popular
               | lists.
        
               | schemescape wrote:
               | Thanks! Most of those seem like a fair trade-off for
               | portability... for an app.
               | 
               | I'm not sure it's a great idea for an OS as in the OP,
               | but I do like that they claim accurate incremental
               | rebuilds, to ensure everything get updated. Certainly an
               | interesting experiment!
        
           | fullspectrumdev wrote:
           | 30-40mb of disk space is absolutely huge in some environments
           | even today though
        
         | digikata wrote:
         | One of the reasons I've switched some builds over to musl over
         | glibc, is that I found that glibc linking is brittle if you're
         | going to run a binary over multiple distros in various
         | container environments. Particularly if you want one binary to
         | work on linux across RH and Debian/Ubuntu derived distros or
         | even different ages of distro.
        
           | skywal_l wrote:
           | Linus Torvald agrees with you:
           | https://youtu.be/Pzl1B7nB9Kc?feature=shared&t=261
        
         | skywal_l wrote:
         | glibc is LGPL. Static linking your application implies some
         | obligation on your part. Musl being MIT is less restrictive.
        
           | Zambyte wrote:
           | > Musl being MIT is less restrictive.
           | 
           | It depends who you're speaking for
        
             | bigstrat2003 wrote:
             | No it doesn't. The MIT license is objectively less
             | restrictive than the LGPL. Whether it's a good or bad thing
             | to be less restrictive is a matter of opinion, but whether
             | or not it is less restrictive is a matter of fact.
        
               | Zambyte wrote:
               | Lots of software licensed as MIT is distributed under a
               | proprietary sublicense, which is as restrictive as it
               | gets. That isn't the case with GPL licenses.
               | 
               | It is a matter of fact that it's a matter of perspective.
        
           | actionfromafar wrote:
           | Not very tough obligations, but it can be a practical hassle.
           | This answer describes it quite well I think:
           | 
           | https://opensource.stackexchange.com/questions/13588/how-
           | sho...
        
         | ComputerGuru wrote:
         | Speaking from heavy experimentation and experience, [0] glibc
         | has some more optimized routines but musl has significantly
         | less bloat. If you are haphazardly calling libc functions left
         | and right for everything and have a generally unoptimized code
         | base, your code may fare better better with glibc. But musl's
         | smaller codebase is a win for faster startup and micro
         | optimizations otherwise - and that's without lto where it
         | stands to gain more.
         | 
         | [0]: https://neosmart.net/blog/a-high-performance-cross-
         | platform-...
         | 
         | Edit:
         | 
         | Sorry, the correct link is this one:
         | https://neosmart.net/blog/using-simd-acceleration-in-rust-to...
        
           | jart wrote:
           | If you want an optimized Musl, try Cosmopolitan in `make
           | toolchain MODE=tinylinux`, since it's based on Musl, and its
           | string routines go 2x faster.
        
             | ComputerGuru wrote:
             | I don't think that was around back then but I can add it to
             | the backlog of things to try for next round. Does that play
             | nice with rust? Presumably I'd have to at least build the
             | standard library from scratch (which I'd want to do against
             | musl as a separate benchmark anyway since it's now a single
             | environment variable away).
             | 
             | (Not that the codebase makes much string function usage.)
        
               | jart wrote:
               | It should if everything is static and you're only
               | targeting Linux.
        
         | o11c wrote:
         | The real comparison is: musl does not provide any preprocessor
         | macro to tell you what libc you're using.
         | 
         | And it has _so_ many weird quirks that you need to work around.
         | 
         | ***
         | 
         | Static linking makes linking more painful, especially regarding
         | global constructors (which are often needed for correctness or
         | performance). This is not a musl-specific issue, but a lot of
         | people are interested in both.
         | 
         | Just do your builds on the oldest supported system, and dynamic
         | linking works just fine. You can relative-rpath your non-libc
         | dependencies if they would be a pain to install, though think
         | twice about libstdc++.
         | 
         | ***
         | 
         | The major advantage of MUSL is that if you're writing a new OS,
         | it's much easier to port.
        
         | joveian wrote:
         | Functional differences described here:
         | 
         | https://wiki.musl-libc.org/functional-differences-from-glibc...
        
       | Koshkin wrote:
       | There's also the "suckless" sta.li
        
         | ratrocket wrote:
         | A comment up-thread (currently) says/implies Oasis is a
         | successor to sta.li by the same person.
         | 
         | https://news.ycombinator.com/item?id=39143029
         | 
         | I also thought sta.li when I saw this was about a statically
         | linked linux system...
        
           | lubutu wrote:
           | It's not by the same person -- sta.li was by Anselm R Garbe.
           | It's more like a spiritual successor.
        
       | Rochus wrote:
       | Interesting, but what is the use case?
       | 
       | What is the advantage of using the croc C compiler instead of
       | e.g. TCC?
       | 
       | I wasn't aware of Netsurf (https://www.netsurf-browser.org/);
       | this is really amazing. But it seems to use Duktape as the JS
       | engine, so performance might be an issue.
        
         | cpach wrote:
         | AFAICT it could be useful for embedded devices.
        
         | helloimhonk wrote:
         | cproc supports C11, tcc only goes up to c99. There is also
         | something to be said for cproc using QBE which is slowly
         | growing backends like risc-v etc which tcc doesnt support
         | afaik.
        
           | Rochus wrote:
           | Ok, thanks, that makes sense. QBE looks interesting, but I'm
           | missing 32 bit support. So currently I'm trying to reuse the
           | TCC backend, which is far from trivial.
        
         | willy_k wrote:
         | Tangential, but the trailing "/" in the URL you gave seems to
         | include the ");" in the hyperlink, giving a "Not Found" error.
         | 
         | Working link: https://www.netsurf-browser.org
        
       | kentonv wrote:
       | Doesn't linking everything statically imply that the base image
       | -- and memory, at runtime -- will be bloated by many copies of
       | libc and other common libraries? I do like the simplicity of
       | static linking but it sort of seems to go against the idea of
       | avoiding "bloat".
        
         | zshrc wrote:
         | musl is significantly smaller and "less bloat" than glibc, so
         | even with a statically linked program, it still remains small
         | in both system memory and storage.
        
           | skywal_l wrote:
           | And using LTO[0] can also help.
           | 
           | [0]https://gcc.gnu.org/wiki/LinkTimeOptimization
        
         | Shorel wrote:
         | In a world where Docker and Kubernetes exist, where whole
         | copies of operating systems are added to each running
         | service...
         | 
         | This seems a weird thing to complain about =)
        
           | kentonv wrote:
           | I mean, if you ran _every single executable_ on your desktop
           | in a separate container I think you 'd see problems. There
           | are a pretty large number of programs running on most
           | desktops, plus all the programs that get called by shell
           | scripts, etc.
           | 
           | Running a handful of containers representing major
           | applications is more reasonable and the memory wastage may be
           | worth it to avoid dependency conflicts.
        
             | drakenot wrote:
             | You've just described Qubes OS!
        
               | palata wrote:
               | Except that QubesOS uses VMs for their security benefits,
               | which are greater than those of containers.
               | 
               | Containers make a lot of sense to me on servers ("deploy
               | a controlled environment"), but often on Desktop I feel
               | like they are used as a solution to "I don't know how to
               | handle dependencies" or "My dependencies are so unstable
               | that it is impossible to install them system-wide", both
               | of which should be solved by making slightly better
               | software.
        
             | Gabrys1 wrote:
             | Each electron app is like that
        
           | lnxg33k1 wrote:
           | Yeah but there I can still update vulnerable libraries
           | independently, to be a statically linked system just means
           | that if there is a bug in libpng then I have to recompile
           | everything?
        
             | bzzzt wrote:
             | Yes, although it very much depends on how big 'everything'
             | is if that's a problem.
        
             | greyw wrote:
             | In most cases relinking is enough.
        
             | Shorel wrote:
             | I was under the impression only Gentoo users recompile
             | everything.
             | 
             | In a statically linked system, your dependency manager will
             | update more packages.
             | 
             | And if your program is written in C/C++/Go/Rust, then yes,
             | it will be recompiled.
        
               | lnxg33k1 wrote:
               | I use Gentoo, so I am not against rebuild everything, but
               | afaik unless you have static-libs USE flag for something,
               | it's dynamically linked so relinking on rebuilding the
               | dependency is enough, with static-libs the dependent
               | package is also rebuilt
        
             | colonwqbang wrote:
             | Not recompile I guess, but you need to relink everything.
             | 
             | Oasis seems to have a good way of doing that, with the
             | whole system being built in a single tree by an efficient
             | build tool (my recollection from last time it was posted).
             | 
             | A dynamic executable needs to relink every time it's run,
             | which also takes time.
        
             | nordsieck wrote:
             | > if there is a bug in libpng then I have to recompile
             | everything?
             | 
             | You say that as if it's such a burden. But it's really not.
             | 
             | I'm somewhat sympathetic to the space argument, but a
             | package manager/docker registry means that updating
             | software is very easy. And it happens all the time for
             | other reasons today anyhow.
        
           | palata wrote:
           | > This seems a weird thing to complain about =)
           | 
           | On the contrary, I find it relevant: I think that the modern
           | way is wasting way, way too much.
        
             | Shorel wrote:
             | On that respect, we agree.
        
         | liampulles wrote:
         | It would be bloated, but how big of a problem is that these
         | days? A TB of storage is pretty cheap.
        
           | cmovq wrote:
           | A TB of memory is not
        
         | thanatos519 wrote:
         | KSM could help with that: https://docs.kernel.org/admin-
         | guide/mm/ksm.html
         | 
         | ... oh wait, the apps have to hint that it's possible.
         | Nebbermind.
        
         | jezze wrote:
         | A linker typically only includes the parts of the library it
         | needs for each binary so some parts will definately have many
         | copies of the same code when you statically link but it will
         | not make complete copies.
         | 
         | But I wouldnt consider this bloat. To me it is just a better
         | seperation of concerns. To me bloat would be to have a system
         | that has to keep track of all library dependencies instead,
         | both from a packaging perspective but also in runtime. I think
         | it depends where you are coming from. To me static linking is
         | just cleaner. I dont care much for the extra memory it might
         | use.
        
           | jvanderbot wrote:
           | Dynamic linking served us when OS upgrades came infrequently,
           | user software was almost never upgraded short of mailing out
           | new disks, and vendors had long lead times to incorporate
           | security fixes.
           | 
           | In the days of fast networks, embedded OSs, emphemeral
           | containers, and big hard drives, a portable static binary is
           | way less complex and only somewhat less secure (unless you're
           | regularly rebuilding your containers/execs in which case it's
           | break even security wise or possibly more secure, simply
           | because each exec may not include vulnerable code)
        
             | teaearlgraycold wrote:
             | Yeah I'd prefer we just use another gigabyte of storage
             | than add so much complexity. Even with what is a modest SSD
             | capacity today I have a hard time imagining how I'd fill my
             | storage. I'm reminded of my old workstation from 8 years
             | ago. It had a 500GB hard drive and a 32GB SSD for caching.
             | I immediately reconfigured to just use the SSD for
             | everything by default. It ended up being plenty.
        
             | gnramires wrote:
             | As far as I can see, it would be unwise to roll back 30
             | years of (Linux) systems building with dynamic linking in
             | favor of static linking. It mostly works very well and does
             | save some memory, disk, and has nice security properties.
             | Both have significant pros and cons.
             | 
             | I've been thinking (not a Linux expert by any means) the
             | ideal solution would be to have better dependency
             | management: I think a solution could be if say binaries
             | themselves carried dependency information. That way you get
             | the benefits of dynamic and static linking by just
             | distributing binaries with embedded library requirements.
             | Also, I think there should be a change of culture in
             | library development to clearly mark compatibility breaks (I
             | think something like semantic versioning works like that?).
             | 
             | That way, your software could support any newer version up
             | to a compatibility break -- which should be extremely rare.
             | And if you must break compatibility there should be an
             | effort to keep old versions available, secure and bug free
             | (or at least the old versions should be flagged as insecure
             | in some widely accessible database).
             | 
             | Moreover, executing old/historical software should become
             | significantly easier if library information was kept in the
             | executable itself (you'd just have to find the old
             | libraries, which could be kept available in repositories).
             | 
             | I think something like that could finally enable portable
             | Linux software? (Flatpak and AppImage notwithstanding)
        
               | josephg wrote:
               | Yes, if someone actually did dependency management in
               | Linux properly then I agree - dynamic linking would be
               | fine. It works pretty well in Nixos as I understand it.
               | But it's called dependency hell for a reason. And the
               | reason is almost no operating systems handle C
               | dependencies well. There's always weird, complex,
               | distribution specific systems involving 18 different
               | versions of every library. Do you want llvm18 or
               | llvm18-dev or llvm-18-full-dev or something else
               | entirely? Oh, you're on gentoo? Better enable some USE
               | flags. Redhat? It's different again.
               | 
               | If Linux dependency management worked well, there would
               | be no need or appetite for docker. But it works badly. So
               | people just use docker and flatpak and whatnot instead,
               | while my hard drive gently weeps. I don't know about you,
               | but I'm happy to declare bankruptcy on this project. I'd
               | take a 2mb statically linked binary over a 300mb Linux
               | docker image any day of the week.
        
               | StillBored wrote:
               | This isn't really an "operating system" problem.
               | Particularly in the open-source world, there are a number
               | of fairly core libraries that refuse to provide any kind
               | of API compatibility.
               | 
               | Then, when there are a couple dozen applications/etc that
               | depend on that library, it's almost an impossible problem
               | because each of those applications then needs to be
               | updated in lockstep with the library version. There is
               | nothing "clean" about how to handle this situation short
               | of having loads of distro maintainers showing up in the
               | upstream packages to fix them to support newer versions
               | of the library. Of course, then all the distro's need to
               | agree on what those versions are going to be...
               | 
               | Hence containers, which don't fix the problem at all.
               | Instead they just move the responsibility away from the
               | distro, which should never really have been packaging
               | applications to begin with.
        
               | kentonv wrote:
               | Everything you describe already exists. Executables _do_
               | list their dependencies, and we have well-defined
               | conventions for indicating ABI breaks. It is entirely
               | normal to have multiple major versions of a library
               | installed for ABI compatibility reasons, and it is also
               | entirely normal to expect that you can upgrade the
               | dependencies out from under a binary as long as the
               | library hasn 't had an ABI break.
               | 
               | The bigger dependency management problem is that every
               | distro has their own package manager and package
               | repository and it's tough for one application developer
               | to build and test every kind of package. But if they just
               | ship a binary, then it's up to the poor user to figure
               | out what packages to install. Often the library you need
               | may not even be available on some distros or the version
               | may be too old.
        
               | rwmj wrote:
               | That's why distros ask you to provide just the sources
               | and we'll do the packaging work for you. The upstream
               | developers shouldn't need to provide packages for every
               | distro. (Of course you can _help_ us downstream packagers
               | by not having insane build requirements, using semantic
               | versioning, not breaking stuff randomly etc).
        
               | kentonv wrote:
               | This is only realistic for established applications with
               | large userbases. For new or very niche apps, distros are
               | understandably not going to be very interested in doing
               | this work. In that case the developer needs to find a way
               | to distribute the app that they can reasonably maintain
               | directly, and that's where containers or statically-
               | linked binaries are really convenient.
        
               | rwmj wrote:
               | This isn't really true, Fedora, Debian and Arch have huge
               | numbers of packages, many very niche. You might well need
               | to make the distro aware that the new program exists, but
               | there are established routes for doing that.
        
               | charcircuit wrote:
               | >Executables do list their dependencies
               | 
               | They list paths to libraries, but not the exact version
               | that the executable depends on. It is a common occurrence
               | for executables to load versions of libraries they were
               | not designed to be used with.
        
             | bscphil wrote:
             | > In the days of fast networks, embedded OSs, emphemeral
             | containers, and big hard drives, a portable static binary
             | is way less complex and only somewhat less secure
             | 
             | If what you're trying to do is run a single program on a
             | server somewhere, then yes absolutely a static binary is
             | the way to go. There are lots of cases, especially end user
             | desktops, where this doesn't really apply though.
             | 
             | In my opinion the debate over static vs dynamic linking is
             | resolved by understanding that they are different tools for
             | different jobs.
        
               | moffkalast wrote:
               | It applies very much to end user desktops as well, with
               | snap, flatpak, etc. working towards it. Lots of software
               | requires dependencies that aren't compatible with each
               | other and result in absolute dependency hell or even a
               | broken install when you dare to have more than one
               | version of something. Because who would ever need that,
               | right? Especially not in a dev desktop environment...
               | 
               | Windows is basically all self-contained executables and
               | the few times it isn't it's a complete mess with
               | installing VC++ redistributables or the correct Java
               | runtime or whatever that clueless users inevitably mess
               | up.
               | 
               | We have the disk space, we have the memory, we have the
               | broadband to download it all. Even more so on desktop
               | than on some cheap VPS.
        
               | marwis wrote:
               | > Windows is basically all self-contained executables
               | 
               | With the caveat that the "standard library" they depend
               | on is multiple GBs and provides more features than entire
               | Gnome.
               | 
               | Also MS always worked in some tech to avoid library
               | duplication such as WinSxS or now MSIX has autodedupe
               | even at the time of download.
        
               | StillBored wrote:
               | understanding that they are different tools for different
               | jobs
               | 
               | Right, but this goes against the dogma on both sides and
               | the fact that much of Linux userspace is the wild west.
               | Ideally, there should be a set of core system libraries
               | (ex glibc, openssl, xlib, etc) that have extremely stable
               | API/ABI somatics and are rarely updated.
               | 
               | Then one dynamically links the core libraries and
               | statically links everything else. This solves the problem
               | that a bug/exploit found in something like OpenSSL
               | doesn't require the entire system to be recompiled and
               | updated while allowing libraries that are not stable,
               | used by few packages, etc, to be statically linked to
               | their users. Then, when lib_coolnew_pos has a bug, it
               | only requires rebuilding the two apps linked to it, and
               | not necessarily even then if those applications don't
               | expose the bug.
        
             | nequo wrote:
             | > Dynamic linking served us when OS upgrades came
             | infrequently, user software was almost never upgraded
             | 
             | Even today, dynamic linking is not only a security feature
             | but also serves convenience. A security fix in OpenSSL or
             | libwebp can be applied to everything that uses them by just
             | updating those libraries instead of having to rebuild
             | userland, with Firefox, Emacs, and so on.
        
             | chaxor wrote:
             | I'm not versed in this, so apologies for the stupid
             | question, but wouldn't statically linking be _more_ secure,
             | if anything? Or at least have potentially better security?
             | 
             | I always thought the better security practice is statically
             | linked Go binary in a docker container for namespace
             | isolation.
        
           | jhallenworld wrote:
           | >A linker typically only includes the parts of the library it
           | needs for each binary so some parts will definately have many
           | copies of the same code when you statically link but it will
           | not make complete copies.
           | 
           | Just to add to what you said: in the old days the linker
           | would include only the .o files in the .a library that were
           | referenced. Really common libraries like libc should be made
           | to have only a single function per .o for this reason.
           | 
           | But modern compilers have link time optimization, which
           | changes everything. The compiler will automatically leave out
           | any items not referenced without regard to .o file
           | boundaries. But more importantly, it can perform more
           | optimizations. Perhaps for a given program a libc function is
           | always called with a constant for a certain argument. The
           | compiler could use this fact to simplify the function.
           | 
           | I'm thinking that you might be giving up quite a lot of
           | performance by using shared libraries, unless you are willing
           | to run the compiler during actual loading.
           | 
           | Even without lto, you can have the same results in C++ by
           | having your library in the form of a template- so the library
           | is fully in the /usr/include header file, with nothing in
           | /usr/lib.
        
           | rwmj wrote:
           | You should be keeping track of those library dependencies
           | anyway if you want to know what you have to recompile when,
           | say, zlib or openssl has a security problem.
        
             | ithkuil wrote:
             | Well, you have to do that anyways
        
           | giljabeab wrote:
           | Can't file systems de dupe this now
        
         | bzzzt wrote:
         | I know lots of compilers/linkers don't optimize for it but it
         | should be possible to 'tree shake' libraries so only the parts
         | that are used by an application are included. That would shake
         | off a lot of the 'bloat'.
        
           | volemo wrote:
           | Wait, it's not being done?
        
             | dieortin wrote:
             | It is, major compilers do that by default
        
             | Fronzie wrote:
             | As far as I know, even with LTO, it requires -ffunction-
             | sections -fdata-sections in order to strip out unused
             | functions.
        
         | Gabrys1 wrote:
         | I guess each of the copies of libc can be optimized away and
         | only the functions the specific binary calls will be left (and
         | the compiler should be allowed to optimize past the library
         | boundary), so maybe this balances the issues a bit.
         | 
         | Not that I really know anything about it, ask jart
        
         | Gazoche wrote:
         | I'll take bloat over dependency hell every day of the week.
         | Feels like every single app is a bundled web browser these days
         | anyways.
        
           | palata wrote:
           | > dependency hell
           | 
           | Dependency hell comes from bad dependencies that don't do
           | semver properly. Choose your deps carefully, and that's
           | perfectly fine.
           | 
           | > Feels like every single app is a bundled web browser these
           | days anyways.
           | 
           | Yep, that's apparently the best way to use the bad libraries
           | people want to use and not give a damn about semver.
        
             | hn_go_brrrrr wrote:
             | Semver is nearly impossible to do "properly" because of
             | https://xkcd.com/1172. With a sufficient number of users,
             | all bug fixes are breaking changes. If the behavior can
             | possibly be observed in any way, some user will be
             | depending on it, deliberately or otherwise.
        
               | Ar-Curunir wrote:
               | Semver defines what is breaking and not-breaking. E.g.,
               | Rust semver says that "code should continue compiling
               | with a minor version bump, but not necessarily for a
               | major version bump"
        
               | steveklabnik wrote:
               | Yes. The very first line of the spec:
               | 
               | > Software using Semantic Versioning MUST declare a
               | public API. This API could be declared in the code itself
               | or exist strictly in documentation. However it is done,
               | it SHOULD be precise and comprehensive.
               | 
               | If it's not in the API, it is not bound by the rules.
               | Many ecosystems come up with various norms, like Rust
               | has, to help guide people in this. But it's almost
               | certainly not a semver violation to make the change
               | described in the XKCD because "handle unknown unknowns"
               | is not possible. That doesn't mean that we should throw
               | out the entire idea of software assisted upgrades to
               | dependencies.
        
               | palata wrote:
               | I would argue that https://xkcd.com/1172 is a case where
               | the user "deserves" the breaking change, because they
               | relied on a hack in the first place.
               | 
               | That's the thing: I feel like people tend to call
               | "dependency hell" what I would consider downright
               | malpractice. "Shared libraries don't work because they
               | require good practice" is, IMO, not a good argument
               | against shared libraries. If you need to design your tool
               | with the constraints that "users will use it wrongly",
               | then it's already lost.
        
               | dwattttt wrote:
               | Semver doesn't stop people from depending on
               | unstable/implementation-specific behaviour; it needs to
               | be coupled with a strong mechanism for defining what
               | behaviour is defined by an API, and the result is that
               | "the bug" is with all those users who depend on un-
               | guaranteed behaviour.
               | 
               | The breaks happen regardless, but you have a principled
               | way of defining whose fault/problem it is.
        
           | nerpderp82 wrote:
           | Dynamic Library hell is why Docker exists. If operating
           | systems had less global state and less ambient authority, our
           | systems would be vastly more tractable. Instead we still
           | create environments that look like replicas of whole hosts.
           | 
           | Might as well go all in and use something with pervasive
           | virtualization like Qubes.
           | 
           | https://www.qubes-os.org/
        
             | palata wrote:
             | To be fair, QubesOS does not really solve the problem of
             | bad libraries creating dependency hell. If you need to ship
             | _every app_ with its own rootfs because you can 't handle
             | dependencies, then you will have to do that on QubesOS as
             | well (you don't want one VM per app).
             | 
             | Also the biggest problem I had with QubesOS is that it
             | doesn't support GPU (for security reasons). It feels like
             | that was a big cause for the reduced performance. I wish
             | there was a solution for the GPU, and then I would love to
             | daily-drive QubesOS.
        
             | IshKebab wrote:
             | Exactly this. Windows apps aren't distributed as Docker
             | images. Guess why...
        
         | jacquesm wrote:
         | Not necessarily. Bloat is one reason why originally dynamic
         | linking was rolled out but the bigger benefit (to
         | manufacturers) was to be able to update libraries without
         | updating the applications. This has been the source of much
         | trouble (dependency hell) and statically linked binaries suffer
         | none of these issues. It's not like every application uses all
         | of every library and an efficient linker is able to see which
         | parts of the library it needs to link and which parts it can
         | safely leave out.
        
         | arghwhat wrote:
         | Static linked binaries are a generally _lot_ smaller than a
         | dynamically linked library and its dependencies, especially
         | with link-time optimizations and inlining.
         | 
         | You wouldn't want have 100 tools statically link the entirety
         | of chromium, but for normal C library sizes you don't get
         | bloat. The preference for dynamic libraries in Linux distros is
         | just so they can roll out patch updates in one place instead of
         | rebuilding dependents.
        
           | marwis wrote:
           | But dynamically linked library only needs to be loaded to RAM
           | once whereas with static linking you'd be loading the same
           | code many times (unless you compile everything to single
           | binary like BusyBox). This also gets you better cache
           | utilization.
           | 
           | Also I think inlining would typically increase the total size
           | of output rather than decrease it.
        
             | jhallenworld wrote:
             | So you only need to load duplicated code for each different
             | statically linked program. If there are many processes
             | running the same program, they will all share the same
             | physical pages for the code. So for example, having 100s of
             | "bash" instances running does not use that much memory.
             | 
             | You can see this by running "pmap <pid> -XX" (the output is
             | very wide- probably load it into an editor). Look at the
             | shared vs. private pages.
             | 
             | Also: There is another way to automatically share pages
             | between different programs: de-duplication. This would
             | require common libraries to be statically linked on page
             | boundaries. The OS would quickly de-duplicate during
             | loading by hashing the pages. VMs use this technique to
             | increase effective memory when there are many guest OS
             | running.
        
               | marwis wrote:
               | Yes but most processes are unique. The only bash process
               | I have running is my interactive shell.
        
         | javierhonduco wrote:
         | Once it's loaded in memory, if Kernel Samepage Merging is
         | enabled it might not be as bad, but would love to hear of
         | somebody has any thoughts https://docs.kernel.org/admin-
         | guide/mm/ksm.html
        
           | LegionMammal978 wrote:
           | From the link:
           | 
           | > KSM only merges anonymous (private) pages, never pagecache
           | (file) pages.
           | 
           | So it wouldn't be able to help with static libraries loaded
           | from different executables. (At any rate, they'd have to be
           | at the same alignment within the page, which is unlikely
           | without some special linker configuration.)
        
             | javierhonduco wrote:
             | Had completely missed that line -- great point!
        
       | peter_d_sherman wrote:
       | I've added links to the below quote:
       | 
       | >"oasis uses _smaller and simpler_ implementations of libraries
       | and tools whenever possible:
       | 
       | musl instead of glibc (https://www.musl-libc.org/)
       | 
       | sbase instead of coreutils
       | (https://git.suckless.org/sbase/file/README.html)
       | 
       | ubase instead of util-linux
       | (https://git.suckless.org/ubase/file/README.html)
       | 
       | pigz instead of gzip (https://zlib.net/pigz/)
       | 
       | mandoc instead of man-db (https://mandoc.bsd.lv/)
       | 
       | bearssl instead of openssl (https://bearssl.org/)
       | 
       | oksh instead of bash (https://github.com/ibara/oksh)
       | 
       | sdhcp instead of dhclient or dhcpcd
       | (https://core.suckless.org/sdhcp/)
       | 
       | vis instead of vim or emacs (https://github.com/martanne/vis)
       | 
       | byacc instead of bison (https://invisible-island.net/byacc/)
       | 
       | perp and sinit instead of sysvinit or system 44
       | (http://b0llix.net/perp/ https://github.com/wereHamster/perp
       | https://troubleshooters.com/linux/diy/suckless_init_on_plop....)
       | 
       | netsurf instead of chromium or firefox (https://www.netsurf-
       | browser.org/)
       | 
       | samurai instead of ninja
       | (https://github.com/michaelforney/samurai)
       | 
       | velox instead of Xorg (https://github.com/michaelforney/velox)
       | 
       | netbsd-curses instead of ncurses (https://github.com/sabotage-
       | linux/netbsd-curses)"
       | 
       | (Oh, and not to quote Dwayne "The Rock" Johnson's character
       | "Maui" from Disney's Moana or anything -- but _" You're
       | welcome!"_ <g> :-) <g>)
        
       | malux85 wrote:
       | Anyone have a link to the QEMU tarball in the README? It is
       | hosted on a private server and it looks like it's been HN hugged
        
       | lordwiz wrote:
       | Interesting, Like how its focused on making it lean by having
       | less bloated versions of the tools
        
       | schemescape wrote:
       | Does anyone know how big the base installation is? I couldn't
       | find an answer anywhere, and the link to the QEMU image appears
       | to be broken, currently.
       | 
       | I'm curious how it compares to, say, Alpine with a similar set of
       | packages.
        
         | jackothy wrote:
         | I have an old (2020) .qcow2 lying around that's about 360MB
        
           | xiconfjs wrote:
           | could you please upload it?
        
             | elfstead wrote:
             | https://elfstead.com/archive/oasis-qemu.tar.xz
        
       | notfed wrote:
       | > Fast builds that are 100% reproducible.
       | 
       | It's unclear to me what "100%" refers to here, but surely it does
       | not include the Linux kernel or drivers? (I've recently read
       | conversations about how difficult this would be.)
        
         | hn_go_brrrrr wrote:
         | Got a link? Sounds interesting.
        
         | azornathogron wrote:
         | I'm no expert, but as an interested amateur I thought the Linux
         | kernel could already be built reproducibly?
         | 
         | There is some documentation at least... and I know several
         | Linux distributions have been working on reproducible builds
         | for a long time now - I'd be surprised if there hasn't been
         | good progress on this.
         | 
         | https://www.kernel.org/doc/html/latest/kbuild/reproducible-b...
        
           | dayjaby wrote:
           | In container context I've heard a definition of "100%
           | reproducible" that means even file timestamps are 100% the
           | same. Like your entire build is bit-by-bit precisely the same
           | if you didn't modify any source.
           | 
           | Not sure if that's what they mean here.
        
       | speedgoose wrote:
       | BearSSL development's seems to have stopped and it's lacking
       | TLS1.3. Are there promising alternatives?
        
         | asmvolatile wrote:
         | wolfSSL. Open source, widely used, flexible licensing model,
         | TLS + DTLS 1.3 support, support for all modern ciphers and
         | protocol extensions, extremely tuneable for performance/size,
         | FIPS module, excellent customer support, the list goes on....
        
       | jollyllama wrote:
       | Anyway, here's wonder -Wall
        
         | notnmeyer wrote:
         | this is funnier than it has any right to be
        
       | sylware wrote:
       | For a real statically-linked linux system, the main issue is GPU
       | support: you must relink all apps _really using_ a GPU, that to
       | include the required GPU drivers.
       | 
       | With sound, alsa, it is fine since there is IPC/shared-memory
       | based mixing that whatever the playback/capture devices
       | [dmix/dsnoop]. Static linking is reasonable. (pulseaudio[012] IPC
       | interfaces are bloaty kludges, hardly stable in time, 0..1..2..,
       | not to be trusted compared to the hardcore stability of alsa one
       | able to do a beyond good enough job *and* _real_ in-process low
       | latency hardware access at the same time).
       | 
       | x11 and wayland are IPC based, then no issue here neither.
       | 
       | But for the GPU, we would need a wayland vulkan3D-inspired set of
       | IPC/shared-memory interfaces (with a 3D enabled wayland
       | compositor). For compute, the interfaces would be de-coupled from
       | the wayland compositor (shared dma-buffers).
       | 
       | The good part of this would be to free our system interfaces from
       | the ultra complex ELF (one could choose an excrutiatingly simple
       | executable file format, aka a modern executable file format, but
       | will need compilers/linkers support to help legacy support).
       | 
       | There is a middle ground though: everything statically linked,
       | except the apps requiring the GPU driver (for that ELF is
       | grotesquely overkill), still provided as a shared library.
        
         | stefan_ wrote:
         | To be fair ELF is complex mostly because of relocations, which
         | are not purely to support shared libraries but also the
         | nowadays ubiquitous PIE. But GPU drivers is a good point; I
         | don't believe you can even statically link them today, you
         | would only be statically linking a shim that tries to find the
         | real driver at runtime.
        
           | sylware wrote:
           | I am exploring an executable file format of my own
           | (excrutiatingly simple, basically userland syscalls) which is
           | only PIE, and until now, the main real "issue" (not really)
           | is actually the lack of support from compilers for static
           | relative global data init (handled by ELF... which is not
           | there anymore).
           | 
           | About the shared libs, well, they are the utility shared
           | libs, and the system interface shared libs. With a mostly
           | statically linked elf/linux distro, all the utility libs
           | would be statically linked, and the system interface shared
           | libs would be statically linked if they have an IPC/shared-
           | mem interface. In the end, only the GPU driver is an issue,
           | namely would stay a shared libs.
        
         | AshamedCaptain wrote:
         | I ponder which kind of malaise would push one to dismiss ELF as
         | "ultra complex" and at the same time propose pervasive IPC
         | through the entire system including Vulkan calls through IPC.
        
       | m463 wrote:
       | How big is it?
       | 
       | I could imagine there were unexpected efficiencies. Although
       | dynamic libraries should be able to share an address space, I
       | think with static libraries, the linked might strip out unused
       | routines.
       | 
       | also, it might be faster
        
       | alexnewman wrote:
       | Now I just need them to switch to GitHub actions for the ci/cd
        
       ___________________________________________________________________
       (page generated 2024-01-26 23:00 UTC)