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.iOS linker removes assembly attributes, but large & useful libraries (e.g. EF Core 2.0) rely on such being preserved #3655

Closed
cwrea opened this issue Mar 4, 2018 · 9 comments · Fixed by #6049
Assignees
Labels
enhancement The issue or pull request is an enhancement iOS Issues affecting iOS macOS Issues affecting macOS
Milestone

Comments

@cwrea
Copy link

cwrea commented Mar 4, 2018

I've been attempting to get Microsoft Entity Framework Core 2.0 working in a Xamarin.iOS application with full linking enabled. EF Core is a large library — exactly the kind that could benefit from linking. Discovering all the critical types/methods to preserve in a LinkDescription XML file has been tedious, owing to extensive reflection and use of DI in EF Core 2.0, but I've been making progress, one crash at a time. (There's also hope that ER Core could one day have linker hints built in.)

However, I hit a major blocker: When EF Core creates a database from a model, it reads its own AssemblyInformationalVersion attribute to preserve in generated metadata. But the Xamarin.iOS linker strips assembly attributes from an assembly that is not link-skipped. So, in an app with full linking enabled, EF Core is crashing as it gets nothing back from reading the desired attribute value.

This behaviour appears to be an intentional linker feature, perhaps desirable and harmless in many cases — but for cases where it is a problem, there exists no fine-grained directive to preserve assembly attributes, as one could do with plain types/methods in a LinkDescription XML file.

The only workaround at present is to go back to link-skipping the large EF Core main assembly, and put up with the resulting bloat. For a small app that doesn't use EF Core's more advanced features, the unnecessary bloat may be considerable. (I haven't measured potential avoidable bloat yet, as I'm blocked from getting to the point where I could compare a working iOS app with full linking vs. one that link-skips EF Core.)

Steps to Reproduce (without EF Core; just the essential issue)

  1. Create a new Xamarin.iOS project using the Single View app template.
  2. In the project's iOS build settings for platform "iPhone" (real device), set linker behavior to "Link All".
  3. In AppDelegate.cs' FinishedLaunching() method, add the following line before the return:
    System.Diagnostics.Debug.WriteLine("TODO");
  4. Change the build to target a real iOS device, then build and run with debugging. Notice "TODO" is printed in the debug output. i.e. The basic application works with full linking.
  5. In Properties/AssemblyInfo.cs, append the following line:
    [assembly: AssemblyInformationalVersion("1.0.0.0")]
  6. From the ProductInfo.cs file from the EF Core 2.0.0 repository, copy and paste just the ProductInfo class definition into AppDelegate.cs, before the AppDelegate class definition.
  7. Change the Debug.WriteLine() call added in step 1 to read:
    System.Diagnostics.Debug.WriteLine("Version: " + ProductInfo.GetVersion());.
  8. Build and run with debugging. Instead of seeing "Informational version: 1.0.0.0" in the debugger output, the application crashes with System.NullReferenceException: Object reference not set to an instance of an object.

If you were to expand the one-liner from EF Core's GetVersion() method into multiple statements and intermediate values instead, you would see that the null reference is the attribute object from which the InformationalVersion property would have been accessed. If you were to change linking back to "Link SDK Assemblies Only", you would avoid the crash and see the expected output.

Expected Behavior

It should be possible to configure the linker to specifically preserve assembly attributes when the need arises — i.e. without completely opting out of linking an assembly.

Developers of .NET Standard class libraries should be able to rely on reading their own assembly's attribute information. Linking should aim to exclude only unnecessary types, methods, and other data from an assembly. Beyond types and methods, when the linker assumes that a kind of thing can safely be excluded, it should provide a fine-grained directive to preserve some or all of the kinds-of-things, for cases where the assumption has been proven unsafe for a specific assembly.

Actual Behavior

Crash. The present workaround requires completely opting out of linking for an assembly that relies on reading its own assembly attributes.

However, linking remains highly desirable for large library dependencies used in mobile applications. The case in point is not only a very large .NET Standard library, but a popular data access framework promoted by Microsoft as cross-platform capable, which ideally would include mobile applications with on-device data access needs.

Environment

Microsoft Visual Studio Community 2017 
Version 15.5.7
VisualStudio.15.Release/15.5.7+27130.2036
Microsoft .NET Framework
Version 4.7.02556

Installed Version: Community

Visual Basic 2017   00369-60000-00001-AA398
Microsoft Visual Basic 2017

Visual C# 2017   00369-60000-00001-AA398
Microsoft Visual C# 2017

Visual C++ 2017   00369-60000-00001-AA398
Microsoft Visual C++ 2017

Visual F# 4.1   00369-60000-00001-AA398
Microsoft Visual F# 4.1

Add New File   3.5
The fastest and easiest way to add new files to any project - including files that start with a dot

Application Insights Tools for Visual Studio Package   8.10.01106.1
Application Insights Tools for Visual Studio

ASP.NET and Web Tools 2017   15.0.31129.0
ASP.NET and Web Tools 2017

ASP.NET Core Razor Language Services   1.0
Provides languages services for ASP.NET Core Razor.

ASP.NET Web Frameworks and Tools 2012   4.0.20601.0
For additional information, visit https://www.asp.net/

ASP.NET Web Frameworks and Tools 2017   5.2.51007.0
For additional information, visit https://www.asp.net/

Azure App Service Tools v3.0.0   15.0.31106.0
Azure App Service Tools v3.0.0

CodeMaid   10.4.53
CodeMaid is an open source Visual Studio extension to cleanup and simplify our C#, C++, F#, VB, PHP, PowerShell, R, JSON, XAML, XML, ASP, HTML, CSS, LESS, SCSS, JavaScript and TypeScript coding.

Common Azure Tools   1.10
Provides common services for use by Azure Mobile Services and Microsoft Azure Tools.

GitHub.VisualStudio   2.4.2.1331
A Visual Studio Extension that brings the GitHub Flow into Visual Studio.

JavaScript Language Service   2.0
JavaScript Language Service

JavaScript Project System   2.0
JavaScript Project System

JavaScript UWP Project System   2.0
JavaScript UWP Project System

JetBrains ReSharper Ultimate 2017.2.2    Build 109.0.20171006.122324
JetBrains ReSharper Ultimate package for Microsoft Visual Studio. For more information about ReSharper Ultimate, visit http://www.jetbrains.com/resharper. Copyright © 2018 JetBrains, Inc.

Merq   1.1.17-rc (cba4571)
Command Bus, Event Stream and Async Manager for Visual Studio extensions.

Microsoft Continuous Delivery Tools for Visual Studio   0.3
Simplifying the configuration of continuous build integration and continuous build delivery from within the Visual Studio IDE.

Microsoft JVM Debugger   1.0
Provides support for connecting the Visual Studio debugger to JDWP compatible Java Virtual Machines

Microsoft MI-Based Debugger   1.0
Provides support for connecting Visual Studio to MI compatible debuggers

Microsoft Visual C++ Wizards   1.0
Microsoft Visual C++ Wizards

Microsoft Visual Studio Tools for Containers   1.1
Develop, run, validate your ASP.NET Core applications in the target environment. F5 your application directly into a container with debugging, or CTRL + F5 to edit & refresh your app without having to rebuild the container.

Microsoft Visual Studio VC Package   1.0
Microsoft Visual Studio VC Package

Mono Debugging for Visual Studio   4.8.4-pre (3fe64e3)
Support for debugging Mono processes with Visual Studio.

Node.js Tools   1.4.11025.7
Adds support for developing and debugging Node.js apps in Visual Studio

NuGet Package Manager   4.5.0
NuGet Package Manager in Visual Studio. For more information about NuGet, visit http://docs.nuget.org/.

Open Command Line   2.1.179
Opens a command line at the root of the project. Support for all consoles such as CMD, PowerShell, Bash etc. Provides syntax highlighting, Intellisense and execution of .cmd and .bat files.

Search in Velocity by Silverlake Software LLC   0.7.1
Provides a command to search in Velocity the offline documentation and docset viewer for Windows

SQL Server Data Tools   15.1.61710.120
Microsoft SQL Server Data Tools

SQLite & SQL Server Compact Toolbox   4.7
SQLite & SQL Server Compact Toolbox adds scripting, import, export, rename, query execution and much more to SQL Server Compact & SQLite Data Connections.

Syntax Visualizer   1.0
An extension for visualizing Roslyn SyntaxTrees.

TypeScript Tools   15.5.11025.1
TypeScript Tools for Microsoft Visual Studio

Visual Studio Code Debug Adapter Host Package   1.0
Interop layer for hosting Visual Studio Code debug adapters in Visual Studio

Visual Studio Tools for Universal Windows Apps   15.0.27130.2036
The Visual Studio Tools for Universal Windows apps allow you to build a single universal app experience that can reach every device running Windows 10: phone, tablet, PC, and more. It includes the Microsoft Windows 10 Software Development Kit.

VisualStudio.Mac   1.0
Mac Extension for Visual Studio

VSColorOutput   2.5.1
Color output for build and debug windows - http://mike-ward.net/vscoloroutput

Xamarin   4.8.0.760 (fc93f3f5b)
Visual Studio extension to enable development for Xamarin.iOS and Xamarin.Android.

Xamarin Designer   4.8.188 (c5813fa34)
Visual Studio extension to enable Xamarin Designer tools in Visual Studio.

Xamarin.Android SDK   8.1.5.0 (HEAD/75f8c6838)
Xamarin.Android Reference Assemblies and MSBuild support.

Xamarin.iOS and Xamarin.Mac SDK   11.6.1.4 (db807ec)
Xamarin.iOS and Xamarin.Mac Reference Assemblies and MSBuild support.

Build Logs

1>------ Rebuild All started: Project: TestXamLinkIssue, Configuration: Debug iPhone ------
1>  Connecting to Mac server cwrea-mini...
1>  TestXamLinkIssue -> D:\Projects\TestXamLinkIssueSoln\TestXamLinkIssue\bin\iPhone\Debug\TestXamLinkIssue.exe
1>  Detected signing identity:
1>    Code Signing Key: "iPhone Developer: [...]" (...)
1>    Provisioning Profile: "cwrea iOS Dev Prov. Profile" (...)
1>    Bundle Id: com.companyname.TestXamLinkIssue
1>    App Id: J7ADM89KY9.com.companyname.TestXamLinkIssue
1>  /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip: removing global symbols from a final linked no longer supported.  Use -exported_symbols_list at link time when building: /Users/cwrea/Library/Caches/Xamarin/mtbs/builds/TestXamLinkIssue/a101bae86211f0bd1960357a25c90492/bin/iPhone/Debug/TestXamLinkIssue.app/TestXamLinkIssue
1>  bin/iPhone/Debug/TestXamLinkIssue.app: valid on disk
1>  bin/iPhone/Debug/TestXamLinkIssue.app: satisfies its Designated Requirement
1>  bin/iPhone/Debug/TestXamLinkIssue.app: explicit requirement satisfied
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

Projects build report:
  Status    | Project [Config|platform]
 -----------|---------------------------------------------------------------------------------------------------
  Succeeded | TestXamLinkIssue\TestXamLinkIssue.csproj [Debug|iPhone]

Time Elapsed 00:00:22.323
@mandel-macaque
Copy link
Member

This looks like an issue with the linker since we should be able to use the xml configuration file to state that attributes should be preserved in the case of libraries like EF.

@mandel-macaque mandel-macaque added this to the Future milestone Mar 5, 2018
@mandel-macaque
Copy link
Member

@spouliot any feedback for this issue? Should we move it to the linker project?

@spouliot
Copy link
Contributor

spouliot commented Mar 5, 2018

@mandel-macaque no (moving), it's a XI/XM specific step

@cwrea the XML file is used to mark code, not metadata. We'll look to see how we can make this more flexible.

@spouliot spouliot added enhancement The issue or pull request is an enhancement macOS Issues affecting macOS iOS Issues affecting iOS labels Mar 5, 2018
@divega
Copy link

divega commented Mar 31, 2019

@marek-safar some time ago we talked about things that could enable EF Core to work better with Xamarin, but I think I did not mention this issue specifically. Having fine-grained control to preserve assembly-level attributes would unblock anyone (us, @cwrea, another contributor, or an application developer) that wants to use EF Core with full linking.

@marek-safar
Copy link
Contributor

@spouliot that's bug in the hardcoded override of attributes in https://github.com/xamarin/xamarin-macios/blob/master/tools/linker/MonoTouch.Tuner/RemoveAttributes.cs I think it'd be better to remove that customization completely and rely on original linker to do the work (I am happy to help with that)

@tipa
Copy link

tipa commented May 7, 2019

I am using EF7 and was able to enable full linking on Android using a LinkDescription.xml. However, this issue now blocks me enabling full linking on iOS, so I am stuck with a 110 MB app size :(

@tipa
Copy link

tipa commented May 9, 2019

What's the current status of this? Don't want to be annoying, but I think this could be a small fix that unblocks & helps a lot of us working with iOS & EF Core

@spouliot
Copy link
Contributor

This is an old step but it removes a lot of unused metadata out of every applications: reducing size and saving build and deploy times.

There's a recent mechanism to enable/disable optimizations (using Additional mtouch arguments). That would be an easy, first fix/hack to disable the step (entirely) when needed (i.e. the extra cost being paid only if needed).

There's a newer, smarter metadata remover step - which checks if 3rd party code use a feature before removing it (e.g. parameters names are removed from metadata only if ParamaterInfo.Name is not referenced/preserved by the app). This is how the (next/final) fix should should be applied.

I have an upcoming trip to Redmond next week so I'll have a look at it (at least the first part) during the flights.

@spouliot spouliot self-assigned this May 10, 2019
@tipa
Copy link

tipa commented May 10, 2019

Thanks for taking care about this!
Is the mechanism to disable this optimization step via mtouch arguments already available? I couldn't find any details about it in this thread. I would assume that with Full linking enabled, I could save more MB than what would be added with the included metadata.

spouliot pushed a commit to spouliot/xamarin-macios that referenced this issue May 14, 2019
…timization. Fix xamarin#3655

This allows the optimization to be disabled in cases where one, or
many, a custom attribute(s) are required by the application at runtime.

While not ideal disabling this single step is much better than disabling
linking for the whole application.

A better approach is described in xamarin#6048
but this configuration optimization makes sense independently of it.

Fix xamarin#3655
monojenkins pushed a commit to monojenkins/xamarin-macios that referenced this issue May 16, 2019
…timization. Fix xamarin#3655

This allows the optimization to be disabled in cases where one, or
many, a custom attribute(s) are required by the application at runtime.

While not ideal disabling this single step is much better than disabling
linking for the whole application.

A better approach is described in xamarin#6048
but this configuration optimization makes sense independently of it.

Fix xamarin#3655
spouliot added a commit that referenced this issue May 16, 2019
…timization. Fix #3655 (#6049)

This allows the optimization to be disabled in cases where one, or
many, a custom attribute(s) are required by the application at runtime.

While not ideal disabling this single step is much better than disabling
linking for the whole application.

A better approach is described in #6048
but this configuration optimization makes sense independently of it.

Fix #3655
spouliot pushed a commit that referenced this issue May 16, 2019
…rable optimization. Fix #3655 (#6058)

This allows the optimization to be disabled in cases where one, or
many, a custom attribute(s) are required by the application at runtime.

While not ideal disabling this single step is much better than disabling
linking for the whole application.

A better approach is described in #6048
but this configuration optimization makes sense independently of it.

Fix #3655
@ghost ghost locked as resolved and limited conversation to collaborators May 6, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement The issue or pull request is an enhancement iOS Issues affecting iOS macOS Issues affecting macOS
Projects
None yet
6 participants