On the LV2 Stack, Dependencies, and Incrementalism

drobilla.net

For quite a while now, I've been working on new major versions of the LV2 host stack (serd, sord, sratom, suil, and lilv) while maintaining the current stable versions. Mainly this is a task of trying to push as many changes back as I can, without actually breaking any APIs. Aside from the usual bug fixes and code improvements, this includes a lot of build system, tooling, and general quality control improvements. This keeps the divergence low, so it will be easier to go back and do maintenance on the old versions where necessary.

At this point, this process is almost done: everything uses meson now, has a consistent QC regime (high-coverage testing, multi-platform CI, strict compiler warnings, machine formatting, clean clang-tidy configurations, and so on), most long-standing issues are fixed, and I'm finally starting to run out of changes that I can do without finally breaking the APIs and releasing new major versions.

It recently occurred to me, though, that there's one more incremental thing I can do here before "ripping the band-aid off", so to speak. In typical low-level C hacker fashion, I have some things that I just copy around piecemeal from project to project as necessary. One of those is zix, a simple library of basic data structures and portability wrappers. This has existed for over a decade, but I have never released it as a "proper" library. More dependencies, more problems, but copy-paste code reuse certainly isn't without its own problems. In this case, I have three projects that use it: sord, lilv, and jalv (and some other developers have discovered this and taken bits for their own purposes as well). This has been troublesome from time to time when bugs need fixing, and depending on how pedantic you are, might technically be considered a violation of some distributions' policies (notably Debian's).

Meanwhile, the lack of a common lowest-level dependency for this kind of very boring and generic stuff (something like the role that glib plays in that ecosystem) has proven increasingly problematic. There is some sketchy code around that exists solely to work around this "missing" dependency, and still some questionable use of things to skirt around missing facilities (for example, jalv has no mutexes). With the new versions I have in the pipeline, this problem becomes more acute for several reasons, so I've decided to release zix and depend on it as a proper released and versioned library, like all the others.

This is something that can be done before the new versions though, and, like all of the above tooling/etc improvements, I think it's best to do as much as possible on the current versions before replacing them, because that process will be painful enough as it is. My thinking originally was to not add any more libraries until I can take advantage of the solid "subproject" abilities of meson and wrap everything up into a single "lv2kit" to decrease the maintenance and packaging burden, but now I'm realizing that this isn't very realistic. For one, it's weird, and weird is bad. For another, it wouldn't really reduce packaging overhead, since distributions would surely want to package the individual libraries separately anyway. The lv2kit idea is still a goal, but pragmatically, I think it's best to just continue on in the good old "shotgun blast of little libraries" way and deal with that later.

Concretely, that will look like this:

serd <--\--- sratom
         --- sord --- lilv --- jalv
zix  <--/------------/--------/

That is, zix will become a thing, and sord, lilv, and jalv will gain it as a dependency. This will let any issues with packaging or subprojects or whatever get ironed out, without changing any of the APIs that LV2 hosts use directly whatsoever.

... and that, I think, is the last non-trivial thing I can do without rocking the boat, before the fun part where I finally get to change whatever I want in these APIs I hastily banged out over a decade ago now, and never intended to live this long in the first place. The dependency tree may get a bit more complicated, but a whole bunch of other things are going to get wildly simplified in exchange, which seems like a pretty good deal to me.