Skip to content

Conversation

@jonpryor
Copy link
Contributor

@jonpryor jonpryor commented Aug 5, 2016

DO NOT MERGE

This is an "alternate" take on PR #146.


We're trying to get make jenkins working on Jenkins, and
it's failing, as one might expect when a particular repo and
associated build system has never been run on Jenkins before:

Android.App/ApplicationTest.cs(9,7): error CS0246: The type or namespace name `NUnit' could not be found. Are you missing an assembly reference?

This error occurs while building
src/Mono.Android/Test/Mono.Android-Tests.csproj, and happens because
the Xamarin.Android.NUnitLite.dll assembly isn't referenced...
because it isn't found:

Microsoft.Common.targets: warning : Reference 'Xamarin.Android.NUnitLite' not resolved

This raises a long-standing issue with building xamarin-android:
The Xamarin.Android SDK is intended to be usable from a system-wide
installation environment, e.g. installed into
$(MSBuildExtensionsPath), as many MSBuild tasks such as
<GetReferenceAssemblyPaths/> are used to resolve assemblies, and
those -- by default -- look in system-wide installation locations.

"Unfortunately," A xamarin-android build should not be built
into the system-wide install location; it should be built in a
separate location, for all manner of "hygiene" and "sanity" reasons.

Additionally, overriding $(TargetFrameworkRootPath) isn't a reliable
solution.

All of which adds up to either build failures such as the above --
when there is no system-wide Xamarin.Android install -- or the
use/resolution of the system-wide Xamarin.Android assemblies when
building e.g. src/Mono.Android/Test, which is wholly undesirable.

A possible "fix"/"workaround": force xbuild to behave as we want
it to by setting the $MSBuildExtensionsPath and
$XBUILD_FRAMEWORK_FOLDERS_PATH environment variables
from within the build process. Since xbuild doesn't cache the
value of these environment variables, calling
Environment.SetEnvironmentVariable() within the build process will
cause subsequent <GetReferenceAssemblyPaths/>/etc. invocations to
use the updated values, allowing us to control which directories are
used for assembly framework resolution purposes.

Update the _GetReferenceAssemblyPaths target within
Xamarin.Android.Common.targets and
Xamarin.Android.Bindings.targets so that they call the new
<SetMSBuildExtensionsPath/> task, which updates the
$MSBuildExtensionsPath and $XBUILD_FRAMEWORK_FOLDERS_PATH
environment variables. This allows building src/Mono.Android/Test
with "normal" xbuild to use the intended assemblies without
requiring the use of tools/scripts/xabuild to build
src/Mono.Android/Test.

@radical
Copy link
Member

radical commented Aug 5, 2016

re:commit-msg, did you miss the links for [make jenkins][0] and [it's failing][1]?

We're trying to get [`make jenkins`][0] working on Jenkins, and
[it's failing][1], as one might expect when a particular repo and
associated build system has never been run on Jenkins before:

	Android.App/ApplicationTest.cs(9,7): error CS0246: The type or namespace name `NUnit' could not be found. Are you missing an assembly reference?

This error occurs while building
`src/Mono.Android/Test/Mono.Android-Tests.csproj`, and happens because
the `Xamarin.Android.NUnitLite.dll` assembly isn't referenced...
because it isn't *found*:

	Microsoft.Common.targets: warning : Reference 'Xamarin.Android.NUnitLite' not resolved

This raises a long-standing issue with building `xamarin-android`:
The Xamarin.Android SDK is intended to be usable from a system-wide
installation environment, e.g. installed into
`$(MSBuildExtensionsPath)`, as many MSBuild tasks such as
`<GetReferenceAssemblyPaths/>` are used to resolve assemblies, and
those -- by default -- look in system-wide installation locations.

"Unfortunately," A `xamarin-android` *build* **should not** be built
into the system-wide install location; it should be built in a
separate location, for all manner of "hygiene" and "sanity" reasons.

Additionally, overriding `$(TargetFrameworkRootPath)` isn't a reliable
solution.

All of which adds up to either build failures such as the above --
when there is no system-wide Xamarin.Android install -- or the
use/resolution of the system-wide Xamarin.Android assemblies when
building e.g. `src/Mono.Android/Test`, which is wholly undesirable.

A possible "fix"/"workaround": *force* `xbuild` to behave as we want
it to by setting the `$MSBuildExtensionsPath` and
`$XBUILD_FRAMEWORK_FOLDERS_PATH` environment variables
*from within the build process*. Since `xbuild` doesn't cache the
value of these environment variables, calling
`Environment.SetEnvironmentVariable()` within the build process will
cause subsequent `<GetReferenceAssemblyPaths/>`/etc. invocations to
use the updated values, allowing us to control which directories are
used for assembly framework resolution purposes.

Update the `_GetReferenceAssemblyPaths` target within
`Xamarin.Android.Common.targets` and
`Xamarin.Android.Bindings.targets` so that they call the new
`<SetMSBuildExtensionsPath/>` task, which updates the
`$MSBuildExtensionsPath` and `$XBUILD_FRAMEWORK_FOLDERS_PATH`
environment variables. This allows building `src/Mono.Android/Test`
with "normal" `xbuild` to use the intended assemblies without
requiring the use of `tools/scripts/xabuild` to build
`src/Mono.Android/Test`.

[0]: dotnet@a16673d
[1]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android/20/console
@jonpryor jonpryor force-pushed the jonp-set-MSBuildExtensionsPath branch from feddd9b to ec426d1 Compare August 5, 2016 21:40
const string XBUILD_FRAMEWORK_FOLDERS_PATH = "XBUILD_FRAMEWORK_FOLDERS_PATH";
public override bool Execute ()
{
var frameworksPath = Path.GetDirectoryName (typeof (SetMSBuildExtensionsPath).Assembly.Location);
Copy link
Member

Choose a reason for hiding this comment

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

Where is this task being loaded from? Can this path that we are trying to determine here, be computed in the targets and passed as input here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The task is being loaded from wherever Xamarin.Android.Build.Tasks.dll is installed, $prefix/lib/xbuild/Xamarin/Android on OS X.

@jonpryor
Copy link
Contributor Author

jonpryor commented Aug 8, 2016

It seems that this approach isn't viable, because of xbuild's AsssemblyResolver. (There's no way to clear/invalidate target_framework_cache.)

Background: we want src/Mono.Android/Test/Mono.Android-Tests.csproj to be as normal as possible, so it uses <Reference Include="Xamarin.Android.NUniteLite" /> instead of a @(ProjectReference) to Xamarin.Android.NuniteLite. (There is a @(ProjectReference) to Xamarin.Android.NuniteLite.csproj, but %(ProjectReference.ReferenceOutputAssembly) is False, preventing the assembly from being referenced. @(ProjectReference) is there solely to control the build order: Xamarin.Android.NUniteLite.dll is required, so it must be built first.)

The idea of PR #147 was to "hack things up" so that Xamarin.Android.NuniteLite.dll would be properly resolved during the build of Mono.Android-Tests.csproj when building everything.

The problem is this can't work, because xbuild has a "target framework cache," with no way to invalidate it, and the cache is populated the first time the target framework is used. Due to build ordering issues, this first use is before Xamarin.Android.NunitLite.dll was built, and thus it doesn't exist in the cache. The result:

Task "ResolveAssemblyReference"
    ....
    TargetFrameworkDirectories:
        /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v7.0
        /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0
        /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/Facades/
    ...
    Primary Reference System.Xml
        Reference System.Xml resolved to /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/System.Xml.dll. CopyLocal = False
    ...
    Primary Reference Xamarin.Android.NUnitLite
Microsoft.Common.targets:  warning : Reference 'Xamarin.Android.NUnitLite' not resolved
    For searchpath {TargetFrameworkDirectory}
    Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v7.0, assembly named 'Xamarin.Android.NUnitLite' not found.
    Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0, assembly named 'Xamarin.Android.NUnitLite' not found.
    Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/Facades/, assembly named 'Xamarin.Android.NUnitLite' not found.
...

Consequently, the mcs invocation is missing a /reference:path/to/Xamarin.Android.NUniteLite.dll, and compilation fails:

Android.App/ApplicationTest.cs(9,7): error CS0246: The type or namespace name `NUnit' could not be found. Are you missing an assembly reference?
...plus 29 others...

jonpryor added a commit to jonpryor/xamarin-android that referenced this pull request Aug 8, 2016
We're trying to get [`make jenkins`][0] working on Jenkins, and
[it's failing][1], as one might expect when a particular repo and
associated build system has never been run on Jenkins before:

	Android.App/ApplicationTest.cs(9,7): error CS0246: The type or namespace name `NUnit' could not be found. Are you missing an assembly reference?

This error occurs while building
`src/Mono.Android/Test/Mono.Android-Tests.csproj`, and happens because
the `Xamarin.Android.NUnitLite.dll` assembly isn't referenced...
because it isn't *found*:

	Microsoft.Common.targets: warning : Reference 'Xamarin.Android.NUnitLite' not resolved

This returns us to a long-standing issue which I thought was mentioned
in a commit somewhere, but I can't find at present:

MSBuild doesn't support updating the assembly resolution directories
*while MSBuild is running*.

For example, we build `Xamarin.Android.NUniteLite.dll` into
`bin/$(Configuration/lib/xbuild-frameworks/MonoAndroid/v1.0`,
but "normal Xamarin.Android referencing projects" don't use a
`@(ProjectReference)` to `Xamarin.Android.NUnitLite.csproj`, but
instead a `@(Reference)` to the assembly:

	<!-- src/Mono.Android/Test/Mono.Android-Tests.csproj -->
	<Reference Include="Xamarin.Android.NUnitLite" />

The *requirement* for a "proper" Xamarin.Android SDK install is that
`Xamarin.Android.NUnitLite.dll` can be found through a normal
`@(Reference)`. In order to satisfy this requirement, we need to tell
MSBuild where to find it, which can be with `xbuild` via the
`$MSBuildExtensionsPath` and `$XBUILD_FRAMEWORK_FOLDERS_PATH`
*environment variables*.

*Environment variables*.

MSBuild doesn't provide a way to update environment variables, short
of writing a new Task which calls
`Environment.SetEnvironmentVariable()`, and while [this works][2], it
doesn't *actually* work [^3].

The short of all this is that it isn't possible,
*within a single `xbuild` invocation*, to both build the
Xamarin.Android SDK "environment" *and use that environment* as
intended for "normal" apps.

The fix, as is often the case, is to bend with the wind. Instead of
requiring the impossible, move
`src/Mono.Android/Test/Mono.Android-Tests.csproj` into a *new*
`Xamarin.Android-Tests.sln` solution, *out of* `Xamarin.Android.sln`.
This allows building `Xamarin.Android.sln` without error in a pristine
environment -- that is, one that doesn't already have a system-wide
Xamarin.Android install -- and separately building the tests by using
`tools/scripts/xabuild`, which *can* export environment variables to
manipulate `xbuild` behavior so that things Just Work™ [^5].

Building `Mono.Android-Tests.csproj` and similar projects
(`HelloWorld.csproj`!) can be done by using the new `make all-tests`
make target.

[0]: dotnet@a16673d
[1]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android/20/console
[2]: dotnet#147
[^3]: [PR dotnet#147][2] isn't viable because of [xbuild's `AsssemblyResolver`][4].
    There's no way to clear/invalidate `target_framework_cache`.

    The idea of PR dotnet#147 was to "hack things up" so that
    `Xamarin.Android.NuniteLite.dll` would be properly resolved during
    the build of `Mono.Android-Tests.csproj` *when building everything*.

    The problem is *this can't work*, because `xbuild` has a
    "target framework cache," with no way to invalidate it, and the
    cache is populated the first time the target framework is used.
    Due to build ordering issues, this first use is *before*
    `Xamarin.Android.NunitLite.dll` was built, and thus it doesn't
    exist in the cache. The result:

        Task "ResolveAssemblyReference"
            ....
            TargetFrameworkDirectories:
                /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v7.0
                /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0
                /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/Facades/
            ...
            Primary Reference System.Xml
                Reference System.Xml resolved to /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/System.Xml.dll. CopyLocal = False
            ...
            Primary Reference Xamarin.Android.NUnitLite
        Microsoft.Common.targets:  warning : Reference 'Xamarin.Android.NUnitLite' not resolved
            For searchpath {TargetFrameworkDirectory}
            Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v7.0, assembly named 'Xamarin.Android.NUnitLite' not found.
            Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0, assembly named 'Xamarin.Android.NUnitLite' not found.
            Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/Facades/, assembly named 'Xamarin.Android.NUnitLite' not found.
        ...

    Consequently, the `mcs` invocation is missing a
    `/reference:path/to/Xamarin.Android.NUniteLite.dll`, and
    compilation fails:

        Android.App/ApplicationTest.cs(9,7): error CS0246: The type or namespace name `NUnit' could not be found. Are you missing an assembly reference?
        ...plus 29 others...

[4]: https://github.com/mono/mono/blob/dd8aadf/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/AssemblyResolver.cs#L131
[^5]: ...except they don't just work, due to other bugs, but those
    will be separately addressed.

        error XA4210: You need to add a reference to Mono.Android.Export.dll when you use ExportAttribute or ExportFieldAttribute
jonpryor added a commit to jonpryor/xamarin-android that referenced this pull request Aug 8, 2016
We're trying to get [`make jenkins`][0] working on Jenkins, and
[it's failing][1], as one might expect when a particular repo and
associated build system has never been run on Jenkins before:

	Android.App/ApplicationTest.cs(9,7): error CS0246: The type or namespace name `NUnit' could not be found. Are you missing an assembly reference?

This error occurs while building
`src/Mono.Android/Test/Mono.Android-Tests.csproj`, and happens because
the `Xamarin.Android.NUnitLite.dll` assembly isn't referenced...
because it isn't *found*:

	Microsoft.Common.targets: warning : Reference 'Xamarin.Android.NUnitLite' not resolved

This returns us to a long-standing issue which I thought was mentioned
in a commit somewhere, but I can't find at present:

MSBuild doesn't support updating the assembly resolution directories
*while MSBuild is running*.

For example, we build `Xamarin.Android.NUniteLite.dll` into
`bin/$(Configuration/lib/xbuild-frameworks/MonoAndroid/v1.0`,
but "normal Xamarin.Android referencing projects" don't use a
`@(ProjectReference)` to `Xamarin.Android.NUnitLite.csproj`, but
instead a `@(Reference)` to the assembly:

	<!-- src/Mono.Android/Test/Mono.Android-Tests.csproj -->
	<Reference Include="Xamarin.Android.NUnitLite" />

The *requirement* for a "proper" Xamarin.Android SDK install is that
`Xamarin.Android.NUnitLite.dll` can be found through a normal
`@(Reference)`. In order to satisfy this requirement, we need to tell
MSBuild where to find it, which can be with `xbuild` via the
`$MSBuildExtensionsPath` and `$XBUILD_FRAMEWORK_FOLDERS_PATH`
*environment variables*.

*Environment variables*.

MSBuild doesn't provide a way to update environment variables, short
of writing a new Task which calls
`Environment.SetEnvironmentVariable()`, and while [this works][2], it
doesn't *actually* work [^3].

The short of all this is that it isn't possible,
*within a single `xbuild` invocation*, to both build the
Xamarin.Android SDK "environment" *and use that environment* as
intended for "normal" apps.

The fix, as is often the case, is to bend with the wind. Instead of
requiring the impossible, move
`src/Mono.Android/Test/Mono.Android-Tests.csproj` into a *new*
`Xamarin.Android-Tests.sln` solution, *out of* `Xamarin.Android.sln`.
This allows building `Xamarin.Android.sln` without error in a pristine
environment -- that is, one that doesn't already have a system-wide
Xamarin.Android install -- and separately building the tests by using
`tools/scripts/xabuild`, which *can* export environment variables to
manipulate `xbuild` behavior so that things Just Work™.

Building `Mono.Android-Tests.csproj` and similar projects
(`HelloWorld.csproj`!) can be done by using the new `make all-tests`
make target.

[0]: dotnet@a16673d
[1]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android/20/console
[2]: dotnet#147
[^3]: [PR dotnet#147][2] isn't viable because of [xbuild's `AsssemblyResolver`][4].
    There's no way to clear/invalidate `target_framework_cache`.

    The idea of PR dotnet#147 was to "hack things up" so that
    `Xamarin.Android.NuniteLite.dll` would be properly resolved during
    the build of `Mono.Android-Tests.csproj` *when building everything*.

    The problem is *this can't work*, because `xbuild` has a
    "target framework cache," with no way to invalidate it, and the
    cache is populated the first time the target framework is used.
    Due to build ordering issues, this first use is *before*
    `Xamarin.Android.NunitLite.dll` was built, and thus it doesn't
    exist in the cache. The result:

        Task "ResolveAssemblyReference"
            ....
            TargetFrameworkDirectories:
                /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v7.0
                /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0
                /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/Facades/
            ...
            Primary Reference System.Xml
                Reference System.Xml resolved to /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/System.Xml.dll. CopyLocal = False
            ...
            Primary Reference Xamarin.Android.NUnitLite
        Microsoft.Common.targets:  warning : Reference 'Xamarin.Android.NUnitLite' not resolved
            For searchpath {TargetFrameworkDirectory}
            Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v7.0, assembly named 'Xamarin.Android.NUnitLite' not found.
            Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0, assembly named 'Xamarin.Android.NUnitLite' not found.
            Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/Facades/, assembly named 'Xamarin.Android.NUnitLite' not found.
        ...

    Consequently, the `mcs` invocation is missing a
    `/reference:path/to/Xamarin.Android.NUniteLite.dll`, and
    compilation fails:

        Android.App/ApplicationTest.cs(9,7): error CS0246: The type or namespace name `NUnit' could not be found. Are you missing an assembly reference?
        ...plus 29 others...

[4]: https://github.com/mono/mono/blob/dd8aadf/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/AssemblyResolver.cs#L131
jonpryor added a commit that referenced this pull request Aug 8, 2016
We're trying to get [`make jenkins`][0] working on Jenkins, and
[it's failing][1], as one might expect when a particular repo and
associated build system has never been run on Jenkins before:

	Android.App/ApplicationTest.cs(9,7): error CS0246: The type or namespace name `NUnit' could not be found. Are you missing an assembly reference?

This error occurs while building
`src/Mono.Android/Test/Mono.Android-Tests.csproj`, and happens because
the `Xamarin.Android.NUnitLite.dll` assembly isn't referenced...
because it isn't *found*:

	Microsoft.Common.targets: warning : Reference 'Xamarin.Android.NUnitLite' not resolved

This returns us to a long-standing issue which I thought was mentioned
in a commit somewhere, but I can't find at present:

MSBuild doesn't support updating the assembly resolution directories
*while MSBuild is running*.

For example, we build `Xamarin.Android.NUniteLite.dll` into
`bin/$(Configuration/lib/xbuild-frameworks/MonoAndroid/v1.0`,
but "normal Xamarin.Android referencing projects" don't use a
`@(ProjectReference)` to `Xamarin.Android.NUnitLite.csproj`, but
instead a `@(Reference)` to the assembly:

	<!-- src/Mono.Android/Test/Mono.Android-Tests.csproj -->
	<Reference Include="Xamarin.Android.NUnitLite" />

The *requirement* for a "proper" Xamarin.Android SDK install is that
`Xamarin.Android.NUnitLite.dll` can be found through a normal
`@(Reference)`. In order to satisfy this requirement, we need to tell
MSBuild where to find it, which can be with `xbuild` via the
`$MSBuildExtensionsPath` and `$XBUILD_FRAMEWORK_FOLDERS_PATH`
*environment variables*.

*Environment variables*.

MSBuild doesn't provide a way to update environment variables, short
of writing a new Task which calls
`Environment.SetEnvironmentVariable()`, and while [this works][2], it
doesn't *actually* work [^3].

The short of all this is that it isn't possible,
*within a single `xbuild` invocation*, to both build the
Xamarin.Android SDK "environment" *and use that environment* as
intended for "normal" apps.

The fix, as is often the case, is to bend with the wind. Instead of
requiring the impossible, move
`src/Mono.Android/Test/Mono.Android-Tests.csproj` into a *new*
`Xamarin.Android-Tests.sln` solution, *out of* `Xamarin.Android.sln`.
This allows building `Xamarin.Android.sln` without error in a pristine
environment -- that is, one that doesn't already have a system-wide
Xamarin.Android install -- and separately building the tests by using
`tools/scripts/xabuild`, which *can* export environment variables to
manipulate `xbuild` behavior so that things Just Work™.

Building `Mono.Android-Tests.csproj` and similar projects
(`HelloWorld.csproj`!) can be done by using the new `make all-tests`
make target.

[0]: a16673d
[1]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android/20/console
[2]: #147
[^3]: [PR #147][2] isn't viable because of [xbuild's `AsssemblyResolver`][4].
    There's no way to clear/invalidate `target_framework_cache`.

    The idea of PR #147 was to "hack things up" so that
    `Xamarin.Android.NuniteLite.dll` would be properly resolved during
    the build of `Mono.Android-Tests.csproj` *when building everything*.

    The problem is *this can't work*, because `xbuild` has a
    "target framework cache," with no way to invalidate it, and the
    cache is populated the first time the target framework is used.
    Due to build ordering issues, this first use is *before*
    `Xamarin.Android.NunitLite.dll` was built, and thus it doesn't
    exist in the cache. The result:

        Task "ResolveAssemblyReference"
            ....
            TargetFrameworkDirectories:
                /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v7.0
                /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0
                /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/Facades/
            ...
            Primary Reference System.Xml
                Reference System.Xml resolved to /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/System.Xml.dll. CopyLocal = False
            ...
            Primary Reference Xamarin.Android.NUnitLite
        Microsoft.Common.targets:  warning : Reference 'Xamarin.Android.NUnitLite' not resolved
            For searchpath {TargetFrameworkDirectory}
            Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v7.0, assembly named 'Xamarin.Android.NUnitLite' not found.
            Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0, assembly named 'Xamarin.Android.NUnitLite' not found.
            Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/Facades/, assembly named 'Xamarin.Android.NUnitLite' not found.
        ...

    Consequently, the `mcs` invocation is missing a
    `/reference:path/to/Xamarin.Android.NUniteLite.dll`, and
    compilation fails:

        Android.App/ApplicationTest.cs(9,7): error CS0246: The type or namespace name `NUnit' could not be found. Are you missing an assembly reference?
        ...plus 29 others...

[4]: https://github.com/mono/mono/blob/dd8aadf/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/AssemblyResolver.cs#L131
@jonpryor
Copy link
Contributor Author

jonpryor commented Aug 8, 2016

This doesn't work, as per a prior comment, so we're going with PR #146.

@jonpryor jonpryor closed this Aug 8, 2016
radekdoulik pushed a commit to radekdoulik/xamarin-android that referenced this pull request Aug 12, 2016
We're trying to get [`make jenkins`][0] working on Jenkins, and
[it's failing][1], as one might expect when a particular repo and
associated build system has never been run on Jenkins before:

	Android.App/ApplicationTest.cs(9,7): error CS0246: The type or namespace name `NUnit' could not be found. Are you missing an assembly reference?

This error occurs while building
`src/Mono.Android/Test/Mono.Android-Tests.csproj`, and happens because
the `Xamarin.Android.NUnitLite.dll` assembly isn't referenced...
because it isn't *found*:

	Microsoft.Common.targets: warning : Reference 'Xamarin.Android.NUnitLite' not resolved

This returns us to a long-standing issue which I thought was mentioned
in a commit somewhere, but I can't find at present:

MSBuild doesn't support updating the assembly resolution directories
*while MSBuild is running*.

For example, we build `Xamarin.Android.NUniteLite.dll` into
`bin/$(Configuration/lib/xbuild-frameworks/MonoAndroid/v1.0`,
but "normal Xamarin.Android referencing projects" don't use a
`@(ProjectReference)` to `Xamarin.Android.NUnitLite.csproj`, but
instead a `@(Reference)` to the assembly:

	<!-- src/Mono.Android/Test/Mono.Android-Tests.csproj -->
	<Reference Include="Xamarin.Android.NUnitLite" />

The *requirement* for a "proper" Xamarin.Android SDK install is that
`Xamarin.Android.NUnitLite.dll` can be found through a normal
`@(Reference)`. In order to satisfy this requirement, we need to tell
MSBuild where to find it, which can be with `xbuild` via the
`$MSBuildExtensionsPath` and `$XBUILD_FRAMEWORK_FOLDERS_PATH`
*environment variables*.

*Environment variables*.

MSBuild doesn't provide a way to update environment variables, short
of writing a new Task which calls
`Environment.SetEnvironmentVariable()`, and while [this works][2], it
doesn't *actually* work [^3].

The short of all this is that it isn't possible,
*within a single `xbuild` invocation*, to both build the
Xamarin.Android SDK "environment" *and use that environment* as
intended for "normal" apps.

The fix, as is often the case, is to bend with the wind. Instead of
requiring the impossible, move
`src/Mono.Android/Test/Mono.Android-Tests.csproj` into a *new*
`Xamarin.Android-Tests.sln` solution, *out of* `Xamarin.Android.sln`.
This allows building `Xamarin.Android.sln` without error in a pristine
environment -- that is, one that doesn't already have a system-wide
Xamarin.Android install -- and separately building the tests by using
`tools/scripts/xabuild`, which *can* export environment variables to
manipulate `xbuild` behavior so that things Just Work™.

Building `Mono.Android-Tests.csproj` and similar projects
(`HelloWorld.csproj`!) can be done by using the new `make all-tests`
make target.

[0]: dotnet@a16673d
[1]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android/20/console
[2]: dotnet#147
[^3]: [PR dotnet#147][2] isn't viable because of [xbuild's `AsssemblyResolver`][4].
    There's no way to clear/invalidate `target_framework_cache`.

    The idea of PR dotnet#147 was to "hack things up" so that
    `Xamarin.Android.NuniteLite.dll` would be properly resolved during
    the build of `Mono.Android-Tests.csproj` *when building everything*.

    The problem is *this can't work*, because `xbuild` has a
    "target framework cache," with no way to invalidate it, and the
    cache is populated the first time the target framework is used.
    Due to build ordering issues, this first use is *before*
    `Xamarin.Android.NunitLite.dll` was built, and thus it doesn't
    exist in the cache. The result:

        Task "ResolveAssemblyReference"
            ....
            TargetFrameworkDirectories:
                /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v7.0
                /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0
                /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/Facades/
            ...
            Primary Reference System.Xml
                Reference System.Xml resolved to /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/System.Xml.dll. CopyLocal = False
            ...
            Primary Reference Xamarin.Android.NUnitLite
        Microsoft.Common.targets:  warning : Reference 'Xamarin.Android.NUnitLite' not resolved
            For searchpath {TargetFrameworkDirectory}
            Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v7.0, assembly named 'Xamarin.Android.NUnitLite' not found.
            Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0, assembly named 'Xamarin.Android.NUnitLite' not found.
            Considered target framework dir /Volumes/Seagate4TB/work/xamarin-android/bin/Debug/lib/xbuild-frameworks/MonoAndroid/v1.0/Facades/, assembly named 'Xamarin.Android.NUnitLite' not found.
        ...

    Consequently, the `mcs` invocation is missing a
    `/reference:path/to/Xamarin.Android.NUniteLite.dll`, and
    compilation fails:

        Android.App/ApplicationTest.cs(9,7): error CS0246: The type or namespace name `NUnit' could not be found. Are you missing an assembly reference?
        ...plus 29 others...

[4]: https://github.com/mono/mono/blob/dd8aadf/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/AssemblyResolver.cs#L131
radical pushed a commit that referenced this pull request May 8, 2018
…rs. (#147)

Constructors had been considered to NOT reference generic type parameters
because Java syntax does not allow them. However, its argument types could
be java.lang.Class<T> in class-parse output XML (which I guess is because
class-parse tries to be as simple-and-stupid as it can be?) and every
difficulty is thrown toward api-xml-adjuster. Hence it is corrected here.

Note that it was not the first time that generic constructor arguments
have been taken care as a valid input (0ec431e).
@github-actions github-actions bot locked and limited conversation to collaborators Feb 6, 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