From 50e8c26e50b06ad2cde22e1b8487528c73b3de79 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Thu, 2 Jun 2016 14:55:30 -0400 Subject: [PATCH] [mxe] Add Windows cross-compiler support. Certain Xamarin.Android features require that Mono be built for Windows, e.g. the [AOT compilers][aot] require a build of mono that executes on Windows to generate the AOT native libraries. Unfortunately, building Mono on Windows continues to be a massive PITA. (Autotools on Windows requires Cygwin/mingw, running shell scripts on Windows is painfully slow, it's all brittle, etc.) To work around this pain, we instead build the Mono/Windows binaries on OS X, via [MXE][mxe], which produces a gcc-based cross-compiler which generates Windows binaries and is executable from Unix. This in turn requires that we have MXE, so add a `_CreateMxeToolchains` target to `android-toolchain.targets` which will build MXE. The installation prefix for MXE can be overridden via the new `$(AndroidMxeInstallPrefix)` MSBuild property; it defaults to `$HOME/android-toolchain/mxe`. Rework the `$(AndroidSupportedAbis)` MSBuild property so that it must include the "host" ABI, and add support for a new `host-win64` value which will use MXE to generate 64-bit Windows binaries for libmonosgen-2.0.dll and libMonoPosixHelper.dll. We can't always process `host-$(HostOS)` because of an xbuild bug. The scenario is that if you want to just build `host-win64`, the obvious thing to do is: cd build-tools/mono-runtimes xbuild /p:AndroidSupportedAbis=host-win64 Alas, if `host-$(HostOS)` is always processed, this inexplicably causes `host-$(HostOS)` to be re-rebuilt, which (1) is a waste of time, and (2) fails -- inexplicably -- in the `_BuildRuntimes` target because make(1) thinks that the configure flags have somehow changed, which currently makes no sense at all. (When can we move to MSBuild?) Changing `$(AndroidSupportedAbis)` so that `host-$(HostOS)` is explicitly processed instead of implicitly processed allows working around the above xbuild bug, as `host-$(HostOS)` won't be implicitly processed on every build, but only when required. Additionally, we add a new MSBuild task so that we can determine if a particular program is in `$PATH`. This is useful because listing requirements within README.md is a road to pain -- e.g. xxd(1) is required to build `src/monodroid` but if it's missing it'll still *build* but you'll instead get a *linker* failure because the `monodroid_config` and `monodroid_machine_config` symbols aren't present. Building MXE requires that even more programs be present within $PATH, so explicitly check for these so that *useful* error messages can be generated instead of obscure ones. Finally, a note about autotools and generating Windows native libraries: creation of `.dll` files *requires* that an appropriate objdump be present so it can determine if e.g. `libkernel32.a` is an import library or an archive. If `x86_64-w64-mingw32.static-objdump` isn't found -- e.g. because $PATH doesn't contain it -- then no `.dll` files will be created, and much head scratching will occur. To rectify this, override the OBJDUMP and DLLTOOL values when invoking `configure` so that that full paths are used and `$PATH` use is reduced. (Who wants `x86_64-w64-mingw32.static-objdump` in `$PATH`?) [aot]: https://developer.xamarin.com/releases/android/xamarin.android_5/xamarin.android_5.1/#AOT_Support [mxe]: http://mxe.cc/ --- .gitmodules | 4 ++ Configuration.Override.props.in | 1 + Configuration.props | 8 ++- README.md | 15 +++- .../android-toolchain.mdproj | 2 + .../android-toolchain.projitems | 38 +++++++++++ .../android-toolchain.targets | 46 +++++++++++++ .../mono-runtimes/mono-runtimes.projitems | 30 +++++++- build-tools/mono-runtimes/mono-runtimes.props | 9 +++ .../mono-runtimes/mono-runtimes.targets | 41 +++++------ external/mxe | 1 + ...amarin.Android.Tools.BootstrapTasks.csproj | 1 + .../Which.cs | 68 +++++++++++++++++++ src/monodroid/monodroid.projitems | 3 + src/monodroid/monodroid.targets | 2 + 15 files changed, 245 insertions(+), 24 deletions(-) create mode 160000 external/mxe create mode 100644 src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/Which.cs diff --git a/.gitmodules b/.gitmodules index be837500980..f5753d5c5d5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,7 @@ path = external/mono url = https://github.com/mono/mono.git branch = mono-4.5.0-branch +[submodule "external/mxe"] + path = external/mxe + url = https://github.com/xamarin/mxe.git + branch = xamarin diff --git a/Configuration.Override.props.in b/Configuration.Override.props.in index c8079c312a8..644aa8ebd8d 100644 --- a/Configuration.Override.props.in +++ b/Configuration.Override.props.in @@ -25,5 +25,6 @@ $(HOME)\android-archives $(HOME)\android-toolchain + $(AndroidToolchainDirectory)\mxe diff --git a/Configuration.props b/Configuration.props index a072963b9ff..aee87a7de37 100644 --- a/Configuration.props +++ b/Configuration.props @@ -9,19 +9,23 @@ Darwin Linux clang - clang++ + clang++ mono $(HOMEDRIVE)$(HOMEPATH) 23 v6.0 $(HOME)\android-archives $(HOME)\android-toolchain + $(AndroidToolchainDirectory)\mxe $(AndroidToolchainDirectory)\sdk $(AndroidToolchainDirectory)\ndk - armeabi-v7a + host-$(HostOS),armeabi-v7a $(MSBuildThisFileDirectory)external\mono $(MSBuildThisFileDirectory) + + $([System.IO.Path]::GetFullPath ('$(AndroidMxeInstallPrefix)')) +