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

[Xamarin.Android.Build.Tasks] don't call <ResolveAssemblyReference/> directly #4215

Merged
merged 1 commit into from
Feb 5, 2020

Conversation

jonathanpeppers
Copy link
Member

@jonathanpeppers jonathanpeppers commented Feb 3, 2020

I found that we were invoking the <ResolveAssemblyReference/>
MSBuild task directly:

<ResolveAssemblyReference ...>
  <Output TaskParameter="SatelliteFiles" ItemName="_AndroidResolvedSatellitePaths"/>
</ResolveAssemblyReference>

What is weird about this, is that <ResolveAssemblyReference/> is
called twice during any Xamarin.Android build.

But the first call from MSBuild itself returns the exact same
assemblies we need here:

Task ResolveAssemblyReference
    ...
    OutputItems
    ...
        ReferenceSatellitePaths
            C:\src\weird-solutions\ClassLibrary1\bin\Debug\es\ClassLibrary3.resources.dll

In this example I added a Strings.resx and Strings.es.resx. The
satellite assembly contains the spanish translation.

It looks to me we can just remove our call to the
<ResolveAssemblyReference/> task, and use the public, built-in
@(ReferenceSatellitePaths) item group instead.

This worked, except for the in the case of
Mono.Android-Tests.csproj. It contains resx files in the main app
project, and these assemblies are not in @(ReferenceSatellitePaths).

Reviewing the code from MSBuild itself:

https://github.com/microsoft/msbuild/blob/master/src/Tasks/Microsoft.Common.CurrentVersion.targets#L4283-L4299

We can use the item transform to get satellite assemblies for the
current project:

@(IntermediateSatelliteAssembliesWithTargetPath->'$(OutDir)%(Culture)\$(TargetName).resources.dll')

There is not an item group for satellite assemblies in the current
project. However, we merely end up with:

<Target Name="_ResolveSatellitePaths" ...>
  <ItemGroup>
    <_AndroidResolvedSatellitePaths Include="@(ReferenceSatellitePaths)" />
    <_AndroidResolvedSatellitePaths Include="@(IntermediateSatelliteAssembliesWithTargetPath->'$(OutDir)%(Culture)\$(TargetName).resources.dll')" />
  </ItemGroup>
</Target>

This target will now take ~0ms instead of calling RAR.

In a build with no changes for the SmartHotel360 app (which includes a
netstandard project):

Before:
244 ms  ResolveAssemblyReference                   3 calls
After:
152 ms  ResolveAssemblyReference                   2 calls

This looks like a ~92ms savings to every build.

During the devloop, Build will run followed by Install. We will
have 2x savings to the devloop in this case: ~184ms.

@jonathanpeppers
Copy link
Member Author

@dellis1972 do we have a test that has something like:

  • Strings.resx
  • Strings.es.resx

And verifies we can get the Spanish string at runtime?

@jonathanpeppers
Copy link
Member Author

do we have a test that has something like...

Maybe this is exactly it: https://github.com/xamarin/xamarin-android/tree/master/tests/locales/Xamarin.Android.Locale-Tests

@jonathanpeppers
Copy link
Member Author

The test failure is probably because I need to make some changes in monodroid:

System.InvalidOperationException : Satellite assembly resource lookup failed for resource 'AppString' from culture 'de-DE'.

Expected='App German'

Actual='App English'

https://github.com/xamarin/monodroid/search?q=_AndroidResolvedSatellitePaths&unscoped_q=_AndroidResolvedSatellitePaths

@dellis1972
Copy link
Contributor

I suspect this is another "fix" we had to do for xbuild. So we probably don't need that call now.

@jonathanpeppers
Copy link
Member Author

jonathanpeppers commented Feb 4, 2020

Ok, it looks like if the main app project has resx files, you also need to look at @(IntermediateSatelliteAssembliesWithTargetPath):

image

https://github.com/microsoft/msbuild/blob/1105f6db2fca58a45920ffb953a00aad2e93d794/src/Tasks/Microsoft.Common.CurrentVersion.targets#L4283-L4299

I may be able to keep the old target and item group, and just remove the direct call to <ResolveAssemblyReference/>.

…directly

I found that we were invoking the `<ResolveAssemblyReference/>`
MSBuild task directly:

    <ResolveAssemblyReference ...>
      <Output TaskParameter="SatelliteFiles" ItemName="_AndroidResolvedSatellitePaths"/>
    </ResolveAssemblyReference>

What is weird about this, is that `<ResolveAssemblyReference/>` is
called twice during any Xamarin.Android build.

But the first call from MSBuild itself returns the exact same
assemblies we need here:

    Task ResolveAssemblyReference
        ...
        OutputItems
        ...
            ReferenceSatellitePaths
                C:\src\weird-solutions\ClassLibrary1\bin\Debug\es\ClassLibrary3.resources.dll

In this example I added a `Strings.resx` and `Strings.es.resx`. The
satellite assembly contains the spanish translation.

It looks to me we can just remove our call to the
`<ResolveAssemblyReference/>` task, and use the public, built-in
`@(ReferenceSatellitePaths)` item group instead.

This worked, except for the in the case of
`Mono.Android-Tests.csproj`. It contains resx files in the main app
project, and these assemblies are not in `@(ReferenceSatellitePaths)`.

Reviewing the code from MSBuild itself:

https://github.com/microsoft/msbuild/blob/master/src/Tasks/Microsoft.Common.CurrentVersion.targets#L4283-L4299

We can use the item transform to get satellite assemblies for the
current project:

    @(IntermediateSatelliteAssembliesWithTargetPath->'$(OutDir)%(Culture)\$(TargetName).resources.dll')

There is not an item group for satellite assemblies in the current
project. However, we merely end up with:

    <Target Name="_ResolveSatellitePaths" ...>
      <ItemGroup>
        <_AndroidResolvedSatellitePaths Include="@(ReferenceSatellitePaths)" />
        <_AndroidResolvedSatellitePaths Include="@(IntermediateSatelliteAssembliesWithTargetPath->'$(OutDir)%(Culture)\$(TargetName).resources.dll')" />
      </ItemGroup>
    </Target>

This target will now take ~0ms instead of calling RAR.

In a build with no changes for the SmartHotel360 app (which includes a
netstandard project):

    Before:
    244 ms  ResolveAssemblyReference                   3 calls
    After:
    152 ms  ResolveAssemblyReference                   2 calls

This looks like a ~92ms savings to every build.

During the devloop, `Build` will run followed by `Install`. We will
have 2x savings to the devloop in this case: ~184ms.
@jonathanpeppers jonathanpeppers changed the title [Xamarin.Android.Build.Tasks] remove _ResolveSatellitePaths and use RAR [Xamarin.Android.Build.Tasks] don't call <ResolveAssemblyReference/> directly Feb 4, 2020
@jonathanpeppers jonathanpeppers removed the do-not-merge PR should not be merged. label Feb 4, 2020
@jonpryor jonpryor merged commit 1e96c79 into dotnet:master Feb 5, 2020
@jonathanpeppers jonathanpeppers deleted the referencesatellitepaths branch February 5, 2020 16:45
jonpryor pushed a commit that referenced this pull request Feb 6, 2020
…directly (#4215)

I found that we were invoking the `<ResolveAssemblyReference/>`
MSBuild task directly:

	<ResolveAssemblyReference ...>
	  <Output TaskParameter="SatelliteFiles" ItemName="_AndroidResolvedSatellitePaths"/>
	</ResolveAssemblyReference>

What is weird about this, is that `<ResolveAssemblyReference/>` is
called twice during any Xamarin.Android build.

But the first call from MSBuild itself returns the exact same
assemblies we need here:

	Task ResolveAssemblyReference
	    ...
	    OutputItems
	    ...
	        ReferenceSatellitePaths
	            C:\src\weird-solutions\ClassLibrary1\bin\Debug\es\ClassLibrary3.resources.dll

In this example I added a `Strings.resx` and `Strings.es.resx`.
The satellite assembly contains the spanish translation.

It looks to me we can just remove our call to the
`<ResolveAssemblyReference/>` task, and use the public, built-in
`@(ReferenceSatellitePaths)` item group instead.

This worked, except in the case of `Mono.Android-Tests.csproj`. It
contains `.resx` files in the main app project, and these assemblies
are not in `@(ReferenceSatellitePaths)`.

Reviewing the code from MSBuild itself:

	https://github.com/microsoft/msbuild/blob/1105f6db2fca58a45920ffb953a00aad2e93d794/src/Tasks/Microsoft.Common.CurrentVersion.targets#L4283-L4299

We can use the item transform to get satellite assemblies for the
current project:

	@(IntermediateSatelliteAssembliesWithTargetPath->'$(OutDir)%(Culture)\$(TargetName).resources.dll')

There is not an item group for satellite assemblies in the current
project.  However, we merely end up with:

	<Target Name="_ResolveSatellitePaths" ...>
	  <ItemGroup>
	    <_AndroidResolvedSatellitePaths Include="@(ReferenceSatellitePaths)" />
	    <_AndroidResolvedSatellitePaths Include="@(IntermediateSatelliteAssembliesWithTargetPath->'$(OutDir)%(Culture)\$(TargetName).resources.dll')" />
	  </ItemGroup>
	</Target>

This target will now take ~0ms instead of calling
`<ResolveAssemblyReference/>`.

In a build with no changes for the SmartHotel360 app (which includes a
netstandard project):

  * Before:

        244 ms  ResolveAssemblyReference                   3 calls
  
  * After:
  
        152 ms  ResolveAssemblyReference                   2 calls

This looks like a ~92ms savings to every build.

During the devloop, `Build` target will run followed by `Install`
target.  We will have 2x savings to the devloop in this case: ~184ms.
@github-actions github-actions bot locked and limited conversation to collaborators Jan 28, 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.

4 participants