Meson Features and Packaging

drobilla.net

Recently, I have been porting all of the software I maintain to meson. For the most part, this has been a nice improvement. Meson strives to be a generally sensible and coherent build system that addresses the needs of both upstream developers and packagers, and it shows. It isn't perfect (like all software), but it's a pretty big improvement over what came before in many ways.

One disagreement has come up, however, and I think it - at best - betrays a misunderstanding of meson feature options, and - at worst - threatens to effectively destroy their utility entirely for no good reason. This disagreement originates from arch-meson, which adds --auto-features=enabled by default. This isn't technically wrong, but it's problematic at scale. To explain why, I first need to explain how meson feature options work.

Meson feature options are a better solution to the --enable-this and --disable-that style options of autoconf and similar. They make all the possible states of a feature clear and explicit. Those states are:

The default value for an option can be any of the three, and is given by the developer in the option definition. This is a better system because there are three states with clear meanings. They allow the builder to:

Each of these states (and desires) are distinct and, importantly, their definitions are not conditional. There is no "unless" in the definition of disabled or enabled, and adding one would destroy their utility. It's not "enabled unless someone feels like it's fine to disable", it's just "enabled".

Concretely, for enabled in particular, this means that, as a builder of whatever meson project, you can:

meson setup build -Dsomething=enabled

Then, you know that if configuration succeeded, the something feature is enabled. This is important. It is also the only way to reliably/mechanically ensure that a build contains a feature. "Destroying" it (as something meson users can generally expect) would therefore mean that there there is no way to ensure that a build contains a feature in general. Surely everyone - especially packagers - can agree that's bad.

Hopefully that's a decent enough explanation of why meson feature options are a good, coherent, and reliable system.

What's the problem then? Well, there is that convenience option, --auto-features=enabled, which enables all features for convenience. This allows the builder to override the developer-chosen defaults, and force the build script to be explicit about all non-enabled features. This is, again, not technically wrong, and is indeed convenient at times.

The problem is more of a social one. Because Arch chose to make this the default (unlike most other distributions, as far as I can tell), people have apparently adopted the mentality that --auto-features=enabled not building is an upstream bug. It isn't. The shorthand --auto-features is just that - a shorthand for enabling all features. It is equivalent to explicitly enabling every feature independently, so doing so is quite literally asking for the build to fail if any feature is not present.

Where this gets weird is when features seem unlikely, or even impossible, to build on a given system. The bug filed against my project was about Cocoa on Linux. I get it, Cocoa is mostly a MacOS thing, and is almost certainly unavailable elsewhere, but my argument is that this doesn't matter at all. Even if it were literally impossible for Cocoa to exist on top of, say, FreeBSD somewhere (which it isn't, and cross-compiling is a thing anyway), it still wouldn't matter. A similar case can be made for optional dependencies that are not publicly available at all (something I have done in the past). Feature options working as expected in general is much more important than any of this subjective case-specific thinking.

"This doesn't work for me, so the package should not build when this feature is enabled" is not a good argument, regardless of why it doesn't work. It doesn't matter if you imagine a feature "can't" be built on some system (anyone who has been in this game long enough should be able to see where that slippery slope leads...). The power of feature options depend on the states meaning just what they say, and making enabled sometimes effectively equivalent to auto destroys that power. There's not really any point in using features at that point, you might as well just use a boolean flag.

Put another way, the proposed "fix" here would make it so that:

meson setup build -Dsomething=enabled

Can successfully configure, but without the something feature being included. Et voila, we've made the feature states effectively meaningless. That would be a bug, and letting this mentality take over would resign us back to manually wading through logs to see if what we asked for actually happened.

It's also worth noting that feature options are deeply integrated all over the place in meson, for example, you can pass them to as "required" parameters and the right thing will happen. Diluting the meaning of enabled would cause deeper problems than the builder-visible ones explained here. What does it even mean for a feature to be enabled, except not actually enabled, when that feature status is being used to dictate that another dependency is required? Everything falls apart. The feature option system, when used as intended, is designed well, but messing around with the meaning of enabled like this ruins it. I don't think it's hyperbole to say it "destroys" the whole thing: it turns a sensible and coherent system into some confused boolean, which is both objectively less powerful, and, well... confusing.

This may seem trivial when you're zoomed in to a single project or handful of options, but globally it is a much bigger deal than it might seem at first. Even in my relatively tidy third-party source directory, there's nearly a thousand meson options. I can't imagine how many there are globally. The basic way that features work can't depend on the builder understanding details about every single option, that would be a complete disaster. It is crucial that disabled and enabled mean exactly what they say, always.

I have never seen this problem come up from a user configuring the project themselves. Presumably, people realize that explicitly requesting a potentially failed build, then complaining that it did what they ask, is... rather silly. This gets obscured when a tool (arch-meson) does it automatically, but remains just as silly. It makes no difference from the perspective of a meson package or its maintainer: by enabling all features, the builder has explicitly requested ignoring the defaults and failing to build if any feature was not present.

Yet, here we are, with upstream developers getting "bug" reports for feature options working exactly how they are supposed to work. This, unfortunately, means that Arch is putting toxic pressure on the meson ecosystem, pushing upstream developers to make things objectively worse.

I don't know what the solution to that is, and I'm not an Arch developer (though I'm typing this on an Arch-derived distribution and have nothing in particular against it). Breaking all the existing packages that use arch-meson is probably not going to happen, but perhaps improving the documentation would be good enough.

All I know is that --auto-features=enabled not building is very definitely not a bug. Quite the opposite, that is literally the whole point of feature options. If there's something out there that's leading people to thinking that enabled features not building is a bug, then it is misleading people in a bad way, and needs to be fixed.