Skip to content

Commit

Permalink
Merge branch 'main' into dev/rolf/vision-version-number
Browse files Browse the repository at this point in the history
  • Loading branch information
rolfbjarne authored Oct 2, 2024
2 parents 72a732f + 5a0d412 commit d6a8279
Show file tree
Hide file tree
Showing 30 changed files with 192 additions and 265 deletions.
2 changes: 1 addition & 1 deletion msbuild/ILMerge.targets
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<MergeSystemAssemblies Condition="'$(MergeSystemAssemblies)' == ''">true</MergeSystemAssemblies>
<MergeSystemAssemblies Condition="'$(MergeSystemAssemblies)' == ''">false</MergeSystemAssemblies>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeCodesignItems.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public override bool Execute ()
for (var i = 1; i < all.Length; i++) {
var nextMetadata = all [i].CloneCustomMetadataToDictionary ();
if (nextMetadata.Count != firstMetadata.Count) {
Log.LogWarning (MSBStrings.W7095, /* Code signing has been requested multiple times for '{0}', with different metadata. The metadata for one are: '{1}', while the metadata for the other are: '{2}' */ group.Key, string.Join (", ", firstMetadata.Keys), string.Join (", ", nextMetadata.Keys));
Log.LogWarning (MSBStrings.W7095, /* Code signing has been requested multiple times for '{0}', with different metadata. The metadata for one are: '{1}', while the metadata for the other are: '{2}' */ group.Key, string.Join (", ", firstMetadata.Keys.OrderBy (v => v)), string.Join (", ", nextMetadata.Keys.OrderBy (v => v)));
} else {
foreach (var kvp in firstMetadata) {
if (!nextMetadata.TryGetValue (kvp.Key, out var nextValue)) {
Expand Down
153 changes: 75 additions & 78 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/UnpackLibraryResources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Collections.Generic;

Expand All @@ -15,7 +17,6 @@

namespace Xamarin.MacDev.Tasks {
public class UnpackLibraryResources : XamarinTask, ITaskCallback, ICancelableTask {
MetadataLoadContext? universe;
List<ITaskItem> unpackedResources = new List<ITaskItem> ();

#region Inputs
Expand All @@ -26,9 +27,6 @@ public class UnpackLibraryResources : XamarinTask, ITaskCallback, ICancelableTas
[Required]
public string IntermediateOutputPath { get; set; } = string.Empty;

[Required]
public ITaskItem [] ReferenceAssemblies { get; set; } = Array.Empty<ITaskItem> ();

[Required]
public ITaskItem [] ReferencedLibraries { get; set; } = Array.Empty<ITaskItem> ();

Expand All @@ -52,15 +50,6 @@ public class UnpackLibraryResources : XamarinTask, ITaskCallback, ICancelableTas
#endregion

public override bool Execute ()
{
try {
return ExecuteImpl ();
} finally {
universe?.Dispose ();
}
}

bool ExecuteImpl ()
{
if (ShouldExecuteRemotely ()) {
var result = new TaskRunner (SessionId, BuildEngine4).RunAsync (this).Result;
Expand All @@ -87,7 +76,7 @@ bool ExecuteImpl ()
Log.LogMessage (MessageImportance.Low, MSBStrings.M0168, asm.ItemSpec);
} else {
var perAssemblyOutputPath = Path.Combine (IntermediateOutputPath, "unpack", asm.GetMetadata ("Filename"));
var extracted = ExtractContentAssembly (asm.ItemSpec, perAssemblyOutputPath).ToArray ();
var extracted = ExtractContentAssembly (asm.ItemSpec, perAssemblyOutputPath);

results.AddRange (extracted);

Expand All @@ -113,58 +102,88 @@ bool IsFrameworkAssembly (ITaskItem asm)
return false;
}

IEnumerable<ITaskItem> ExtractContentAssembly (string assembly, string intermediatePath)
List<ITaskItem> ExtractContentAssembly (string assembly, string intermediatePath)
{
var rv = new List<ITaskItem> ();

if (!File.Exists (assembly)) {
Log.LogMessage (MessageImportance.Low, $"Not inspecting assembly because it doesn't exist: {assembly}");
yield break;
return rv;
}

var asmWriteTime = File.GetLastWriteTimeUtc (assembly);
var manifestResources = GetAssemblyManifestResources (assembly).ToArray ();
if (!manifestResources.Any ())
yield break;

Log.LogMessage (MessageImportance.Low, $"Inspecting assembly with {manifestResources.Length} resources: {assembly}");
foreach (var embedded in manifestResources) {
string rpath;

if (embedded.Name.StartsWith ("__" + Prefix + "_content_", StringComparison.Ordinal)) {
var mangled = embedded.Name.Substring (("__" + Prefix + "_content_").Length);
rpath = UnmangleResource (mangled);
} else if (embedded.Name.StartsWith ("__" + Prefix + "_page_", StringComparison.Ordinal)) {
var mangled = embedded.Name.Substring (("__" + Prefix + "_page_").Length);
rpath = UnmangleResource (mangled);
} else {
continue;
}

var path = Path.Combine (intermediatePath, rpath);
var file = new FileInfo (path);

var item = new TaskItem (path);
item.SetMetadata ("LogicalName", rpath);
item.SetMetadata ("Optimize", "false");

if (file.Exists && file.LastWriteTimeUtc >= asmWriteTime) {
Log.LogMessage (" Up to date: {0}", rpath);
} else {
Log.LogMessage (" Unpacking: {0}", rpath);

Directory.CreateDirectory (Path.GetDirectoryName (path));
try {
var asmWriteTime = File.GetLastWriteTimeUtc (assembly);
using var peStream = File.OpenRead (assembly);
using var peReader = new PEReader (peStream);
var metadataReader = PEReaderExtensions.GetMetadataReader (peReader);
Log.LogMessage (MessageImportance.Low, $"Inspecting resources in assembly {assembly}");
foreach (var manifestResourceHandle in metadataReader.ManifestResources) {
var manifestResource = metadataReader.GetManifestResource (manifestResourceHandle);
if (!manifestResource.Implementation.IsNil)
continue; // embedded resources have Implementation.IsNil = true, and those are the ones we care about

var name = metadataReader.GetString (manifestResource.Name);
if (string.IsNullOrEmpty (name))
continue;

string rpath;

if (name.StartsWith ("__" + Prefix + "_content_", StringComparison.Ordinal)) {
var mangled = name.Substring (("__" + Prefix + "_content_").Length);
rpath = UnmangleResource (mangled);
} else if (name.StartsWith ("__" + Prefix + "_page_", StringComparison.Ordinal)) {
var mangled = name.Substring (("__" + Prefix + "_page_").Length);
rpath = UnmangleResource (mangled);
} else {
continue;
}

using (var stream = File.Open (path, FileMode.Create)) {
using (var resource = embedded.Open ())
resource.CopyTo (stream);
var path = Path.Combine (intermediatePath, rpath);
var file = new FileInfo (path);

var item = new TaskItem (path);
item.SetMetadata ("LogicalName", rpath);
item.SetMetadata ("Optimize", "false");

if (file.Exists && file.LastWriteTimeUtc >= asmWriteTime) {
Log.LogMessage (" Up to date: {0}", rpath);
} else {
Log.LogMessage (" Unpacking: {0}", rpath);

Directory.CreateDirectory (Path.GetDirectoryName (path));

var resourceDirectory = peReader.GetSectionData (peReader.PEHeaders.CorHeader!.ResourcesDirectory.RelativeVirtualAddress);
var reader = resourceDirectory.GetReader ((int) manifestResource.Offset, resourceDirectory.Length - (int) manifestResource.Offset);
var length = reader.ReadUInt32 ();
if (length > reader.RemainingBytes)
throw new BadImageFormatException ();
#if NET
using var fs = new FileStream (path, FileMode.Create, FileAccess.Write, FileShare.Read);
unsafe {
var span = new ReadOnlySpan<byte> (reader.CurrentPointer, (int) length);
fs.Write (span);
}
#else
var buffer = new byte [4096];
using var fs = new FileStream (path, FileMode.Create, FileAccess.Write, FileShare.Read, buffer.Length);
var left = (int) length;
while (left > 0) {
var read = Math.Min (left, buffer.Length);
reader.ReadBytes (read, buffer, 0);
fs.Write (buffer, 0, read);
left -= read;
}
#endif
unpackedResources.Add (item);
}

unpackedResources.Add (item);
rv.Add (item);
}

yield return item;
} catch (Exception e) {
Log.LogMessage (MessageImportance.Low, $"Unable to load the resources from the assembly '{assembly}': {e}");
return new List<ITaskItem> ();
}

yield break;
return rv;
}

static string UnmangleResource (string mangled)
Expand Down Expand Up @@ -237,27 +256,5 @@ public bool ShouldCopyToBuildServer (ITaskItem item)

public IEnumerable<ITaskItem> GetAdditionalItemsToBeCopied () => ItemsFiles;

IEnumerable<ManifestResource> GetAssemblyManifestResources (string fileName)
{
if (universe is null)
universe = new MetadataLoadContext (new PathAssemblyResolver (ReferenceAssemblies.Select (v => v.ItemSpec)));

Assembly assembly;
try {
assembly = universe.LoadFromAssemblyPath (fileName);
} catch (Exception e) {
Log.LogMessage (MessageImportance.Low, $"Unable to load the assembly '{fileName}: {e}");
yield break;
}

foreach (var resourceName in assembly.GetManifestResourceNames ()) {
if (string.IsNullOrEmpty (resourceName))
continue;
var info = assembly.GetManifestResourceInfo (resourceName);
if (!info.ResourceLocation.HasFlag (ResourceLocation.Embedded))
continue;
yield return new ManifestResource (resourceName, () => assembly.GetManifestResourceStream (resourceName));
}
}
}
}
6 changes: 3 additions & 3 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1933,7 +1933,9 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<_StampDirectory>$(DeviceSpecificIntermediateOutputPath)resourcestamps\</_StampDirectory>
</PropertyGroup>
<ItemGroup>
<_UnpackLibraryResourceItems Include="@(ReferencePath);@(ReferenceDependencyPaths)">
<_UnpackLibraryResourceItems Include="@(ReferencePath)" Condition="'%(ReferencePath.FrameworkReferenceName)' != 'Microsoft.NETCore.App' And '%(ReferencePath.FrameworkReferenceName)' != 'Microsoft.$(_PlatformName)'" />
<_UnpackLibraryResourceItems Include="@(ReferenceDependencyPaths)" Condition="'%(ReferenceDependencyPaths.FrameworkReferenceName)' != 'Microsoft.NETCore.App' And '%(ReferenceDependencyPaths.FrameworkReferenceName)' != 'Microsoft.$(_PlatformName)'" />
<_UnpackLibraryResourceItems>
<StampFile>$(_StampDirectory)%(FileName).stamp</StampFile>
<ItemsFile>$(_StampDirectory)%(FileName).items</ItemsFile>
</_UnpackLibraryResourceItems>
Expand Down Expand Up @@ -1982,14 +1984,12 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<MakeDir Directories="$(_StampDirectory)" />

<!-- This task may be executed locally on Windows (for Hot Restart) -->
<!-- Note that ReferenceAssemblies must always be passed all referenced assemblies, even for incremental builds when we're not necessarily unpacking from all assemblies -->
<UnpackLibraryResources
Condition="'$(IsMacEnabled)' == 'true' Or '$(IsHotRestartBuild)' == 'true'"
SessionId="$(BuildSessionId)"
Prefix="$(_EmbeddedResourcePrefix)"
IntermediateOutputPath="$(DeviceSpecificIntermediateOutputPath)"
TargetFrameworkDirectory="$(TargetFrameworkDirectory)"
ReferenceAssemblies="@(ReferencePath);@(ReferenceDependencyPaths)"
ReferencedLibraries="@(_UnpackLibraryResourceItems)"
>
<Output TaskParameter="BundleResourcesWithLogicalNames" ItemName="_BundleResourceWithLogicalName" />
Expand Down
12 changes: 8 additions & 4 deletions tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -217,15 +217,19 @@ killall:
NUNIT_MSBUILD_DIR=$(TOP)/packages/NUnit.Runners.2.6.4/tools/lib
test-ios-tasks: test-macdev-tests test-macdev-tasks

# Example TEST_FILTER:
# TEST_FILTER="--filter FullyQualifiedName~BuildMyCocoaApp"
# Docs: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test#filter-option-details
test-macdev-tests: export MSBUILD_EXE_PATH=
test-macdev-tests: verify-system-vsmac-xcode-match
$(Q) $(DOTNET) build "/bl:$@.binlog" $(TOP)/tests/msbuild/Xamarin.MacDev.Tests/Xamarin.MacDev.Tests.csproj /p:Configuration=Debug $(DOTNET_BUILD_VERBOSITY)
cd $(TOP)/tests/msbuild/Xamarin.MacDev.Tests && $(SYSTEM_XIBUILD) -t -- $(abspath $(TOP)/tools/nunit3-console-3.11.1) $(abspath $(TOP)/tests/msbuild/Xamarin.MacDev.Tests/bin/Debug/net472/Xamarin.MacDev.Tests.dll) "--result=$(abspath $(CURDIR)/TestResults_Xamarin.MacDev.Tests.xml);format=nunit2" -labels=After $(TEST_FIXTURE)
$(Q) $(DOTNET) test $(TOP)/tests/msbuild/Xamarin.MacDev.Tests/Xamarin.MacDev.Tests.csproj $(TEST_FILTER)

# Example TEST_FILTER:
# TEST_FILTER="--filter FullyQualifiedName~BuildMyCocoaApp"
# Docs: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test#filter-option-details
test-macdev-tasks: export MSBUILD_EXE_PATH=
test-macdev-tasks: verify-system-vsmac-xcode-match
$(Q) $(DOTNET) build "/bl:$@.binlog" $(TOP)/tests/msbuild/Xamarin.MacDev.Tasks.Tests/Xamarin.MacDev.Tasks.Tests.csproj /p:Configuration=Debug $(DOTNET_BUILD_VERBOSITY)
cd $(TOP)/tests/msbuild/Xamarin.MacDev.Tasks.Tests && $(SYSTEM_XIBUILD) -t -- $(abspath $(TOP)/tools/nunit3-console-3.11.1) $(abspath $(TOP)/tests/msbuild/Xamarin.MacDev.Tasks.Tests/bin/Debug/net472/Xamarin.MacDev.Tasks.Tests.dll) "--result=$(abspath $(CURDIR)/TestResults_Xamarin.MacDev.Tasks.Tests.xml)" -labels=After $(TEST_FIXTURE)
$(Q) $(DOTNET) test $(TOP)/tests/msbuild/Xamarin.MacDev.Tasks.Tests/Xamarin.MacDev.Tasks.Tests.csproj $(TEST_FILTER)

mac-test-package.zip:
ifdef INCLUDE_MAC
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ CompileAppManifest CreateTask (string? tmpdir = null, ApplePlatform platform = A
task.AssemblyName = "AssemblyName";
task.AppBundleName = "AppBundleName";
task.CompiledAppManifest = new TaskItem (Path.Combine (tmpdir, "TemporaryAppManifest.plist"));
task.DefaultSdkVersion = Sdks.GetAppleSdk (platform).GetInstalledSdkVersions (false).First ().ToString ();
task.SdkVersion = task.DefaultSdkVersion;
task.DefaultSdkVersion = Sdks.GetAppleSdk (platform).GetInstalledSdkVersions (false).First ().ToString ()!;
task.SdkVersion = task.DefaultSdkVersion ?? string.Empty;
task.TargetFrameworkMoniker = TargetFramework.GetTargetFramework (platform, true).ToString ();

return task;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ CustomCompileEntitlements CreateEntitlementsTask (out string compiledEntitlement
task.AppBundleDir = AppBundlePath;
task.BundleIdentifier = "com.xamarin.MySingleView";
task.CompiledEntitlements = new TaskItem (Path.Combine (MonoTouchProjectObjPath, "Entitlements.xcent"));
task.Entitlements = Path.Combine (Path.GetDirectoryName (GetType ().Assembly.Location), "Resources", "Entitlements.plist");
task.ProvisioningProfile = Path.Combine (Path.GetDirectoryName (GetType ().Assembly.Location), "Resources", "profile.mobileprovision");
task.Entitlements = Path.Combine (Path.GetDirectoryName (GetType ().Assembly.Location)!, "Resources", "Entitlements.plist");
task.ProvisioningProfile = Path.Combine (Path.GetDirectoryName (GetType ().Assembly.Location)!, "Resources", "profile.mobileprovision");
task.SdkPlatform = "iPhoneOS";
task.SdkVersion = "6.1";
task.TargetFrameworkMoniker = "Xamarin.iOS,v1.0";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ public void DuplicatedWithDifferentMetadata (ApplePlatform platform, bool isDotN
Assert.AreEqual (3, Engine.Logger.WarningsEvents.Count, "Warning Count");
Assert.AreEqual ("Code signing has been requested multiple times for 'Bundle.app/Contents/MonoBundle/createdump', with different metadata. The metadata 'OnlyIn1=true' has been set for one item, but not the other.", Engine.Logger.WarningsEvents [0].Message, "Message #0");
Assert.AreEqual ("Code signing has been requested multiple times for 'Bundle.app/Contents/MonoBundle/createdump', with different metadata. The metadata 'InOneAndTwoWithDifferentValues' has different values for each item (once it's '1', another time it's '2').", Engine.Logger.WarningsEvents [1].Message, "Message #1");
Assert.AreEqual ("Code signing has been requested multiple times for 'Bundle.app/Contents/MonoBundle/createdump', with different metadata. The metadata for one are: 'RequireCodeSigning, OnlyIn1, InOneAndTwoWithDifferentValues, CodesignStampFile', while the metadata for the other are: 'RequireCodeSigning, CodesignStampFile'", Engine.Logger.WarningsEvents [2].Message, "Message #2");
Assert.AreEqual ("Code signing has been requested multiple times for 'Bundle.app/Contents/MonoBundle/createdump', with different metadata. The metadata for one are: 'CodesignStampFile, InOneAndTwoWithDifferentValues, OnlyIn1, RequireCodeSigning', while the metadata for the other are: 'CodesignStampFile, RequireCodeSigning'", Engine.Logger.WarningsEvents [2].Message, "Message #2");

VerifyCodesigningResults (infos, task.OutputCodesignItems, platform);
} finally {
Expand Down Expand Up @@ -532,7 +532,7 @@ void VerifyCodesigningResults (CodesignInfo [] infos, ITaskItem [] outputCodesig
var metadata = item.GetMetadata (kvp.Key);
if (metadata == string.Empty && kvp.Value != string.Empty) {
failures.Add ($"Item '{info.ItemSpec}': Expected metadata '{kvp.Key}' not found (with value '{kvp.Value}').");
} else if (!string.Equals (metadata, kvp.Value)) {
} else if (!string.Equals (metadata, kvp.Value, StringComparison.Ordinal)) {
failures.Add ($"Item '{info.ItemSpec}': Expected value '{kvp.Value}' for metadata '{kvp.Key}', but got '{metadata}' instead.\nExpected: {kvp.Value}\nActual: {metadata}");
}
}
Expand Down Expand Up @@ -587,7 +587,7 @@ void Touch (string root, params string [] files)
if (file.EndsWith (".appex", StringComparison.OrdinalIgnoreCase) || file.EndsWith (".app", StringComparison.OrdinalIgnoreCase)) {
Directory.CreateDirectory (f);
} else {
Directory.CreateDirectory (Path.GetDirectoryName (file));
Directory.CreateDirectory (Path.GetDirectoryName (file)!);
File.WriteAllText (file, string.Empty);
}
}
Expand Down Expand Up @@ -637,7 +637,7 @@ public static Dictionary<string, string> CopyCustomMetadata (this ITaskItem self
{
var rv = new Dictionary<string, string> ();
foreach (DictionaryEntry de in self.CloneCustomMetadata ()) {
rv [(string) de.Key] = (string) de.Value;
rv [(string) de.Key!] = (string) de.Value!;
}
return rv;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void Xcode12_x (string targetFrameworkMoniker, bool isSimulator, string a
// some architecture changes recently, e.g.
// in Xcode 12.1+ watchOS does not have an i386 architecture anymore
// on Xcode 12.2+ you get arm64 for all (iOS, tvOS and watchOS) simulators
var path = Path.Combine (Path.GetDirectoryName (GetType ().Assembly.Location), "Resources", "xcf-xcode12.2.plist");
var path = Path.Combine (Path.GetDirectoryName (GetType ().Assembly.Location)!, "Resources", "xcf-xcode12.2.plist");
var plist = PDictionary.FromFile (path)!;
var result = ResolveNativeReferences.TryResolveXCFramework (log, plist, "N/A", targetFrameworkMoniker, isSimulator, architecture, out var frameworkPath);
Assert.AreEqual (result, !string.IsNullOrEmpty (expected), "result");
Expand All @@ -51,7 +51,7 @@ public void Xcode12_x (string targetFrameworkMoniker, bool isSimulator, string a
[TestCase (TargetFramework.Xamarin_WatchOS_1_0_String, true, "i386", "watchos-i386-simulator/XTest.framework/XTest")]
public void PreXcode12 (string targetFrameworkMoniker, bool isSimulator, string architecture, string expected)
{
var path = Path.Combine (Path.GetDirectoryName (GetType ().Assembly.Location), "Resources", "xcf-prexcode12.plist");
var path = Path.Combine (Path.GetDirectoryName (GetType ().Assembly.Location)!, "Resources", "xcf-prexcode12.plist");
var plist = PDictionary.FromFile (path)!;
var result = ResolveNativeReferences.TryResolveXCFramework (log, plist, "N/A", targetFrameworkMoniker, isSimulator, architecture, out var frameworkPath);
Assert.AreEqual (result, !string.IsNullOrEmpty (expected), "result");
Expand Down
Loading

0 comments on commit d6a8279

Please sign in to comment.