[android-toolchain] Permit zero-configuration builds.
This might be a suspect idea, but lets see if we can make this work.
[The Joel Test: 12 Steps to Better Code][0] outlines 12 steps
to better code. The first two steps are:
1. Do you use source control?
2. Can you make a build in one step?
github is being used for source control, so (1) is handled, but how
simple can we make (2)? How easy can we make it to build
Xamarin.Android upon a fresh checkout?
The ideal to strive for is simple:
Load Xamarin.Android.sln into your IDE and Build the project.
I *know* we're not going to be able to do this, if only because we're
going to be using git submodules, which will require a separate
`git submodule init` invocation [1].
Knowing we can't reach that level of simplicitly doesn't mean we
shouldn't *try* to reach it for all other parts of the build system.
Which brings us to the Android NDK and SDK. The Android NDK will be
required in order to build native code, such as libmonodroid.so, while
the Android SDK will be required in order to compile
Java Callable Wrappers (née Android Callable Wrappers [2]) and
eventual samples and unit tests.
There are three ways we can deal with the Android NDK and SDK:
1. Complicate the "build" process by requiring that developers go to
the Android SDK Download Page [3], download and install
"somewhere" the required bits, and then configure the
Xamarin.Android build to use these bits.
2. Complicate the "build" process by requiring that developers run
the Xamarin Unified Installer [4], let it install everything
required, then configure the Xamarin.Android build to use those
bits.
3. Painstakingly determine which files are actually required, then
automatically download and extract those files into a "well-known"
location known by the Xamarin.Android build process.
(1) and (2) can be infuriating. Let's give (3) a try. :-)
Add a Xamarin.Android.Tools.BootstrapTasks project which contains
MSBuild tasks to facilitate downloading the Android SDK and NDK files.
Add an android-toolchain project which uses
Xamarin.Android.Tools.BootstrapTasks to download a painstakingly
determined set of files and install them "somewhere".
Unfortunately [5] the "somewhere" to download and install these files
needs to be in a known absolute path, so I've arbitrary decided to
download the files into $(HOME)\android-archives and install them into
$(HOME)\android-toolchain. On windows, this is
%HOMEDRIVE%%HOMEPATH%\android-archives and
%HOMEDRIVE%%HOMEPATH%\android-toolchain.
These locations may be modified by creating a
Configuration.Override.props file; see README.md for details.
TL;DR: This setup is able to magically download the Android NDK and
SDK files and install them for later use in a reasonably overridable
location, all within MSBuild.
[0]: http://www.joelonsoftware.com/articles/fog0000000043.html
[1]: Though maybe there's some MSBuild-fu we can use to address that.
[2]: https://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/android_callable_wrappers/
[3]: http://developer.android.com/sdk/index.html
[4]: https://www.xamarin.com/download
[5]: Because I couldn't find a reliable way to use $(SolutionDir) when
only building a project, and relative paths would require an
in-tree installation location, which might not work.
2016-04-19 03:33:04 +03:00
Xamarin.Android
===============
Xamarin.Android provides open-source bindings of the Android SDK for use with
.NET managed languages such as C#.
2016-04-28 22:14:46 +03:00
[![Gitter ](https://badges.gitter.im/Join%20Chat.svg )](https://gitter.im/xamarin/xamarin-android?utm_source=badge& utm_medium=badge& utm_campaign=pr-badge& utm_content=badge)
2016-08-09 17:37:47 +03:00
# Build Status
2016-08-01 23:18:48 +03:00
2016-08-09 17:37:47 +03:00
| Platform | Status |
|-----------------------|--------|
| **OSS macOS** | [![OSS macOS x86_64][oss-macOS-x86_64-icon]][oss-macOS-x86_64-status] |
| **OSS Ubuntu** | [![OSS Linux/Ubuntu x86_64][oss-ubuntu-x86_64-icon]][oss-ubuntu-x86_64-status] |
2016-08-01 23:18:48 +03:00
2016-08-09 17:37:47 +03:00
[oss-macOS-x86_64-icon]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android/badge/icon
[oss-macOS-x86_64-status]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android/
[oss-ubuntu-x86_64-icon]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android-linux/badge/icon
[oss-ubuntu-x86_64-status]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android-linux/
# Downloads
| Platform | Status |
|-----------------|--------|
| **Commercial Xamarin.Android 6.2 (Cycle 8)** for macOS | [![Commercial Xamarin.Android 6.2, macOS][commercial-c8-macOS-x86_64-icon]][commercial-c8-macOS-x86_64-status] |
| **Commercial Xamarin.Android 7.0.99 (master)** for macOS | [![Commercial Xamarin.Android 7.1, macOS][commercial-master-macOS-x86_64-icon]][commercial-master-macOS-x86_64-status] |
[commercial-c8-macOS-x86_64-icon]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android-builds-cycle8/badge/icon
[commercial-c8-macOS-x86_64-status]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android-builds-cycle8/
[commercial-master-macOS-x86_64-icon]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android-builds-master/badge/icon
[commercial-master-macOS-x86_64-status]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android-builds-master/
# Configuration.Override.props
2016-04-21 04:45:28 +03:00
The Xamarin.Android build is heavily dependent on MSBuild, with the *intention*
that it should (eventually?) be possible to build the project simply by
checking out the repo, loading `Xamarin.Android.sln` into an IDE, and Building
the solution. (This isn't currently possible, and may never be, but it's
the *vision* .)
However, some properties may need to be altered in order to suit your
requirements, such as the location of a cache directory to store
the Android SDK and NDK.
To modify the build process, copy
2016-05-02 16:50:39 +03:00
[`Configuration.Override.props.in` ](Configuration.Override.props.in )
2016-04-21 04:45:28 +03:00
to `Configuration.Override.props` , and edit the file as appropriate.
`Configuration.Override.props` is `<Import/>` ed by `Configuration.props`
and will override any default values specified in `Configuration.props` .
Overridable MSBuild properties include:
2016-04-21 21:32:11 +03:00
* `$(AndroidApiLevel)` : The Android API level to bind in `src/Mono.Android` .
2016-05-02 16:50:39 +03:00
This is an integer value, e.g. `15` for
[API-15 (Android 4.0.3) ](http://developer.android.com/about/versions/android-4.0.3.html ).
2016-04-21 21:32:11 +03:00
* `$(AndroidFrameworkVersion)` : The Xamarin.Android `$(TargetFrameworkVersion)`
2016-05-02 16:50:39 +03:00
version which corresponds to `$(AndroidApiLevel)` . This is *usually* the
Android version number with a leading `v` , e.g. `v4.0.3` for API-15.
[build] Allow building with `msbuild`. (#74)
Fix the solution and project files so that `msbuild` may be used to
build the solution instead of requiring `xbuild`.
There were a few issues that `msbuild` didn't like:
1. MSBuild doesn't like the "extra" configuration mappings in
Xamarin.Android.sln.
2. MSBuild doesn't like the presence of `.dll` within `@(Reference)`
entries. `<Reference Include="System.dll" />` is Bad™, so
Don't Do That™.™.
3. Turning `$(AndroidSupportedAbis)` into an item group is...broken.
(1) and (2) are straightforward fixes. (3) requires some explanation.
`src/monodroid` needs to *only* build `libmonodroid.so` for the
non-"host" ABIs within `$(AndroidSupportedAbis)`. It needs this
restriction because non-selected ABIs may not be configured in
`$(AndroidNdkDirectory)`, and thus can't be built.
This *could* be done by following
`build-tools/mono-runtimes/mono-runtimes.projitems` and doing lots of
`Condition`s on `$(AndroidSupportedAbisForConditionalChecks)`:
<_MonoRuntime Include="armeabi-v7a" Condition="$(AndroidSupportedAbisForConditionalChecks.Contains(':armeabi-v7a:'))" />
...
However, that's kinda ugly when *all* we need is the ABI name, so
`monodroid.projitems` was "cute":
<PropertyGroup>
<_SupportedAbis>$(AndroidSupportedAbis.Replace(':', ';'))</_SupportedAbis>
</PropertyGroup>
<ItemGroup>
<_MonoRuntime Include="$(_SupportedAbis)" Exclude="@(HostOSName)" />
</ItemGroup>
<!-- @(_MonoRuntime) is `armeabi-v7a` by default -->
This works...on xbuild, but *not* `msbuild`. Doh!
(`msbuild` is "smart" and doesn't treat the `;` as an item separator,
so if `$(AndroidSupportedAbis)` is `host-Darwin;armeabi-v7a` then
MSBuild treats the `;` as part of the filename -- NOT a filename
separator -- and `@(_MonoRuntime)` contains *one* item with
an `%(Identity)` of `host-Darwin;armeabi-v7a`. On the one hand, this
is kinda awesome and answers the question "how can you have a filename
that contains `;`?", but on the other hand it broke my project!)
The only fix I could think of was to use `.Split(':')`:
<_MonoRuntime Include="$(AndroidSupportedAbis.Split(':'))" Exclude="@(HostOSName)" />
That provides desired behavior with `msbuild`, but `xbuild` doesn't
support it and appears to either *ignore* it, or treat it literally,
in that `@(_MonoRuntime)` would contain a *single* item with the
literal value `$(AndroidSupportedAbis.Split(':'))` (argh!).
Fortunately, there's a "cute" workaround: using `.Split()` within an
item's `Include` attribute doesn't work, but using `.Split()` within a
property group declaration *does* work:
<PropertyGroup>
<_SupportedAbis>$(AndroidSupportedAbis.Split(':'))</_SupportedAbis>
</PropertyGroup>
<ItemGroup>
<_MonoRuntime Include="$(_SupportedAbis)" Exclude="@(HostOSName)" />
</ItemGroup>
<!-- @(_MonoRuntime) is `armeabi-v7a` by default -->
This implies that a property value isn't limited to string values, but
(as here) can be string *arrays*, which is interesting.
~~~
All that aside, while exploring the proper fix for (3) (it took a
remarkably long time to run across it), I decided to reconsider the
property and item arrangement here.
The prior approach was to have a single `$(AndroidSupportedAbis)`
MSBuild property which controlled *both* Android target ABIs and host
ABIs. This worked...but wasn't entirely scalable (separate moving
parts need to be kept in sync). Additionally, we need to add AOT
cross-compiler support, which logically would be controlled by the
same/similar mechanism, so a value of "build everything" would start
to look insane:
msbuild /p:AndroidSupportedAbis=armeabi:armeabi-v7a:arm64-v8a:x86:x86_64:host-Darwin:host-Win64:cross-Darwin-arm:cross-Darwin-arm64:cross-Darwin-x86:cross-Darwin-x86_64:cross-Win64-arm:cross-Win64-arm64:cross-Win64-x86:cross-Win64-x86_64
And that's assuming I'm not missing anything, or that we don't add
MIPS support in the future, or...
Blech.
Furthermore, Xamarin.Android *already* uses
[`$(AndroidSupportedAbis)` in its build system][0], which means a
top-level override of `$(AndroidSupportedAbis)` would also impact all
projects which build `.apk` files, e.g.
`src/Mono.Android/Test/Mono.Android-Tests.csproj`, which might not be
desirable.
In short, I think we're overloading "Android supported ABIs," and it
should be split up into smaller, easier to rationalize, chunks.
Thus, leave `$(AndroidSupportedAbis)` to Xamarin.Android's tasks, and
replace it with *two* new properties:
* `$(AndroidSupportedHostJitAbis)`: The "host" ABIs to build.
* `$(AndroidSupportedTargetJitAbis)`: The "target" ABIs to build.
AOT support, when added, would use a new
`$(AndroidSupportedHostAotAbis)` property, thus keeping the set of
acceptable values small and more easily rationalizable.
Finally, "split up" these new Abis properties into corresponding Abi
item groups, to allow consistent and reusable "mapping" of ABI names
to filesystem locations, etc. The new `@(AndroidSupportedHostAotAbi)`
and `@(AndroidSupportedTargetJitAbi)` item groups are derived from
their corresponding values. (Note singular from plural in naming.)
[0]: https://developer.xamarin.com/guides/android/under_the_hood/build_process/#AndroidSupportedAbis
2016-06-15 14:05:59 +03:00
* `$(AndroidSupportedHostJitAbis)` : The Android ABIs for which to build a
host JIT *and* Xamarin.Android base class libraries (`mscorlib.dll`/etc.).
The "host JIT" is used e.g. with the Xamarin Studio Designer, to render
Xamarin.Android apps on the developer's machine.
[mxe] Add Windows cross-compiler support. (#55)
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 <Which/> 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/
2016-06-07 00:12:49 +03:00
There can also be support for cross-compiling mono for a different
host, e.g. to build Windows `libmonosgen-2.0.dll` from OS X.
Supported host values include:
[build] Allow building with `msbuild`. (#74)
Fix the solution and project files so that `msbuild` may be used to
build the solution instead of requiring `xbuild`.
There were a few issues that `msbuild` didn't like:
1. MSBuild doesn't like the "extra" configuration mappings in
Xamarin.Android.sln.
2. MSBuild doesn't like the presence of `.dll` within `@(Reference)`
entries. `<Reference Include="System.dll" />` is Bad™, so
Don't Do That™.™.
3. Turning `$(AndroidSupportedAbis)` into an item group is...broken.
(1) and (2) are straightforward fixes. (3) requires some explanation.
`src/monodroid` needs to *only* build `libmonodroid.so` for the
non-"host" ABIs within `$(AndroidSupportedAbis)`. It needs this
restriction because non-selected ABIs may not be configured in
`$(AndroidNdkDirectory)`, and thus can't be built.
This *could* be done by following
`build-tools/mono-runtimes/mono-runtimes.projitems` and doing lots of
`Condition`s on `$(AndroidSupportedAbisForConditionalChecks)`:
<_MonoRuntime Include="armeabi-v7a" Condition="$(AndroidSupportedAbisForConditionalChecks.Contains(':armeabi-v7a:'))" />
...
However, that's kinda ugly when *all* we need is the ABI name, so
`monodroid.projitems` was "cute":
<PropertyGroup>
<_SupportedAbis>$(AndroidSupportedAbis.Replace(':', ';'))</_SupportedAbis>
</PropertyGroup>
<ItemGroup>
<_MonoRuntime Include="$(_SupportedAbis)" Exclude="@(HostOSName)" />
</ItemGroup>
<!-- @(_MonoRuntime) is `armeabi-v7a` by default -->
This works...on xbuild, but *not* `msbuild`. Doh!
(`msbuild` is "smart" and doesn't treat the `;` as an item separator,
so if `$(AndroidSupportedAbis)` is `host-Darwin;armeabi-v7a` then
MSBuild treats the `;` as part of the filename -- NOT a filename
separator -- and `@(_MonoRuntime)` contains *one* item with
an `%(Identity)` of `host-Darwin;armeabi-v7a`. On the one hand, this
is kinda awesome and answers the question "how can you have a filename
that contains `;`?", but on the other hand it broke my project!)
The only fix I could think of was to use `.Split(':')`:
<_MonoRuntime Include="$(AndroidSupportedAbis.Split(':'))" Exclude="@(HostOSName)" />
That provides desired behavior with `msbuild`, but `xbuild` doesn't
support it and appears to either *ignore* it, or treat it literally,
in that `@(_MonoRuntime)` would contain a *single* item with the
literal value `$(AndroidSupportedAbis.Split(':'))` (argh!).
Fortunately, there's a "cute" workaround: using `.Split()` within an
item's `Include` attribute doesn't work, but using `.Split()` within a
property group declaration *does* work:
<PropertyGroup>
<_SupportedAbis>$(AndroidSupportedAbis.Split(':'))</_SupportedAbis>
</PropertyGroup>
<ItemGroup>
<_MonoRuntime Include="$(_SupportedAbis)" Exclude="@(HostOSName)" />
</ItemGroup>
<!-- @(_MonoRuntime) is `armeabi-v7a` by default -->
This implies that a property value isn't limited to string values, but
(as here) can be string *arrays*, which is interesting.
~~~
All that aside, while exploring the proper fix for (3) (it took a
remarkably long time to run across it), I decided to reconsider the
property and item arrangement here.
The prior approach was to have a single `$(AndroidSupportedAbis)`
MSBuild property which controlled *both* Android target ABIs and host
ABIs. This worked...but wasn't entirely scalable (separate moving
parts need to be kept in sync). Additionally, we need to add AOT
cross-compiler support, which logically would be controlled by the
same/similar mechanism, so a value of "build everything" would start
to look insane:
msbuild /p:AndroidSupportedAbis=armeabi:armeabi-v7a:arm64-v8a:x86:x86_64:host-Darwin:host-Win64:cross-Darwin-arm:cross-Darwin-arm64:cross-Darwin-x86:cross-Darwin-x86_64:cross-Win64-arm:cross-Win64-arm64:cross-Win64-x86:cross-Win64-x86_64
And that's assuming I'm not missing anything, or that we don't add
MIPS support in the future, or...
Blech.
Furthermore, Xamarin.Android *already* uses
[`$(AndroidSupportedAbis)` in its build system][0], which means a
top-level override of `$(AndroidSupportedAbis)` would also impact all
projects which build `.apk` files, e.g.
`src/Mono.Android/Test/Mono.Android-Tests.csproj`, which might not be
desirable.
In short, I think we're overloading "Android supported ABIs," and it
should be split up into smaller, easier to rationalize, chunks.
Thus, leave `$(AndroidSupportedAbis)` to Xamarin.Android's tasks, and
replace it with *two* new properties:
* `$(AndroidSupportedHostJitAbis)`: The "host" ABIs to build.
* `$(AndroidSupportedTargetJitAbis)`: The "target" ABIs to build.
AOT support, when added, would use a new
`$(AndroidSupportedHostAotAbis)` property, thus keeping the set of
acceptable values small and more easily rationalizable.
Finally, "split up" these new Abis properties into corresponding Abi
item groups, to allow consistent and reusable "mapping" of ABI names
to filesystem locations, etc. The new `@(AndroidSupportedHostAotAbi)`
and `@(AndroidSupportedTargetJitAbi)` item groups are derived from
their corresponding values. (Note singular from plural in naming.)
[0]: https://developer.xamarin.com/guides/android/under_the_hood/build_process/#AndroidSupportedAbis
2016-06-15 14:05:59 +03:00
* `Darwin`
* `Linux`
* `mxe-Win64` : Cross-compile Windows 64-bit binaries from Unix.
[mxe] Add Windows cross-compiler support. (#55)
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 <Which/> 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/
2016-06-07 00:12:49 +03:00
[build] Allow building with `msbuild`. (#74)
Fix the solution and project files so that `msbuild` may be used to
build the solution instead of requiring `xbuild`.
There were a few issues that `msbuild` didn't like:
1. MSBuild doesn't like the "extra" configuration mappings in
Xamarin.Android.sln.
2. MSBuild doesn't like the presence of `.dll` within `@(Reference)`
entries. `<Reference Include="System.dll" />` is Bad™, so
Don't Do That™.™.
3. Turning `$(AndroidSupportedAbis)` into an item group is...broken.
(1) and (2) are straightforward fixes. (3) requires some explanation.
`src/monodroid` needs to *only* build `libmonodroid.so` for the
non-"host" ABIs within `$(AndroidSupportedAbis)`. It needs this
restriction because non-selected ABIs may not be configured in
`$(AndroidNdkDirectory)`, and thus can't be built.
This *could* be done by following
`build-tools/mono-runtimes/mono-runtimes.projitems` and doing lots of
`Condition`s on `$(AndroidSupportedAbisForConditionalChecks)`:
<_MonoRuntime Include="armeabi-v7a" Condition="$(AndroidSupportedAbisForConditionalChecks.Contains(':armeabi-v7a:'))" />
...
However, that's kinda ugly when *all* we need is the ABI name, so
`monodroid.projitems` was "cute":
<PropertyGroup>
<_SupportedAbis>$(AndroidSupportedAbis.Replace(':', ';'))</_SupportedAbis>
</PropertyGroup>
<ItemGroup>
<_MonoRuntime Include="$(_SupportedAbis)" Exclude="@(HostOSName)" />
</ItemGroup>
<!-- @(_MonoRuntime) is `armeabi-v7a` by default -->
This works...on xbuild, but *not* `msbuild`. Doh!
(`msbuild` is "smart" and doesn't treat the `;` as an item separator,
so if `$(AndroidSupportedAbis)` is `host-Darwin;armeabi-v7a` then
MSBuild treats the `;` as part of the filename -- NOT a filename
separator -- and `@(_MonoRuntime)` contains *one* item with
an `%(Identity)` of `host-Darwin;armeabi-v7a`. On the one hand, this
is kinda awesome and answers the question "how can you have a filename
that contains `;`?", but on the other hand it broke my project!)
The only fix I could think of was to use `.Split(':')`:
<_MonoRuntime Include="$(AndroidSupportedAbis.Split(':'))" Exclude="@(HostOSName)" />
That provides desired behavior with `msbuild`, but `xbuild` doesn't
support it and appears to either *ignore* it, or treat it literally,
in that `@(_MonoRuntime)` would contain a *single* item with the
literal value `$(AndroidSupportedAbis.Split(':'))` (argh!).
Fortunately, there's a "cute" workaround: using `.Split()` within an
item's `Include` attribute doesn't work, but using `.Split()` within a
property group declaration *does* work:
<PropertyGroup>
<_SupportedAbis>$(AndroidSupportedAbis.Split(':'))</_SupportedAbis>
</PropertyGroup>
<ItemGroup>
<_MonoRuntime Include="$(_SupportedAbis)" Exclude="@(HostOSName)" />
</ItemGroup>
<!-- @(_MonoRuntime) is `armeabi-v7a` by default -->
This implies that a property value isn't limited to string values, but
(as here) can be string *arrays*, which is interesting.
~~~
All that aside, while exploring the proper fix for (3) (it took a
remarkably long time to run across it), I decided to reconsider the
property and item arrangement here.
The prior approach was to have a single `$(AndroidSupportedAbis)`
MSBuild property which controlled *both* Android target ABIs and host
ABIs. This worked...but wasn't entirely scalable (separate moving
parts need to be kept in sync). Additionally, we need to add AOT
cross-compiler support, which logically would be controlled by the
same/similar mechanism, so a value of "build everything" would start
to look insane:
msbuild /p:AndroidSupportedAbis=armeabi:armeabi-v7a:arm64-v8a:x86:x86_64:host-Darwin:host-Win64:cross-Darwin-arm:cross-Darwin-arm64:cross-Darwin-x86:cross-Darwin-x86_64:cross-Win64-arm:cross-Win64-arm64:cross-Win64-x86:cross-Win64-x86_64
And that's assuming I'm not missing anything, or that we don't add
MIPS support in the future, or...
Blech.
Furthermore, Xamarin.Android *already* uses
[`$(AndroidSupportedAbis)` in its build system][0], which means a
top-level override of `$(AndroidSupportedAbis)` would also impact all
projects which build `.apk` files, e.g.
`src/Mono.Android/Test/Mono.Android-Tests.csproj`, which might not be
desirable.
In short, I think we're overloading "Android supported ABIs," and it
should be split up into smaller, easier to rationalize, chunks.
Thus, leave `$(AndroidSupportedAbis)` to Xamarin.Android's tasks, and
replace it with *two* new properties:
* `$(AndroidSupportedHostJitAbis)`: The "host" ABIs to build.
* `$(AndroidSupportedTargetJitAbis)`: The "target" ABIs to build.
AOT support, when added, would use a new
`$(AndroidSupportedHostAotAbis)` property, thus keeping the set of
acceptable values small and more easily rationalizable.
Finally, "split up" these new Abis properties into corresponding Abi
item groups, to allow consistent and reusable "mapping" of ABI names
to filesystem locations, etc. The new `@(AndroidSupportedHostAotAbi)`
and `@(AndroidSupportedTargetJitAbi)` item groups are derived from
their corresponding values. (Note singular from plural in naming.)
[0]: https://developer.xamarin.com/guides/android/under_the_hood/build_process/#AndroidSupportedAbis
2016-06-15 14:05:59 +03:00
The default value is `$(HostOS)` , where `$(HostOS)` is based on probing
various environment variables and filesystem locations.
On OS X, the default would be `Darwin` .
* `$(AndroidSupportedTargetJitAbis)` : The Android ABIs for which to build the
the Mono JIT for inclusion within apps. This is a `:` -separated list of
ABIs to build. Supported values are:
[android-toolchains, mono-runtimes] Build armeabi, arm64-v8a, x86, x86_64 (#40)
Commit 38dbfcaf mentions that commercial Xamarin.Android 6.0
provides Mono for five architectures, but "[i]n the interest of
expediency" only adds support to build *one* architecture:
armeabi-v7a (32-bit ARM v7).
It's time to fix that: add build system support for armeabi,
arm64-v8a, x86, and x86_64.
*However*, it takes *time* to build all those ABIs: on a 2013 6-core
Mac Pro, it takes ~29 minutes to build all five of those ABIs plus the
"host" ABI (for BCL assemblies), which is presumably 29 minutes that
very few people want to spend, and will be even longer in a variety of
build environments (virtual machines, slower hardware, etc.).
Which means we don't want to require that they all be built.
To better support this, add a new `$(AndroidSupportedAbis)` MSBuild
property which contains a comma-separated list of ABIs to support.
This allows manually overriding the ABIs on the command-line:
# build everything!
$ xbuild /p:AndroidSupportedAbis=armeabi,armeabi-v7a,arm64-v8a,x86,x86_64
or setting a value within `Configuration.Override.props`:
<PropertyGroup>
<!-- only build x86 -->
<AndroidSupportedAbis>x86,x86_64</AndroidSupportedAbis>
</PropertyGroup>
The *default* continues to be just armeabi-v7a.
2016-05-13 22:50:23 +03:00
[build] Allow building with `msbuild`. (#74)
Fix the solution and project files so that `msbuild` may be used to
build the solution instead of requiring `xbuild`.
There were a few issues that `msbuild` didn't like:
1. MSBuild doesn't like the "extra" configuration mappings in
Xamarin.Android.sln.
2. MSBuild doesn't like the presence of `.dll` within `@(Reference)`
entries. `<Reference Include="System.dll" />` is Bad™, so
Don't Do That™.™.
3. Turning `$(AndroidSupportedAbis)` into an item group is...broken.
(1) and (2) are straightforward fixes. (3) requires some explanation.
`src/monodroid` needs to *only* build `libmonodroid.so` for the
non-"host" ABIs within `$(AndroidSupportedAbis)`. It needs this
restriction because non-selected ABIs may not be configured in
`$(AndroidNdkDirectory)`, and thus can't be built.
This *could* be done by following
`build-tools/mono-runtimes/mono-runtimes.projitems` and doing lots of
`Condition`s on `$(AndroidSupportedAbisForConditionalChecks)`:
<_MonoRuntime Include="armeabi-v7a" Condition="$(AndroidSupportedAbisForConditionalChecks.Contains(':armeabi-v7a:'))" />
...
However, that's kinda ugly when *all* we need is the ABI name, so
`monodroid.projitems` was "cute":
<PropertyGroup>
<_SupportedAbis>$(AndroidSupportedAbis.Replace(':', ';'))</_SupportedAbis>
</PropertyGroup>
<ItemGroup>
<_MonoRuntime Include="$(_SupportedAbis)" Exclude="@(HostOSName)" />
</ItemGroup>
<!-- @(_MonoRuntime) is `armeabi-v7a` by default -->
This works...on xbuild, but *not* `msbuild`. Doh!
(`msbuild` is "smart" and doesn't treat the `;` as an item separator,
so if `$(AndroidSupportedAbis)` is `host-Darwin;armeabi-v7a` then
MSBuild treats the `;` as part of the filename -- NOT a filename
separator -- and `@(_MonoRuntime)` contains *one* item with
an `%(Identity)` of `host-Darwin;armeabi-v7a`. On the one hand, this
is kinda awesome and answers the question "how can you have a filename
that contains `;`?", but on the other hand it broke my project!)
The only fix I could think of was to use `.Split(':')`:
<_MonoRuntime Include="$(AndroidSupportedAbis.Split(':'))" Exclude="@(HostOSName)" />
That provides desired behavior with `msbuild`, but `xbuild` doesn't
support it and appears to either *ignore* it, or treat it literally,
in that `@(_MonoRuntime)` would contain a *single* item with the
literal value `$(AndroidSupportedAbis.Split(':'))` (argh!).
Fortunately, there's a "cute" workaround: using `.Split()` within an
item's `Include` attribute doesn't work, but using `.Split()` within a
property group declaration *does* work:
<PropertyGroup>
<_SupportedAbis>$(AndroidSupportedAbis.Split(':'))</_SupportedAbis>
</PropertyGroup>
<ItemGroup>
<_MonoRuntime Include="$(_SupportedAbis)" Exclude="@(HostOSName)" />
</ItemGroup>
<!-- @(_MonoRuntime) is `armeabi-v7a` by default -->
This implies that a property value isn't limited to string values, but
(as here) can be string *arrays*, which is interesting.
~~~
All that aside, while exploring the proper fix for (3) (it took a
remarkably long time to run across it), I decided to reconsider the
property and item arrangement here.
The prior approach was to have a single `$(AndroidSupportedAbis)`
MSBuild property which controlled *both* Android target ABIs and host
ABIs. This worked...but wasn't entirely scalable (separate moving
parts need to be kept in sync). Additionally, we need to add AOT
cross-compiler support, which logically would be controlled by the
same/similar mechanism, so a value of "build everything" would start
to look insane:
msbuild /p:AndroidSupportedAbis=armeabi:armeabi-v7a:arm64-v8a:x86:x86_64:host-Darwin:host-Win64:cross-Darwin-arm:cross-Darwin-arm64:cross-Darwin-x86:cross-Darwin-x86_64:cross-Win64-arm:cross-Win64-arm64:cross-Win64-x86:cross-Win64-x86_64
And that's assuming I'm not missing anything, or that we don't add
MIPS support in the future, or...
Blech.
Furthermore, Xamarin.Android *already* uses
[`$(AndroidSupportedAbis)` in its build system][0], which means a
top-level override of `$(AndroidSupportedAbis)` would also impact all
projects which build `.apk` files, e.g.
`src/Mono.Android/Test/Mono.Android-Tests.csproj`, which might not be
desirable.
In short, I think we're overloading "Android supported ABIs," and it
should be split up into smaller, easier to rationalize, chunks.
Thus, leave `$(AndroidSupportedAbis)` to Xamarin.Android's tasks, and
replace it with *two* new properties:
* `$(AndroidSupportedHostJitAbis)`: The "host" ABIs to build.
* `$(AndroidSupportedTargetJitAbis)`: The "target" ABIs to build.
AOT support, when added, would use a new
`$(AndroidSupportedHostAotAbis)` property, thus keeping the set of
acceptable values small and more easily rationalizable.
Finally, "split up" these new Abis properties into corresponding Abi
item groups, to allow consistent and reusable "mapping" of ABI names
to filesystem locations, etc. The new `@(AndroidSupportedHostAotAbi)`
and `@(AndroidSupportedTargetJitAbi)` item groups are derived from
their corresponding values. (Note singular from plural in naming.)
[0]: https://developer.xamarin.com/guides/android/under_the_hood/build_process/#AndroidSupportedAbis
2016-06-15 14:05:59 +03:00
* `armeabi`
* `armeabi-v7a`
* `arm64-v8a`
* `x86`
* `x86_64`
2016-04-21 04:45:28 +03:00
* `$(AndroidToolchainCacheDirectory)` : The directory to cache the downloaded
Android NDK and SDK files. This value defaults to
`$(HOME)\android-archives` .
* `$(AndroidToolchainDirectory)` : The directory to install the downloaded
Android NDK and SDK files. This value defaults to
`$(HOME)\android-toolchain` .
2016-04-22 22:28:12 +03:00
* `$(HostCc)` , `$(HostCxx)` : The C and C++ compilers to use to generate
host-native binaries.
2016-06-15 05:14:20 +03:00
* `$(JavaInteropSourceDirectory)` : The Java.Interop source directory to
build and reference projects from. By default, this is
`external/Java.Interop` directory, maintained by `git submodule update` .
2016-08-14 00:40:37 +03:00
* `$(MakeConcurrency)` : **make** (1) parameters to use intended to influence
the number of CPU cores used when **make** (1) executes. By default this uses
2016-09-13 17:16:19 +03:00
`-jCOUNT` , where `COUNT` is obtained from `sysctl hw.ncpu` .
* `$(MonoSgenBridgeVersion)` : The Mono SGEN Bridge version to support.
Valid values include:
Bump to mono/mono-4.8.0-branch/9e164326, Java.Interop/a1d3ecc8 (#223)
Mono 4.8 has new SGEN bridge performance characteristics and
semantics, requiring that we bump the SGEN Bridge Version to 5.
Additionally, Mono 4.8 is using Cecil/master, which is
API INCOMPATIBLE with Cecil 0.9.6, and Mono sources are included in
`Xamarin.Android.Build.Tasks.dll`.
We could attempt to address the Cecil incompatibility by building
Mono's `external/cecil` projects, but that doesn't work because
Java.Interop assemblies *also* use Cecil, and
`Xamarin.Android.Build.Tasks.dll` uses `Java.Interop.Tools.Cecil.dll`,
which uses Cecil via NuGet package, so everything gets very intermixed
and confusing if Java.Interop tries to use e.g. Cecil 0.9.6 via nuget
while xamarin-android attempts to use Cecil via Mono's source.
Skip that problem, and bump to Java.Interop/a1d3ecc8, which in turn
uses the Cecil 0.10.0-beta1-v2 *Preview* NuGet package, which is
API compoatible with Cecil/master and mono/master.
Additionally, update xamarin-android's Cecil 0.9.6 use to likewise use
Cecil 0.10.0-beta1-v2.
This allows xamarin-android to build while using Mono 4.8 sources.
Finally, there's lots of "unrelated noise" in this patch, largely
because every time I add a project to the solution via Xamarin Studio,
Xamarin Studio decides to modify EVERY PROJECT IN THE REPO. Preserve
some of these changes -- and "fix" others -- so that I can reduce the
"visual noise" of future Xamarin Studio changes.
2016-09-15 19:13:56 +03:00
* `4` : Mono 4.6 support.
* `5` : Mono 4.8 support. This is the default.
2016-04-21 04:45:28 +03:00
# Build Requirements
[android-toolchain] Permit zero-configuration builds.
This might be a suspect idea, but lets see if we can make this work.
[The Joel Test: 12 Steps to Better Code][0] outlines 12 steps
to better code. The first two steps are:
1. Do you use source control?
2. Can you make a build in one step?
github is being used for source control, so (1) is handled, but how
simple can we make (2)? How easy can we make it to build
Xamarin.Android upon a fresh checkout?
The ideal to strive for is simple:
Load Xamarin.Android.sln into your IDE and Build the project.
I *know* we're not going to be able to do this, if only because we're
going to be using git submodules, which will require a separate
`git submodule init` invocation [1].
Knowing we can't reach that level of simplicitly doesn't mean we
shouldn't *try* to reach it for all other parts of the build system.
Which brings us to the Android NDK and SDK. The Android NDK will be
required in order to build native code, such as libmonodroid.so, while
the Android SDK will be required in order to compile
Java Callable Wrappers (née Android Callable Wrappers [2]) and
eventual samples and unit tests.
There are three ways we can deal with the Android NDK and SDK:
1. Complicate the "build" process by requiring that developers go to
the Android SDK Download Page [3], download and install
"somewhere" the required bits, and then configure the
Xamarin.Android build to use these bits.
2. Complicate the "build" process by requiring that developers run
the Xamarin Unified Installer [4], let it install everything
required, then configure the Xamarin.Android build to use those
bits.
3. Painstakingly determine which files are actually required, then
automatically download and extract those files into a "well-known"
location known by the Xamarin.Android build process.
(1) and (2) can be infuriating. Let's give (3) a try. :-)
Add a Xamarin.Android.Tools.BootstrapTasks project which contains
MSBuild tasks to facilitate downloading the Android SDK and NDK files.
Add an android-toolchain project which uses
Xamarin.Android.Tools.BootstrapTasks to download a painstakingly
determined set of files and install them "somewhere".
Unfortunately [5] the "somewhere" to download and install these files
needs to be in a known absolute path, so I've arbitrary decided to
download the files into $(HOME)\android-archives and install them into
$(HOME)\android-toolchain. On windows, this is
%HOMEDRIVE%%HOMEPATH%\android-archives and
%HOMEDRIVE%%HOMEPATH%\android-toolchain.
These locations may be modified by creating a
Configuration.Override.props file; see README.md for details.
TL;DR: This setup is able to magically download the Android NDK and
SDK files and install them for later use in a reasonably overridable
location, all within MSBuild.
[0]: http://www.joelonsoftware.com/articles/fog0000000043.html
[1]: Though maybe there's some MSBuild-fu we can use to address that.
[2]: https://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/android_callable_wrappers/
[3]: http://developer.android.com/sdk/index.html
[4]: https://www.xamarin.com/download
[5]: Because I couldn't find a reliable way to use $(SolutionDir) when
only building a project, and relative paths would require an
in-tree installation location, which might not work.
2016-04-19 03:33:04 +03:00
2016-04-29 18:09:50 +03:00
Building Xamarin.Android requires:
* [Mono 4.4 or later ](#mono-sdk )
* [The Java Development Kit (JDK) ](#jdk )
* [Autotools (`autoconf`, `automake`, etc.) ](#autotools )
* [`xxd` ](#xxd )
* [The Android SDK and NDK ](#ndk )
< a name = "mono-sdk" / >
## Mono MDK
Mono 4.4 or later is required to build on [OS X][osx-mono] and Linux.
(This is because the build system uses the [XmlPeek][xmlpeek] task, which
was first added in Mono 4.4.)
[osx-mono]: http://www.mono-project.com/download/#download-mac
[xmlpeek]: https://msdn.microsoft.com/en-us/library/ff598684.aspx
< a name = "jdk" / >
## Java Development Kit
[android-toolchain] Permit zero-configuration builds.
This might be a suspect idea, but lets see if we can make this work.
[The Joel Test: 12 Steps to Better Code][0] outlines 12 steps
to better code. The first two steps are:
1. Do you use source control?
2. Can you make a build in one step?
github is being used for source control, so (1) is handled, but how
simple can we make (2)? How easy can we make it to build
Xamarin.Android upon a fresh checkout?
The ideal to strive for is simple:
Load Xamarin.Android.sln into your IDE and Build the project.
I *know* we're not going to be able to do this, if only because we're
going to be using git submodules, which will require a separate
`git submodule init` invocation [1].
Knowing we can't reach that level of simplicitly doesn't mean we
shouldn't *try* to reach it for all other parts of the build system.
Which brings us to the Android NDK and SDK. The Android NDK will be
required in order to build native code, such as libmonodroid.so, while
the Android SDK will be required in order to compile
Java Callable Wrappers (née Android Callable Wrappers [2]) and
eventual samples and unit tests.
There are three ways we can deal with the Android NDK and SDK:
1. Complicate the "build" process by requiring that developers go to
the Android SDK Download Page [3], download and install
"somewhere" the required bits, and then configure the
Xamarin.Android build to use these bits.
2. Complicate the "build" process by requiring that developers run
the Xamarin Unified Installer [4], let it install everything
required, then configure the Xamarin.Android build to use those
bits.
3. Painstakingly determine which files are actually required, then
automatically download and extract those files into a "well-known"
location known by the Xamarin.Android build process.
(1) and (2) can be infuriating. Let's give (3) a try. :-)
Add a Xamarin.Android.Tools.BootstrapTasks project which contains
MSBuild tasks to facilitate downloading the Android SDK and NDK files.
Add an android-toolchain project which uses
Xamarin.Android.Tools.BootstrapTasks to download a painstakingly
determined set of files and install them "somewhere".
Unfortunately [5] the "somewhere" to download and install these files
needs to be in a known absolute path, so I've arbitrary decided to
download the files into $(HOME)\android-archives and install them into
$(HOME)\android-toolchain. On windows, this is
%HOMEDRIVE%%HOMEPATH%\android-archives and
%HOMEDRIVE%%HOMEPATH%\android-toolchain.
These locations may be modified by creating a
Configuration.Override.props file; see README.md for details.
TL;DR: This setup is able to magically download the Android NDK and
SDK files and install them for later use in a reasonably overridable
location, all within MSBuild.
[0]: http://www.joelonsoftware.com/articles/fog0000000043.html
[1]: Though maybe there's some MSBuild-fu we can use to address that.
[2]: https://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/android_callable_wrappers/
[3]: http://developer.android.com/sdk/index.html
[4]: https://www.xamarin.com/download
[5]: Because I couldn't find a reliable way to use $(SolutionDir) when
only building a project, and relative paths would require an
in-tree installation location, which might not work.
2016-04-19 03:33:04 +03:00
The Java Development Kit may be downloaded from the
[Oracle Java SE Downloads page][download-jdk].
[download-jdk]: http://www.oracle.com/technetwork/java/javase/downloads/
2016-04-29 18:09:50 +03:00
< a name = "autotools" / >
## Autotools
Autotools -- including `autoconf` and `automake` -- are required to build
the Mono runtimes.
On OS X, autotools are distributed with [Mono.framework][osx-mono].
< a name = "xxd" / >
## `xxd`
The [xxd][xxd] utility is used to build [src/monodroid ](src/monodroid ).
It is installed by default on OS X. Linux users may need to separately
install it; it may be part of the [**vim-common** package][sid-vim-common].
[xxd]: http://linux.die.net/man/1/xxd
[sid-vim-common]: https://packages.debian.org/sid/vim-common
< a name = "ndk" / >
## Android NDK, SDK
[android-toolchain] Permit zero-configuration builds.
This might be a suspect idea, but lets see if we can make this work.
[The Joel Test: 12 Steps to Better Code][0] outlines 12 steps
to better code. The first two steps are:
1. Do you use source control?
2. Can you make a build in one step?
github is being used for source control, so (1) is handled, but how
simple can we make (2)? How easy can we make it to build
Xamarin.Android upon a fresh checkout?
The ideal to strive for is simple:
Load Xamarin.Android.sln into your IDE and Build the project.
I *know* we're not going to be able to do this, if only because we're
going to be using git submodules, which will require a separate
`git submodule init` invocation [1].
Knowing we can't reach that level of simplicitly doesn't mean we
shouldn't *try* to reach it for all other parts of the build system.
Which brings us to the Android NDK and SDK. The Android NDK will be
required in order to build native code, such as libmonodroid.so, while
the Android SDK will be required in order to compile
Java Callable Wrappers (née Android Callable Wrappers [2]) and
eventual samples and unit tests.
There are three ways we can deal with the Android NDK and SDK:
1. Complicate the "build" process by requiring that developers go to
the Android SDK Download Page [3], download and install
"somewhere" the required bits, and then configure the
Xamarin.Android build to use these bits.
2. Complicate the "build" process by requiring that developers run
the Xamarin Unified Installer [4], let it install everything
required, then configure the Xamarin.Android build to use those
bits.
3. Painstakingly determine which files are actually required, then
automatically download and extract those files into a "well-known"
location known by the Xamarin.Android build process.
(1) and (2) can be infuriating. Let's give (3) a try. :-)
Add a Xamarin.Android.Tools.BootstrapTasks project which contains
MSBuild tasks to facilitate downloading the Android SDK and NDK files.
Add an android-toolchain project which uses
Xamarin.Android.Tools.BootstrapTasks to download a painstakingly
determined set of files and install them "somewhere".
Unfortunately [5] the "somewhere" to download and install these files
needs to be in a known absolute path, so I've arbitrary decided to
download the files into $(HOME)\android-archives and install them into
$(HOME)\android-toolchain. On windows, this is
%HOMEDRIVE%%HOMEPATH%\android-archives and
%HOMEDRIVE%%HOMEPATH%\android-toolchain.
These locations may be modified by creating a
Configuration.Override.props file; see README.md for details.
TL;DR: This setup is able to magically download the Android NDK and
SDK files and install them for later use in a reasonably overridable
location, all within MSBuild.
[0]: http://www.joelonsoftware.com/articles/fog0000000043.html
[1]: Though maybe there's some MSBuild-fu we can use to address that.
[2]: https://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/android_callable_wrappers/
[3]: http://developer.android.com/sdk/index.html
[4]: https://www.xamarin.com/download
[5]: Because I couldn't find a reliable way to use $(SolutionDir) when
only building a project, and relative paths would require an
in-tree installation location, which might not work.
2016-04-19 03:33:04 +03:00
To simplify building Xamarin.Android, important pieces of the Android SDK
and Android NDK will be automatically downloaded and installed from
Google's website. Downloaded files are cached locally, by default into
2016-07-04 15:08:08 +03:00
`$(AndroidToolchainCacheDirectory)` . The Android NDK and SDK will be installed by
2016-04-21 04:45:28 +03:00
default into `$(AndroidToolchainDirectory)` .
[android-toolchain] Permit zero-configuration builds.
This might be a suspect idea, but lets see if we can make this work.
[The Joel Test: 12 Steps to Better Code][0] outlines 12 steps
to better code. The first two steps are:
1. Do you use source control?
2. Can you make a build in one step?
github is being used for source control, so (1) is handled, but how
simple can we make (2)? How easy can we make it to build
Xamarin.Android upon a fresh checkout?
The ideal to strive for is simple:
Load Xamarin.Android.sln into your IDE and Build the project.
I *know* we're not going to be able to do this, if only because we're
going to be using git submodules, which will require a separate
`git submodule init` invocation [1].
Knowing we can't reach that level of simplicitly doesn't mean we
shouldn't *try* to reach it for all other parts of the build system.
Which brings us to the Android NDK and SDK. The Android NDK will be
required in order to build native code, such as libmonodroid.so, while
the Android SDK will be required in order to compile
Java Callable Wrappers (née Android Callable Wrappers [2]) and
eventual samples and unit tests.
There are three ways we can deal with the Android NDK and SDK:
1. Complicate the "build" process by requiring that developers go to
the Android SDK Download Page [3], download and install
"somewhere" the required bits, and then configure the
Xamarin.Android build to use these bits.
2. Complicate the "build" process by requiring that developers run
the Xamarin Unified Installer [4], let it install everything
required, then configure the Xamarin.Android build to use those
bits.
3. Painstakingly determine which files are actually required, then
automatically download and extract those files into a "well-known"
location known by the Xamarin.Android build process.
(1) and (2) can be infuriating. Let's give (3) a try. :-)
Add a Xamarin.Android.Tools.BootstrapTasks project which contains
MSBuild tasks to facilitate downloading the Android SDK and NDK files.
Add an android-toolchain project which uses
Xamarin.Android.Tools.BootstrapTasks to download a painstakingly
determined set of files and install them "somewhere".
Unfortunately [5] the "somewhere" to download and install these files
needs to be in a known absolute path, so I've arbitrary decided to
download the files into $(HOME)\android-archives and install them into
$(HOME)\android-toolchain. On windows, this is
%HOMEDRIVE%%HOMEPATH%\android-archives and
%HOMEDRIVE%%HOMEPATH%\android-toolchain.
These locations may be modified by creating a
Configuration.Override.props file; see README.md for details.
TL;DR: This setup is able to magically download the Android NDK and
SDK files and install them for later use in a reasonably overridable
location, all within MSBuild.
[0]: http://www.joelonsoftware.com/articles/fog0000000043.html
[1]: Though maybe there's some MSBuild-fu we can use to address that.
[2]: https://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/android_callable_wrappers/
[3]: http://developer.android.com/sdk/index.html
[4]: https://www.xamarin.com/download
[5]: Because I couldn't find a reliable way to use $(SolutionDir) when
only building a project, and relative paths would require an
in-tree installation location, which might not work.
2016-04-19 03:33:04 +03:00
The files that will be downloaded and installed are controlled by
[build-tools/android-toolchain/android-toolchain.projitems][android-toolchain.projitems]
via the `@(AndroidNdkItem)` and `@(AndroidSdkItem)` item groups, and the
URL to download files from is controlled by the `$(AndroidUri)` property.
[android-toolchain.projitems]: build-tools/android-toolchain/android-toolchain.projitems
# Build
At this point in time, building Xamarin.Android is only supported on OS X.
We will work to improve this.
2016-04-20 04:30:00 +03:00
To build Xamarin.Android, first prepare the project:
make prepare
This will perform `git submodule update` , and any other pre-build tasks
that need to be performed.
Then, you may do one of the following:
1. Run make:
make
2. Load `Xamarin.Android.sln` into Xamarin Studio and Build the project.
[Mono.Android] Import from monodroid/3e934261
(*Now* things are starting to come together...)
One of the important infrastructural pieces of Xamarin.Android is
Mono.Android.dll, a "binding" for the Android SDK `android.jar` file.
Bindings are generated by using the `generator` tool from
Java.Interop, along with tools/jnienv-gen, and various other programs.
This in turn requires adding a git submodule for Java.Interop.
Stitch all these pieces together so that we can take an
*API description* (stored in Profiles\api-*.xml.in) and generate a
binding for that API description.
The generated files are located in
obj\$(Configuration)\android-$(ApiLevel), and the resulting
Mono.Android.dll is copied to
$(topdir)\bin\$(Configuration)\xbuild-frameworks\MonoAndroid\$(XAFrameworkVersion).
One SNAFU: currently, Mono.Android.csproj conditinally <Import/>s a
Mono.Android.projitems file generated by Java.Interop's generator
tool, which contains a list of all the generated files.
When the project is first loaded, Mono.Android.projitems will not
exist, so on that initial build, source code will be generated but
xbuild won't re-read Mono.Android.projitems (once it exists). This
will result in a failing build.
Simply rebuild the project to get a valid build, or use the `make all`
Makefile target.
2016-04-21 03:50:21 +03:00
*Note* : The `Mono.Android` project may *fail* on the first build
because it generates sources, and those sources won't exist on the
initial project load. Rebuild the project should this happen.
[mono-runtimes] Build AOT+LLVM cross-compilers (#125)
The commit implements building of LLVM and cross-compilers to support
Xamarin.Android/Mono AOT. LLVM and cross-compilers can be built for
both the host platform (Linux and OS/X at the moment) as well as
cross-compiled for 32-bit and 64-bit Windows platforms.
Windows builds are done with MXE toolchain on OS/X and with the packaged
mingw-w64 toolchain on Linux (tested on Ubuntu 16.04 ONLY).
Also introducing a new set of MSBuild properties that contain information
about the host system. Some of those properties (HostOS, HostCC, HostCXX
for instance) have been moved from Configuration.props to better support
auto-detection. A new script, build-tools/scripts/generate-os-info, is
invoked as part of `make prepare` to generate file that contains the
new properties. The generated file is required for the build to work and
is also host-specific (it mustn't be moved between different machines)
Cross compiler builds require access to a configured Mono build tree, in
order to generate C structure offsets header file that is used by the AOT
compilers to properly generate AOT-ed binaries. Therefore, even if a JIT
target is not enabled in the configuration, enabling a cross-compiler for
some target will configure Mono for that JIT target but it will NOT build
it, to save time. To facilitate this, the _MonoRuntimes items defined in
build-tools/mono-runtimes/mono-runtimes.projitems gain an additional metadata
item called `DoBuild` which will be set to `true` if the runtime actually needs
to be built, as opposed to just configured.
MXE builds are disabled on Linux as mingw-w64 works just fine.
A `make prepare` warning is issued for Linux hosts which have the binfmt_misc
module enabled and either Wine of Mono (cli) registered as PE32/PE32+ binary
interpreters. In such instance building of the Windows cross-compilers will
fail because Autotools determine whether software is being cross compiled by
building a test program and attempting to execute it. In normal circumstances
such an attempt will fail, but with Windows cross-compilation and either Wine
or Mono registered to handle the PE32 executables this attempt will succeed
thus causing the cross compilation detection to fail.
Currently to build cross compilers on Linux you need to generate the C structure
offsets header file on OS/X and copy the resulting headers to appropriate places
on Linux. The header files should be placed in
build-tools/mono-runtimes/obj/Debug/cross-*/
directories. The header files are:
{cross-arm,cross-arm-win}/aarch64-v8a-linux-android.h
{cross-arm64,cross-arm64-win}/armv5-none-linux-androideabi.h
{cross-x86,cross-x86-win}/i686-none-linux-android.h
{cross-x86_64,cross-x86_64-win}/x86_64-none-linux-android.h
Offsets header generation doesn't work on Linux atm because of missing support
for it in the Mono utility used to generate the offsets. Hopefully this limitation
will be removed in the near future and a start-to-end build of everything will be
possible on Linux.
It is now mandatory to run at least `make prepare-props` before Xamarin.Android
can be built. The target generates the OS-specific props file which is required
by the build. `make prepare` depends on the target.
2016-07-26 16:27:31 +03:00
## Linux build notes
If you have the `binfmt_misc` module enabled with any of Mono or Wine installed and
you plan to cross-build the Windows compilers and tools (by enabling the `mxe-Win32`
or `mxe-Win64` host targets) as well as LLVM+AOT targets, you will need to disable
`binfmt_misc` for the duration of the build or the Mono/LLVM configure scripts will
fail to detect they are cross-compiling and they will produce Windows PE executables
for tools required by the build.
To disable `binfmt_misc` you need to issue the following command as root:
echo 0 > /proc/sys/fs/binfmt_misc/status
and to enable it again, issue the following command:
echo 1 > /proc/sys/fs/binfmt_misc/status
2016-04-20 04:30:00 +03:00
# Build Output Directory Structure
There are two configurations, `Debug` and `Release` , controlled by the
`$(Configuration)` MSBuild property.
The `bin\Build$(Configuration)` directory, e.g. `bin\BuildDebug` , contains
artifacts needed for *building* the repository. They should not be needed
for later execution.
The `bin\$(Configuration)` directory, e.g. `bin\Debug` , contains
*redistributable* artifacts, such as tooling and runtimes. This directory
acts as a *local installation prefix* , in which the directory structure
mirrors that of the OS X Xamarin.Android.framework directory structure:
* `bin\$(Configuration)\lib\xbuild\Xamarin\Android` : MSBuild-related support
files and required runtimes used by the MSBuild tooling.
* `bin\$(Configuration)\lib\xbuild-frameworks\MonoAndroid` : Xamarin.Android
[Mono.Android] Import from monodroid/3e934261
(*Now* things are starting to come together...)
One of the important infrastructural pieces of Xamarin.Android is
Mono.Android.dll, a "binding" for the Android SDK `android.jar` file.
Bindings are generated by using the `generator` tool from
Java.Interop, along with tools/jnienv-gen, and various other programs.
This in turn requires adding a git submodule for Java.Interop.
Stitch all these pieces together so that we can take an
*API description* (stored in Profiles\api-*.xml.in) and generate a
binding for that API description.
The generated files are located in
obj\$(Configuration)\android-$(ApiLevel), and the resulting
Mono.Android.dll is copied to
$(topdir)\bin\$(Configuration)\xbuild-frameworks\MonoAndroid\$(XAFrameworkVersion).
One SNAFU: currently, Mono.Android.csproj conditinally <Import/>s a
Mono.Android.projitems file generated by Java.Interop's generator
tool, which contains a list of all the generated files.
When the project is first loaded, Mono.Android.projitems will not
exist, so on that initial build, source code will be generated but
xbuild won't re-read Mono.Android.projitems (once it exists). This
will result in a failing build.
Simply rebuild the project to get a valid build, or use the `make all`
Makefile target.
2016-04-21 03:50:21 +03:00
profiles.
* `bin\$(Configuration)\lib\xbuild-frameworks\MonoAndroid\v1.0` : Xamarin.Android
Base Class Library assemblies such as `mscorlib.dll` .
* `bin\$(Configuration)\lib\xbuild-frameworks\MonoAndroid\*` : Contains
`Mono.Android.dll` for a given Xamarin.Android `$(TargetFrameworkVersion)` .
# Xamarin.Android `$(TargetFrameworkVersion)`s
Xamarin.Android uses the MSBuild `$(TargetFrameworkVersion)` mechanism
to provide a separate `Mono.Android.dll` *binding assembly* for each API
level.
This means there is no *single* `Mono.Android.dll` , there is instead a *set*
of them.
This complicates the "mental model" for the `Mono.Android` project, as
a *project* can have only one output, not many (...within reason...).
As such, building the `Mono.Android` project will only generate a single
`Mono.Android.dll` .
2016-04-21 21:32:11 +03:00
To control which API level is bound, set the `$(AndroidApiLevel)` and
`$(AndroidFrameworkVersion)` properties. `$(AndroidApiLevel)` is the
Android API level, *usually* a number, while `$(AndroidFrameworkVersion)`
is the Xamarin.Android `$(TargetFrameworkVersion)` .
[Mono.Android] Import from monodroid/3e934261
(*Now* things are starting to come together...)
One of the important infrastructural pieces of Xamarin.Android is
Mono.Android.dll, a "binding" for the Android SDK `android.jar` file.
Bindings are generated by using the `generator` tool from
Java.Interop, along with tools/jnienv-gen, and various other programs.
This in turn requires adding a git submodule for Java.Interop.
Stitch all these pieces together so that we can take an
*API description* (stored in Profiles\api-*.xml.in) and generate a
binding for that API description.
The generated files are located in
obj\$(Configuration)\android-$(ApiLevel), and the resulting
Mono.Android.dll is copied to
$(topdir)\bin\$(Configuration)\xbuild-frameworks\MonoAndroid\$(XAFrameworkVersion).
One SNAFU: currently, Mono.Android.csproj conditinally <Import/>s a
Mono.Android.projitems file generated by Java.Interop's generator
tool, which contains a list of all the generated files.
When the project is first loaded, Mono.Android.projitems will not
exist, so on that initial build, source code will be generated but
xbuild won't re-read Mono.Android.projitems (once it exists). This
will result in a failing build.
Simply rebuild the project to get a valid build, or use the `make all`
Makefile target.
2016-04-21 03:50:21 +03:00
2016-08-01 16:12:20 +03:00
The default values will target Android API-24, Android 7.0.
[Mono.Android] Import from monodroid/3e934261
(*Now* things are starting to come together...)
One of the important infrastructural pieces of Xamarin.Android is
Mono.Android.dll, a "binding" for the Android SDK `android.jar` file.
Bindings are generated by using the `generator` tool from
Java.Interop, along with tools/jnienv-gen, and various other programs.
This in turn requires adding a git submodule for Java.Interop.
Stitch all these pieces together so that we can take an
*API description* (stored in Profiles\api-*.xml.in) and generate a
binding for that API description.
The generated files are located in
obj\$(Configuration)\android-$(ApiLevel), and the resulting
Mono.Android.dll is copied to
$(topdir)\bin\$(Configuration)\xbuild-frameworks\MonoAndroid\$(XAFrameworkVersion).
One SNAFU: currently, Mono.Android.csproj conditinally <Import/>s a
Mono.Android.projitems file generated by Java.Interop's generator
tool, which contains a list of all the generated files.
When the project is first loaded, Mono.Android.projitems will not
exist, so on that initial build, source code will be generated but
xbuild won't re-read Mono.Android.projitems (once it exists). This
will result in a failing build.
Simply rebuild the project to get a valid build, or use the `make all`
Makefile target.
2016-04-21 03:50:21 +03:00
For example, to generate `Mono.Android.dll` for API-19 (Android 4.4):
cd src/Mono.Android
2016-04-21 21:32:11 +03:00
xbuild /p:AndroidApiLevel=19 /p:AndroidFrameworkVersion=v4.4
[Mono.Android] Import from monodroid/3e934261
(*Now* things are starting to come together...)
One of the important infrastructural pieces of Xamarin.Android is
Mono.Android.dll, a "binding" for the Android SDK `android.jar` file.
Bindings are generated by using the `generator` tool from
Java.Interop, along with tools/jnienv-gen, and various other programs.
This in turn requires adding a git submodule for Java.Interop.
Stitch all these pieces together so that we can take an
*API description* (stored in Profiles\api-*.xml.in) and generate a
binding for that API description.
The generated files are located in
obj\$(Configuration)\android-$(ApiLevel), and the resulting
Mono.Android.dll is copied to
$(topdir)\bin\$(Configuration)\xbuild-frameworks\MonoAndroid\$(XAFrameworkVersion).
One SNAFU: currently, Mono.Android.csproj conditinally <Import/>s a
Mono.Android.projitems file generated by Java.Interop's generator
tool, which contains a list of all the generated files.
When the project is first loaded, Mono.Android.projitems will not
exist, so on that initial build, source code will be generated but
xbuild won't re-read Mono.Android.projitems (once it exists). This
will result in a failing build.
Simply rebuild the project to get a valid build, or use the `make all`
Makefile target.
2016-04-21 03:50:21 +03:00
# creates bin\Debug\lib\xbuild-frameworks\MonoAndroid\v4.4\Mono.Android.dll
2016-04-28 18:15:08 +03:00
2016-05-04 21:40:41 +03:00
# Samples
2016-04-28 18:15:08 +03:00
2016-05-04 21:40:41 +03:00
The [HelloWorld ](samples/HelloWorld ) sample may be built with the
[xabuild ](tools/scripts/xabuild ) script:
$ tools/scripts/xabuild /t:SignAndroidPackage samples/HelloWorld/HelloWorld.csproj
`xabuild /t:SignAndroidPackage` will generate an `.apk` file, which may be
installed onto an Android device with the [`adb install`][adb-commands]
command:
[adb-commands]: http://developer.android.com/tools/help/adb.html#commandsummary
$ adb install samples/HelloWorld/bin/Debug/com.xamarin.android.helloworld-Signed.apk
**HelloWorld** may be launched manually through the Android app launcher,
or via `adb shell am` :
$ adb shell am start com.xamarin.android.helloworld/example.MainActivity
# Contributing
## Mailing Lists
2016-04-28 18:15:08 +03:00
2016-04-28 18:16:44 +03:00
To discuss this project, and participate in the design, we use the [android-devel@lists.xamarin.com ](http://lists.xamarin.com/mailman/listinfo/android-devel ) mailing list.
2016-04-28 18:15:08 +03:00
2016-05-04 21:40:41 +03:00
## Coding Guidelines
2016-04-28 18:15:08 +03:00
We use [Mono's Coding Guidelines ](http://www.mono-project.com/community/contributing/coding-guidelines/ ).
2016-05-04 21:40:41 +03:00
## Reporting Bugs
2016-04-28 18:15:08 +03:00
2016-04-28 22:14:46 +03:00
We use [Bugzilla ](https://bugzilla.xamarin.com/enter_bug.cgi?product=Android ) to track issues.
2016-04-28 18:15:08 +03:00
2016-08-14 00:40:37 +03:00
# Maintainer FAQ
## How do I rebuild the Mono Runtime and Native Binaries?
The various Mono runtimes -- over *20* of them (!) -- all store object code
within `build-tools/mono-runtimes/obj/$(Configuration)/TARGET` .
If you change sources within `external/mono` , a top-level `make` /`xbuild`
invocation may not rebuild those mono native binaries. To explicitly rebuild
[xa-prep-tasks] Use the Mono bundle (#162)
Context: https://github.com/xamarin/xamarin-android/commit/fbfd676c102c63e4e06e750857b178725e33450c
Stage 3 of the cunning plan is to (attempt to) use the mono bundle
introduced in commit fbfd676c.
This "simple" desire (ha!) re-raises the architectural project
dependency issue "solved" in fbfd676c, but first, a simple question:
What should download the mono bundle?
There are two plausible answers:
1. `make prepare` can (somehow) handle it.
2. MSBuild can (somehow) handle it.
Both are plausible. The problem with using `make` targets (1) is there
is increased potential for "duplication" -- duplication of the bundle
filename, downloading it, and extracting it. Plus, `make` isn't
"Windows friendly", in that GNU make isn't (normally) present with
Visual Studio. (`NMAKE` is, but the Makefiles in this project are not
compatible with `NMAKE`.)
Which brings us to MSBuild (2): can it handle the task?
To tackle that, we need to be able to have an MSBuild task project
which has *no dependencies*, so that it can download and extract the
mono bundle *before anything else runs*, as it may be downloading
contents which mean that other projects don't *need* to run.
The need for a "pre-bootstrap" task assembly -- called `xa-prep-tasks`
-- thus "undoes" *some* of the logic regarding `libzip-windows.mdproj`
and the `<Zip/>` task from fbfd676c: it isn't *possible* to rely on
`libzip` from a "pre-build" state, as `libzip` is one of the things in
the mono bundle, so now we need *two* "bootstrap" task assemblies:
one without a `libzip` dependency -- `xa-prep-tasks.dll` -- and one
*with* a `libzip` dependency --
`Xamarin.Android.Tools.BootstrapTasks.dll`
Move tasks which don't currently require `libzip` -- or won't in the
future, or laziness -- from `Xamarin.Android.Tools.BootstrapTasks.dll`
and move them into `xa-prep-tasks.dll`.
With that architectural compromise in place, add `xa-prep-tasks` as a
`@(ProjectReference)` to various projects to help ensure it's built
*first*, and rearchitect `bundle.mdproj` so that
`xa-prep-tasks.targets` and `bundle.targets` can use the same targets
to compute the bundle filename, now in
`build-tools/bundle/bundle-path.targets`.
Add a post-build step to `xa-prep-tasks.csproj` which downloads and
extracts the expected mono bundle.
One "problem" (feature?) is that the new `<SystemUnzip/>` task doesn't
report errors as errors when unzip'ing the file. This turns out to be
fine here because when downloading the mono bundle from Azure we don't
get a 404 *anyway* -- Azure instead returns an XML document containing
an error message (wat?!). We can thus ignore most error handling
entirely...though we're *also* ignoring any checking for invalid
downloads, which is something we should address in the future.
Update the varioous project files so that they won't attempt to
rebuild binaries that were present in the mono bundle.
2016-08-16 23:02:48 +03:00
*all* Mono runtimes, use the `ForceBuild` target:
# Build and install all runtimes
$ xbuild /t:ForceBuild build-tools/mono-runtimes/mono-runtimes.mdproj
To build Mono for a specific target, run `make` from the relevant directory
and invoke the `_InstallRuntimes` target. For example, to rebuild
Mono for armeabi-v7a:
2016-08-14 00:40:37 +03:00
$ cd build-tools/mono-runtimes
$ make -C obj/Debug/armeabi-v7a
# This updates bin/$(Configuration)/lib/xbuild/Xamarin/Android/lib/armeabi-v7a/libmonosgen-2.0.so
$ xbuild /t:_InstallRuntimes
## How do I rebuild BCL assemblies?
The Xamarin.Android Base Class Library assemblies, such as `mscorlib.dll` ,
are built within `external/mono` , using Mono's normal build system:
# This updates external/mono/mcs/class/lib/monodroid/ASSEMBLY.dll
$ make -C external/mono/mcs/class/ASSEMBLY PROFILE=monodroid
Alternatively, if you want to rebuild *all* the assemblies, the "host"
Mono needs to be rebuilt. Note that the name of the "host" directory
varies based on the operating system you're building from:
$ make -C build-tools/mono-runtimes/obj/Debug/host-Darwin
Once the assemblies have been rebuilt, they can be copied into the appropriate
Xamarin.Android SDK directory by using the `_InstallBcl` target:
# This updates bin/$(Configuration)/lib/xbuild-frameworks/MonoAndroid/v1.0/ASSEMBLY.dll
$ xbuild build-tools/mono-runtimes/mono-runtimes.mdproj /t:_InstallBcl