bakeware
bakeware copied to clipboard
[Knowledge share] Cross-compiling to Windows from Linux
Hi,
EDIT:
Ah I saw in another issue you are pointing people to https://github.com/burrito-elixir/burrito which seems to support this out of the box
After looking at Burrito for a bit, I can confirm it is taking the same approach, plus using
zig
instead of C, which allows it to have an easier time at cross-compiling.
Just sharing my workaround for getting a bakeware executable that's compiled on Linux to run on Windows (for me it has CI benefits, doing it this way). I've also cached the otp_win64_24.3.4.5.exe
binary (added to my git repo via LFS). Basically it just replaces the ERTS and other erlang libraries to the Windows one in the release.
Also of course, I have CC ="/path/to/x86_64-w64-mingw32-gcc"
to compile the bakeware executable to .exe
I didn't know where best to put it, this is a workaround rather than a full solution, but I think it is a good enough workaround that it's worth sharing.
defp otp_full_version() do
otp_major = :erlang.system_info(:otp_release)
File.read!(Path.join([:code.root_dir(), "releases", otp_major, "OTP_VERSION"]))
|> String.trim()
end
defp extract_cross_erlang() do
cached_version = "24.3.4.5"
erts_version = :erlang.system_info(:version)
otp_version = otp_full_version()
if otp_version != cached_version do
raise """
Wrong erlang version, download the one matching your version:
OTP: #{otp_version}, ERTS: #{erts_version}
from e.g. this was from
https://www.erlang.org/patches/otp-#{cached_version}, so for you it's
probably https://www.erlang.org/patches/otp-#{otp_version}
"""
end
if not File.exists?("cross-erlang") do
case System.get_env("MIX_TARGET") do
"win64" -> System.cmd("7z", ["x", "otp_win64_#{cached_version}.exe", "-ocross-erlang"])
end
end
end
defp patch_for_cross_compile(release) do
if System.get_env("MIX_TARGET") do
extract_cross_erlang()
cross_release = %{release |
erts_source: './cross-erlang/erts-12.3.2.5',
applications:
for {app, cfg} <- release.applications, into: %{} do
path = cfg[:path] |> to_string
root_dir = :code.root_dir() |> to_string()
if String.starts_with?(path, root_dir) do
{app,
put_in(
cfg[:path],
String.replace(path, root_dir, "./cross-erlang")
|> to_charlist)}
else
{app, cfg}
end
end}
if System.get_env("MIX_RELEASE_DEBUG") do
File.write!("release", inspect(release, pretty: true, limit: :infinity))
File.write!("cross_release", inspect(cross_release, pretty: true, limit: :infinity))
end
cross_release
else
release
end
end
defp release do
[
overwrite: true,
cookie: "#{@app}_cookie",
quiet: true,
steps: [
&patch_for_cross_compile/1,
:assemble,
&Bakeware.assemble/1
],
strip_beams: Mix.env() == :prod
]
end
And a small patch on top of Elixir I use as a workaround to not having got a matching Elixir 1.12.3 that works with OTP 24 (Elixir doesn't have any DLLs anyway, just BEAM files, it was just missing the Windows .bat
files)
diff --git a/Makefile b/Makefile
index 8f5d093..058f81f 100644
--- a/Makefile
+++ b/Makefile
@@ -122,7 +122,7 @@ install: compile
$(INSTALL_DATA) $$dir/ebin/* "$(DESTDIR)$(PREFIX)/$(LIBDIR)/elixir/$$dir/ebin"; \
done
$(Q) $(INSTALL_DIR) "$(DESTDIR)$(PREFIX)/$(LIBDIR)/elixir/bin"
- $(Q) $(INSTALL_PROGRAM) $(filter-out %.ps1, $(filter-out %.bat, $(wildcard bin/*))) "$(DESTDIR)$(PREFIX)/$(LIBDIR)/elixir/bin"
+ $(Q) $(INSTALL_PROGRAM) $(wildcard bin/*) "$(DESTDIR)$(PREFIX)/$(LIBDIR)/elixir/bin"
$(Q) $(INSTALL_DIR) "$(DESTDIR)$(PREFIX)/$(BINDIR)"
$(Q) for file in "$(DESTDIR)$(PREFIX)"/$(LIBDIR)/elixir/bin/*; do \
ln -sf "../$(LIBDIR)/elixir/bin/$${file##*/}" "$(DESTDIR)$(PREFIX)/$(BINDIR)/"; \