// Writes a list of lines to stderr, writing only a limited number of lines if there are too many of them. protected void WriteLimitedOutput(string first, IEnumerable <string> lines, List <Exception> exceptions) { if ((first == null || first.Length == 0) && !lines.Any()) { return; } if (Driver.Verbosity < 6 && lines.Count() > 1000) { lines = lines.Take(1000); // Limit the output so that we don't overload VSfM. exceptions.Add(ErrorHelper.CreateWarning(5108, "The compiler output is too long, it's been limited to 1000 lines.")); } // Construct the entire message before writing anything, so that there's a better chance the message isn't // mixed up with output from other threads. var sb = new StringBuilder(); if (first != null && first.Length > 0) { sb.AppendLine(first); } foreach (var line in lines) { sb.AppendLine(line); } sb.Length -= Environment.NewLine.Length; // strip off the last newline, since we're adding it in the next line Console.Error.WriteLine(sb); }
public virtual AssemblyDefinition Load(string fileName) { if (!File.Exists(fileName)) { return(null); } AssemblyDefinition assembly; var name = Path.GetFileNameWithoutExtension(fileName); if (cache.TryGetValue(name, out assembly)) { return(assembly); } try { fileName = Target.GetRealPath(fileName); // Check the architecture-specific directory if (Path.GetDirectoryName(fileName) == FrameworkDirectory && !string.IsNullOrEmpty(ArchDirectory)) { var archName = Path.Combine(ArchDirectory, Path.GetFileName(fileName)); if (File.Exists(archName)) { fileName = archName; } } var parameters = CreateDefaultReaderParameters(fileName); try { assembly = ModuleDefinition.ReadModule(fileName, parameters).Assembly; params_cache [assembly.Name.ToString()] = parameters; if (!assembly.MainModule.HasSymbols) { // We Cecil didn't load symbols, but there's a pdb, then something went wrong loading it (maybe an old-style pdb?). // Warn about this. var pdb = Path.ChangeExtension(fileName, "pdb"); if (File.Exists(pdb)) { ErrorHelper.Show(ErrorHelper.CreateWarning(178, Errors.MX0178, fileName)); } } } catch (SymbolsNotMatchingException) { parameters.ReadSymbols = false; parameters.SymbolReaderProvider = null; assembly = ModuleDefinition.ReadModule(fileName, parameters).Assembly; // only report the warning (on symbols) if we can actually load the assembly itself (otherwise it's more confusing than helpful) ErrorHelper.Show(ErrorHelper.CreateWarning(129, Errors.MX0129, fileName)); } } catch (Exception e) { throw new ProductException(9, true, e, Errors.MX0009, fileName); } return(CacheAssembly(assembly)); }
void ParseOption(ApplePlatform platform, string option, List <ProductException> messages) { bool enabled; string opt; switch (option [0]) { case '-': enabled = false; opt = option.Substring(1); break; case '+': enabled = true; opt = option.Substring(1); break; default: opt = option; enabled = true; break; } if (opt == "all") { for (int i = 0; i < values.Length; i++) { var valid = valid_platforms [i]; if (Array.IndexOf(valid, platform) < 0) { continue; // Don't apply 'all' to optimizations that aren't valid for the current platform } values [i] = enabled; } } else { var found = false; for (int i = 0; i < values.Length; i++) { if (opt_names [i] != opt) { continue; } found = true; values [i] = enabled; } if (!found) { messages.Add(ErrorHelper.CreateWarning(132, Errors.MX0132, opt, string.Join(", ", Enum.GetValues(typeof(Opt)).Cast <Opt> ().Where(o => Array.IndexOf(valid_platforms [(int)o], platform) >= 0).Select(o => opt_names [(int)o])))); } } }
public virtual AssemblyDefinition Load(string fileName) { if (!File.Exists(fileName)) { return(null); } AssemblyDefinition assembly; var name = Path.GetFileNameWithoutExtension(fileName); if (cache.TryGetValue(name, out assembly)) { return(assembly); } try { fileName = Target.GetRealPath(fileName); // Check the architecture-specific directory if (Path.GetDirectoryName(fileName) == FrameworkDirectory && !string.IsNullOrEmpty(ArchDirectory)) { var archName = Path.Combine(ArchDirectory, Path.GetFileName(fileName)); if (File.Exists(archName)) { fileName = archName; } } var parameters = CreateDefaultReaderParameters(fileName); try { assembly = ModuleDefinition.ReadModule(fileName, parameters).Assembly; params_cache [assembly.Name.ToString()] = parameters; } catch (InvalidOperationException e) { // cecil use the default message so it's not very helpful to detect the root cause if (!e.TargetSite.ToString().Contains("Void ReadSymbols(Mono.Cecil.Cil.ISymbolReader)")) { throw; } parameters.ReadSymbols = false; parameters.SymbolReaderProvider = null; assembly = ModuleDefinition.ReadModule(fileName, parameters).Assembly; // only report the warning (on symbols) if we can actually load the assembly itself (otherwise it's more confusing than helpful) ErrorHelper.Show(ErrorHelper.CreateWarning(129, $"Debugging symbol file for '{fileName}' does not match the assembly and is ignored.")); } } catch (Exception e) { throw new ProductException(9, true, e, "Error while loading assemblies: {0}", fileName); } cache.Add(name, assembly); return(assembly); }
public virtual AssemblyDefinition Load(string fileName) { if (!File.Exists(fileName)) { return(null); } AssemblyDefinition assembly; var name = Path.GetFileNameWithoutExtension(fileName); if (cache.TryGetValue(name, out assembly)) { return(assembly); } try { fileName = Target.GetRealPath(fileName); // Check the architecture-specific directory if (Path.GetDirectoryName(fileName) == FrameworkDirectory && !string.IsNullOrEmpty(ArchDirectory)) { var archName = Path.Combine(ArchDirectory, Path.GetFileName(fileName)); if (File.Exists(archName)) { fileName = archName; } } var parameters = CreateDefaultReaderParameters(fileName); try { assembly = ModuleDefinition.ReadModule(fileName, parameters).Assembly; params_cache [assembly.Name.ToString()] = parameters; } catch (SymbolsNotMatchingException) { parameters.ReadSymbols = false; parameters.SymbolReaderProvider = null; assembly = ModuleDefinition.ReadModule(fileName, parameters).Assembly; // only report the warning (on symbols) if we can actually load the assembly itself (otherwise it's more confusing than helpful) ErrorHelper.Show(ErrorHelper.CreateWarning(129, Errors.MX0129, fileName)); } } catch (Exception e) { throw new ProductException(9, true, e, Errors.MX0009, fileName); } cache.Add(name, assembly); return(assembly); }
public void RunRegistrar() { // The static registrar. if (Registrar != RegistrarMode.Static) { throw new PlatformException(67, "Invalid registrar: {0}", Registrar); // this is only called during our own build } if (RootAssemblies.Count < 1) { throw ErrorHelper.CreateError(130, "No root assemblies found. You should provide at least one root assembly."); } var registrar_m = RegistrarOutputLibrary; var RootAssembly = RootAssemblies [0]; var resolvedAssemblies = new Dictionary <string, AssemblyDefinition> (); var resolver = new PlatformResolver() { FrameworkDirectory = Driver.GetPlatformFrameworkDirectory(this), RootDirectory = Path.GetDirectoryName(RootAssembly), #if MMP CommandLineAssemblies = RootAssemblies, #endif }; if (Platform == ApplePlatform.iOS || Platform == ApplePlatform.MacOSX) { if (Is32Build) { resolver.ArchDirectory = Driver.GetArch32Directory(this); } else { resolver.ArchDirectory = Driver.GetArch64Directory(this); } } var ps = new ReaderParameters(); ps.AssemblyResolver = resolver; resolvedAssemblies.Add("mscorlib", ps.AssemblyResolver.Resolve(AssemblyNameReference.Parse("mscorlib"), new ReaderParameters())); var productAssembly = Driver.GetProductAssembly(this); bool foundProductAssembly = false; foreach (var asm in RootAssemblies) { var rootName = Path.GetFileNameWithoutExtension(asm); if (rootName == productAssembly) { foundProductAssembly = true; } try { AssemblyDefinition lastAssembly = ps.AssemblyResolver.Resolve(AssemblyNameReference.Parse(rootName), new ReaderParameters()); if (lastAssembly == null) { ErrorHelper.CreateWarning(7, "The root assembly '{0}' does not exist", rootName); continue; } if (resolvedAssemblies.TryGetValue(rootName, out var previousAssembly)) { if (lastAssembly.MainModule.RuntimeVersion != previousAssembly.MainModule.RuntimeVersion) { Driver.Log(2, "Attemping to load an assembly another time {0} (previous {1})", lastAssembly.FullName, previousAssembly.FullName); } continue; } resolvedAssemblies.Add(rootName, lastAssembly); Driver.Log(3, "Loaded {0}", lastAssembly.MainModule.FileName); } catch (Exception ex) { ErrorHelper.Warning(9, ex, "Error while loading assemblies: {0}: {1}", rootName, ex.Message); continue; } } if (!foundProductAssembly) { throw ErrorHelper.CreateError(131, "Product assembly '{0}' not found in assembly list: '{1}'", productAssembly, string.Join("', '", RootAssemblies.ToArray())); } #if MONOTOUCH BuildTarget = BuildTarget.Simulator; #endif var registrar = new Registrar.StaticRegistrar(this); if (RootAssemblies.Count == 1) { registrar.GenerateSingleAssembly(resolvedAssemblies.Values, Path.ChangeExtension(registrar_m, "h"), registrar_m, Path.GetFileNameWithoutExtension(RootAssembly)); } else { registrar.Generate(resolvedAssemblies.Values, Path.ChangeExtension(registrar_m, "h"), registrar_m); } }
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(); var code = await Driver.RunCommandAsync(Target.App.CompilerPath, CompilerFlags.ToString(), null, output); Application.ProcessNativeLinkerOutput(Target, output.ToString(), CompilerFlags.AllLibraries, linker_errors, code != 0); if (code != 0) { // 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) if (!String.IsNullOrEmpty(Target.App.UserGccFlags)) { linker_errors.Add(new MonoTouchException(5201, true, "Native linking failed. Please review the build log and the user flags provided to gcc: {0}", Target.App.UserGccFlags)); } linker_errors.Add(new MonoTouchException(5202, true, "Native linking failed. Please review the build log.", Target.App.UserGccFlags)); if (code == 255) { // check command length // getconf ARG_MAX StringBuilder getconf_output = new StringBuilder(); if (Driver.RunCommand("getconf", "ARG_MAX", output: getconf_output, suppressPrintOnErrors: true) == 0) { 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 void RunRegistrar() { // The static registrar. if (Registrar != RegistrarMode.Static) { throw new ProductException(67, Errors.MT0067, Registrar); // this is only called during our own build } if (RootAssemblies.Count < 1) { throw ErrorHelper.CreateError(130, Errors.MX0130); } var registrar_m = RegistrarOutputLibrary; var RootAssembly = RootAssemblies [0]; var resolvedAssemblies = new Dictionary <string, AssemblyDefinition> (); var resolver = new PlatformResolver() { RootDirectory = Path.GetDirectoryName(RootAssembly), #if MMP CommandLineAssemblies = RootAssemblies, #endif }; if (Platform == ApplePlatform.iOS && !Driver.IsDotNet) { if (Is32Build) { resolver.ArchDirectory = Driver.GetArch32Directory(this); } else { resolver.ArchDirectory = Driver.GetArch64Directory(this); } } var ps = new ReaderParameters(); ps.AssemblyResolver = resolver; foreach (var reference in References) { var r = resolver.Load(reference); if (r == null) { throw ErrorHelper.CreateError(2002, Errors.MT2002, reference); } } var productAssembly = Driver.GetProductAssembly(this); bool foundProductAssembly = false; foreach (var asm in RootAssemblies) { var rootName = Path.GetFileNameWithoutExtension(asm); if (rootName == productAssembly) { foundProductAssembly = true; } try { AssemblyDefinition lastAssembly = ps.AssemblyResolver.Resolve(AssemblyNameReference.Parse(rootName), new ReaderParameters()); if (lastAssembly == null) { ErrorHelper.CreateWarning(7, Errors.MX0007, rootName); continue; } if (resolvedAssemblies.TryGetValue(rootName, out var previousAssembly)) { if (lastAssembly.MainModule.RuntimeVersion != previousAssembly.MainModule.RuntimeVersion) { Driver.Log(2, "Attemping to load an assembly another time {0} (previous {1})", lastAssembly.FullName, previousAssembly.FullName); } continue; } resolvedAssemblies.Add(rootName, lastAssembly); Driver.Log(3, "Loaded {0}", lastAssembly.MainModule.FileName); } catch (Exception ex) { ErrorHelper.Warning(9, ex, Errors.MX0009, $"{rootName}: {ex.Message}"); continue; } } if (!foundProductAssembly) { throw ErrorHelper.CreateError(131, Errors.MX0131, productAssembly, string.Join("', '", RootAssemblies.ToArray())); } #if MONOTOUCH if (SelectAbis(Abis, Abi.SimulatorArchMask).Count > 0) { BuildTarget = BuildTarget.Simulator; } else if (SelectAbis(Abis, Abi.DeviceArchMask).Count > 0) { BuildTarget = BuildTarget.Device; } else { throw ErrorHelper.CreateError(99, Errors.MX0099, "No valid ABI"); } #endif var registrar = new Registrar.StaticRegistrar(this); if (RootAssemblies.Count == 1) { registrar.GenerateSingleAssembly(resolver, resolvedAssemblies.Values, Path.ChangeExtension(registrar_m, "h"), registrar_m, Path.GetFileNameWithoutExtension(RootAssembly)); } else { registrar.Generate(resolvedAssemblies.Values, Path.ChangeExtension(registrar_m, "h"), registrar_m); } }
public void Initialize(Application app, out List <ProductException> messages) { messages = new List <ProductException> (); // warn if the user asked to optimize something when the optimization can't be applied for (int i = 0; i < values.Length; i++) { if (!values [i].HasValue) { continue; } // check if the optimization is valid for the current platform var valid = valid_platforms [i]; if (Array.IndexOf(valid, app.Platform) < 0) { messages.Add(ErrorHelper.CreateWarning(2003, Errors.MT2003_C, opt_names [i], string.Join(", ", valid.Select(v => v.AsString())))); values [i] = false; continue; } switch ((Opt)i) { case Opt.StaticBlockToDelegateLookup: if (app.Registrar != RegistrarMode.Static) { messages.Add(ErrorHelper.CreateWarning(2003, Errors.MT2003, (values [i].Value ? "" : "-"), opt_names [i])); values [i] = false; continue; } break; // does not require the linker case Opt.TrimArchitectures: break; // Does not require linker case Opt.RegisterProtocols: case Opt.RemoveDynamicRegistrar: if (app.Registrar != RegistrarMode.Static) { messages.Add(ErrorHelper.CreateWarning(2003, Errors.MT2003, (values[i].Value ? "" : "-"), opt_names[i])); values [i] = false; continue; } goto default; // also requires the linker default: if (app.LinkMode == LinkMode.None) { messages.Add(ErrorHelper.CreateWarning(2003, Errors.MT2003_B, (values [i].Value ? "" : "-"), opt_names [i])); values [i] = false; } break; } } // by default we keep the code to ensure we're executing on the UI thread (for UI code) for debug builds // but this can be overridden to either (a) remove it from debug builds or (b) keep it in release builds if (!RemoveUIThreadChecks.HasValue) { RemoveUIThreadChecks = !app.EnableDebug; } // By default we always eliminate dead code. if (!DeadCodeElimination.HasValue) { DeadCodeElimination = true; } if (!InlineIsDirectBinding.HasValue) { if (app.Platform != ApplePlatform.MacOSX) { // By default we always inline calls to NSObject.IsDirectBinding // unless the interpreter is enabled (we can't predict if code will be subclassed) InlineIsDirectBinding = !app.UseInterpreter; } else { // NSObject.IsDirectBinding is not a safe optimization to apply to XM apps, // because there may be additional code/assemblies we don't know about at build time. InlineIsDirectBinding = false; } } // The default behavior for InlineIntPtrSize depends on the assembly being linked, // which means we can't set it to a global constant. It's handled in the OptimizeGeneratedCodeSubStep directly. if (app.Platform != ApplePlatform.MacOSX) { // By default we always inline calls to Runtime.Arch if (!InlineRuntimeArch.HasValue) { InlineRuntimeArch = true; } } // We try to optimize calls to BlockLiteral.SetupBlock if the static registrar is enabled if (!OptimizeBlockLiteralSetupBlock.HasValue) { OptimizeBlockLiteralSetupBlock = app.Registrar == RegistrarMode.Static; } // We will register protocols if the static registrar is enabled and loading assemblies is not possible if (!RegisterProtocols.HasValue) { if (app.Platform != ApplePlatform.MacOSX) { RegisterProtocols = (app.Registrar == RegistrarMode.Static) && !app.UseInterpreter; } else { RegisterProtocols = false; } } else if (app.Registrar != RegistrarMode.Static && RegisterProtocols == true) { RegisterProtocols = false; // we've already shown a warning for this. } // By default we always inline calls to Runtime.DynamicRegistrationSupported if (!InlineDynamicRegistrationSupported.HasValue) { InlineDynamicRegistrationSupported = true; } // By default always enable static block-to-delegate lookup (it won't make a difference unless the static registrar is used though) if (!StaticBlockToDelegateLookup.HasValue) { StaticBlockToDelegateLookup = true; } if (!RemoveDynamicRegistrar.HasValue) { if (InlineDynamicRegistrationSupported != true) { // Can't remove the dynamic registrar unless also inlining Runtime.DynamicRegistrationSupported RemoveDynamicRegistrar = false; } else if (StaticBlockToDelegateLookup != true) { // Can't remove the dynamic registrar unless also generating static lookup of block-to-delegates in the static registrar. RemoveDynamicRegistrar = false; } else if (app.Registrar != RegistrarMode.Static || app.LinkMode == LinkMode.None) { // Both the linker and the static registrar are also required RemoveDynamicRegistrar = false; } else { if (app.Platform != ApplePlatform.MacOSX) { // we can't predict is unknown (at build time) code will require registration (at runtime) if (app.UseInterpreter) { RemoveDynamicRegistrar = false; } // We don't have enough information yet to determine if we can remove the dynamic // registrar or not, so let the value stay unset until we do know (when running the linker). } else { // By default disabled for XM apps RemoveDynamicRegistrar = false; } } } if (app.Platform == ApplePlatform.MacOSX) { // By default on macOS trim-architectures for Release and not for debug if (!TrimArchitectures.HasValue) { TrimArchitectures = !app.EnableDebug; } } if (app.Platform != ApplePlatform.MacOSX) { if (!RemoveUnsupportedILForBitcode.HasValue) { // By default enabled for watchOS device builds. RemoveUnsupportedILForBitcode = app.Platform == ApplePlatform.WatchOS && app.IsDeviceBuild; } if (!SealAndDevirtualize.HasValue) { // by default run the linker SealerSubStep unless the interpreter is enabled SealAndDevirtualize = !app.UseInterpreter; } } // By default Runtime.IsARM64CallingConvention inlining is always enabled. if (!InlineIsARM64CallingConvention.HasValue) { InlineIsARM64CallingConvention = true; } // by default we try to eliminate any .cctor we can if (!StaticConstructorBeforeFieldInit.HasValue) { StaticConstructorBeforeFieldInit = true; } // by default we remove rarely used custom attributes if (!CustomAttributesRemoval.HasValue) { CustomAttributesRemoval = true; } }