diff --git a/PRECOMPILATION_GUIDE.md b/PRECOMPILATION_GUIDE.md index 8ed891f..4f97e7b 100644 --- a/PRECOMPILATION_GUIDE.md +++ b/PRECOMPILATION_GUIDE.md @@ -43,8 +43,7 @@ def project do make_precompiler_filename: "nif", make_precompiler_priv_paths: ["nif.*"], make_precompiler_nif_versions: [ - versions: ["2.14", "2.15", "2.16"], - availability: &target_available_for_nif_version?/2 + versions: ["2.14", "2.15", "2.16"] ] # ... ] @@ -113,15 +112,14 @@ The default value for `make_precompiler_nif_versions` is [versions: ["#{:erlang.system_info(:nif_version)}"]] ``` -There're three sub-keys for `make_precompiler_nif_versions`: +There're two sub-keys for `make_precompiler_nif_versions`: - `versions` - `fallback_version` -- `availability` ##### `versions` sub-key -The `versions` sub-key is a list of NIF versions that the precompiled artefacts are available for: +The `versions` sub-key is either a list of NIF versions of a function that returns a list of NIF versions that the precompiled artefacts are available for: ```elixir make_precompiler_nif_versions: [ @@ -129,6 +127,25 @@ make_precompiler_nif_versions: [ ] ``` +The above example tells `:elixir_make` that all targets have precompiled artefacts for NIF version `2.15` and `2.16`. + +For some platforms maybe we only have precompiled artefacts after a certain NIF version, say for x86_64 Windows we have precompiled artefacts available when NIF version >= `2.16` while other platforms have precompiled artefacts available from NIF version >= `2.15`. + +In such case we can inform `:elixir_make` that Windows targets don't have precompiled artefacts available except for NIF version `2.16` by passing a function to the `availability` sub-key. This function should accept two arguments, `target` and `nif_version`, and returns a boolean value indicating whether the precompiled artefacts for the target and NIF version are available. + +```elixir +make_precompiler_nif_versions: [ + versions: fn opts -> + target = opts.target + if String.contains?(target, "windows") do + ["2.16"] + else + ["2.15", "2.16"] + end + end +] +``` + The default behaviour is to use the exact NIF version that is available to the current target. If one is not available, it may fallback (see `fallback_version` next) to the highest matching major version prior to the current version. For example: - if the current host is using Erlang/OTP 23 (NIF version `2.15`), `elixir_make` will use the precompiled artefacts for NIF version `2.15`; @@ -139,25 +156,11 @@ If the current host is using Erlang/OTP with a new major Erlang NIF version (NIF ##### `fallback_version` sub-key -The behaviour when `elixir_make` cannot find the exact NIF version of the precompiled binary can be customized by setting the `fallback_version` sub-key. The value of the `fallback_version` sub-key should be a function that accepts three arguments, `target`, `current_nif_version` and `target_versions`. The `target` is the target triplet (or other name format, defined by the precompiler of your choice), `current_nif_version` is the NIF version on the current host, and `target_versions` is a list of NIF versions that are available to the target. - -The `fallback_version` function should return either the NIF version that `elixir_make` should use from the `target_versions` list or the `current_nif_version`. +The behaviour when `elixir_make` cannot find the exact NIF version of the precompiled binary can be customized by setting the `fallback_version` sub-key. -##### `availability` sub-key +The value of the `fallback_version` sub-key should be a function that accepts one argument, `opts`, which is a map that include one key `target`. The `target` is the target triplet (or other naming format, defined by the precompiler of your choice). -For some platforms maybe we only have precompiled artefacts after a certain NIF version, say for x86_64 Windows we have precompiled artefacts available when NIF version >= `2.16` while other platforms have precompiled artefacts available from NIF version >= `2.15`. - -In such case we can inform `:elixir_make` that Windows targets don't have precompiled artefacts available except for NIF version `2.16` by passing a function to the `availability` sub-key. This function should accept two arguments, `target` and `nif_version`, and returns a boolean value indicating whether the precompiled artefacts for the target and NIF version are available. - -```elixir -defp target_available_for_nif_version?(target, nif_version) do - if String.contains?(target, "windows") do - nif_version == "2.16" - else - true - end -end -``` +The `fallback_version` function should return the NIF version that is available and should be chosen for the current target. ### (Optional) Customise Precompilation Targets diff --git a/lib/elixir_make/artefact.ex b/lib/elixir_make/artefact.ex index 66f2b10..c2aa4ca 100644 --- a/lib/elixir_make/artefact.ex +++ b/lib/elixir_make/artefact.ex @@ -146,13 +146,14 @@ defmodule ElixirMake.Artefact do {String.to_integer(major), String.to_integer(minor)} end - defp fallback_version(_current_target, current_nif_version, versions) do + defp fallback_version(opts) do + current_nif_version = "#{:erlang.system_info(:nif_version)}" {major, minor} = nif_version_to_tuple(current_nif_version) # Get all matching major versions, earlier than the current version # and their distance. We want the closest (smallest distance). candidates = - for version <- versions, + for version <- opts.versions, {^major, candidate_minor} <- [nif_version_to_tuple(version)], candidate_minor <= minor, do: {minor - candidate_minor, version} @@ -163,6 +164,16 @@ defmodule ElixirMake.Artefact do end end + defp get_versions_for_target(versions, current_target) do + case versions do + version_list when is_list(version_list) -> + version_list + + version_func when is_function(version_func, 1) -> + version_func.(%{target: current_target}) + end + end + @doc """ Returns all available {{target, nif_version}, url} pairs available. """ @@ -179,15 +190,19 @@ defmodule ElixirMake.Artefact do config[:make_precompiler_nif_versions] || [versions: [current_nif_version]] - versions = nif_versions[:versions] - Enum.reduce(targets, [], fn target, archives -> + versions = get_versions_for_target(nif_versions[:versions], target) + archive_filenames = Enum.reduce(versions, [], fn nif_version_for_target, acc -> availability = nif_versions[:availability] available? = if is_function(availability, 2) do + IO.warn( + ":availability key in elixir_make is deprecated, pass a function as :versions instead" + ) + availability.(target, nif_version_for_target) else true @@ -220,14 +235,15 @@ defmodule ElixirMake.Artefact do config[:make_precompiler_nif_versions] || [versions: []] - versions = nif_versions[:versions] + versions = get_versions_for_target(nif_versions[:versions], current_target) nif_version_to_use = if current_nif_version in versions do current_nif_version else - fallback_version = nif_versions[:fallback_version] || (&fallback_version/3) - fallback_version.(current_target, current_nif_version, versions) + fallback_version = nif_versions[:fallback_version] || (&fallback_version/1) + opts = %{target: current_target, versions: versions} + fallback_version.(opts) end available_urls = available_target_urls(config, precompiler)