xamarin-macios/tools/mtouch/BuildTasks.mtouch.cs

686 строки
20 KiB
C#
Исходник Обычный вид История

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
[mtouch] Rework how tasks are built. The previous build system kept a forward-pointing single linked list of tasks to execute: task X had a list of subsequent tasks to execute. If task X was up-to-date, it was not created (and the next tasks were directly added to the list of tasks to execute). In this world it became complicated to merge output from tasks (for instance if the output of task X and task Y should be a consumed by a single task producing a single output, since the corresponding task would end up in both X's and Y's list of subsequent tasks). Example: creating a single framework from the aot-compiled output of multiple assemblies. So I've reversed the logic: now we keep track of the final output, and then each task has a list of dependencies that must be built. This makes it trivial to create merging tasks (for the previous example, there could for instance be a CreateFrameworkTask, where its dependencies would be all the corresponding AotTasks). We also always create every task, and then each task decides when its executed whether it should do anything or not. This makes it unnecessary to 'forward- delete' files when creating tasks (say you have three tasks, A, B, C; B depends on A, and C depends on B; if A's output isn't up-to-date, it has to delete its own output if it exists, otherwise B would not detect that it would have to re-execute, because at task *creation* time, B's input hadn't changed). Additionally make it based on async/await, since much of the work happens in externel processes (and we don't need to spin up additional threads just to run external processes). This makes us have less code run on background threads, which makes any issues with thread-safety less likely.
2017-01-26 12:56:55 +03:00
using System.Threading.Tasks;
using Xamarin.MacDev;
using Xamarin.Utils;
namespace Xamarin.Bundler
{
public abstract class ProcessTask : BuildTask
{
public ProcessStartInfo ProcessStartInfo;
protected StringBuilder Output;
protected string Command {
get {
var result = new StringBuilder ();
if (ProcessStartInfo.EnvironmentVariables.ContainsKey ("MONO_PATH")) {
result.Append ("MONO_PATH=");
result.Append (StringUtils.Quote (ProcessStartInfo.EnvironmentVariables ["MONO_PATH"]));
result.Append (' ');
}
result.Append (ProcessStartInfo.FileName);
result.Append (' ');
result.Append (ProcessStartInfo.Arguments);
return result.ToString ();
}
}
[mtouch] Rework how tasks are built. The previous build system kept a forward-pointing single linked list of tasks to execute: task X had a list of subsequent tasks to execute. If task X was up-to-date, it was not created (and the next tasks were directly added to the list of tasks to execute). In this world it became complicated to merge output from tasks (for instance if the output of task X and task Y should be a consumed by a single task producing a single output, since the corresponding task would end up in both X's and Y's list of subsequent tasks). Example: creating a single framework from the aot-compiled output of multiple assemblies. So I've reversed the logic: now we keep track of the final output, and then each task has a list of dependencies that must be built. This makes it trivial to create merging tasks (for the previous example, there could for instance be a CreateFrameworkTask, where its dependencies would be all the corresponding AotTasks). We also always create every task, and then each task decides when its executed whether it should do anything or not. This makes it unnecessary to 'forward- delete' files when creating tasks (say you have three tasks, A, B, C; B depends on A, and C depends on B; if A's output isn't up-to-date, it has to delete its own output if it exists, otherwise B would not detect that it would have to re-execute, because at task *creation* time, B's input hadn't changed). Additionally make it based on async/await, since much of the work happens in externel processes (and we don't need to spin up additional threads just to run external processes). This makes us have less code run on background threads, which makes any issues with thread-safety less likely.
2017-01-26 12:56:55 +03:00
protected Task<int> StartAsync ()
{
return Task.Run (() => Start ());
}
// both stdout and stderr will be sent to this function.
// null will be sent when there's no more output
// calls to this function will be synchronized (no need to lock in here).
protected virtual void OutputReceived (string line)
{
if (line != null)
Output.AppendLine (line);
}
protected int Start ()
{
if (Driver.Verbosity > 0)
Console.WriteLine (Command);
var info = ProcessStartInfo;
var stdout_completed = new ManualResetEvent (false);
var stderr_completed = new ManualResetEvent (false);
var lockobj = new object ();
Output = new StringBuilder ();
using (var p = Process.Start (info)) {
p.OutputDataReceived += (sender, e) =>
{
if (e.Data != null) {
lock (lockobj)
OutputReceived (e.Data);
} else {
stdout_completed.Set ();
}
};
p.ErrorDataReceived += (sender, e) =>
{
if (e.Data != null) {
lock (lockobj)
OutputReceived (e.Data);
} else {
stderr_completed.Set ();
}
};
p.BeginOutputReadLine ();
p.BeginErrorReadLine ();
p.WaitForExit ();
stderr_completed.WaitOne (TimeSpan.FromSeconds (1));
stdout_completed.WaitOne (TimeSpan.FromSeconds (1));
OutputReceived (null);
GC.Collect (); // Workaround for: https://bugzilla.xamarin.com/show_bug.cgi?id=43462#c14
if (Driver.Verbosity >= 2 && Output.Length > 0)
Console.Error.WriteLine (Output.ToString ());
return p.ExitCode;
}
}
}
class GenerateMainTask : BuildTask
{
public Target Target;
public Abi Abi;
public string MainM;
public IList<string> RegistrationMethods;
public override IEnumerable<string> Inputs {
get {
foreach (var asm in Target.Assemblies)
yield return asm.FullPath;
}
}
public override IEnumerable<string> Outputs {
get {
yield return MainM;
}
}
protected override void Execute ()
{
Driver.GenerateMain (Target, Target.Assemblies, Target.App.AssemblyName, Abi, MainM, RegistrationMethods);
}
}
class CompileMainTask : CompileTask
{
protected override void CompilationFailed (int exitCode)
{
throw ErrorHelper.CreateError (5103, "Failed to compile the file(s) '{0}'. Please file a bug report at https://github.com/xamarin/xamarin-macios/issues/new", string.Join ("', '", CompilerFlags.SourceFiles.ToArray ()));
}
}
class PinvokesTask : CompileTask
{
protected override void CompilationFailed (int exitCode)
{
throw ErrorHelper.CreateError (4002, "Failed to compile the generated code for P/Invoke methods. Please file a bug report at https://github.com/xamarin/xamarin-macios/issues/new");
}
}
2017-01-25 14:06:42 +03:00
class RunRegistrarTask : BuildTask
{
public Target Target;
public string RegistrarCodePath;
public string RegistrarHeaderPath;
2017-01-25 14:06:42 +03:00
public override IEnumerable<string> Inputs {
get {
foreach (var asm in Target.Assemblies)
yield return asm.FullPath;
}
}
public override IEnumerable<string> Outputs {
get {
yield return RegistrarHeaderPath;
yield return RegistrarCodePath;
}
}
protected override void Execute ()
2017-01-25 14:06:42 +03:00
{
Target.StaticRegistrar.Generate (Target.Assemblies.Select ((a) => a.AssemblyDefinition), RegistrarHeaderPath, RegistrarCodePath);
2017-01-25 14:06:42 +03:00
}
}
class CompileRegistrarTask : CompileTask
{
public string RegistrarCodePath;
public string RegistrarHeaderPath;
public override IEnumerable<string> Inputs {
get {
yield return RegistrarHeaderPath;
yield return RegistrarCodePath;
}
}
protected override void CompilationFailed (int exitCode)
{
throw ErrorHelper.CreateError (4109, "Failed to compile the generated registrar code. Please file a bug report at https://github.com/xamarin/xamarin-macios/issues/new");
}
}
public class AOTTask : ProcessTask
{
public Assembly Assembly;
public string AssemblyName;
public bool AddBitcodeMarkerSection;
public string AssemblyPath; // path to the .s file.
List<string> inputs;
[mtouch] Rework how tasks are built. The previous build system kept a forward-pointing single linked list of tasks to execute: task X had a list of subsequent tasks to execute. If task X was up-to-date, it was not created (and the next tasks were directly added to the list of tasks to execute). In this world it became complicated to merge output from tasks (for instance if the output of task X and task Y should be a consumed by a single task producing a single output, since the corresponding task would end up in both X's and Y's list of subsequent tasks). Example: creating a single framework from the aot-compiled output of multiple assemblies. So I've reversed the logic: now we keep track of the final output, and then each task has a list of dependencies that must be built. This makes it trivial to create merging tasks (for the previous example, there could for instance be a CreateFrameworkTask, where its dependencies would be all the corresponding AotTasks). We also always create every task, and then each task decides when its executed whether it should do anything or not. This makes it unnecessary to 'forward- delete' files when creating tasks (say you have three tasks, A, B, C; B depends on A, and C depends on B; if A's output isn't up-to-date, it has to delete its own output if it exists, otherwise B would not detect that it would have to re-execute, because at task *creation* time, B's input hadn't changed). Additionally make it based on async/await, since much of the work happens in externel processes (and we don't need to spin up additional threads just to run external processes). This makes us have less code run on background threads, which makes any issues with thread-safety less likely.
2017-01-26 12:56:55 +03:00
public AotInfo AotInfo;
List<Exception> exceptions = new List<Exception> ();
List<string> output_lines = new List<string> ();
public override IEnumerable<string> Outputs {
get {
[mtouch] Rework how tasks are built. The previous build system kept a forward-pointing single linked list of tasks to execute: task X had a list of subsequent tasks to execute. If task X was up-to-date, it was not created (and the next tasks were directly added to the list of tasks to execute). In this world it became complicated to merge output from tasks (for instance if the output of task X and task Y should be a consumed by a single task producing a single output, since the corresponding task would end up in both X's and Y's list of subsequent tasks). Example: creating a single framework from the aot-compiled output of multiple assemblies. So I've reversed the logic: now we keep track of the final output, and then each task has a list of dependencies that must be built. This makes it trivial to create merging tasks (for the previous example, there could for instance be a CreateFrameworkTask, where its dependencies would be all the corresponding AotTasks). We also always create every task, and then each task decides when its executed whether it should do anything or not. This makes it unnecessary to 'forward- delete' files when creating tasks (say you have three tasks, A, B, C; B depends on A, and C depends on B; if A's output isn't up-to-date, it has to delete its own output if it exists, otherwise B would not detect that it would have to re-execute, because at task *creation* time, B's input hadn't changed). Additionally make it based on async/await, since much of the work happens in externel processes (and we don't need to spin up additional threads just to run external processes). This makes us have less code run on background threads, which makes any issues with thread-safety less likely.
2017-01-26 12:56:55 +03:00
return AotInfo.AotDataFiles
.Union (AotInfo.AsmFiles)
.Union (AotInfo.BitcodeFiles)
.Union (AotInfo.ObjectFiles);
}
}
public override IEnumerable<string> Inputs {
get {
yield return Assembly.FullPath;
}
}
public override IEnumerable<string> FileDependencies {
get {
if (inputs == null) {
inputs = new List<string> ();
if (Assembly.HasDependencyMap)
inputs.AddRange (Assembly.DependencyMap);
inputs.Add (AssemblyName);
foreach (var abi in Assembly.Target.Abis)
inputs.Add (Driver.GetAotCompiler (Assembly.App, abi, Assembly.Target.Is64Build));
var mdb = Assembly.FullPath + ".mdb";
if (File.Exists (mdb))
inputs.Add (mdb);
var pdb = Path.ChangeExtension (Assembly.FullPath, ".pdb");
if (File.Exists (pdb))
inputs.Add (pdb);
var config = Assembly.FullPath + ".config";
if (File.Exists (config))
inputs.Add (config);
}
return inputs;
}
}
public override bool IsUptodate {
get {
// We can only check dependencies if we know the assemblies this assembly depend on (otherwise always rebuild).
return Assembly.HasDependencyMap && base.IsUptodate;
}
}
protected override void OutputReceived (string line)
{
if (line == null)
return;
if (line.StartsWith ("AOT restriction: Method '", StringComparison.Ordinal) && line.Contains ("must be static since it is decorated with [MonoPInvokeCallback]")) {
exceptions.Add (ErrorHelper.CreateError (3002, line));
} else {
CheckFor5107 (AssemblyName, line, exceptions);
}
output_lines.Add (line);
}
[mtouch] Rework how tasks are built. The previous build system kept a forward-pointing single linked list of tasks to execute: task X had a list of subsequent tasks to execute. If task X was up-to-date, it was not created (and the next tasks were directly added to the list of tasks to execute). In this world it became complicated to merge output from tasks (for instance if the output of task X and task Y should be a consumed by a single task producing a single output, since the corresponding task would end up in both X's and Y's list of subsequent tasks). Example: creating a single framework from the aot-compiled output of multiple assemblies. So I've reversed the logic: now we keep track of the final output, and then each task has a list of dependencies that must be built. This makes it trivial to create merging tasks (for the previous example, there could for instance be a CreateFrameworkTask, where its dependencies would be all the corresponding AotTasks). We also always create every task, and then each task decides when its executed whether it should do anything or not. This makes it unnecessary to 'forward- delete' files when creating tasks (say you have three tasks, A, B, C; B depends on A, and C depends on B; if A's output isn't up-to-date, it has to delete its own output if it exists, otherwise B would not detect that it would have to re-execute, because at task *creation* time, B's input hadn't changed). Additionally make it based on async/await, since much of the work happens in externel processes (and we don't need to spin up additional threads just to run external processes). This makes us have less code run on background threads, which makes any issues with thread-safety less likely.
2017-01-26 12:56:55 +03:00
protected async override Task ExecuteAsync ()
{
[mtouch] Rework how tasks are built. The previous build system kept a forward-pointing single linked list of tasks to execute: task X had a list of subsequent tasks to execute. If task X was up-to-date, it was not created (and the next tasks were directly added to the list of tasks to execute). In this world it became complicated to merge output from tasks (for instance if the output of task X and task Y should be a consumed by a single task producing a single output, since the corresponding task would end up in both X's and Y's list of subsequent tasks). Example: creating a single framework from the aot-compiled output of multiple assemblies. So I've reversed the logic: now we keep track of the final output, and then each task has a list of dependencies that must be built. This makes it trivial to create merging tasks (for the previous example, there could for instance be a CreateFrameworkTask, where its dependencies would be all the corresponding AotTasks). We also always create every task, and then each task decides when its executed whether it should do anything or not. This makes it unnecessary to 'forward- delete' files when creating tasks (say you have three tasks, A, B, C; B depends on A, and C depends on B; if A's output isn't up-to-date, it has to delete its own output if it exists, otherwise B would not detect that it would have to re-execute, because at task *creation* time, B's input hadn't changed). Additionally make it based on async/await, since much of the work happens in externel processes (and we don't need to spin up additional threads just to run external processes). This makes us have less code run on background threads, which makes any issues with thread-safety less likely.
2017-01-26 12:56:55 +03:00
var exit_code = await StartAsync ();
if (exit_code == 0) {
if (AddBitcodeMarkerSection)
File.AppendAllText (AssemblyPath, @"
.section __LLVM, __bitcode
.byte 0
.section __LLVM, __cmdline
.byte 0
");
return;
}
WriteLimitedOutput ($"AOT Compilation exited with code {exit_code}, command:\n{Command}", output_lines, exceptions);
exceptions.Add (ErrorHelper.CreateError (3001, "Could not AOT the assembly '{0}'", AssemblyName));
throw new AggregateException (exceptions);
}
public override string ToString ()
{
return Path.GetFileName (AssemblyName);
}
}
public class NativeLinkTask : BuildTask
{
public Target Target;
public string OutputFile;
public CompilerFlags CompilerFlags;
public override IEnumerable<string> Inputs {
get {
CompilerFlags.PopulateInputs ();
return CompilerFlags.Inputs;
}
}
public override IEnumerable<string> Outputs {
get {
yield return OutputFile;
}
}
[mtouch] Rework how tasks are built. The previous build system kept a forward-pointing single linked list of tasks to execute: task X had a list of subsequent tasks to execute. If task X was up-to-date, it was not created (and the next tasks were directly added to the list of tasks to execute). In this world it became complicated to merge output from tasks (for instance if the output of task X and task Y should be a consumed by a single task producing a single output, since the corresponding task would end up in both X's and Y's list of subsequent tasks). Example: creating a single framework from the aot-compiled output of multiple assemblies. So I've reversed the logic: now we keep track of the final output, and then each task has a list of dependencies that must be built. This makes it trivial to create merging tasks (for the previous example, there could for instance be a CreateFrameworkTask, where its dependencies would be all the corresponding AotTasks). We also always create every task, and then each task decides when its executed whether it should do anything or not. This makes it unnecessary to 'forward- delete' files when creating tasks (say you have three tasks, A, B, C; B depends on A, and C depends on B; if A's output isn't up-to-date, it has to delete its own output if it exists, otherwise B would not detect that it would have to re-execute, because at task *creation* time, B's input hadn't changed). Additionally make it based on async/await, since much of the work happens in externel processes (and we don't need to spin up additional threads just to run external processes). This makes us have less code run on background threads, which makes any issues with thread-safety less likely.
2017-01-26 12:56:55 +03:00
protected override async Task ExecuteAsync ()
{
// always show the native linker warnings since many of them turn out to be very important
// and very hard to diagnose otherwise when hidden from the build output. Ref: bug #2430
var linker_errors = new List<Exception> ();
var output = new StringBuilder ();
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
var code = await Driver.RunCommandAsync (Target.App.CompilerPath, CompilerFlags.ToArray (), null, output, suppressPrintOnErrors: true);
Application.ProcessNativeLinkerOutput (Target, output.ToString (), CompilerFlags.AllLibraries, linker_errors, code != 0);
if (code != 0) {
Console.WriteLine ($"Process exited with code {code}, command:\n{Target.App.CompilerPath} {CompilerFlags.ToString ()}\n{output} ");
// if the build failed - it could be because of missing frameworks / libraries we identified earlier
foreach (var assembly in Target.Assemblies) {
if (assembly.UnresolvedModuleReferences == null)
continue;
foreach (var mr in assembly.UnresolvedModuleReferences) {
// TODO: add more diagnose information on the warnings
var name = Path.GetFileNameWithoutExtension (mr.Name);
linker_errors.Add (new MonoTouchException (5215, false, "References to '{0}' might require additional -framework=XXX or -lXXX instructions to the native linker", name));
}
}
// mtouch does not validate extra parameters given to GCC when linking (--gcc_flags)
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
if (Target.App.UserGccFlags?.Count > 0)
linker_errors.Add (new MonoTouchException (5201, true, "Native linking failed. Please review the build log and the user flags provided to gcc: {0}", StringUtils.FormatArguments (Target.App.UserGccFlags)));
else
linker_errors.Add (new MonoTouchException (5202, true, "Native linking failed. Please review the build log."));
[mtouch] Improve how we make sure native symbols aren't stripped away. Fixes #51710 and #54417. (#2162) * [mtouch] Improve how we make sure native symbols aren't stripped away. Fixes #51710 and #54417. * Refactor required symbol collection to store more information about each symbol (field, function, Objective-C class), and in general make the code more straight forward. * Implement support for generating source code that references these symbols, and do this whenever we can't ask the native linker to keep these symbols (when using bitcode). Additionally make it possible to do this manually, so that the source code can be generated for non-bitcode platforms too (which is useful if the number of symbols is enormous, in which case we might surpass the maximum command-line length). * Also make it possible to completely ignore native symbols, or ignore them on a per-symbol basis. This provides a fallback for users if we get something right and we try to preserve something that shouldn't be preserved (for instance if it doesn't exist), and the user ends up with unfixable linker errors. * Don't collect Objective-C classes unless they're in an assembly with LinkWith attributes. We don't need to preserve Objective-C classes in any other circumstances. * Implement everything for both Xamarin.iOS and Xamarin.Mac, and share the code between them. * Remove previous workaround for bug #51710, since it's no longer needed. * Add tests. https://bugzilla.xamarin.com/show_bug.cgi?id=54417 https://bugzilla.xamarin.com/show_bug.cgi?id=51710 * [mtouch] Make sure to only keep symbols from the current app when code sharing. This fixes a build problem with the interdependent-binding-projects test when testing in Today Extension mode.
2017-06-02 19:29:19 +03:00
if (code == 255) {
// check command length
// getconf ARG_MAX
StringBuilder getconf_output = new StringBuilder ();
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
if (Driver.RunCommand ("getconf", new [] { "ARG_MAX" }, output: getconf_output, suppressPrintOnErrors: true) == 0) {
[mtouch] Improve how we make sure native symbols aren't stripped away. Fixes #51710 and #54417. (#2162) * [mtouch] Improve how we make sure native symbols aren't stripped away. Fixes #51710 and #54417. * Refactor required symbol collection to store more information about each symbol (field, function, Objective-C class), and in general make the code more straight forward. * Implement support for generating source code that references these symbols, and do this whenever we can't ask the native linker to keep these symbols (when using bitcode). Additionally make it possible to do this manually, so that the source code can be generated for non-bitcode platforms too (which is useful if the number of symbols is enormous, in which case we might surpass the maximum command-line length). * Also make it possible to completely ignore native symbols, or ignore them on a per-symbol basis. This provides a fallback for users if we get something right and we try to preserve something that shouldn't be preserved (for instance if it doesn't exist), and the user ends up with unfixable linker errors. * Don't collect Objective-C classes unless they're in an assembly with LinkWith attributes. We don't need to preserve Objective-C classes in any other circumstances. * Implement everything for both Xamarin.iOS and Xamarin.Mac, and share the code between them. * Remove previous workaround for bug #51710, since it's no longer needed. * Add tests. https://bugzilla.xamarin.com/show_bug.cgi?id=54417 https://bugzilla.xamarin.com/show_bug.cgi?id=51710 * [mtouch] Make sure to only keep symbols from the current app when code sharing. This fixes a build problem with the interdependent-binding-projects test when testing in Today Extension mode.
2017-06-02 19:29:19 +03:00
int arg_max;
if (int.TryParse (getconf_output.ToString ().Trim (' ', '\t', '\n', '\r'), out arg_max)) {
var cmd_length = Target.App.CompilerPath.Length + 1 + CompilerFlags.ToString ().Length;
if (cmd_length > arg_max) {
linker_errors.Add (ErrorHelper.CreateWarning (5217, $"Native linking possibly failed because the linker command line was too long ({cmd_length} characters)."));
} else {
Driver.Log (3, $"Linker failure is probably not due to command-line length (actual: {cmd_length} limit: {arg_max}");
}
} else {
Driver.Log (3, "Failed to parse 'getconf ARG_MAX' output: {0}", getconf_output);
}
} else {
Driver.Log (3, "Failed to execute 'getconf ARG_MAX'\n{0}", getconf_output);
}
}
}
ErrorHelper.Show (linker_errors);
// the native linker can prefer private (and existing) over public (but non-existing) framework when weak_framework are used
// on an iOS target version where the framework does not exists, e.g. targeting iOS6 for JavaScriptCore added in iOS7 results in
// /System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore instead of
// /System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore
// more details in https://bugzilla.xamarin.com/show_bug.cgi?id=31036
if (CompilerFlags.WeakFrameworks.Count > 0)
Target.AdjustDylibs (OutputFile);
Driver.Watch ("Native Link", 1);
}
public override string ToString ()
{
return Path.GetFileName (OutputFile);
}
}
public class LinkTask : CompileTask
{
protected override async Task ExecuteAsync ()
{
await base.ExecuteAsync ();
// we can't trust the native linker to pick the right (non private) framework when an older TargetVersion is used
if (CompilerFlags.WeakFrameworks.Count > 0)
Target.AdjustDylibs (OutputFile);
}
protected override void CompilationFailed (int exitCode)
{
throw ErrorHelper.CreateError (5216, "Native linking failed for '{0}'. Please file a bug report at https://github.com/xamarin/xamarin-macios/issues/new", OutputFile);
}
}
public class CompileTask : BuildTask
{
public Target Target;
public Application App { get { return Target.App; } }
public bool SharedLibrary;
public string OutputFile;
public Abi Abi;
public string InstallName;
public string Language;
public override IEnumerable<string> Inputs {
get {
CompilerFlags.PopulateInputs ();
return CompilerFlags.Inputs;
}
}
public override IEnumerable<string> Outputs {
get {
yield return OutputFile;
}
}
public bool IsAssembler {
get {
return Language == "assembler";
}
}
public string InputFile {
set {
// This is an accumulative setter-only property,
// to make it possible add dependencies using object initializers.
CompilerFlags.AddSourceFile (value);
}
}
CompilerFlags compiler_flags;
public CompilerFlags CompilerFlags {
get { return compiler_flags ?? (compiler_flags = new CompilerFlags (Target)); }
set { compiler_flags = value; }
}
public static void GetArchFlags (CompilerFlags flags, params Abi [] abis)
{
GetArchFlags (flags, (IEnumerable<Abi>) abis);
}
public static void GetArchFlags (CompilerFlags flags, IEnumerable<Abi> abis)
{
bool enable_thumb = false;
foreach (var abi in abis) {
var arch = abi.AsArchString ();
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
flags.AddOtherFlag ($"-arch", arch);
enable_thumb |= (abi & Abi.Thumb) != 0;
}
if (enable_thumb)
flags.AddOtherFlag ("-mthumb");
}
public static void GetCompilerFlags (Application app, CompilerFlags flags, bool is_assembler, string language = null)
{
if (!is_assembler)
flags.AddOtherFlag ("-gdwarf-2");
if (!is_assembler) {
if (language != "objective-c") {
// error: invalid argument '-std=c++14' not allowed with 'Objective-C'
flags.AddOtherFlag ("-std=c++14");
}
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
flags.AddOtherFlag ($"-I{Path.Combine (Driver.GetProductSdkDirectory (app), "usr", "include")}");
}
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
flags.AddOtherFlag ($"-isysroot", Driver.GetFrameworkDirectory (app));
flags.AddOtherFlag ("-Qunused-arguments"); // don't complain about unused arguments (clang reports -std=c99 and -Isomething as unused).
}
public static void GetSimulatorCompilerFlags (CompilerFlags flags, bool is_assembler, Application app, string language = null)
{
GetCompilerFlags (app, flags, is_assembler, language);
string sim_platform = Driver.GetPlatformDirectory (app);
string plist = Path.Combine (sim_platform, "Info.plist");
var dict = Driver.FromPList (plist);
var dp = dict.Get<PDictionary> ("DefaultProperties");
if (dp.GetString ("GCC_OBJC_LEGACY_DISPATCH") == "YES")
flags.AddOtherFlag ("-fobjc-legacy-dispatch");
string objc_abi = dp.GetString ("OBJC_ABI_VERSION");
if (!String.IsNullOrWhiteSpace (objc_abi))
flags.AddOtherFlag ($"-fobjc-abi-version={objc_abi}");
plist = Path.Combine (Driver.GetFrameworkDirectory (app), "SDKSettings.plist");
string min_prefix = app.CompilerPath.Contains ("clang") ? Driver.GetTargetMinSdkName (app) : "iphoneos";
dict = Driver.FromPList (plist);
dp = dict.Get<PDictionary> ("DefaultProperties");
if (app.DeploymentTarget == new Version ()) {
string target = dp.GetString ("IPHONEOS_DEPLOYMENT_TARGET");
if (!String.IsNullOrWhiteSpace (target))
flags.AddOtherFlag ($"-m{min_prefix}-version-min={target}");
} else {
flags.AddOtherFlag ($"-m{min_prefix}-version-min={app.DeploymentTarget}");
}
string defines = dp.GetString ("GCC_PRODUCT_TYPE_PREPROCESSOR_DEFINITIONS");
if (!String.IsNullOrWhiteSpace (defines))
flags.AddDefine (defines.Replace (" ", String.Empty));
}
void GetDeviceCompilerFlags (CompilerFlags flags, bool is_assembler)
{
GetCompilerFlags (App, flags, is_assembler, Language);
flags.AddOtherFlag ($"-m{Driver.GetTargetMinSdkName (App)}-version-min={App.DeploymentTarget.ToString ()}");
}
void GetSharedCompilerFlags (CompilerFlags flags, string install_name)
{
if (string.IsNullOrEmpty (install_name))
throw new ArgumentNullException (nameof (install_name));
flags.AddOtherFlag ("-shared");
if (!App.EnableBitCode && !Target.Is64Build)
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
flags.AddOtherFlag ("-read_only_relocs", "suppress");
if (App.EnableBitCode)
flags.AddOtherFlag ("-lc++");
flags.LinkWithMono ();
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
flags.AddOtherFlag ("-install_name", install_name);
flags.AddOtherFlag ("-fapplication-extension"); // fixes this: warning MT5203: Native linking warning: warning: linking against dylib not safe for use in application extensions: [..]/actionextension.dll.arm64.dylib
}
void GetStaticCompilerFlags (CompilerFlags flags)
{
flags.AddOtherFlag ("-c");
}
void GetBitcodeCompilerFlags (CompilerFlags flags)
{
flags.AddOtherFlag (App.EnableMarkerOnlyBitCode ? "-fembed-bitcode-marker" : "-fembed-bitcode");
}
[mtouch] Rework how tasks are built. The previous build system kept a forward-pointing single linked list of tasks to execute: task X had a list of subsequent tasks to execute. If task X was up-to-date, it was not created (and the next tasks were directly added to the list of tasks to execute). In this world it became complicated to merge output from tasks (for instance if the output of task X and task Y should be a consumed by a single task producing a single output, since the corresponding task would end up in both X's and Y's list of subsequent tasks). Example: creating a single framework from the aot-compiled output of multiple assemblies. So I've reversed the logic: now we keep track of the final output, and then each task has a list of dependencies that must be built. This makes it trivial to create merging tasks (for the previous example, there could for instance be a CreateFrameworkTask, where its dependencies would be all the corresponding AotTasks). We also always create every task, and then each task decides when its executed whether it should do anything or not. This makes it unnecessary to 'forward- delete' files when creating tasks (say you have three tasks, A, B, C; B depends on A, and C depends on B; if A's output isn't up-to-date, it has to delete its own output if it exists, otherwise B would not detect that it would have to re-execute, because at task *creation* time, B's input hadn't changed). Additionally make it based on async/await, since much of the work happens in externel processes (and we don't need to spin up additional threads just to run external processes). This makes us have less code run on background threads, which makes any issues with thread-safety less likely.
2017-01-26 12:56:55 +03:00
protected override async Task ExecuteAsync ()
{
[mtouch] Rework how tasks are built. The previous build system kept a forward-pointing single linked list of tasks to execute: task X had a list of subsequent tasks to execute. If task X was up-to-date, it was not created (and the next tasks were directly added to the list of tasks to execute). In this world it became complicated to merge output from tasks (for instance if the output of task X and task Y should be a consumed by a single task producing a single output, since the corresponding task would end up in both X's and Y's list of subsequent tasks). Example: creating a single framework from the aot-compiled output of multiple assemblies. So I've reversed the logic: now we keep track of the final output, and then each task has a list of dependencies that must be built. This makes it trivial to create merging tasks (for the previous example, there could for instance be a CreateFrameworkTask, where its dependencies would be all the corresponding AotTasks). We also always create every task, and then each task decides when its executed whether it should do anything or not. This makes it unnecessary to 'forward- delete' files when creating tasks (say you have three tasks, A, B, C; B depends on A, and C depends on B; if A's output isn't up-to-date, it has to delete its own output if it exists, otherwise B would not detect that it would have to re-execute, because at task *creation* time, B's input hadn't changed). Additionally make it based on async/await, since much of the work happens in externel processes (and we don't need to spin up additional threads just to run external processes). This makes us have less code run on background threads, which makes any issues with thread-safety less likely.
2017-01-26 12:56:55 +03:00
int exitCode = await CompileAsync ();
if (exitCode != 0)
CompilationFailed (exitCode);
}
protected virtual void CompilationFailed (int exitCode)
{
throw ErrorHelper.CreateError (5106, "Could not compile the file(s) '{0}'. Please file a bug report at https://github.com/xamarin/xamarin-macios/issues/new", string.Join ("', '", CompilerFlags.SourceFiles.ToArray ()));
}
[mtouch] Rework how tasks are built. The previous build system kept a forward-pointing single linked list of tasks to execute: task X had a list of subsequent tasks to execute. If task X was up-to-date, it was not created (and the next tasks were directly added to the list of tasks to execute). In this world it became complicated to merge output from tasks (for instance if the output of task X and task Y should be a consumed by a single task producing a single output, since the corresponding task would end up in both X's and Y's list of subsequent tasks). Example: creating a single framework from the aot-compiled output of multiple assemblies. So I've reversed the logic: now we keep track of the final output, and then each task has a list of dependencies that must be built. This makes it trivial to create merging tasks (for the previous example, there could for instance be a CreateFrameworkTask, where its dependencies would be all the corresponding AotTasks). We also always create every task, and then each task decides when its executed whether it should do anything or not. This makes it unnecessary to 'forward- delete' files when creating tasks (say you have three tasks, A, B, C; B depends on A, and C depends on B; if A's output isn't up-to-date, it has to delete its own output if it exists, otherwise B would not detect that it would have to re-execute, because at task *creation* time, B's input hadn't changed). Additionally make it based on async/await, since much of the work happens in externel processes (and we don't need to spin up additional threads just to run external processes). This makes us have less code run on background threads, which makes any issues with thread-safety less likely.
2017-01-26 12:56:55 +03:00
protected async Task<int> CompileAsync ()
{
if (App.IsDeviceBuild) {
GetDeviceCompilerFlags (CompilerFlags, IsAssembler);
} else {
GetSimulatorCompilerFlags (CompilerFlags, IsAssembler, App, Language);
}
if (App.EnableBitCode)
GetBitcodeCompilerFlags (CompilerFlags);
GetArchFlags (CompilerFlags, Abi);
if (SharedLibrary) {
GetSharedCompilerFlags (CompilerFlags, InstallName);
} else {
GetStaticCompilerFlags (CompilerFlags);
}
if (App.EnableDebug)
CompilerFlags.AddDefine ("DEBUG");
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
CompilerFlags.AddOtherFlag ("-o", OutputFile);
if (!string.IsNullOrEmpty (Language))
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
CompilerFlags.AddOtherFlag ("-x", Language);
Directory.CreateDirectory (Path.GetDirectoryName (OutputFile));
var exceptions = new List<Exception> ();
var output = new List<string> ();
var assembly_name = Path.GetFileNameWithoutExtension (OutputFile);
var output_received = new Action<string> ((string line) => {
if (line == null)
return;
output.Add (line);
CheckFor5107 (assembly_name, line, exceptions);
});
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
var rv = await Driver.RunCommandAsync (App.CompilerPath, CompilerFlags.ToArray (), null, output_received, suppressPrintOnErrors: true);
WriteLimitedOutput (rv != 0 ? $"Compilation failed with code {rv}, command:\n{App.CompilerPath} {CompilerFlags.ToString ()}" : null, output, exceptions);
ErrorHelper.Show (exceptions);
return rv;
}
public override string ToString ()
{
if (compiler_flags == null || compiler_flags.SourceFiles == null)
return Path.GetFileName (OutputFile);
return string.Join (", ", compiler_flags.SourceFiles.Select ((arg) => Path.GetFileName (arg)).ToArray ());
}
}
public class BitCodeifyTask : BuildTask
{
public string Input { get; set; }
public string OutputFile { get; set; }
public ApplePlatform Platform { get; set; }
public Abi Abi { get; set; }
public Version DeploymentTarget { get; set; }
public override IEnumerable<string> Inputs {
get {
yield return Input;
}
}
public override IEnumerable<string> Outputs {
get {
yield return OutputFile;
}
}
protected override void Execute ()
{
new BitcodeConverter (Input, OutputFile, Platform, Abi, DeploymentTarget).Convert ();
}
public override string ToString ()
{
return Path.GetFileName (Input);
}
}
public class LipoTask : BuildTask
{
public IEnumerable<string> InputFiles { get; set; }
public string OutputFile { get; set; }
public override IEnumerable<string> Inputs {
get {
return InputFiles;
}
}
public override IEnumerable<string> Outputs {
get {
yield return OutputFile;
}
}
protected override void Execute ()
{
Application.Lipo (OutputFile, InputFiles.ToArray ());
}
public override string ToString ()
{
return Path.GetFileName (string.Join (",", InputFiles));
}
}
public class FileCopyTask : BuildTask
{
public string InputFile { get; set; }
public string OutputFile { get; set; }
public override IEnumerable<string> Inputs {
get {
yield return InputFile;
}
}
public override IEnumerable<string> Outputs {
get {
yield return OutputFile;
}
}
protected override void Execute ()
{
Application.UpdateFile (InputFile, OutputFile);
}
public override string ToString ()
{
return $"cp {InputFile} {OutputFile}";
}
}
}