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

Linker does not remove unused assemblies if they are referenced in NSObject subclasses #15723

Closed
tipa opened this issue Aug 22, 2022 · 7 comments · Fixed by #17949
Closed

Linker does not remove unused assemblies if they are referenced in NSObject subclasses #15723

tipa opened this issue Aug 22, 2022 · 7 comments · Fixed by #17949
Labels
feature A feature to be implemented
Milestone

Comments

@tipa
Copy link

tipa commented Aug 22, 2022

The linked does not correctly remove unused assemblies / methods when those calls are located in a NSObject subclass.
This increases the built .ipa unnecessarily.

Steps to Reproduce

  1. Download test project
  2. Open terminal and navigate into the test folder
  3. call dotnet publish -c Release
  4. rename /test/bin/Release/net6.0-ios/ios-arm64/publish/test.ipa to a zip file and inspect

Expected Behavior

The package does not contain System.Text.Json.dll & others
Screenshot 2022-08-22 at 18 51 52

Actual Behavior

The package does not contain System.Text.Json.dll & others
Screenshot 2022-08-22 at 18 51 59

Additional notes

The linker also correctly removes the assembly when the UnusedClass is commented out or when the UnusedClass does not extend NSObject.

Environment

Version information
Visual Studio Community 2022 for Mac Preview
Version 17.4 Preview (17.4 build 715)
Installation UUID: 67751e62-e762-44da-8eb3-677faa27413a

Runtime
.NET 6.0.5 (64-bit)
Architecture: Arm64

Roslyn (Language Service)
4.4.0-1.22371.1+c07f2571612b471671c809b5b0db59b0c37aab57

NuGet
Version: 6.2.1.2

.NET SDK (Arm64)
SDK: /usr/local/share/dotnet/sdk/6.0.400/Sdks
SDK Version: 6.0.400
MSBuild SDKs: /Applications/Visual Studio (Preview).app/Contents/MonoBundle/MSBuild/Current/bin/Sdks

.NET Runtime (Arm64)
Runtime: /usr/local/share/dotnet/dotnet
Runtime Versions:
	6.0.8
	6.0.0

.NET Runtime (x64)
Runtime: /usr/local/share/dotnet/x64/dotnet
Runtime Version: 6.0.8

Xamarin.Profiler
Version: 1.8.0.19
Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler

Updater
Version: 11

Xamarin Designer
Version: 17.4.0.32
Hash: 439b92ed7b
Branch: remotes/origin/d17-4
Build date: 2022-08-04 16:29:17 UTC

Xamarin.Android
Not Installed

Microsoft Build of OpenJDK
Java SDK: Not Found

Eclipse Temurin JDK
Java SDK: Not Found

Android SDK Manager
Version: 17.4.0.24
Hash: b3b6672
Branch: remotes/origin/HEAD~1
Build date: 2022-08-04 16:29:21 UTC

Android Device Manager
Version: 0.0.0.1179
Hash: 0f220c0
Branch: main
Build date: 2022-08-04 16:29:21 UTC

Apple Developer Tools
Xcode 13.4.1 (20504)
Build 13F100

Xamarin.Mac
Version: 8.12.0.2 (Visual Studio Community)
Hash: 87f98a75e
Branch: d17-3
Build date: 2022-07-25 20:18:54-0400

Xamarin.iOS
Version: 15.12.0.2 (Visual Studio Community)
Hash: 87f98a75e
Branch: d17-3
Build date: 2022-07-25 20:18:55-0400

Build Information
Release ID: 1704000715
Git revision: 09071dadfc1b81e4f0e2c9505cd8a5ef0b41d312
Build date: 2022-08-04 16:26:39+00
Build branch: release-17.4
Build lane: release-17.4

Operating System
Mac OS X 12.5.1
Darwin 21.6.0 Darwin Kernel Version 21.6.0
    Wed Aug 10 14:28:35 PDT 2022
    root:xnu-8020.141.5~2/RELEASE_ARM64_T8101 arm64


Example Project (If Possible)

test.zip

@rolfbjarne
Copy link
Member

This is expected behavior: we tell the linker to not remove any NSObject subclasses, because they might be used in a storyboard without any other reference from managed code (and if the linker removed such classes, the app wouldn't work correctly).

Admittedly it might be possible to scan storyboards to figure out which classes they need, and tell the linker to keep those, but this would likely be a rather big task to implement, and probably won't happen any time soon (also there might be other reasons to keep NSObject subclasses that I don't remember right now).

@rolfbjarne
Copy link
Member

Keeping open in case we decide to look into detecting any NSObject-subclass-usage from storyboards.

@rolfbjarne rolfbjarne added the feature A feature to be implemented label Aug 23, 2022
@rolfbjarne rolfbjarne added this to the Future milestone Aug 23, 2022
@rdavisau
Copy link

Could it be possible to opt-out of the NSObject-subclass-ignoring behavior with some build parameters? I have an app that doesn't use storyboards (besides LaunchScreen.storyboard) and would be willing to see if anything else blows up.

@rolfbjarne
Copy link
Member

Could it be possible to opt-out of the NSObject-subclass-ignoring behavior with some build parameters? I have an app that doesn't use storyboards (besides LaunchScreen.storyboard) and would be willing to see if anything else blows up.

There's no official way to do it, but there might be a really hacky way to do it: rename your assembly to Xamarin.Forms.Platform.iOS:

static bool IsProductType (TypeDefinition type)
{
var name = type.Module.Assembly.Name.Name;
switch (name) {
case "Xamarin.Forms.Platform.iOS":
return true;

and we should skip preserving NSObject subclasses in that assembly.

Of course do this at your own risk (and it won't work if you're using Xamarin.Forms)... but I'm also curious about what you find out if you do it :)

@rdavisau
Copy link

I enthusiastically tried this and got a build with a teeny tiny difference in my "Xamarin.Forms.Platform.iOS" assembly (and it worked fine). From that I remembered that what I'd really want is to have this behaviour applied to one of my dependencies (ReactiveUI, which has many 'Reactive' subclasses of UIKit pieces, many of which I don't use), not the core project. Renaming that one will be a bit more involved I think :')

@rolfbjarne
Copy link
Member

I enthusiastically tried this and got a build with a teeny tiny difference in my "Xamarin.Forms.Platform.iOS" assembly (and it worked fine). From that I remembered that what I'd really want is to have this behaviour applied to one of my dependencies (ReactiveUI, which has many 'Reactive' subclasses of UIKit pieces, many of which I don't use), not the core project. Renaming that one will be a bit more involved I think :')

It shouldn't be too hard to make this an opt-out behavior (at your own risk), but it might take some time until it reaches a stable release. Are you building a .NET app or a legacy Xamarin.iOS app?

@rolfbjarne rolfbjarne changed the title Linker does not remove unused assemblies they are referenced in NSObject subclasses Linker does not remove unused assemblies if they are referenced in NSObject subclasses Mar 23, 2023
rolfbjarne added a commit to rolfbjarne/xamarin-macios that referenced this issue Mar 30, 2023
… assemblies. Fixes xamarin#15723.

We mark all types that derive from NSObject when we find them in user
assemblies, so that these types may be used in storyboards (where the linker
can't see them), without having to go through hoops to make sure the linker
doesn't remove these types (which would make the storyboard fail to load,
because it would reference types that were linked away).

However, not everybody uses storyboards, so in some cases it may make sense to
link away as much as possible, so make it opt-in to skip this custom marking.

This is an experimental feature, and will break at least some apps. It may
break most apps, but if someone wants to try it out, they're welcome!

Fixes xamarin#15723.
rolfbjarne added a commit to rolfbjarne/xamarin-macios that referenced this issue Mar 30, 2023
… assemblies. Fixes xamarin#15723.

We mark all types that derive from NSObject when we find them in user
assemblies, so that these types may be used in storyboards (where the linker
can't see them), without having to go through hoops to make sure the linker
doesn't remove these types (which would make the storyboard fail to load,
because it would reference types that were linked away).

However, not everybody uses storyboards, so in some cases it may make sense to
link away as much as possible, so make it opt-in to skip this custom marking.

This is an experimental feature, and will break at least some apps. It may
break most apps, but if someone wants to try it out, they're welcome!

Fixes xamarin#15723.
@rolfbjarne
Copy link
Member

This has been implemented now (as an opt-in), and will be included in .NET 8.

It can be turned on by passing --skip-marking-nsobjects-in-user-assemblies=true to mtouch/mmp:

<PropertyGroup>
    <MtouchExtraArgs>--skip-marking-nsobjects-in-user-assemblies=true</MtouchExtraArgs>
</PropertyGroup>

rolfbjarne added a commit that referenced this issue Apr 13, 2023
… assemblies. Fixes #15723. (#17949)

We mark all types that derive from NSObject when we find them in user
assemblies, so that these types may be used in storyboards (where the linker
can't see them), without having to go through hoops to make sure the linker
doesn't remove these types (which would make the storyboard fail to load,
because it would reference types that were linked away).

However, not everybody uses storyboards, so in some cases it may make sense to
link away as much as possible, so make it opt-in to skip this custom marking.

This is an experimental feature, and will break at least some apps. It may
break most apps, but if someone wants to try it out, they're welcome!

It can be turned on by passing `--skip-marking-nsobjects-in-user-assemblies=true` to mtouch/mmp:

```xml
<PropertyGroup>
    <MtouchExtraArgs>--skip-marking-nsobjects-in-user-assemblies=true</MtouchExtraArgs>
</PropertyGroup>
```

Fixes #15723.
@ghost ghost locked as resolved and limited conversation to collaborators May 13, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature A feature to be implemented
Projects
None yet
3 participants