One thing I'm missing in the Rust ecosystem of bindings to C libraries is easy conditional compilation based on the build-time library version. Something like the GTK_CHECK_VERSION() macros in C.

In Rust bindings, it's common to expose some baseline version API, then have feature flags to expose (and depend on) newer versions of the library. But there's no simple way to do, as a downstream user:

#[cfg(have_gtk_4_12)]
use_new_api();
#[cfg(not(have_gtk_4_12))]
fallback_with_old_api();

#rust

Related: how do distros track these build-time dependency checks? E.g. my app did a build-time check and used the GTK < 4.12 code path, then the distro updated GTK to 4.12, so now my app needs to be rebuilt to take advantage of the new API. How is this tracked?

I guess this question is more relevant for rolling-release distros, but it's very possible for a build-time check to test for a minor version which would be updated even in a non-rolling-release distro.

#linux #fedora

@YaLTeR well, I suppose they put gtk as a dependency of the program, and then they rebuild all its dependents, although probably it's not quite as simple as I'm thinking here. I can totally imagine, for example, arch, doing that

@esoteric_programmer I'd expect the opposite, i.e. dependencies aren't tracked this precisely, and updates to shared libraries never cause a rebuild of their dependents. Doing otherwise will lose much of the benefit provided by shared libraries. Also, if rebuilding dependents was a common practice, there wouldn't be such backslash against statically linked languages like Rust and Go.

@YaLTeR

@minoru @YaLTeR well, either that or soname stuff would be done to keep the program running, because if it's linked against a specific gtk version and that's no longer in the filesystem, things can break. And yeah, I'm imagining something like this happening because the rust and go model popularized this practice, but yeah, probably not.
@YaLTeR It is traditionally handled via shared libraries, and not having such static version-checks at all. That approach is going out of fad, especially in the Go/Rust eco-systems, which lead to Debian not covering Go/Rust with generic security support because the only way to fix it is to rebuild tons of packages. This is clearly not sustainable. Debian’s preference has been for Rust/Go to switch to shared libraries, but I think that effort is mostly lead by non-Go/Rust people.
@jas the problem I'm talking about is orthogonal to shared vs. static libraries
@jas actually you could even say it's *more* relevant when using shared libraries
@YaLTeR If you assume shared libraries, such build-time static checks doesn’t make sense do they? You need to make runtime-decisions, because at build time you don’t know which shared library will be used. And if you do runtime-checks, things ought to work regardless of version, and distributions doesn’t have to track this in any way. Still, there is a lot of hidden complexity (and source for weird bugs) with conditional code like this.

@YaLTeR @jas If you built the application with an older version of the library and it was working, this behavior is maintained, isn't it? It still uses the fallback as before.

Removing the fallback from the library would change the ABI, and soname would change, then package deps would no longer be satisfied, so a rebuild would be needed.

What you are asking for is runtime detection, which you'd need to know in advance and handle with dlopen.

Why does it sound like yet another Ubuntu problem?

@wolfpld @jas currently I have a more of a "call this new function that enables a new feature if library version is new enough to have the function, no other difference" case. While I can use dlopen() for this, it feels brittle to do it just for this one function, when I already properly dynamically link to the rest of the library. So I went with a build-time version check. Meaning that if a distro updates the library without rebuilding my app, the app won't get the new feature yeah
@wolfpld @jas a more complex case would be something like Ghostty which uses new Adw widgetry as the respective Adw versions are detected at build time. That's a whole set of new functions, I imagine would be annoying to dlsym and thread pointers everywhere
@YaLTeR, Nix and Guix handles this by rebuilding dependents whenever one of their dependency changes.
@cnx even on minor bumps?
@YaLTeR @cnx
Of course, even when one bit changes.
@YaLTeR @cnx Yep! Their deal is that builds must be reproducible and deterministic. Nix flakes often lock dependencies down to their source files' hashes.
@YaLTeR
openSUSE Buildservice rebuilds all dependent packages in this case. Making Tumbleweed allways consistent.
@vyskocilm even on minor bumps?
@YaLTeR
Yes, gtk 4.11 -> 4.12 would trigger the rebuild of all dependent packages in Tumbleweed.
@YaLTeR In Gentoo it is handled by subslot dependencies. When a dependency is updated to a higher subslot, the dependents that specify a subslot dependency are rebuilt.