Skip to content

Conversation

@jonpryor
Copy link
Contributor

@jonpryor jonpryor commented Jan 5, 2017

MSBuild is open source -- has been for ages -- and we'd really like
to migrate all things Mono to MSBuild and deprecate/remove xbuild.

Which means we need to ensure that all of our products build with
msbuild. Which unfortunately isn't the case in Java.Interop:

MSB3375: The file "../../bin/Release/Xamarin.Android.Cecil.dll" does not exist.
...
Java.Interop/MarshalMemberBuilder.cs(9,20): error CS0234:
The type or namespace name `Expressions' does not exist in the namespace `Java.Interop'. Are you missing an assembly reference?
...
    36 Warning(s)
    69 Error(s)

For starters, bring Java.Interop into aligntment/convention with the
xamarin-android repo, so that $(MSBUILD) is the Make variable
to specify the MSBuild engine to use, not $(XBUILD), and allow
$(V) to set $MONO_OPTIONS so that line numbers are included in
stack traces from mono.

Which brings us to the build errors. The MSB3375 error happens when
building e.g. Xamarin.Android.Cecil.csproj from another directory:

$ msbuild src/Xamarin.Android.Cecil/Xamarin.Android.Cecil.csproj
...
.../src/Xamarin.Android.Cecil/Xamarin.Android.Cecil.targets(33,5):
error MSB3375: The file "../../bin/Debug/Xamarin.Android.Cecil.dll" does not exist.
...

The cause, in turn, is because the nested <MSBuild/> invocation
overrides $(OutputPath) when building
external/Cecil/Mono.Cecil.csproj to be
Xamarin.Android.Cecil.csproj's $(OutputPath):

<PropertyGroup>
  <CecilOutputPath>$([System.IO.Path]::GetFullPath ('$(OutputPath)'))</CecilOutputPath>
</PropertyGroup>
<MSBuild
    Properties="OutputPath=$(CecilOutputPath)"
    ...
/>

Or rather, it tries to. It uses Path.GetFullPath() on
$(OutputPath) so that Mono.Cecil.csproj writes the assembly into
the expected Xamarin.Android.Cecil.csproj-specified directory. The
problem is that the Path.GetFullPath() call is relative to the
current working directory, so when:

  1. The current working directory isn't the same directory as the
    directory containing Xamarin.Android.Cecil.csproj, and
  2. We're building Xamarin.Android.Cecil.csproj, which defines
    $(OutputPath) as e.g. ..\..\Debug

(1) and (2) interplay so that $(CecilOutputPath) becomes e.g.
$CWD/../../bin/Debug, which is not the correct directory, and may
(will!) be outside of the repo checkout directory.

Modify the $(CecilOutputPath) definition so that it instead assumes
that $(OutputPath) is a directory relative to
$(MSBuildThisFileDirectory), equivalent to C#:

var OutputPath                = ...
var MSBuildThisFileDirectory  = ...

var CecilOutputPath = Path.Combine (MSBuildThisFileDirectory, OutputPath);
CecilOutputPath     = Path.GetFullPath (CecilOutputPath);

This fixes the above interplay by "inserting" use of
$(MSBuildThisFileDirectory) into the "normal"
msbuild Xamarin.Android.Cecil.csproj invocation path, ensuring that
output paths behave as expected.

This in turn allows Xamarin.Android.Cecil.dll to be placed into the
correct directory, which in turn fixes all of the other C# errors
(present apparently because Xamarin.Android.Cecil.dll couldn't be
resolved).

MSBuild is open source -- has been for ages -- and we'd *really* like
to migrate all things Mono to MSBuild and deprecate/remove `xbuild`.

Which means we need to ensure that all of our products build with
`msbuild`. [Which unfortunately isn't the case in `Java.Interop`][0]:

	MSB3375: The file "../../bin/Release/Xamarin.Android.Cecil.dll" does not exist.
	...
	Java.Interop/MarshalMemberBuilder.cs(9,20): error CS0234:
	The type or namespace name `Expressions' does not exist in the namespace `Java.Interop'. Are you missing an assembly reference?
	...
	    36 Warning(s)
	    69 Error(s)

For starters, bring Java.Interop into aligntment/convention with the
[`xamarin-android` repo][1], so that `$(MSBUILD)` is the Make variable
to specify the MSBuild engine to use, not `$(XBUILD)`, and allow
`$(V)` to set `$MONO_OPTIONS` so that line numbers are included in
stack traces from mono.

Which brings us to the build errors. The MSB3375 error happens when
building e.g. `Xamarin.Android.Cecil.csproj` from another directory:

	$ msbuild src/Xamarin.Android.Cecil/Xamarin.Android.Cecil.csproj
	...
	.../src/Xamarin.Android.Cecil/Xamarin.Android.Cecil.targets(33,5):
	error MSB3375: The file "../../bin/Debug/Xamarin.Android.Cecil.dll" does not exist.
	...

The cause, in turn, is because the nested `<MSBuild/>` invocation
overrides `$(OutputPath)` when building
`external/Cecil/Mono.Cecil.csproj` to be
*`Xamarin.Android.Cecil.csproj`'s* `$(OutputPath)`:

	<PropertyGroup>
	  <CecilOutputPath>$([System.IO.Path]::GetFullPath ('$(OutputPath)'))</CecilOutputPath>
	</PropertyGroup>
	<MSBuild
	    Properties="OutputPath=$(CecilOutputPath)"
	    ...
	/>

Or rather, it *tries* to. It uses `Path.GetFullPath()` on
`$(OutputPath)` so that `Mono.Cecil.csproj` writes the assembly into
the expected `Xamarin.Android.Cecil.csproj`-specified directory. The
problem is that the `Path.GetFullPath()` call is relative to the
*current working directory*, so when:

1. The current working directory isn't the same directory as the
    directory containing `Xamarin.Android.Cecil.csproj`, and
2. We're building `Xamarin.Android.Cecil.csproj`, which defines
    `$(OutputPath)` as e.g. `..\..\Debug`

(1) and (2) interplay so that `$(CecilOutputPath)` becomes e.g.
`$CWD/../../bin/Debug`, which is *not* the correct directory, and may
(will!) be outside of the repo checkout directory.

Modify the `$(CecilOutputPath)` definition so that it instead assumes
that `$(OutputPath)` is a directory *relative to*
`$(MSBuildThisFileDirectory)`, equivalent to C#:

	var OutputPath                = ...
	var MSBuildThisFileDirectory  = ...

	var CecilOutputPath = Path.Combine (MSBuildThisFileDirectory, OutputPath);
	CecilOutputPath     = Path.GetFullPath (CecilOutputPath);

This fixes the above interplay by "inserting" use of
`$(MSBuildThisFileDirectory)` into the "normal"
`msbuild Xamarin.Android.Cecil.csproj` invocation path, ensuring that
output paths behave as expected.

This in turn allows `Xamarin.Android.Cecil.dll` to be placed into the
correct directory, which in turn fixes all of the other C# errors
(present apparently because `Xamarin.Android.Cecil.dll` couldn't be
resolved).

[0]: https://jenkins.mono-project.com/view/Xamarin.Android/job/Java.Interop-msbuild/5/consoleText
[1]: https://github.com/xamarin/xamarin-android
@radekdoulik radekdoulik merged commit 65a0157 into dotnet:master Jan 5, 2017
jonpryor added a commit to jonpryor/java.interop that referenced this pull request Apr 19, 2021
Context: https://developercommunity.visualstudio.com/t/illegal-character-exception-in-xamarinandroid-afte/1363149

Changes: dotnet/android-tools@554d45a...d92fc3e

  * dotnet/android-tools@d92fc3e: [Xamarin.Android.Tools.AndroidSdk] Probe for AdoptOpenJDK Locations (dotnet#115)
  * dotnet/android-tools@dca30d9: [Xamarin.Android.Tools.AndroidSdk] Probe for Zulu JDK (dotnet#114)
  * dotnet/android-tools@237642c: [Xamarin.Android.Tools.AndroidSdk] Probe for Microsoft OpenJDK dirs (dotnet#113)
  * dotnet/android-tools@e618e00: [Xamarin.Android.Tools.AndroidSdk] Fix quotes in %PATH% or %PATHEXT% (dotnet#112)
jonpryor added a commit that referenced this pull request Apr 20, 2021
Context: https://developercommunity.visualstudio.com/t/illegal-character-exception-in-xamarinandroid-afte/1363149

Changes: dotnet/android-tools@554d45a...d92fc3e

  * dotnet/android-tools@d92fc3e: [Xamarin.Android.Tools.AndroidSdk] Probe for AdoptOpenJDK Locations (#115)
  * dotnet/android-tools@dca30d9: [Xamarin.Android.Tools.AndroidSdk] Probe for Zulu JDK (#114)
  * dotnet/android-tools@237642c: [Xamarin.Android.Tools.AndroidSdk] Probe for Microsoft OpenJDK dirs (#113)
  * dotnet/android-tools@e618e00: [Xamarin.Android.Tools.AndroidSdk] Fix quotes in %PATH% or %PATHEXT% (#112)

Finally, *prefer* JDK 8, as hilarious as that is, for two reasons:

 1. `gradlew` fails to execute when running under OpenJDK 14:

        [ERROR] [system.err] java.lang.NoClassDefFoundError: Could not initialize class org.codehaus.groovy.vmplugin.v7.Java7

 2. The unit tests added in 69e1b80 currently depend upon the XML
    formatting conventions of JDK 8, and the tests fail when running
    under JDK 11 because of whitespace changes in `javax.xml` output.

For now, it's currently easier to just require JDK 8.

The preferred JDK version is controlled by the new `$(MaxJdkVersion)`
YAML variable, which in turn sets `$(JI_MAX_JDK)` (55c56f7) and/or
the `$(MaxJdkVersion)` MSBuild property, which
`dotnet build -t:Prepare` uses to generate `bin/Build*/JdkInfo.props`.

Finally, *for consistency*, update `TestJVM` to look for the generated
`JdkInfo.props`.  If found, use the `$(JdkJvmPath)` value at
`/Project/Chooose/When/PropertyGroup/JdkJvmPath` instead of using
`JdkInfo.GetKnownSystemJdkInfos()`, so that the JVM that we built
against is also used for unit test execution.
@github-actions github-actions bot locked and limited conversation to collaborators Apr 15, 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.

3 participants