Skip to content
This repository has been archived by the owner on Sep 18, 2024. It is now read-only.

[Knowledge share] Cross-compiling to Windows from Linux #134

Open
KoviRobi opened this issue Nov 27, 2022 · 0 comments
Open

[Knowledge share] Cross-compiling to Windows from Linux #134

KoviRobi opened this issue Nov 27, 2022 · 0 comments

Comments

@KoviRobi
Copy link

KoviRobi commented Nov 27, 2022

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)/"; \
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant