A Tale of a Shared Library
This a tale of a shared library that was meant not to be born. Once upon a time, there was a static library named sline, mostly developed by a young lady… namely me… It was written and designed as that, as a static library… and the Readme file even stated that no support for a shared library was planned… until, one day, it became a shared library. So… what happened? Why did that young lady change her mind?
TL;DR: Reality hit hard because I was stubborn. Damned be reality!
I sort of explained this in a post on the sline-devel mailing list, but not in great detail. I believe mailing lists should provide information in a way that makes projects move forward. All I felt I needed to clarify there was that sline was going to also provide a shared library and that this came to be because I learned from a user who had stumbled upon a bug in cras, another project of mine that uses sline… But that bug had already been solved in sline!
And no, that’s not the user’s fault. The resurrection of that old bug was made possible due to sline being a static library. Updating sline to its latest version only updated the library, but all programs that use the library would remain untouched… precisely because sline was a static library only at that point.
“That user should’ve known better!” No, this is the dev’s (= me) fault. Think of this for a moment…
First, the user is not thinking about sline; they were thinking about cras… because that’s the piece of software facing users. Libraries face developers and other code, not users. So, even if that particular user was tech-savvy and did think the bug could lie in sline, they defaulted to cras… which makes sense as an initial guess.
Second, and I say this with lots of gratitude in my heart, my software is packaged in various places. I’ve been reached by people wanting to package my projects for their distros of choice… I always avoid getting in the way of packagers, because I truly believe there’s nothing worse than a developer trying to influence downstream… so I genuinely don’t even know whether the packages are or aren’t up-to-date of if they were when this happened. Let’s assume both cras’s and sline’s packages were up-to-date when this “zombie bug” rose back from the dead.
What does it mean that a package is up-to-date? It might many different things depending on whether you’re on Debian stable or on a bleeding/cutting-edge1 rolling release, but let’s assume the packaging policy of that user’s distro tracks the latest stable releases of my projects.
sline being a static library made it a make-dependency or build dependency. You could even remove the package and none of the dependent software would be affected… because it’s a static library; its code is embedded into the binaries. And there lies the main issue here; if the library gets a new release, no matter what changed, all dependent packages should be rebuilt, even if it’s just to be recompiled against the new library. And if we’re talking ports-like systems like the AUR or others… will the user be aware of the need to do that?
It’s not that it’s unfeasible… but hey… this is super annoying if you’re a user.
That’s why I told you before that reality hit me hard. My dear, let me tell you this: I never expected anyone use my software, yet I do release it… so as soon as I released it, my software having users is a possibility! When you’ve got users, they may critically depend on what you release or may just be toying around with a project they feel is fun… In any case, the reality there is that you’re no longer alone… All of a sudden, your code is out there… in the wild.
Meaning that like it or not, idealism gets sadly in the way of everyone.
Yep, idealism. I was blinded by an ideal that would be great but can be harmful to users. Yes, statically-linked systems or projects are super fun… until you realize you might be shifting some of your burden as a dev to your users… And why should they do the work?
It is true that there are lots, and lots, and lots of unfounded urban legends about dynamic linking being some sort of the Holy Grail of modularity in OS and that they bring on many, awesome, and great benefits that should put the nail in the coffin of static linking, right? No, most of the “advantages” are not there; all you’re doing is kicking the bucket of symbol resolution2 down the road into run-time. I talked more about this on this earlier post of mine.
But! That’s precisely the goal, isn’t it? To have programs look up symbols at run-time, so the implementations of those symbols have a life-cycle of their own. And yes, that means we want the ability to safely modify library code avoiding to rebuild the programs that use that code. That ability, to modify code, is precisely the whole shebang! Not binary size, not security, nothing like that.
Some people see shared libraries as harmful. OK, yeah, cat-v is a very weird… what are they, actually? That’s a great question, to be honest, because I’m not sure at all if they’re a group, a project, someone pretending to be a group, who knows. I know they’re such an extremist site (maybe that’s the most neutral and accurate way to portray them) that their arguments are pretty laughable at. But my point is that yes, there are people who’d like to see the world only work with static libraries in the name of minimalism.
However, and I myself like minimalism… but… minimalism depends so much on the eye of the beholder, doesn’t it? I’m pretty sure KDE Plasma fans see GNOME Shell as “way too minimalist” for their taste… while nobody in the “minimalist scene” would think of including GNOME Shell in their lists of “minimalist software.” What is minimalism? You tell me… I can tell you my idea of minimalism… in a future post, of course.3
And there we get to the very heart of the problem: Echo Chambers. You see: One major reason why I didn’t want sline to become a shared library was just out of trying to be super minimalist and do things in a way that is “different, free, unconventional…” I had went down a rabbit hole of blindly following other people’s ideas posted online in grandious words when I should’ve thought on what my own views are… I consumed way too much of certain opinions which I may agree with on many things, but why should I agree on everything and then make my life miserable? The liberation that comes from realizing this and just doing whatever you truly feel will help others or make your project interesting is awesome, to be honest.
Hey, don’t get me wrong: a static-only release makes a hell of sense when you’re testing out stuff,4 like you being at the early stage of a project… But as soon as you’re trying to make something where you care about users, how to deploy the library onto systems, etc… Reality hits you and you might be the hippest, most glamorous, gorgeous Lady of C in the FOSS world…5 but something will break because you tried to do things “differently…”
Is doing things differently a bad thing per se? No, of course not! Hey, I think I’ve got a bit of real life experience in that? 😉 But the thing is that you somehow need to make it make sense to the rest of the world… or decide to create a new world of your own,5 namely a new Linux distro built from scratch that works under totally different premises than the rest; NixOS is one interesting example of this. It all boils down to what you’re trying to do.
But trying to break expectations while also trying to make things in the way users expect… Well… You see the contradiction there, right? I didn’t for months…
You always learn something new along the way. That’s where the fun is. Now I want to focus my efforts on scalc, though. I feel it needs to grow. Not sure how, though; I’ve got a couple of vague ideas, but who knows. What I definitely need is to close the sline book for a while; VT100 code and Unicode were two very hard nuts to crack… and while fun, I need to switch to the original project that launched all of this in the first place… What a ride!
While writing this I went on a tangent and looked up the difference between both terms and… I wish I didn’t do so 🤣 So, at least for me, cutting-edge is less extreme than bleeding-edge. Using Arch as an example, cutting-edge would be not using any of the testing repos (namely, using the latest stable versions of things)… and bleeding-edge would be using those testing repos. Not sure if you’d agree on this with me? Let me know! ↩︎
Actually, not all of it. You surely know that at compile-time, you need shared libraries to be located and provide the symbols you invoke from them… Dynamic loading, on the other hand, is the way to totally forget about symbol resolution at compile-time. ↩︎
And no, GNOME Shell isn’t minimalist for me… just to be sure! ↩︎
I’ve found out that it eases setting up a testing binary a lot. sline includes a small testing utility which compiles against the static library, never the shared one… because that way I can avoid dealing with arcane
rpathstuff or environment libraries needed when you’re trying to dynamically link to a shared library in a path not used by the linker. The static library is infinitely more practical for doing stuff that is meant to live inside the development tree and not used in production. ↩︎