diff --git a/docs/build-apps/build-items.md b/docs/build-apps/build-items.md index ca29996cd0a2..2c5b8b1244ae 100644 --- a/docs/build-apps/build-items.md +++ b/docs/build-apps/build-items.md @@ -30,6 +30,13 @@ See also: * The [AppIcon](build-properties.md#AppIcon) property. * The [IncludeAllAppIcons](build-properties.md#IncludeAllAppIcons) property. +## BGenReferencePath + +The list of assembly references to pass to the `bgen` tool (binding generator). + +Typically this is handled automatically by adding references as +`ProjectReference` or `PackageReference` items instead. + ## PartialAppManifest `PartialAppManifest` can be used to add additional partial app manifests that diff --git a/docs/build-apps/build-properties.md b/docs/build-apps/build-properties.md index b405f6b4833b..5464bc38b226 100644 --- a/docs/build-apps/build-properties.md +++ b/docs/build-apps/build-properties.md @@ -33,6 +33,28 @@ See also: * The [AlternateAppIcon](build-items.md#AlternateAppIcon) item group. * The [IncludeAllAppIcons](#IncludeAllAppIcons) property. +### BGenEmitDebugInformation + +Whether the `bgen` tool (the binding generator) should emit debug information or not. + +The default behavior is `true` when the `Debug` property is set to `true`. + +## BGenExtraArgs + +Any extra arguments to the `bgen` tool (the binding generator). + +## BGenToolExe + +The name of the `bgen` executable (a tool used by binding projects to generate bindings). + +The default behavior is to use the `bgen` tool shipped with our workload. + +## BGenToolPath + +The directory to where the `bgen` ([BGenToolExe](#BGenToolExe)) is located. + +The default behavior is to use the `bgen` tool shipped with our workload. + ## DittoPath The full path to the `ditto` executable. diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index f7329f9b6ba1..1504cb8c6a9f 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -1416,8 +1416,8 @@ - bgen.dll - $(_XamarinSdkRootDirectory)\tools\lib\bgen + bgen.dll + $(_XamarinSdkRootDirectory)\tools\lib\bgen $(_XamarinRefAssemblyPath) <_GeneratorAttributeAssembly>$(_XamarinSdkRootDirectory)/tools/lib/Xamarin.Apple.BindingAttributes.dll <_DotNetCscCompiler>$(RoslynTargetsPath)\bincore\csc.dll diff --git a/msbuild/Xamarin.MacDev.Tasks/CommandLineArgumentBuilder.cs b/msbuild/Xamarin.MacDev.Tasks/CommandLineArgumentBuilder.cs index 9d13fcc21f96..1b76873c86d7 100644 --- a/msbuild/Xamarin.MacDev.Tasks/CommandLineArgumentBuilder.cs +++ b/msbuild/Xamarin.MacDev.Tasks/CommandLineArgumentBuilder.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Linq; using System.Text; using System.Collections.Generic; @@ -229,5 +230,32 @@ public string CreateResponseFile (Task task, string responseFilePath, IList CreateResponseFile (Task task, string responseFilePath, IList responseArguments, IList nonResponseArguments) + { + // Generate a response file + var responseFile = Path.GetFullPath (responseFilePath); + + if (File.Exists (responseFile)) + File.Delete (responseFile); + + try { + File.WriteAllLines (responseFile, StringUtils.Quote (responseArguments.ToArray ())); + } catch (Exception ex) { + task.Log.LogWarning ("Failed to create response file '{0}': {1}", responseFile, ex); + } + + // Some arguments can not safely go in the response file and are + // added separately. They must go _after_ the response file + // as they may override options passed in the response file + var actualArgs = new List (); + + actualArgs.Add ($"@{responseFile}"); + if (nonResponseArguments is not null) + actualArgs.AddRange (nonResponseArguments); + + // Generate the command line + return actualArgs; + } } } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/BTouch.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/BGen.cs similarity index 60% rename from msbuild/Xamarin.MacDev.Tasks/Tasks/BTouch.cs rename to msbuild/Xamarin.MacDev.Tasks/Tasks/BGen.cs index 48ba271c855e..d10948aba353 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/BTouch.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/BGen.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -15,123 +17,107 @@ using Xamarin.Messaging; using Xamarin.Messaging.Build.Client; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Xamarin.MacDev.Tasks { - public class BTouch : XamarinToolTask, ITaskCallback { + public class BGen : XamarinTask, ICancelableTask { + CancellationTokenSource? cancellationTokenSource; - public string OutputPath { get; set; } + public string OutputPath { get; set; } = string.Empty; [Required] - public string BTouchToolPath { get; set; } + public string BGenToolPath { get; set; } = string.Empty; [Required] - public string BTouchToolExe { get; set; } + public string BGenToolExe { get; set; } = string.Empty; - public ITaskItem [] ObjectiveCLibraries { get; set; } + public ITaskItem [] ObjectiveCLibraries { get; set; } = Array.Empty (); - public ITaskItem [] AdditionalLibPaths { get; set; } + public ITaskItem [] AdditionalLibPaths { get; set; } = Array.Empty (); public bool AllowUnsafeBlocks { get; set; } [Required] - public string BaseLibDll { get; set; } + public string BaseLibDll { get; set; } = string.Empty; [Required] - public ITaskItem [] ApiDefinitions { get; set; } + public ITaskItem [] ApiDefinitions { get; set; } = Array.Empty (); - public string AttributeAssembly { get; set; } + public string AttributeAssembly { get; set; } = string.Empty; - public ITaskItem CompiledApiDefinitionAssembly { get; set; } + public ITaskItem? CompiledApiDefinitionAssembly { get; set; } - public ITaskItem [] CoreSources { get; set; } + public ITaskItem [] CoreSources { get; set; } = Array.Empty (); - public string DefineConstants { get; set; } + public string DefineConstants { get; set; } = string.Empty; public bool EmitDebugInformation { get; set; } - public string ExtraArgs { get; set; } + public string ExtraArgs { get; set; } = string.Empty; public int Verbosity { get; set; } - public string GeneratedSourcesDir { get; set; } + public string GeneratedSourcesDir { get; set; } = string.Empty; - public string GeneratedSourcesFileList { get; set; } + public string GeneratedSourcesFileList { get; set; } = string.Empty; - public string Namespace { get; set; } + public string Namespace { get; set; } = string.Empty; public bool NoNFloatUsing { get; set; } - public ITaskItem [] NativeLibraries { get; set; } + public ITaskItem [] NativeLibraries { get; set; } = Array.Empty (); - public string OutputAssembly { get; set; } + public string OutputAssembly { get; set; } = string.Empty; public bool ProcessEnums { get; set; } [Required] - public string ProjectDir { get; set; } + public string ProjectDir { get; set; } = string.Empty; - public ITaskItem [] References { get; set; } + public ITaskItem [] References { get; set; } = Array.Empty (); - public ITaskItem [] Resources { get; set; } + public ITaskItem [] Resources { get; set; } = Array.Empty (); - public ITaskItem [] Sources { get; set; } + public ITaskItem [] Sources { get; set; } = Array.Empty (); [Required] - public string ResponseFilePath { get; set; } + public string ResponseFilePath { get; set; } = string.Empty; - protected override string ToolName { - get { - if (IsDotNet) - return Path.GetFileName (this.GetDotNetPath ()); - - return Path.GetFileNameWithoutExtension (ToolExe); - } - } - - protected override string GenerateFullPathToTool () - { - // If we're building a .NET app, executing bgen using the same - // dotnet binary as we're executed with, instead of using the - // wrapper bgen script, because that script will try to use the - // system dotnet, which might not exist or not have the version we - // need. - if (IsDotNet) - return this.GetDotNetPath (); - - return Path.Combine (ToolPath, ToolExe); - } - - protected virtual void HandleReferences (CommandLineArgumentBuilder cmd) + protected virtual void HandleReferences (List cmd) { if (References is not null) { foreach (var item in References) - cmd.AddQuoted ("-r:" + Path.GetFullPath (item.ItemSpec)); + cmd.Add ($"-r:{Path.GetFullPath (item.ItemSpec)}"); } } - protected override string GenerateCommandLineCommands () + public virtual List GenerateCommandLineArguments () { - var cmd = new CommandLineArgumentBuilder (); + var cmd = new List (); #if DEBUG cmd.Add ("/v"); #endif - if (CompiledApiDefinitionAssembly is not null) - cmd.AddQuotedSwitchIfNotNull ("/compiled-api-definition-assembly:", CompiledApiDefinitionAssembly.ItemSpec); + var compiledApiDefinitionAssembly = CompiledApiDefinitionAssembly?.ItemSpec; +#if NET + if (!string.IsNullOrEmpty (compiledApiDefinitionAssembly)) +#else + if (compiledApiDefinitionAssembly is not null && !string.IsNullOrEmpty (compiledApiDefinitionAssembly)) +#endif + cmd.Add ($"/compiled-api-definition-assembly:{compiledApiDefinitionAssembly}"); cmd.Add ("/nostdlib"); - cmd.AddQuotedSwitchIfNotNull ("/baselib:", BaseLibDll); - cmd.AddQuotedSwitchIfNotNull ("/out:", OutputAssembly); + if (!string.IsNullOrEmpty (BaseLibDll)) + cmd.Add ($"/baselib:{BaseLibDll}"); + if (!string.IsNullOrEmpty (OutputAssembly)) + cmd.Add ($"/out:{OutputAssembly}"); - cmd.AddQuotedSwitchIfNotNull ("/attributelib:", AttributeAssembly); + cmd.Add ($"/attributelib:{AttributeAssembly}"); - string dir; if (!string.IsNullOrEmpty (BaseLibDll)) { - dir = Path.GetDirectoryName (BaseLibDll); - cmd.AddQuotedSwitchIfNotNull ("/lib:", dir); + var dir = Path.GetDirectoryName (BaseLibDll); + cmd.Add ($"/lib:{dir}"); } if (ProcessEnums) @@ -143,7 +129,8 @@ protected override string GenerateCommandLineCommands () if (AllowUnsafeBlocks) cmd.Add ("/unsafe"); - cmd.AddQuotedSwitchIfNotNull ("/ns:", Namespace); + if (!string.IsNullOrEmpty (Namespace)) + cmd.Add ($"/ns:{Namespace}"); if (NoNFloatUsing) cmd.Add ("/no-nfloat-using:true"); @@ -151,27 +138,27 @@ protected override string GenerateCommandLineCommands () if (!string.IsNullOrEmpty (DefineConstants)) { var strv = DefineConstants.Split (new [] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (var str in strv) - cmd.AddQuoted ("/d:" + str); + cmd.Add ($"/d:{str}"); } //cmd.AppendSwitch ("/e"); foreach (var item in ApiDefinitions) - cmd.AddQuoted (Path.GetFullPath (item.ItemSpec)); + cmd.Add (Path.GetFullPath (item.ItemSpec)); if (CoreSources is not null) { foreach (var item in CoreSources) - cmd.AddQuoted ("/s:" + Path.GetFullPath (item.ItemSpec)); + cmd.Add ($"/s:{Path.GetFullPath (item.ItemSpec)}"); } if (Sources is not null) { foreach (var item in Sources) - cmd.AddQuoted ("/x:" + Path.GetFullPath (item.ItemSpec)); + cmd.Add ($"/x:{Path.GetFullPath (item.ItemSpec)}"); } if (AdditionalLibPaths is not null) { foreach (var item in AdditionalLibPaths) - cmd.AddQuoted ("/lib:" + Path.GetFullPath (item.ItemSpec)); + cmd.Add ($"/lib:{Path.GetFullPath (item.ItemSpec)}"); } HandleReferences (cmd); @@ -183,7 +170,7 @@ protected override string GenerateCommandLineCommands () if (!string.IsNullOrEmpty (id)) argument += "," + id; - cmd.AddQuoted ("/res:" + argument); + cmd.Add ($"/res:{argument}"); } } @@ -194,15 +181,15 @@ protected override string GenerateCommandLineCommands () if (string.IsNullOrEmpty (id)) id = Path.GetFileName (argument); - cmd.AddQuoted ("/res:" + argument + "," + id); + cmd.Add ($"/res:{argument},{id}"); } } - if (GeneratedSourcesDir is not null) - cmd.AddQuoted ("/tmpdir:" + Path.GetFullPath (GeneratedSourcesDir)); + if (!string.IsNullOrEmpty (GeneratedSourcesDir)) + cmd.Add ($"/tmpdir:{Path.GetFullPath (GeneratedSourcesDir)}"); - if (GeneratedSourcesFileList is not null) - cmd.AddQuoted ("/sourceonly:" + Path.GetFullPath (GeneratedSourcesFileList)); + if (!string.IsNullOrEmpty (GeneratedSourcesFileList)) + cmd.Add ($"/sourceonly:{Path.GetFullPath (GeneratedSourcesFileList)}"); cmd.Add ($"/target-framework={TargetFrameworkMoniker}"); @@ -227,7 +214,7 @@ protected override string GenerateCommandLineCommands () // { "solutiondir", proj.ParentSolution is not null ? proj.ParentSolution.BaseDirectory : proj.BaseDirectory }, }; // OutputAssembly is optional so it can be null - if (target is not null) { + if (!string.IsNullOrEmpty (target)) { var d = Path.GetDirectoryName (target); var n = Path.GetFileName (target); customTags.Add ("targetpath", Path.Combine (d, n)); @@ -242,20 +229,16 @@ protected override string GenerateCommandLineCommands () } } - cmd.Add (VerbosityUtils.Merge (ExtraArgs, (LoggerVerbosity) Verbosity)); - - var commandLine = cmd.CreateResponseFile (this, ResponseFilePath, null); - if (IsDotNet) - commandLine = StringUtils.Quote (Path.Combine (BTouchToolPath, BTouchToolExe)) + " " + commandLine; + cmd.AddRange (VerbosityUtils.Merge (ExtraArgs, (LoggerVerbosity) Verbosity)); - return commandLine.ToString (); + return CommandLineArgumentBuilder.CreateResponseFile (this, ResponseFilePath, cmd, null); } public override bool Execute () { if (ShouldExecuteRemotely ()) { try { - BTouchToolPath = PlatformPath.GetPathForCurrentPlatform (BTouchToolPath); + BGenToolPath = PlatformPath.GetPathForCurrentPlatform (BGenToolPath); BaseLibDll = PlatformPath.GetPathForCurrentPlatform (BaseLibDll); TaskItemFixer.FixFrameworkItemSpecs (Log, item => OutputPath, TargetFramework.Identifier, References.Where (x => x.IsFrameworkItem ()).ToArray ()); @@ -277,18 +260,11 @@ public override bool Execute () AttributeAssembly = PathUtils.ConvertToMacPath (AttributeAssembly); BaseLibDll = PathUtils.ConvertToMacPath (BaseLibDll); - BTouchToolExe = PathUtils.ConvertToMacPath (BTouchToolExe); - BTouchToolPath = PathUtils.ConvertToMacPath (BTouchToolPath); - if (IsDotNet) { - var customHome = Environment.GetEnvironmentVariable ("DOTNET_CUSTOM_HOME"); - - if (!string.IsNullOrEmpty (customHome)) { - EnvironmentVariables = EnvironmentVariables.CopyAndAdd ($"HOME={customHome}"); - } - } else { - ToolExe = BTouchToolExe; - ToolPath = BTouchToolPath; + var customHome = Environment.GetEnvironmentVariable ("DOTNET_CUSTOM_HOME"); + var env = new Dictionary (); + if (!string.IsNullOrEmpty (customHome)) { + env ["HOME"] = customHome; } if (!string.IsNullOrEmpty (SessionId) && @@ -302,7 +278,18 @@ public override bool Execute () return false; } - return base.Execute (); + var bgenPath = PathUtils.ConvertToMacPath (BGenToolPath); + var bgenExe = PathUtils.ConvertToMacPath (BGenToolExe); + var bgen = Path.Combine (bgenPath, bgenExe); + var args = GenerateCommandLineArguments (); + args.Insert (0, bgen); + var executable = this.GetDotNetPath (); + if (Log.HasLoggedErrors) + return false; + + cancellationTokenSource = new CancellationTokenSource (); + ExecuteAsync (Log, executable, args, environment: env, cancellationToken: cancellationTokenSource.Token).Wait (); + return !Log.HasLoggedErrors; } public bool ShouldCopyToBuildServer (ITaskItem item) => !item.IsFrameworkItem (); @@ -320,12 +307,13 @@ public IEnumerable GetAdditionalItemsToBeCopied () }).ToArray (); } - public override void Cancel () + public void Cancel () { - base.Cancel (); - - if (!string.IsNullOrEmpty (SessionId)) + if (ShouldExecuteRemotely ()) { BuildConnection.CancelAsync (BuildEngine4).Wait (); + } else { + cancellationTokenSource?.Cancel (); + } } async System.Threading.Tasks.Task GetGeneratedSourcesAsync (TaskRunner taskRunner) diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeRemoteGeneratorProperties.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeRemoteGeneratorProperties.cs index 745da29e5f86..bbd2f68a4560 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeRemoteGeneratorProperties.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeRemoteGeneratorProperties.cs @@ -26,10 +26,10 @@ public class ComputeRemoteGeneratorProperties : XamarinTask, ITaskCallback, ICan public string BaseLibDllPath { get; set; } = string.Empty; [Output] - public string BTouchToolExe { get; set; } = string.Empty; + public string BGenToolExe { get; set; } = string.Empty; [Output] - public string BTouchToolPath { get; set; } = string.Empty; + public string BGenToolPath { get; set; } = string.Empty; [Output] public string DotNetCscCompiler { get; set; } = string.Empty; @@ -139,11 +139,11 @@ void ComputeProperties () case "BaseLibDllPath": BaseLibDllPath = value; break; - case "BTouchToolExe": - BTouchToolExe = value; + case "BGenToolExe": + BGenToolExe = value; break; - case "BTouchToolPath": - BTouchToolPath = value; + case "BGenToolPath": + BGenToolPath = value; break; case "_DotNetCscCompiler": DotNetCscCompiler = value; diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.props b/msbuild/Xamarin.Shared/Xamarin.Shared.props index 79045a9f800e..de3df76b9fa5 100644 --- a/msbuild/Xamarin.Shared/Xamarin.Shared.props +++ b/msbuild/Xamarin.Shared/Xamarin.Shared.props @@ -315,12 +315,6 @@ Copyright (C) 2020 Microsoft. All rights reserved. $(_XamarinPlatformAssemblyPath) - $(_XamarinSdkRoot)/bin/ - $(MSBuildExtensionsPath)\Xamarin\iOS\ - - bgen - bgen.exe - $(IntermediateOutputPath)$(_PlatformName) $(GeneratedSourcesDir)\ <_GeneratedSourcesFileList>$(GeneratedSourcesDir)sources.list diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets index 262ede852e16..acefc72ca72c 100644 --- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets +++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets @@ -38,7 +38,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. - + @@ -1713,8 +1713,8 @@ Copyright (C) 2018 Microsoft. All rights reserved. <_ComputedRemoteGeneratorProperties Include="BaseLibDllPath=$(BaseLibDllPath)" /> - <_ComputedRemoteGeneratorProperties Include="BTouchToolExe=$(BTouchToolExe)" /> - <_ComputedRemoteGeneratorProperties Include="BTouchToolPath=$(BTouchToolPath)" /> + <_ComputedRemoteGeneratorProperties Include="BGenToolExe=$(BGenToolExe)" /> + <_ComputedRemoteGeneratorProperties Include="BGenToolPath=$(BGenToolPath)" /> <_ComputedRemoteGeneratorProperties Include="_DotNetCscCompiler=$(_DotNetCscCompiler)" /> <_ComputedRemoteGeneratorProperties Include="_GeneratorAttributeAssembly=$(_GeneratorAttributeAssembly)" /> @@ -1730,7 +1730,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. - + @@ -1751,7 +1751,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. <_CompiledApiDefinitionReferences Include="$(_GeneratorAttributeAssembly)" /> <_CompiledApiDefinitionReferences Include="@(ReferencePath)" /> - <_CompiledApiDefinitionReferences Include="@(BTouchReferencePath)" /> + <_CompiledApiDefinitionReferences Include="@(BGenReferencePath)" /> <_CompiledApiDefinitionsCompile Include="@(ObjcBindingApiDefinition)" /> <_CompiledApiDefinitionsCompile Include="@(ObjcBindingCoreSource)" /> @@ -1814,10 +1814,17 @@ Copyright (C) 2018 Microsoft. All rights reserved. - false - true + $(BTouchEmitDebugInformation) + true + false + + $(BTouchExtraArgs) + + + + @@ -1828,13 +1835,13 @@ Copyright (C) 2018 Microsoft. All rights reserved. TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)" > - - + + - - + (); + var task = CreateTask (); task.ApiDefinitions = new [] { new TaskItem ("apidefinition.cs") }; task.References = new [] { new TaskItem ("a.dll"), new TaskItem ("b.dll"), new TaskItem ("c.dll") }; task.ResponseFilePath = Path.Combine (Cache.CreateTemporaryDirectory (), "response-file.txt"); - var args = task.GetCommandLineCommands () + " " + File.ReadAllText (task.ResponseFilePath); + var args = task.GenerateCommandLineArguments (); + args.AddRange (File.ReadAllLines (task.ResponseFilePath)); Assert.That (args, Does.Contain ("-r:" + Path.Combine (Environment.CurrentDirectory, "a.dll")), "#1a"); Assert.That (args, Does.Contain ("-r:" + Path.Combine (Environment.CurrentDirectory, "b.dll")), "#1b"); Assert.That (args, Does.Contain ("-r:" + Path.Combine (Environment.CurrentDirectory, "c.dll")), "#1c"); @@ -33,7 +28,7 @@ public void StandardCommandline () [Test] public void Bug656983 () { - var task = CreateTask (); + var task = CreateTask (); task.ApiDefinitions = new [] { new TaskItem ("apidefinition.cs") }; task.References = new [] { new TaskItem ("a.dll"), new TaskItem ("b.dll"), new TaskItem ("c.dll") }; @@ -42,8 +37,9 @@ public void Bug656983 () task.OutputAssembly = null; // default, but important for the bug (in case that default changes) task.ExtraArgs = "-invalid"; - var args = task.GetCommandLineCommands () + " " + File.ReadAllText (task.ResponseFilePath); - Assert.That (args.Contains (" -invalid"), "incorrect ExtraArg not causing an exception"); + var args = task.GenerateCommandLineArguments (); + args.AddRange (File.ReadAllLines (task.ResponseFilePath)); + Assert.That (args.Contains ("-invalid"), "incorrect ExtraArg not causing an exception"); } } }