public static BuildResult Compile(ProjectItemCollection projectItems, DotNetProjectConfiguration configuration, ConfigurationSelector configSelector, ProgressMonitor monitor) { var compilerParameters = (CSharpCompilerParameters)configuration.CompilationParameters ?? new CSharpCompilerParameters(); var projectParameters = (CSharpProject)configuration.ParentItem; FilePath outputName = configuration.CompiledOutputName; string responseFileName = Path.GetTempFileName(); //make sure that the output file is writable if (File.Exists(outputName)) { bool isWriteable = false; int count = 0; do { try { outputName.MakeWritable(); using (var stream = File.OpenWrite(outputName)) { isWriteable = true; } } catch (Exception) { Thread.Sleep(20); } } while (count++ < 5 && !isWriteable); if (!isWriteable) { MessageService.ShowError(string.Format(GettextCatalog.GetString("Can't lock file: {0}."), outputName)); return(null); } } //get the runtime TargetRuntime runtime = MonoDevelop.Core.Runtime.SystemAssemblyService.DefaultRuntime; DotNetProject project = configuration.ParentItem as DotNetProject; if (project != null) { runtime = project.TargetRuntime; } //get the compiler name string compilerName; try { compilerName = GetCompilerName(runtime, configuration.TargetFramework); } catch (Exception e) { string message = "Could not obtain a C# compiler"; monitor.ReportError(message, e); return(null); } var sb = new StringBuilder(); HashSet <string> alreadyAddedReference = new HashSet <string> (); var monoRuntime = runtime as MonoTargetRuntime; if (!compilerParameters.NoStdLib && (monoRuntime == null || monoRuntime.HasMultitargetingMcs)) { string corlib = project.AssemblyContext.GetAssemblyFullName("mscorlib", project.TargetFramework); if (corlib != null) { corlib = project.AssemblyContext.GetAssemblyLocation(corlib, project.TargetFramework); } if (corlib == null) { var br = new BuildResult(); br.AddError(string.Format("Could not find mscorlib for framework {0}", project.TargetFramework.Id)); return(br); } AppendQuoted(sb, "/r:", corlib); sb.AppendLine("-nostdlib"); } List <string> gacRoots = new List <string> (); sb.AppendFormat("\"/out:{0}\"", outputName); sb.AppendLine(); foreach (ProjectReference lib in projectItems.GetAll <ProjectReference> ()) { if (lib.ReferenceType == ReferenceType.Project) { var ownerProject = lib.OwnerProject; if (ownerProject != null) { var parentSolution = ownerProject.ParentSolution; if (parentSolution != null && !(lib.ResolveProject(parentSolution) is DotNetProject)) { continue; } } } string refPrefix = string.IsNullOrEmpty(lib.Aliases) ? "" : lib.Aliases + "="; foreach (string fileName in lib.GetReferencedFileNames(configSelector)) { switch (lib.ReferenceType) { case ReferenceType.Package: SystemPackage pkg = lib.Package; if (pkg == null) { string msg = string.Format(GettextCatalog.GetString("{0} could not be found or is invalid."), lib.Reference); monitor.ReportWarning(msg); continue; } if (alreadyAddedReference.Add(fileName)) { AppendQuoted(sb, "/r:", refPrefix + fileName); } if (pkg.GacRoot != null && !gacRoots.Contains(pkg.GacRoot)) { gacRoots.Add(pkg.GacRoot); } if (!string.IsNullOrEmpty(pkg.Requires)) { foreach (string requiredPackage in pkg.Requires.Split(' ')) { SystemPackage rpkg = runtime.AssemblyContext.GetPackage(requiredPackage); if (rpkg == null) { continue; } foreach (SystemAssembly assembly in rpkg.Assemblies) { if (alreadyAddedReference.Add(assembly.Location)) { AppendQuoted(sb, "/r:", assembly.Location); } } } } break; default: if (alreadyAddedReference.Add(fileName)) { AppendQuoted(sb, "/r:", refPrefix + fileName); } break; } } } if (alreadyAddedReference.Any(reference => SystemAssemblyService.ContainsReferenceToSystemRuntime(reference))) { LoggingService.LogInfo("Found PCLv2 assembly."); var facades = runtime.FindFacadeAssembliesForPCL(project.TargetFramework); foreach (var facade in facades) { AppendQuoted(sb, "/r:", facade); } } string sysCore = project.AssemblyContext.GetAssemblyFullName("System.Core", project.TargetFramework); if (sysCore != null && !alreadyAddedReference.Contains(sysCore)) { var asm = project.AssemblyContext.GetAssemblyFromFullName(sysCore, null, project.TargetFramework); if (asm != null) { AppendQuoted(sb, "/r:", asm.Location); } } sb.AppendLine("/nologo"); sb.Append("/warn:"); sb.Append(compilerParameters.WarningLevel.ToString()); sb.AppendLine(); if (configuration.SignAssembly) { if (File.Exists(configuration.AssemblyKeyFile)) { AppendQuoted(sb, "/keyfile:", configuration.AssemblyKeyFile); } if (configuration.DelaySign) { sb.AppendLine("/delaySign"); } } var debugType = configuration.DebugType; if (string.IsNullOrEmpty(debugType)) { debugType = configuration.DebugSymbols ? "full" : "none"; } else if (string.Equals(debugType, "pdbonly", StringComparison.OrdinalIgnoreCase)) { //old Mono compilers don't support pdbonly if (monoRuntime != null && !monoRuntime.HasMultitargetingMcs) { debugType = "full"; } } if (!string.Equals(debugType, "none", StringComparison.OrdinalIgnoreCase)) { sb.AppendLine("/debug:" + debugType); } if (compilerParameters.LangVersion != LangVersion.Default) { var langVersionString = CSharpCompilerParameters.TryLangVersionToString(compilerParameters.LangVersion); if (langVersionString == null) { string message = "Invalid LangVersion enum value '" + compilerParameters.LangVersion.ToString() + "'"; monitor.ReportError(message, null); LoggingService.LogError(message); return(null); } sb.AppendLine("/langversion:" + langVersionString); } // mcs default is + but others might not be if (compilerParameters.Optimize) { sb.AppendLine("/optimize+"); } else { sb.AppendLine("/optimize-"); } bool hasWin32Res = !string.IsNullOrEmpty(projectParameters.Win32Resource) && File.Exists(projectParameters.Win32Resource); if (hasWin32Res) { AppendQuoted(sb, "/win32res:", projectParameters.Win32Resource); } if (!string.IsNullOrEmpty(projectParameters.Win32Icon) && File.Exists(projectParameters.Win32Icon)) { if (hasWin32Res) { monitor.ReportWarning("Both Win32 icon and Win32 resource cannot be specified. Ignoring the icon."); } else { AppendQuoted(sb, "/win32icon:", projectParameters.Win32Icon); } } if (projectParameters.CodePage != 0) { sb.AppendLine("/codepage:" + projectParameters.CodePage); } else if (runtime is MonoTargetRuntime) { sb.AppendLine("/codepage:utf8"); } if (compilerParameters.UnsafeCode) { sb.AppendLine("-unsafe"); } if (compilerParameters.NoStdLib) { sb.AppendLine("-nostdlib"); } if (!string.IsNullOrEmpty(compilerParameters.PlatformTarget) && compilerParameters.PlatformTarget.ToLower() != "anycpu") { //HACK: to ignore the platform flag for Mono <= 2.4, because gmcs didn't support it if (runtime.RuntimeId == "Mono" && runtime.AssemblyContext.GetAssemblyLocation("Mono.Debugger.Soft", null) == null) { LoggingService.LogWarning("Mono runtime '" + runtime.DisplayName + "' appears to be too old to support the 'platform' C# compiler flag."); } else { sb.AppendLine("/platform:" + compilerParameters.PlatformTarget); } } if (compilerParameters.TreatWarningsAsErrors) { sb.AppendLine("-warnaserror"); if (!string.IsNullOrEmpty(compilerParameters.WarningsNotAsErrors)) { sb.AppendLine("-warnaserror-:" + compilerParameters.WarningsNotAsErrors); } } foreach (var define in configuration.GetDefineSymbols()) { AppendQuoted(sb, "/define:", define); sb.AppendLine(); } CompileTarget ctarget = configuration.CompileTarget; if (!string.IsNullOrEmpty(projectParameters.MainClass)) { sb.AppendLine("/main:" + projectParameters.MainClass); // mcs does not allow providing a Main class when compiling a dll // As a workaround, we compile as WinExe (although the output will still // have a .dll extension). if (ctarget == CompileTarget.Library) { ctarget = CompileTarget.WinExe; } } switch (ctarget) { case CompileTarget.Exe: sb.AppendLine("/t:exe"); break; case CompileTarget.WinExe: sb.AppendLine("/t:winexe"); break; case CompileTarget.Library: sb.AppendLine("/t:library"); break; } foreach (ProjectFile finfo in projectItems.GetAll <ProjectFile> ()) { if (finfo.Subtype == Subtype.Directory) { continue; } switch (finfo.BuildAction) { case "Compile": AppendQuoted(sb, "", finfo.Name); break; case "EmbeddedResource": string fname = finfo.Name; if (string.Compare(Path.GetExtension(fname), ".resx", StringComparison.OrdinalIgnoreCase) == 0) { fname = Path.ChangeExtension(fname, ".resources"); } sb.Append('"'); sb.Append("/res:"); sb.Append(fname); sb.Append(','); sb.Append(finfo.ResourceId); sb.Append('"'); sb.AppendLine(); break; default: continue; } } if (!compilerParameters.DocumentationFile.IsNullOrEmpty) { AppendQuoted(sb, "/doc:", compilerParameters.DocumentationFile); } if (!string.IsNullOrEmpty(compilerParameters.NoWarnings)) { AppendQuoted(sb, "/nowarn:", compilerParameters.NoWarnings); } if (runtime.RuntimeId == "MS.NET") { sb.AppendLine("/fullpaths"); sb.AppendLine("/utf8output"); } string output = ""; string error = ""; File.WriteAllText(responseFileName, sb.ToString()); monitor.Log.WriteLine(compilerName + " /noconfig " + sb.ToString().Replace('\n', ' ')); // Dummy projects created for single files have no filename // and so no BaseDirectory. string workingDir = null; if (configuration.ParentItem != null) { workingDir = configuration.ParentItem.BaseDirectory; } LoggingService.LogInfo(compilerName + " " + sb); ExecutionEnvironment envVars = runtime.GetToolsExecutionEnvironment(project.TargetFramework); string cargs = "/noconfig @\"" + responseFileName + "\""; int exitCode = DoCompilation(monitor, compilerName, cargs, workingDir, envVars, gacRoots, ref output, ref error); BuildResult result = ParseOutput(workingDir, output, error); if (result.CompilerOutput.Trim().Length != 0) { monitor.Log.WriteLine(result.CompilerOutput); } //if compiler crashes, output entire error string if (result.ErrorCount == 0 && exitCode != 0) { try { monitor.Log.Write(File.ReadAllText(error)); } catch (IOException) { } result.AddError("The compiler appears to have crashed. Check the build output pad for details."); LoggingService.LogError("C# compiler crashed. Response file '{0}', stdout file '{1}', stderr file '{2}'", responseFileName, output, error); } else { FileService.DeleteFile(responseFileName); FileService.DeleteFile(output); FileService.DeleteFile(error); } return(result); }