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

[build] Cursory JDK 9 support #1214

Merged
merged 1 commit into from
Jan 23, 2018
Merged

[build] Cursory JDK 9 support #1214

merged 1 commit into from
Jan 23, 2018

Conversation

jonpryor
Copy link
Member

We have a VSTS+macOS build machine which has JDK 9 as the default JDK,
thus causing all xamarin-android builds to fail, as gradlew and
JDK 9 don't directly mix:

Executing: ./gradlew assembleDebug --stacktrace
...
org.gradle.api.ProjectConfigurationException: A problem occurred configuring project ':library'.
  ...
Caused by: org.gradle.internal.event.ListenerNotificationException:
Failed to notify project evaluation listener.
  ...
Caused by: java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
  ...
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema

When using JDK 9, gradlew fails because something within it
attempts to use the deprecated type
javax.xml.bind.annotation.XmlSchema, and JDK 9 doesn't provide
deprecated modules in the default $CLASSPATH.

Knowing that the VSTS machine also has JDK 8 installed, we've tried
to "filter out" JDK 9 so that it wouldn't be used; see e.g. a3c4358.
Unfortunately that doesn't work, because on macOS the default JDK used
is always the JDK with the highest version number, and
this can't be easily changed system-wide because changing this
behavior requires "removing" a Info.plist file to prevent the JDK
from being "seen" by /usr/bin/java:

# Don't use JDK 9 by default on macOS:
$ cd /Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents
$ mv Info.plist Info.plist.disabled

(Renaming Info.plist.disabled to Info.plist will restore JDK 9 as
the default JDK on the machine.)

A "proper" fix would presumably involve using and exporting
$JAVA_HOME everywhere, which isn't currently the case.
This is something that should be explored.

In the meantime, a question: Can we build with JDK 9?
Is it even possible in the first place?

Turns out, yes, it is possible. The above gradlew error can be
fixed by providing the (new-in-JDK9) --add-modules option, so that
the java.xml.bind module is accessible:

$ ANDROID_HOME=... JAVA_OPTS="--add-modules java.xml.bind" ./gradlew assembleDebug --stacktrace --no-daemon
# ...works!

Unfortunately, other parts xamarin-android get in the way, e.g. the
<ResolveSdks/> task doesn't correctly parse the version number out
of java -version, and JDK 9 javac requires -source and -target
when -bootclasspath is used.

Update the build system and tests so that things can be built under
JDK 9.

Note: This does NOT mean that building and/or using JDK 9
will be commercially supported in any way. (It might not even work!)

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any way we can merge these Xamarin.Android.BindingResolveImportLib*.targets files into one? For the most part the BuildJar and CleanJar targets are identical.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. There is now a new build-tools/scripts/Jar.targets file which contains a BuildTestJarFile target. This takes the @(TestJarEntry) item group -- which is assumed to contain Java source code -- compiles it with javac, and then jars it into %(TestJarEntry.OutputFile). Through the joy of Target batching, this allows a project to fairly easily generate any number of output .jar files without too much difficulty.

We have a VSTS+macOS build machine which has JDK 9 as the default JDK,
thus causing *all* xamarin-android builds to fail, as `gradlew` and
JDK 9 don't *directly* mix:

	Executing: ./gradlew assembleDebug --stacktrace
	...
	org.gradle.api.ProjectConfigurationException: A problem occurred configuring project ':library'.
	  ...
	Caused by: org.gradle.internal.event.ListenerNotificationException:
	Failed to notify project evaluation listener.
	  ...
	Caused by: java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
	  ...
	Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema

When using JDK 9, `gradlew` fails because *something* within it
attempts to use the deprecated type
`javax.xml.bind.annotation.XmlSchema`, and JDK 9 doesn't provide
deprecated modules in the default `$CLASSPATH`.

Knowing that the VSTS machine *also* has JDK 8 installed, we've tried
to "filter out" JDK 9 so that it wouldn't be used; see e.g. a3c4358.
Unfortunately that doesn't work, because on macOS the default JDK used
is [always the JDK with the highest version number][macOS-jdk], and
this can't be easily changed system-wide because changing this
behavior requires "removing" a `Info.plist` file to prevent the JDK
from being "seen" by `/usr/bin/java`:

[macOS-jdk]: https://stackoverflow.com/a/44169445

	# Don't use JDK 9 by default on macOS:
	$ cd /Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents
	$ mv Info.plist Info.plist.disabled

(Renaming `Info.plist.disabled` to `Info.plist` will restore JDK 9 as
the default JDK on the machine.)

A "proper" fix would presumably involve using and exporting
`$JAVA_HOME` *everywhere*, which isn't currently the case.
[This is something that *should* be explored.][xa-1213]

[xa-1213]: dotnet#1213

In the meantime, a question: *Can* we build with JDK 9?
*Is it even possible in the first place*?

Turns out, *yes*, it *is* possible. The above `gradlew` error can be
fixed by providing the (new-in-JDK9) `--add-modules` option, so that
the `java.xml.bind` module is accessible:

	$ ANDROID_HOME=... JAVA_OPTS="--add-modules java.xml.bind" ./gradlew assembleDebug --stacktrace --no-daemon
	# ...works!

Unfortunately, *other* parts xamarin-android get in the way, e.g. the
`<ResolveSdks/>` task doesn't correctly parse the version number out
of `java -version`, and JDK 9 `javac` requires `-source` and `-target`
when `-bootclasspath` is used.

Update the build system and tests so that things *can* be built under
JDK 9.

Additionally, cleanup the internal build system a bit: instead of
having `javac` and `jar` calls strewn throughout *7* different
projects -- all of which would need to be updated to provide usable
`javac -source` and `javac -target` values (JDK 9 doesn't support
`-target 1.6` anymore!), introduce `build-tools\scripts\Jar.targets`
and the new `BuildTestJarFile` target. This takes all
`@(TestJarEntry)` files, compiles them with `javac`, and `jar`s the
compiled files into `%(TestJarEntry.OutputFile)`.

**Note**: This does ***NOT*** mean that building and/or using JDK 9
will be commercially supported in *any* way. (It might not even work!)
@dellis1972 dellis1972 merged commit 0e1d1c8 into dotnet:master Jan 23, 2018
@jonpryor jonpryor deleted the jonp-jdk9 branch January 23, 2018 15:45
dellis1972 pushed a commit that referenced this pull request Jan 30, 2018
We have a VSTS+macOS build machine which has JDK 9 as the default JDK,
thus causing *all* xamarin-android builds to fail, as `gradlew` and
JDK 9 don't *directly* mix:

	Executing: ./gradlew assembleDebug --stacktrace
	...
	org.gradle.api.ProjectConfigurationException: A problem occurred configuring project ':library'.
	  ...
	Caused by: org.gradle.internal.event.ListenerNotificationException:
	Failed to notify project evaluation listener.
	  ...
	Caused by: java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
	  ...
	Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema

When using JDK 9, `gradlew` fails because *something* within it
attempts to use the deprecated type
`javax.xml.bind.annotation.XmlSchema`, and JDK 9 doesn't provide
deprecated modules in the default `$CLASSPATH`.

Knowing that the VSTS machine *also* has JDK 8 installed, we've tried
to "filter out" JDK 9 so that it wouldn't be used; see e.g. a3c4358.
Unfortunately that doesn't work, because on macOS the default JDK used
is [always the JDK with the highest version number][macOS-jdk], and
this can't be easily changed system-wide because changing this
behavior requires "removing" a `Info.plist` file to prevent the JDK
from being "seen" by `/usr/bin/java`:

[macOS-jdk]: https://stackoverflow.com/a/44169445

	# Don't use JDK 9 by default on macOS:
	$ cd /Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents
	$ mv Info.plist Info.plist.disabled

(Renaming `Info.plist.disabled` to `Info.plist` will restore JDK 9 as
the default JDK on the machine.)

A "proper" fix would presumably involve using and exporting
`$JAVA_HOME` *everywhere*, which isn't currently the case.
[This is something that *should* be explored.][xa-1213]

[xa-1213]: #1213

In the meantime, a question: *Can* we build with JDK 9?
*Is it even possible in the first place*?

Turns out, *yes*, it *is* possible. The above `gradlew` error can be
fixed by providing the (new-in-JDK9) `--add-modules` option, so that
the `java.xml.bind` module is accessible:

	$ ANDROID_HOME=... JAVA_OPTS="--add-modules java.xml.bind" ./gradlew assembleDebug --stacktrace --no-daemon
	# ...works!

Unfortunately, *other* parts xamarin-android get in the way, e.g. the
`<ResolveSdks/>` task doesn't correctly parse the version number out
of `java -version`, and JDK 9 `javac` requires `-source` and `-target`
when `-bootclasspath` is used.

Update the build system and tests so that things *can* be built under
JDK 9.

Additionally, cleanup the internal build system a bit: instead of
having `javac` and `jar` calls strewn throughout *7* different
projects -- all of which would need to be updated to provide usable
`javac -source` and `javac -target` values (JDK 9 doesn't support
`-target 1.6` anymore!), introduce `build-tools\scripts\Jar.targets`
and the new `BuildTestJarFile` target. This takes all
`@(TestJarEntry)` files, compiles them with `javac`, and `jar`s the
compiled files into `%(TestJarEntry.OutputFile)`.

**Note**: This does ***NOT*** mean that building and/or using JDK 9
will be commercially supported in *any* way. (It might not even work!)
jonpryor pushed a commit that referenced this pull request Aug 11, 2021
…Tasks (#6116)

Context: https://discord.com/channels/732297728826277939/732297837953679412/865316625950572554
Context: https://discord.com/channels/732297728826277939/732297837953679412/869307441601470484

Changes: https://github.com/xamarin/monodroid/compare/b359d3b43774ff031add3d7a4949483052957db3...fb0d502139bc222d4e9ad82f912b1c6f1d4ca34e

  * xamarin/monodroid@fb0d50213: StrongName Xamarin.Android.Build.Debugging.Tasks (#1214)
  * xamarin/monodroid@71ac9a81b: Bump to xamarin/xamarin-android/main@4ea37883 (#1220)

Occasionally when:

 1. Building on Windows within Visual Studio, with
 2. "Legacy" Xamarin.Android installed, and
 3. A preview .NET for Android (net6.0 + Android) workload installed

the build may fail:

	C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\30.0.100-preview.6.62\tools\Xamarin.Android.Common.targets(512,7): error MSB4064: The "ManifestPlaceholders" parameter is not supported by the "GetAndroidPackageName" task loaded from assembly: Xamarin.Android.Build.Tasks, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null from the path: D:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Xamarin\Android\Xamarin.Android.Build.Tasks.dll. Verify that the parameter exists on the task, the <UsingTask> points to the correct assembly, and it is a settable public instance property.
	C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\30.0.100-preview.6.62\tools\Xamarin.Android.Common.targets(509,3): error MSB4063: The "GetAndroidPackageName" task could not be initialized with its input parameters.

The root cause of the problem is that *both* "Legacy" Xamarin.Android
and .NET SDK for Android contain a non-strong-named
`Xamarin.Android.Build.Tasks.dll`, and if a Project Solution `.sln`
contains Projects `.csproj` which reference both SDKs, then
`Xamarin.Android.Build.Tasks.dll` will only be loaded *once*, which
will be incompatible with the other.  In the above error message,
the legacy `Xamarin.Android.Build.Tasks.dll` was loaded first,
causing the build to fail when trying to build the .NET SDK for Android
project.

There are three ways to solve this:

 1. Maintain API compatibility between Legacy & .NET 6+
 2. Use different assembly names between "Legacy" and .NET 6+, or
 3. [Strong-name][0] all MSBuild-related assemblies.

(1) is a non-starter; new or different functionality is introduced as
part of .NET SDK for Android.  The assemblies can't be API compatible.

We could solve via (2) by renaming the .NET SDK for Android assembly
to e.g. `Microsoft.Android.Build.Tasks.dll`, but this only delays the
problem; come .NET 7, we'll still have the same assembly name for two
different installation locations (.NET 6, .NET 7), and they won't be
compatible with each other.

Which leaves (3): we strong-name our MSBuild assemblies.
Strong-naming allows us to have different versions installed
"side by side" (Legacy and .net 6) in separate directories.
Strong-naming is the best solution to this issue.

A few notes though.

 1. `pdb2mdb.exe` is now ILRepacked into `Xamarin.Android.Build.Tasks`
    via [`ILRepack`][1], as it is not Strong-named.  See also 610ade7.

 2. The `Xamarin.Android.Build.Tasks.csproj` project itself is *NOT*
    StrongNamed. This is because `pdb2mdb.exe` is not either.
    We handle the StrongNaming via the `ILRepacker` target later in
    the build.  The end result is a Strong-named 
    `Xamarin.Android.Build.Tasks.dll`.

Co-authored-by: Jonathan Peppers <[email protected]>

[0]: https://docs.microsoft.com/en-us/dotnet/standard/assembly/strong-named
[1]: https://www.nuget.org/packages/ILRepack/
@github-actions github-actions bot locked and limited conversation to collaborators Feb 4, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants