Example #1
0
        public ConfigurationParameters CreateCompilationParameters(XmlElement projectOptions)
        {
            PlayScriptCompilerParameters pars = new PlayScriptCompilerParameters();

            if (projectOptions != null)
            {
                string platform = projectOptions.GetAttribute("Platform");
                if (SupportedPlatforms.Contains(platform))
                {
                    pars.PlatformTarget = platform;
                }
                string debugAtt = projectOptions.GetAttribute("DefineDebug");
                if (string.Compare("True", debugAtt, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    pars.AddDefineSymbol("DEBUG");
                }
                string releaseAtt = projectOptions.GetAttribute("Release");
                if (string.Compare("True", releaseAtt, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    pars.Optimize = true;
                }
            }
            return(pars);
        }
Example #2
0
        public static BuildResult Compile(ProjectItemCollection projectItems, DotNetProjectConfiguration configuration, ConfigurationSelector configSelector, IProgressMonitor monitor)
        {
            var compilerParameters = (PlayScriptCompilerParameters)configuration.CompilationParameters ?? new PlayScriptCompilerParameters();
            var projectParameters  = (PlayScriptProjectParameters)configuration.ProjectParameters ?? new PlayScriptProjectParameters();

            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 PlayScript 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();

            string        outputPath  = System.IO.Path.GetDirectoryName(outputName);
            List <string> filesToCopy = new List <string> ();

            foreach (ProjectReference lib in projectItems.GetAll <ProjectReference> ())
            {
                if (lib.ReferenceType == ReferenceType.Project && !(lib.OwnerProject.ParentSolution.FindProjectByName(lib.Reference) 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 (lib.LocalCopy)
                            {
                                filesToCopy.Add(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);
                                        if (lib.LocalCopy)
                                        {
                                            filesToCopy.Add(assembly.Location);
                                        }
                                    }
                                }
                            }
                        }
                        break;

                    default:
                        if (alreadyAddedReference.Add(fileName))
                        {
                            AppendQuoted(sb, "/r:", refPrefix + fileName);
                        }
                        break;
                    }
                }
            }

            if (filesToCopy.Count > 0)
            {
                CopyFilesToOutput(filesToCopy, outputPath);
            }

            string sysCore = project.AssemblyContext.GetAssemblyFullName("System.Core", project.TargetFramework);

            if (sysCore != null)
            {
                sysCore = project.AssemblyContext.GetAssemblyLocation(sysCore, project.TargetFramework);
                if (sysCore != null && !alreadyAddedReference.Contains(sysCore))
                {
                    AppendQuoted(sb, "/r:", sysCore);
                }
            }

            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 = compilerParameters.DebugType;

            if (string.IsNullOrEmpty(debugType))
            {
                debugType = configuration.DebugMode ? "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 = PlayScriptCompilerParameters.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' PlayScript compiler flag.");
                }
                else
                {
                    sb.AppendLine("/platform:" + compilerParameters.PlatformTarget);
                }
            }

            if (compilerParameters.TreatWarningsAsErrors)
            {
                sb.AppendLine("-warnaserror");
                if (!string.IsNullOrEmpty(compilerParameters.WarningsNotAsErrors))
                {
                    sb.AppendLine("-warnaserror-:" + compilerParameters.WarningsNotAsErrors);
                }
            }

            if (compilerParameters.DefineSymbols.Length > 0)
            {
                string define_str = string.Join(";", compilerParameters.DefineSymbols.Split(new char [] { ',', ' ', ';' }, StringSplitOptions.RemoveEmptyEntries));
                if (define_str.Length > 0)
                {
                    AppendQuoted(sb, "/define:", define_str);
                    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", true) == 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.GenerateXmlDocumentation)
            {
                AppendQuoted(sb, "/doc:", Path.ChangeExtension(outputName, ".xml"));
            }

            if (!string.IsNullOrEmpty(compilerParameters.AdditionalArguments))
            {
                sb.AppendLine(compilerParameters.AdditionalArguments);
            }

            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', ' '));

            string workingDir = ".";

            if (configuration.ParentItem != null)
            {
                workingDir = configuration.ParentItem.BaseDirectory;
                if (workingDir == null)
                {
                    // Dummy projects created for single files have no filename
                    // and so no BaseDirectory.
                    // This is a workaround for a bug in
                    // ProcessStartInfo.WorkingDirectory - not able to handle null
                    workingDir = ".";
                }
            }

            LoggingService.LogInfo(compilerName + " " + sb.ToString());

            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(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("PlayScript 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);
        }