Bug 11883 - Improvements to Preserve attribute for Link All Assemblies
Summary: Improvements to Preserve attribute for Link All Assemblies
Status: RESOLVED FIXED
Alias: None
Product: iOS
Classification: Xamarin
Component: Tools ()
Version: master
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: 8.10
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2013-04-22 10:50 UTC by jesse.attas
Modified: 2015-02-04 16:13 UTC (History)
4 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description jesse.attas 2013-04-22 10:50:56 UTC
I'd like to request two enhancements to the Preserve attribute. I talked about this at Evolve with Jon Pryor and he suggested it be tracked in Bugzilla. 

1) Make it cleaner across platforms. Right now the attribute lives in a different namespace on iOS and Android, which means my cross platform classes need to be decorated with several lines of conditional code to apply this attribute:
#if __iOS__
[Xamarin.iOS.Foundation.Preserve(AllMembers=true)]
#elif __ANDROID__
[Android.Runtime.Preserve(AllMembers=true)]
#end
public class MyCrossPlatformClass {}

Ideally this would be just one line. Bonus if you can somehow make it compile on Windows too, but I'd be OK with putting the one line in a #if !WIN block.

2) Make it play better with MEF. When a class is decorated with [System.ComponentModel.Composition.ExportAttribute], I will always want it to have the PreserveAttribute too. It would be nice if there were some way to do this automatically. One idea we had was to make our ExportAttribute inherit from PreserveAttribute, but that's not currently possible because PreserveAttribute is sealed.
Comment 1 Miguel de Icaza [MSFT] 2013-07-26 14:25:58 UTC
Sebastien,

My feeling is that we should probably introduce a [Preserve] in our libraries in a namespace like System.Runtime.InteropServices, so we can make this available on all platforms.

The second is trickier, because I do not think we support MEF ourselves in iOS and Android, so this seems like an atribute that is being defined by a user assembly.   

It is worth discussing if we want to bake-in support with MEF with Preserve semantics, or if users should use XML maps to achieve this.
Comment 2 jesse.attas 2013-07-26 16:14:40 UTC
Yes, we are using an open-source implementation of MEF, so we do have control over the Export attribute. But we haven't been able to use that fact to our advantage.

Generally speaking, dealing with MEF issues is by far the biggest headache we've encountered when trying to use Link All Assemblies. Pretty much every class used by MEF (whether imported, exported, or metadata) needs to be preserved since they're not necessarily statically referenced from the application. But detecting these classes is a challenge and if you miss one it results in hard-to-debug runtime errors and crashes.
Comment 3 Sebastien Pouliot 2013-08-08 09:34:32 UTC
JonP asked me similar questions at Evolve, sorry if the information did not get back to you.

> Ideally this would be just one line. 

Yes, this can be done in a single line. 

The linker share code across products so (to make it easier*) it does not care about its namespace. IOW you can define your own [Preserve] attribute, inside your own code base, and remove the #if #elif #end related conditions in all other files. 

* In fact that's how the original (open source) monolinker works. It check for [Preserve] when nothing from Mono's BCL provides such an attribute.

>  Bonus if you can somehow make it compile on Windows too

If you have your own [Preserve] type then it will work on Windows too (with or without using the monolinker).

> Make it play better with MEF.

I have not played with MEF yet. It might be possible to make the linker aware of it, e.g. it's own [Export] attributes. We already have similar features for XML serialization and data contract attributes (i.e. they are treated like [Preserve] without further changes).

A general (not MEF specific) solution for this problem would be to create a tool that scan your assemblies and create an xml file for the linker. E.g.

a. scan assembly.dll for types decorated with [System.ComponentModel.Composition.ExportAttribute]

b. write them down in a assembly.xml file;

c. add a post-build step to your assembly.csproj project to re-generate the xml each time the assembly is rebuilt;

d. add the --xml=assembly.xml to your project additional options

> One idea we had was to make our ExportAttribute inherit from PreserveAttribute,

It can't. The above "namespace-less" [Preserve] ease the linker code but it makes it impossible to subclass it. OTOH it's not a big deal because subclassing is also very slow to process (compared to a string comparison) and there are generally much better ways to do it.

> Pretty much every
> class used by MEF (whether imported, exported, or metadata) needs to be
> preserved since they're not necessarily statically referenced from the
> application.

If the types are located in specific assemblies then you might want to mix --linkall with some --linkskip=assembly

Another solution is to use "Link SDK" and mark some assemblies, not used by MEF, with [LinkerSafe].

There's a bit more about both solutions in my Evolve talk @ http://xamarin.com/evolve/2013#session-37jlfjcqmn
Comment 4 Miguel de Icaza [MSFT] 2013-08-08 10:23:49 UTC
On MEF: while we do not actively test or port MEF on iOS, it should work out of the box on Android.

While I agree an external tool could be written, this is a candidate to just be handled directly by the linker due to its high profile as a library.

That said, I think we should add two assembly-level attributes to the linker that would achieve many of the same things that the external XML does without the downsides of the XML file [1].

[assembly:PreserveType (typeof (SomeType))]

Instructs the linker to preserve a given type, without having source code access to the type.

[assembly:AttributePreservesType (typeof(TinyIOC.MyPreserveAttribute))]

Instructs the linker to treat the specified attribute as a Preserve attribute, this would allow a third party library that looks like MEF to register their own attributes.

And in fact, if we ever ship MEF ourselves, our MEF would just contain the line:

[assembly:AttributePreservesType (typeof (MEF.Export))]

[1] having to pass special arguments to mtouch is cumbersome because the developer needs to maintain due to having to replicate this command line for every configuration.  This is error prone, also our docs are too terse.
Comment 5 T.J. Purtell 2013-11-22 15:55:45 UTC
+1: I am now having to add boilerplate to each shared code file for linking hints.  I look forward to being able to eliminate it.  I like the suggestion of the assembly attributes to eliminate the XML in many cases.
Comment 6 Sebastien Pouliot 2015-02-04 16:13:25 UTC
Fixed in maccore/5237be6e9d7ad174cb19eac9b0cd961aeab1a102