Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/building-apps/build-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,25 @@ The full path to the `strip` command-line tool.

The default behavior is to use `xcrun strip`.

## StripMergeableLibraries

A boolean property that specifies whether static linking metadata (`LC_ATOM_INFO`)
is removed from mergeable libraries embedded in the app bundle.

Mergeable libraries are dynamic libraries that also contain metadata for static
linking. This metadata can roughly double the size of the library. When this
property is `true`, the metadata is stripped to reduce app size.

The default value is the value of the `Optimize` property, which means `Release`
builds strip mergeable library metadata by default, while `Debug` builds preserve
it.

```xml
<PropertyGroup>
<StripMergeableLibraries>true</StripMergeableLibraries>
</PropertyGroup>
```

## SupportedOSPlatformVersion

Specifies the minimum OS version the app can run on.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using Microsoft.Build.Framework;
using Xamarin.Messaging.Build.Client;

#nullable enable

namespace Xamarin.MacDev.Tasks {
// Strips LC_ATOM_INFO (mergeable library metadata) from frameworks and dylibs in an app bundle.
public class StripMergeableLibraryMetadata : XamarinTask, ITaskCallback {
#region Inputs

// The Frameworks directory inside the app bundle.
public string FrameworksDirectory { get; set; } = string.Empty;

// Additional directories to scan for mergeable dylibs (e.g. MonoBundle).
public string [] DylibDirectories { get; set; } = [];

public string StripPath { get; set; } = string.Empty;

#endregion

public override bool Execute ()
{
if (ShouldExecuteRemotely ())
return ExecuteRemotely ();

StripFrameworks ();
StripDylibs ();

return !Log.HasLoggedErrors;
}

void StripFrameworks ()
{
if (string.IsNullOrEmpty (FrameworksDirectory) || !Directory.Exists (FrameworksDirectory))
return;

foreach (var framework in Directory.GetDirectories (FrameworksDirectory, "*.framework")) {
var name = Path.GetFileNameWithoutExtension (framework);
var executable = Path.Combine (framework, name);
StripIfMergeable (executable);
}
}

void StripDylibs ()
{
if (DylibDirectories is null)
return;

foreach (var dir in DylibDirectories) {
if (string.IsNullOrEmpty (dir) || !Directory.Exists (dir))
continue;

foreach (var dylib in Directory.GetFiles (dir, "*.dylib")) {
StripIfMergeable (dylib);
}
}
}

void StripIfMergeable (string path)
{
if (!File.Exists (path))
return;

if (!MachO.IsMergeableLibrary (path)) {
Log.LogMessage (MessageImportance.Low, $"Not a mergeable library: {path}");
return;
}

Log.LogMessage (MessageImportance.Normal, $"Stripping mergeable library metadata from: {path}");

var args = new List<string> ();
var stripExecutable = GetExecutable (args, "strip", StripPath);
args.Add ("-no_atom_info");
args.Add (Path.GetFullPath (path));
ExecuteAsync (stripExecutable, args).Wait ();
}

public bool ShouldCopyToBuildServer (ITaskItem item) => false;

public bool ShouldCreateOutputFile (ITaskItem item) => false;

public IEnumerable<ITaskItem> GetAdditionalItemsToBeCopied () => Enumerable.Empty<ITaskItem> ();
}
}
8 changes: 8 additions & 0 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/SymbolStrip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public class SymbolStrip : XamarinParallelTask, ITaskCallback {

// This can also be specified as metadata on the Executable item (as 'Kind')
public string Kind { get; set; } = string.Empty;

// Whether to strip mergeable library metadata (LC_ATOM_INFO) from frameworks.
public bool StripMergeableLibraries { get; set; }
#endregion

bool GetIsFramework (ITaskItem item)
Expand All @@ -49,6 +52,11 @@ void ExecuteStrip (ITaskItem item)
// Only remove debug symbols from frameworks.
args.Add ("-S");
args.Add ("-x");
if (StripMergeableLibraries) {
// Remove atom info (LC_ATOM_INFO) from mergeable libraries to reduce size.
// This is a no-op for non-mergeable libraries.
args.Add ("-no_atom_info");
}
}

args.Add (Path.GetFullPath (item.ItemSpec));
Expand Down
5 changes: 5 additions & 0 deletions msbuild/Xamarin.Shared/Xamarin.Shared.props
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ Copyright (C) 2020 Microsoft. All rights reserved.
<NoSymbolStrip Condition="'$(NoSymbolStrip)' == '' And ('$(_PlatformName)' == 'iOS' Or '$(_PlatformName)' == 'tvOS' Or '$(_PlatformName)' == 'watchOS') And '$(ComputedPlatform)' != 'iPhone'">true</NoSymbolStrip>
<NoSymbolStrip Condition="'$(NoSymbolStrip)' == ''">false</NoSymbolStrip>

<!-- StripMergeableLibraries: remove static linking metadata (LC_ATOM_INFO) from mergeable libraries to reduce app size -->
<!-- Default to true when optimizing (typically Release builds) -->
<StripMergeableLibraries Condition="'$(StripMergeableLibraries)' == ''">$(Optimize)</StripMergeableLibraries>
Comment thread
rolfbjarne marked this conversation as resolved.
<StripMergeableLibraries Condition="'$(StripMergeableLibraries)' == ''">false</StripMergeableLibraries>

<!-- NoDSymUtil -->
<!-- Xamarin.Mac never had an equivalent for MtouchNoDSymUtil and never produced them -> now, produce them by default when archiving -->
<NoDSymUtil Condition="'$(NoDSymUtil)' == '' And '$(_PlatformName)' != 'macOS'">$(MtouchNoDSymUtil)</NoDSymUtil>
Expand Down
22 changes: 22 additions & 0 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<UsingTask TaskName="Xamarin.MacDev.Tasks.ScnTool" AssemblyFile="$(_TaskAssemblyName)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.SmartCopy" AssemblyFile="$(_TaskAssemblyName)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.SpotlightIndexer" AssemblyFile="$(_TaskAssemblyName)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.StripMergeableLibraryMetadata" AssemblyFile="$(_TaskAssemblyName)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.SymbolStrip" AssemblyFile="$(_TaskAssemblyName)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.TextureAtlas" AssemblyFile="$(_TaskAssemblyName)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.UnpackLibraryResources" AssemblyFile="$(_TaskAssemblyName)" />
Expand Down Expand Up @@ -3005,6 +3006,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
_PreparePostProcessing;
_GenerateDSym;
_NativeStripFiles;
_StripMergeableLibraryMetadata;
_NotifySpotlight;
</_PostProcessAppBundleDependsOn>
</PropertyGroup>
Expand Down Expand Up @@ -3089,6 +3091,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
Executable="$(_AppContainerDir)%(_NativeStripItems.Identity)"
Kind="%(_NativeStripItems.Kind)"
MaxDegreeOfParallelism="$(SymbolStripMaxDegreeOfParallelism)"
StripMergeableLibraries="$(StripMergeableLibraries)"
StripPath="$(StripPath)"
SymbolFile="%(_NativeStripItems.SymbolFile)"
/>
Expand Down Expand Up @@ -3116,6 +3119,25 @@ Copyright (C) 2018 Microsoft. All rights reserved.
/>
</Target>

<!--
Strip mergeable library metadata (LC_ATOM_INFO) from frameworks and dylibs in the app bundle.
This runs independently of the regular symbol stripping, because symbol stripping
may be disabled (e.g. simulator builds, debug builds, macOS/MacCatalyst).
-->
<Target
Name="_StripMergeableLibraryMetadata"
Condition="'$(_PostProcess)' == 'true' And '$(StripMergeableLibraries)' == 'true'"
DependsOnTargets="_PreparePostProcessing"
>

<StripMergeableLibraryMetadata
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true'"
FrameworksDirectory="$(_AppFrameworksPath)"
DylibDirectories="$(_AppContentsPath)"
/>
</Target>

<!-- make sure spotlight indexes everything we've built -->
<Target
Name="_NotifySpotlight"
Expand Down
22 changes: 22 additions & 0 deletions tests/dotnet/NativeMergeableDylibReferencesApp/AppDelegate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Runtime.InteropServices;

using Foundation;

namespace NativeMergeableDylibReferencesApp {
public class Program {
[DllImport ("libMergeableFramework.dylib")]
static extern int theUltimateAnswer ();

static int Main (string [] args)
{
Console.WriteLine ($"Mergeable Dynamic library: {theUltimateAnswer ()}");

GC.KeepAlive (typeof (NSObject)); // prevent linking away the platform assembly

Console.WriteLine (Environment.GetEnvironmentVariable ("MAGIC_WORD"));

return 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-maccatalyst</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
2 changes: 2 additions & 0 deletions tests/dotnet/NativeMergeableDylibReferencesApp/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TOP=../../..
include $(TOP)/tests/common/shared-dotnet-test.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-ios</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-macos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
20 changes: 20 additions & 0 deletions tests/dotnet/NativeMergeableDylibReferencesApp/shared.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<OutputType>Exe</OutputType>

<ApplicationTitle>NativeMergeableDylibReferencesApp</ApplicationTitle>
<ApplicationId>com.xamarin.nativemergeabledylibreferences</ApplicationId>
<ApplicationVersion>1.0</ApplicationVersion>
</PropertyGroup>

<Import Project="../../common/shared-dotnet.csproj" />

<ItemGroup>
<NativeReference Include="..\..\..\test-libraries\.libs\$(NativeLibName)\libMergeableFramework.dylib" Kind="Dynamic" />
</ItemGroup>

<ItemGroup>
<Compile Include="../*.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-tvos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
22 changes: 22 additions & 0 deletions tests/dotnet/NativeMergeableFrameworkReferencesApp/AppDelegate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Runtime.InteropServices;

using Foundation;

namespace NativeMergeableFrameworkReferencesApp {
public class Program {
[DllImport ("XMergeableTest.framework/XMergeableTest")]
static extern int theUltimateAnswer ();

static int Main (string [] args)
{
Console.WriteLine ($"Mergeable Framework: {theUltimateAnswer ()}");

GC.KeepAlive (typeof (NSObject)); // prevent linking away the platform assembly

Console.WriteLine (Environment.GetEnvironmentVariable ("MAGIC_WORD"));

return 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-maccatalyst</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
2 changes: 2 additions & 0 deletions tests/dotnet/NativeMergeableFrameworkReferencesApp/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TOP=../../..
include $(TOP)/tests/common/shared-dotnet-test.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-ios</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-macos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
20 changes: 20 additions & 0 deletions tests/dotnet/NativeMergeableFrameworkReferencesApp/shared.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<OutputType>Exe</OutputType>

<ApplicationTitle>NativeMergeableFrameworkReferencesApp</ApplicationTitle>
<ApplicationId>com.xamarin.nativemergeableframeworkreferences</ApplicationId>
<ApplicationVersion>1.0</ApplicationVersion>
</PropertyGroup>

<Import Project="../../common/shared-dotnet.csproj" />

<ItemGroup>
<NativeReference Include="..\..\..\test-libraries\.libs\$(NativeLibName)\XMergeableTest.framework" Kind="Framework" />
</ItemGroup>

<ItemGroup>
<Compile Include="../*.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-tvos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Loading
Loading