From 7e854827d4a9f7b8e1f45bd5bea658aa174ebe5a Mon Sep 17 00:00:00 2001 From: Sebastien Pouliot Date: Tue, 27 Oct 2020 21:11:08 -0400 Subject: [PATCH] [msbuild] Have `XcodeCompilerToolTask` use `xcrun` to start Apple tools (#9965) (#9972) 1. Use `xcrun` to run `ibtool` (and `actool`) and avoid toolchain mismatches 2. Set `DEVELOPER_DIR` so everyone (well `xcrun`) use the same toolchain 3. Workaround for `macos-arm64` issue (FB8827920) * Start `ibtool` as an `Apple` [Silicon] process * This will ensure the `ibtoold` daemon is also running as `Apple` * If `ibtoold` is run as `Intel` then `ibtool` asserts and build fail ``` LaunchScreen.storyboard : error : 2020-10-26 14:24:52.757 ibtoold[37142:6681382] [MT] DVTAssertions: Warning in /Library/Caches/com.apple.xbs/Sources/IDEInterfaceBuilder/IDEInterfaceBuilder-17506/InterfaceBuilderKit/Utilities/IBAbstractInterfaceBuilderPlatformToolManager.m:481 LaunchScreen.storyboard : error : Details: Failed to attach to IBAgent-iOS with error: Error Domain=com.apple.InterfaceBuilder Code=-1 "Encountered an error communicating with IBAgent-iOS." UserInfo={NSLocalizedFailureReason=IBAgent-iOS (37146) failed to launch and exited with status 10, NSUnderlyingError=0x7fa4e58fc760 {Error Domain=com.apple.InterfaceBuilder Code=-1 "Failed to launch IBAgent-iOS via CoreSimulator spawn" UserInfo={NSLocalizedDescription=Failed to launch IBAgent-iOS via CoreSimulator spawn, NSUnderlyingError=0x7fa4e5e8a900 {Error Domain=com.apple.InterfaceBuilder Code=-1 "Failed to handshake with platform tool" UserInfo={NSLocalizedFailureReason=Failed to open connection over FIFOs with platform tool, NSLocalizedDescription=Failed to handshake with platform tool, NSUnderlyingError=0x7fa4e5e237c0 {Error Domain=com.apple.InterfaceBuilder Code=-1 "" UserInfo=0x7fa4e5e8bba0 (not displayed)}}}}}, NSLocalizedRecoverySuggestion=Please check Console.app for crash reports for "IBAgent-iOS" for further information., NSLocalizedDescription=Encountered an error communicating with IBAgent-iOS.} LaunchScreen.storyboard : error : Object: LaunchScreen.storyboard : error : Method: +_THREADSAFE_launchNewToolWithLaunchContext:executionContext:toolProxyClass:proxyDelegate:failureContext:requestingMethod:error:forReason: LaunchScreen.storyboard : error : Thread: {number = 1, name = main} LaunchScreen.storyboard : error : Please file a bug at https://feedbackassistant.apple.com with this warning message and any useful information you can provide. LaunchScreen.storyboard : error : 2020-10-26 14:24:52.766 ibtoold[37142:6681382] [MT] IBPlatformTool: *** Failed to launch tool with description System content for IBCocoaTouchFramework-fourteenAndLater scaleFactor=2x, renderMode.identifier=(null): Encountered an error communicating with IBAgent-iOS. (Failure reason: IBAgent-iOS (37146) failed to launch and exited with status 10): Failed to launch IBAgent-iOS via CoreSimulator spawn: Failed to handshake with platform tool (Failure reason: Failed to open connection over FIFOs with platform tool): : Failed to open FIFOs for handshaking with platform tool (Failure reason: IBAgent-iOS exited before we could handshake) /Library/Frameworks/Mono.framework/External/xbuild/Xamarin/iOS/Xamarin.iOS.Common.targets(1425,3): error : ibtool exited with code 1 /Library/Frameworks/Mono.framework/External/xbuild/Xamarin/iOS/Xamarin.iOS.Common.targets(1425,3): error : LaunchScreen.storyboard : ibtool error : Encountered an error communicating with IBAgent-iOS. ``` Note: `main` has diverged quite a bit (net6 support) so this pull request will need to be re-worked (it won't apply) Fixes https://github.com/xamarin/xamarin-macios/issues/4634 Foreport of #9965 since the source code diverged from `xcode12.2` --- .../Tasks/IBToolTaskBase.cs | 1 - .../Tasks/XcodeCompilerToolTask.cs | 38 ++++++++++++++----- tests/mmptest/src/MMPTest.cs | 7 ++-- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/IBToolTaskBase.cs b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/IBToolTaskBase.cs index 6d62e1b76c..4a6de1009c 100644 --- a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/IBToolTaskBase.cs +++ b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/IBToolTaskBase.cs @@ -52,7 +52,6 @@ namespace Xamarin.MacDev.Tasks protected override void AppendCommandLineArguments (IDictionary environment, CommandLineArgumentBuilder args, ITaskItem[] items) { - environment.Add ("DEVELOPER_DIR", SdkDevPath); environment.Add ("IBSC_MINIMUM_COMPATIBILITY_VERSION", MinimumOSVersion); environment.Add ("IBC_MINIMUM_COMPATIBILITY_VERSION", MinimumOSVersion); diff --git a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/XcodeCompilerToolTask.cs b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/XcodeCompilerToolTask.cs index 8a71a396dc..3ed0486ca9 100644 --- a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/XcodeCompilerToolTask.cs +++ b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/XcodeCompilerToolTask.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Diagnostics; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -102,14 +103,20 @@ namespace Xamarin.MacDev.Tasks protected abstract void AppendCommandLineArguments (IDictionary environment, CommandLineArgumentBuilder args, ITaskItem[] items); - string GetFullPathToTool () + static bool? translated; + + [DllImport ("/usr/lib/libSystem.dylib", SetLastError = true)] + static extern int sysctlbyname (/* const char */ [MarshalAs (UnmanagedType.LPStr)] string property, ref long oldp, ref long oldlenp, IntPtr newp, /* size_t */ long newlen); + + // https://developer.apple.com/documentation/apple_silicon/about_the_rosetta_translation_environment + static bool IsTranslated () { - if (!string.IsNullOrEmpty (ToolPath)) - return Path.Combine (ToolPath, ToolExe); - - var path = Path.Combine (DefaultBinDir, ToolExe); - - return File.Exists (path) ? path : ToolExe; + if (translated == null) { + long result = 0; + long size = sizeof (long); + translated = ((sysctlbyname ("sysctl.proc_translated", ref result, ref size, IntPtr.Zero, 0) != -1) && (result == 1)); + } + return translated.Value; } protected int Compile (ITaskItem[] items, string output, ITaskItem manifest) @@ -123,6 +130,20 @@ namespace Xamarin.MacDev.Tasks if (!string.IsNullOrEmpty (SdkUsrPath)) environment.Add ("XCODE_DEVELOPER_USR_PATH", SdkUsrPath); + if (!string.IsNullOrEmpty (SdkDevPath)) + environment.Add ("DEVELOPER_DIR", SdkDevPath); + + // workaround for ibtool[d] bug / asserts if Intel version is loaded + string tool; + if (IsTranslated ()) { + // we force the Intel (translated) msbuild process to launch ibtool as "Apple" + tool = "arch"; + args.Add ("-arch", "arm64e"); + args.Add ("/usr/bin/xcrun"); + } else { + tool = "/usr/bin/xcrun"; + } + args.Add (ToolName); args.Add ("--errors", "--warnings", "--notices"); args.Add ("--output-format", "xml1"); @@ -140,9 +161,8 @@ namespace Xamarin.MacDev.Tasks foreach (var item in items) args.AddQuoted (item.GetMetadata ("FullPath")); - var fileName = GetFullPathToTool (); var arguments = args.ToList (); - var rv = ExecuteAsync (fileName, arguments, sdkDevPath, environment: environment, mergeOutput: false).Result; + var rv = ExecuteAsync (tool, arguments, sdkDevPath, environment: environment, mergeOutput: false).Result; var exitCode = rv.ExitCode; var messages = rv.StandardOutput.ToString (); File.WriteAllText (manifest.ItemSpec, messages); diff --git a/tests/mmptest/src/MMPTest.cs b/tests/mmptest/src/MMPTest.cs index 67abe4692a..b4dc585d14 100644 --- a/tests/mmptest/src/MMPTest.cs +++ b/tests/mmptest/src/MMPTest.cs @@ -703,6 +703,7 @@ namespace Xamarin.MMP.Tests [Test] public void BuildingSameSolutionTwice_ShouldNotRunACToolTwice () { + const string actool = " execution started with arguments: actool --errors --warnings --notices --output-format xml1 --output-partial-info-plist "; RunMMPTest (tmpDir => { TI.UnifiedTestConfig test = new TI.UnifiedTestConfig (tmpDir) { AssetIcons = true @@ -711,15 +712,15 @@ namespace Xamarin.MMP.Tests string project = TI.GenerateUnifiedExecutableProject (test); string buildOutput = TI.BuildProject (project); - Assert.True (buildOutput.Contains ("actool execution started with arguments"), $"Initial build should run actool"); + Assert.True (buildOutput.Contains (actool), $"Initial build should run actool"); buildOutput = TI.BuildProject (project); - Assert.False (buildOutput.Contains ("actool execution started with arguments"), $"Second build should not run actool"); + Assert.False (buildOutput.Contains (actool), $"Second build should not run actool"); TI.RunAndAssert ("touch", new [] { Path.Combine (tmpDir, "Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png") }, "touch icon"); buildOutput = TI.BuildProject (project); - Assert.True (buildOutput.Contains ("actool execution started with arguments"), $"Build after touching icon must run actool"); + Assert.True (buildOutput.Contains (actool), $"Build after touching icon must run actool"); }); }