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

431 строка
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
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 (ProcessStartInfo.EnvironmentVariables ["MONO_PATH"]);
result.Append (' ');
}
result.Append (ProcessStartInfo.FileName);
result.Append (' ');
result.Append (ProcessStartInfo.Arguments);
return result.ToString ();
}
}
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);
Output = new StringBuilder ();
using (var p = Process.Start (info)) {
p.OutputDataReceived += (sender, e) =>
{
if (e.Data != null) {
lock (Output)
Output.AppendLine (e.Data);
} else {
stdout_completed.Set ();
}
};
p.ErrorDataReceived += (sender, e) =>
{
if (e.Data != null) {
lock (Output)
Output.AppendLine (e.Data);
} else {
stderr_completed.Set ();
}
};
p.BeginOutputReadLine ();
p.BeginErrorReadLine ();
p.WaitForExit ();
stderr_completed.WaitOne (TimeSpan.FromSeconds (1));
stdout_completed.WaitOne (TimeSpan.FromSeconds (1));
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 IEnumerable<string> Inputs {
get {
foreach (var asm in Target.Assemblies)
yield return asm.FullPath;
}
}
protected override void Execute ()
{
Driver.GenerateMain (Target.App, Target.Assemblies, Target.App.AssemblyName, Abi, MainM, RegistrationMethods);
}
}
class CompileMainTask : CompileTask
{
protected override void Execute ()
{
if (Compile () != 0)
throw new MonoTouchException (5103, true, "Failed to compile the file '{0}'. Please file a bug report at http://bugzilla.xamarin.com", InputFile);
}
}
class PinvokesTask : CompileTask
{
public static void Create (List<BuildTask> tasks, IEnumerable<Abi> abis, Target target, string ifile)
{
foreach (var abi in abis)
Create (tasks, abi, target, ifile);
}
public static void Create (List<BuildTask> tasks, Abi abi, Target target, string ifile)
{
var arch = abi.AsArchString ();
var ext = target.App.FastDev ? ".dylib" : ".o";
var ofile = Path.Combine (target.App.Cache.Location, arch, "lib" + Path.GetFileNameWithoutExtension (ifile) + ext);
if (!Application.IsUptodate (ifile, ofile)) {
var task = new PinvokesTask ()
{
Target = target,
Abi = abi,
InputFile = ifile,
OutputFile = ofile,
SharedLibrary = target.App.FastDev,
Language = "objective-c++",
};
if (target.App.FastDev) {
task.InstallName = "lib" + Path.GetFileNameWithoutExtension (ifile) + ext;
task.CompilerFlags.AddFramework ("Foundation");
task.CompilerFlags.LinkWithXamarin ();
}
tasks.Add (task);
} else {
Driver.Log (3, "Target '{0}' is up-to-date.", ofile);
}
target.LinkWith (ofile);
target.LinkWithAndShip (ofile);
}
protected override void Execute ()
{
if (Compile () != 0)
throw new MonoTouchException (4002, true, "Failed to compile the generated code for P/Invoke methods. Please file a bug report at http://bugzilla.xamarin.com");
}
}
class RunRegistrarTask : BuildTask
{
public Target Target;
public string RegistrarM;
public string RegistrarH;
protected override void Execute ()
{
Target.StaticRegistrar.Generate (Target.Assemblies.Select ((a) => a.AssemblyDefinition), RegistrarH, RegistrarM);
}
}
class CompileRegistrarTask : CompileTask
{
public static void Create (List<BuildTask> tasks, IEnumerable<Abi> abis, Target target, string ifile)
{
foreach (var abi in abis)
Create (tasks, abi, target, ifile);
}
public static void Create (List<BuildTask> tasks, Abi abi, Target target, string ifile)
{
var app = target.App;
var arch = abi.AsArchString ();
var ofile = Path.Combine (app.Cache.Location, arch, Path.GetFileNameWithoutExtension (ifile) + ".o");
if (!Application.IsUptodate (ifile, ofile)) {
tasks.Add (new CompileRegistrarTask ()
{
Target = target,
Abi = abi,
InputFile = ifile,
OutputFile = ofile,
SharedLibrary = false,
Language = "objective-c++",
});
} else {
Driver.Log (3, "Target '{0}' is up-to-date.", ofile);
}
target.LinkWith (ofile);
}
protected override void Execute ()
{
if (Driver.IsUsingClang (App)) {
// This is because iOS has a forward declaration of NSPortMessage, but no actual declaration.
// They still use NSPortMessage in other API though, so it can't just be removed from our bindings.
CompilerFlags.AddOtherFlag ("-Wno-receiver-forward-class");
}
if (Compile () != 0)
throw new MonoTouchException (4109, true, "Failed to compile the generated registrar code. Please file a bug report at http://bugzilla.xamarin.com");
}
}
public class AOTTask : ProcessTask
{
public string AssemblyName;
public bool AddBitcodeMarkerSection;
public string AssemblyPath; // path to the .s file.
// executed with Parallel.ForEach
protected override void Execute ()
{
var exit_code = base.Start ();
if (exit_code == 0) {
if (AddBitcodeMarkerSection)
File.AppendAllText (AssemblyPath, @"
.section __LLVM, __bitcode
.byte 0
.section __LLVM, __cmdline
.byte 0
");
return;
}
Console.Error.WriteLine ("AOT Compilation exited with code {0}, command:\n{1}{2}", exit_code, Command, Output.Length > 0 ? ("\n" + Output.ToString ()) : string.Empty);
if (Output.Length > 0) {
List<Exception> exceptions = new List<Exception> ();
foreach (var line in Output.ToString ().Split ('\n')) {
if (line.StartsWith ("AOT restriction: Method '", StringComparison.Ordinal) && line.Contains ("must be static since it is decorated with [MonoPInvokeCallback]")) {
exceptions.Add (new MonoTouchException (3002, true, line));
}
}
if (exceptions.Count > 0)
throw new AggregateException (exceptions.ToArray ());
}
throw new MonoTouchException (3001, true, "Could not AOT the assembly '{0}'", AssemblyName);
}
}
public class LinkTask : CompileTask
{
}
public class CompileTask : BuildTask
{
public Target Target;
public Application App { get { return Target.App; } }
public bool SharedLibrary;
public string InputFile;
public string OutputFile;
public Abi Abi;
public string AssemblyName;
public string InstallName;
public string Language;
public bool IsAssembler {
get {
return Language == "assembler";
}
}
CompilerFlags compiler_flags;
public CompilerFlags CompilerFlags {
get { return compiler_flags ?? (compiler_flags = new CompilerFlags () { Target = 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 ();
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 (string.IsNullOrEmpty (language) || !language.Contains ("++")) {
// error: invalid argument '-std=c99' not allowed with 'C++/ObjC++'
flags.AddOtherFlag ("-std=c99");
}
flags.AddOtherFlag ($"-I{Driver.Quote (Path.Combine (Driver.GetProductSdkDirectory (app), "usr", "include"))}");
}
flags.AddOtherFlag ($"-isysroot {Driver.Quote (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.EnableMarkerOnlyBitCode)
flags.AddOtherFlag ("-read_only_relocs suppress");
flags.LinkWithMono ();
flags.AddOtherFlag ("-install_name " + Driver.Quote ($"@rpath/{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");
}
protected override void Execute ()
{
if (Compile () != 0)
throw new MonoTouchException (3001, true, "Could not AOT the assembly '{0}'", AssemblyName);
}
public int Compile ()
{
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");
CompilerFlags.AddOtherFlag ($"-o {Driver.Quote (OutputFile)}");
if (!string.IsNullOrEmpty (Language))
CompilerFlags.AddOtherFlag ($"-x {Language}");
CompilerFlags.AddOtherFlag (Driver.Quote (InputFile));
var rv = Driver.RunCommand (App.CompilerPath, CompilerFlags.ToString (), null, null);
return rv;
}
}
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; }
protected override void Execute ()
{
new BitcodeConverter (Input, OutputFile, Platform, Abi, DeploymentTarget).Convert ();
}
}
}