Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 84 additions & 4 deletions lib/steps/patch/recompile_nifs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ defmodule Burrito.Steps.Patch.RecompileNIFs do
context
end

@compilers [:elixir_make, :build_dot_zig]
def nif_sniff() do
# The current procedure for finding out if a dependency has a NIF:
# - List all deps in the project using Mix.Project.deps_paths/0
Expand All @@ -51,18 +52,22 @@ defmodule Burrito.Steps.Patch.RecompileNIFs do
Enum.map(paths, fn {dep_name, path} ->
Mix.Project.in_project(dep_name, path, fn module ->
if module && Keyword.has_key?(module.project(), :compilers) do
{dep_name, path, Enum.member?(module.project()[:compilers], :elixir_make)}
{dep_name, path, first_matching_compiler(module, @compilers)}
else
{dep_name, path, false}
{dep_name, path, nil}
end
end)
end)
end

defp maybe_recompile_nif({_, _, false}, _, _, _, _, _, _, _), do: :no_nif
defp first_matching_compiler(module, compilers) do
Enum.find(module.project()[:compilers], &(&1 in compilers))
end

defp maybe_recompile_nif({_, _, nil}, _, _, _, _, _, _, _), do: :no_nif

defp maybe_recompile_nif(
{dep, path, true},
{dep, path, :elixir_make},
release_working_path,
erts_path,
cross_target,
Expand Down Expand Up @@ -134,6 +139,81 @@ defmodule Burrito.Steps.Patch.RecompileNIFs do
end
end

defp maybe_recompile_nif(
{dep, path, :build_dot_zig},
release_working_path,
erts_path,
cross_target,
_extra_cflags,
_extra_cxxflags,
extra_env,
_extra_make_args
) do
dep = Atom.to_string(dep)

Log.info(
:step,
"Going to recompile NIF with build_dot_zig for cross-build: #{dep} -> #{cross_target}"
)

output_priv_dir =
Path.join(release_working_path, ["lib/#{dep}*/"])
|> Path.expand()
|> Path.wildcard()
|> List.first()

erts_env = erts_make_env(erts_path)

build_mode = "ReleaseSafe"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be great to at least check whether it's a debug build and then go for Debug mode. Or otherwise allow overriding the build mode somehow.

zig_install_dir = Path.join([output_priv_dir, "priv", "host"])

zig_args = [
"build",
"-Dtarget=#{cross_target}",
"-Doptimize=#{build_mode}",
"--prefix",
"#{zig_install_dir}"
]

build_result =
System.cmd(
"zig",
zig_args,
cd: path,
env: erts_env ++ extra_env,
stderr_to_stdout: true,
into: IO.stream()
)

case build_result do
{_, 0} ->
Log.info(:step, "Successfully re-built #{dep} for #{cross_target}!")

output_files =
Path.join([zig_install_dir, "**"])
|> Path.expand()
|> Path.wildcard()

if String.contains?(cross_target, "windows") do
Enum.each(output_files, &rename_to_dll!(&1))
end

{_output, _non_zero} ->
Log.error(:step, "Failed to rebuild #{dep} for #{cross_target}!")
exit(1)
end
end

defp rename_to_dll!(file) do
if Path.extname(file) == ".so" do
dst_fullpath = String.replace_trailing(file, ".so", ".dll")

Log.info(:step, "#{file} -> #{dst_fullpath}")

File.rename!(file, dst_fullpath)
end
end

defp erts_make_env(erts_path) do
ei_include =
Path.join(erts_path, ["otp*/", "usr/", "include/"])
Expand Down