Preferences
Since Julia 1.6 Preferences.jl
allows packages to declare options/preferences that the user can set on a per project
level.
Preferences are read and written from Julia with the Preferences.jl package.
module MyPackage
using Preferences
const favorite_icecream = @load_preference("icecream", "vanilla")
function change_mind!(flavor)
@set_preferences!("icecream"=>flavor)
end
end
When a preference is set it is stored in a file called LocalPreferences.toml
next to your current Project.toml
.
LocalPreferences.toml
[MyPackage]
icecream = "chocolate"
Note how the LocalPreferences.toml
is scoped by package name, and thus each
package has it's own namespace.
Setting preferences of dependencies
A common use-case of preferences is to configure the library path of libraries
provided through _jll
packages.
As an example let's add UCX.jl
as a dependency to a package.
> cat Project.toml
[deps]
Preferences = "21216c6a-2e73-6563-6e65-726566657250"
UCX = "6b349878-927d-5bd5-ab28-bc3aa4175a33"
and we can see that it currently uses the libucp.so
from UCX_jll
.
julia> using UCX
julia> UCX.API.libucp
/home/vchuravy/.julia/artifacts/33301dce3561b1e57216ae5a4fc16d847e066a1d/lib/libucp.so
Now if I want to change the library used we have two options. Firstly the manual
one where we directly manipulate the LocalPreferences.toml
, and secondly using
Prefrences set_preference(UCX.UCX_jll, "libucp_path"=>"...")
.
Manual approach
The LocalPreferences.toml
we create next to our Project.toml
will look like:
> cat LocalPreferences.toml
[UCX_jll]
libucp_path="/home/vchuravy/builds/ucx/lib/libucp.so"
Running the same commands as before:
julia> using UCX
julia> UCX.API.libucp
/home/vchuravy/.julia/artifacts/33301dce3561b1e57216ae5a4fc16d847e066a1d/lib/libucp.so
We see that nothing has changed. Why? Julia internally referers to packages by UUIDs
so if you take another look at the Project.toml
you can see that in [deps]
we
declare a mapping from name to UUID, and the LocalPreferences.toml
needs exactly
this mapping to know what package owns the namespace. We could add UCX_jll
to our
[deps]
section in our package but that would unecessarily polute our dependency set.
Instead the right solution is to add UCX_jll
to the [extras]
section.
> cat Project.toml
[deps]
Preferences = "21216c6a-2e73-6563-6e65-726566657250"
UCX = "6b349878-927d-5bd5-ab28-bc3aa4175a33"
[extras]
UCX_jll = "16e4e860-d6b8-5056-a518-93e88b6392ae"
Loading UCX now delightfully fails since of course we haven't done the work of placing a library in that location.
julia> using UCX
ERROR: InitError: could not load library "/home/vchuravy/builds/ucx/lib/libucp.so"
/home/vchuravy/builds/ucx/lib/libucp.so: cannot open shared object file: No such file or directory
Keep this in mind if you are ever wondering why settings in LocalPreferences.toml
don't seem to take effect.
The "proper" way
Let's reset our environment to the state it was before:
> cat Project.toml
[deps]
Preferences = "21216c6a-2e73-6563-6e65-726566657250"
UCX = "6b349878-927d-5bd5-ab28-bc3aa4175a33"
julia> using UCX
julia> @eval UCX using UCX_jll
julia> using Preferences
julia> set_preferences!(UCX.UCX_jll, "libucp_path" => "/home/vchuravy/builds/ucx/lib/libucp.so")
julia> UCX.UCX_jll.libucp_path
"/home/vchuravy/.julia/artifacts/33301dce3561b1e57216ae5a4fc16d847e066a1d/lib/libucp.so"
As we can see the preference has not yet taken effect, and it will require a restart of Julia. This is because the preference lookup is cached during package precompilation.
Inspecting our Project.toml
and LocalPreferences.toml
we see that Preferences.jl
automatically added UCX_jll
to the [extras]
section.
> cat Project.toml
[deps]
Preferences = "21216c6a-2e73-6563-6e65-726566657250"
UCX = "6b349878-927d-5bd5-ab28-bc3aa4175a33"
[extras]
UCX_jll = "16e4e860-d6b8-5056-a518-93e88b6392ae"
> cat example/LocalPreferences.toml
[UCX_jll]
libucp_path = "/home/vchuravy/builds/ucx/lib/libucp.so"
After restarting we see the expected behavior.
julia> using UCX
ERROR: InitError: could not load library "/home/vchuravy/builds/ucx/lib/libucp.so"
/home/vchuravy/builds/ucx/lib/libucp.so: cannot open shared object file: No such file or directory
Interactions with the JULIA_LOAD_PATH
Preferences are merged across the entire JULIA_LOAD_PATH
to illustrate this
let's create a new directory preferences
and mv over our current LocalPreferences.toml
.
mkdir preferences
mv example/LocalPreferences.toml preferences/
printf "[extras]\nUCX_jll = \"16e4e860-d6b8-5056-a518-93e88b6392ae\"" > preferences/Project.toml
and remove UCX_jll
from Project.toml
in the current directory.
> JULIA_LOAD_PATH="@:./preferences" julia --project=.
julia> using UCX
ERROR: InitError: could not load library "/home/vchuravy/builds/ucx/lib/libucp.so"