Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[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 join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant