RFC: Allow runtime configuration of `XXX_jll` packages.
Consider the following real example:
I have a binary dependency libFoo that that can be linked in the following ways:
- against
libglew.so+libGL.so(hardware-accelerated, typical for a desktop environment) - against
libglewosmesa.so+libOSMesa.so(software rendering fallback) - against
libEGL.so+libglewegl.so+libOpenGL.so(hardware-accelerated, headless) (As you probably guessed,libglew{egl, osmesa}.sois just GLEW linked against each graphics backend)
Downstream, there is a Foo.jl which depends on Foo_jll. Ideally:
(1) Users could (optionally) specify which configuration to use (e.g. with an ENV variable).
(2) If a backend fails to load, a set of fallbacks is considered.
For (1), my first thought was to extend the definition of platforms (e.g. Linux <: Platform) to include ENV variables e.g.:
platforms = [
Linux(:x86_64, envflags=(GLBACKEND="EGL", OPTION2="A")),
Linux(:x86_64, envflags=(GLBACKEND="GL", OPTION2="A")),
Linux(:x86_64, envflags=(GLBACKEND="EGL", OPTION2="B")),
Linux(:x86_64, envflags=(GLBACKEND="GL", OPTION2="B"))
]
This could correspond to ENV variables like "FOO_JLL_GLBACKEND" that would be exposed in the build script and that could be set by the user. Similarly, this would generate wrapper files like x86_64-linux-gnu-EGL-A.jl.
Another option that @giordano and I discussed was to create a *_jll package for each configuration. Following the above example, we would have:
GLEW_GL_jll,GLEW_EGL_jll,GLEW_OSMesa_jllFoo_GL_jll,Foo_EGL_jll,Foo_OSMesa_jll
It is unclear how one would actually choose amongst these at runtime. As @giordano pointed out, this relates to the discussion in https://github.com/JuliaLang/Pkg.jl/issues/1285. My other concern is that this would lead to a fair bit of code duplication and a plethora of *_jll packages.
As for (2), that seems a bit more difficult and perhaps not as necessary, but may constrain the design of (1) so I included it here anyways.
I think these are all good questions, and something we'll need eventually. At the moment, the closest thing to this that we have so far is the MKL.jl package and ArpackMKL.jl. It's not that great, but it does kind of work. You can do stuff like
glbackend = get(ENV, "GLBACKEND", "GL")
if glbackend == "GL"
using GLEW_GL_jll
elseif glbackend == "EGL"
using GLEW_EGL_jll
else
error("Must provide a value GLBACKEND value!")
end
Then, in your __init__() method, you would check that it still matches, to avoid stale values:
function __init__()
if glbackend != get(ENV, "GLBACKEND", "GL")
error("GLBACKEND has changed! Force recompilation of this package somehow!")
end
end
Of course it would be better if this wasn't environment-variable-based, but was instead based on a file or something, to avoid unnecessary cache invalidations.
Thanks for circling back to this! Yeah I imagine it'll become more clear what "jll 2.0" will look like after more usage.
For my case, your suggestion actually works pretty well! I'd be loading GLEW_EGL_jll only on headless machines, so the DISPLAY variable shouldn't be changing too often :)
I think this could now be achieved (well, at least if you are OK with requiring Julia >= 1.6) via augment_platform!, see https://docs.binarybuilder.org/stable/reference/#BinaryBuilder.build_tarballs plus examples here in Yggdrasil
See also https://pkgdocs.julialang.org/v1/artifacts/#Extending-Platform-Selection for much more detailed information (perhaps the BinaryBuild docs should have a link to that?)