public int Execute() { var inputResourceFiles = Args.Select(ParseInputFile).ToArray(); var outputResourceFile = ResourceFile.Create(OutputFileName); switch (outputResourceFile.Type) { case ResourceFileType.Dll: using (var outputStream = outputResourceFile.File.Create()) { var metadata = new AssemblyInfoOptions { Culture = AssemblyCulture, AssemblyVersion = AssemblyVersion, }; ResourceAssemblyGenerator.Generate(inputResourceFiles, outputStream, metadata, Path.GetFileNameWithoutExtension(outputResourceFile.File.Name), CompilationReferences.ToArray() ); } break; case ResourceFileType.Resources: using (var outputStream = outputResourceFile.File.Create()) { if (inputResourceFiles.Length > 1) { Reporter.Error.WriteLine("Only one input file required when generating .resource output"); return(1); } ResourcesFileGenerator.Generate(inputResourceFiles.Single().Resource, outputStream); } break; default: Reporter.Error.WriteLine("Resx output type not supported"); return(1); } return(0); }
public static bool GenerateCultureResourceAssemblies(Project project, List <CompilerUtility.CultureResgenIO> cultureResgenFiles, List <string> referencePaths, IList <string> diagnostics) { foreach (var resgenFile in cultureResgenFiles) { var resourceOutputPath = Path.GetDirectoryName(resgenFile.OutputFile); Directory.CreateDirectory(resourceOutputPath); var inputResourceFiles = resgenFile.InputFileToMetadata .Select(fileToMetadata => new ResourceSource(ResourceFile.Create(fileToMetadata.Key), fileToMetadata.Value)) .ToArray(); var outputResourceFile = ResourceFile.Create(resgenFile.OutputFile); if (outputResourceFile.Type != ResourceFileType.Dll) { diagnostics.Add("Resource output type not supported"); return(false); } using (var outputStream = outputResourceFile.File.Create()) { var metadata = new AssemblyInfoOptions { Culture = resgenFile.Culture, AssemblyVersion = project.Version.Version.ToString(), }; ResourceAssemblyGenerator.Generate(inputResourceFiles, outputStream, metadata, Path.GetFileNameWithoutExtension(outputResourceFile.File.Name), referencePaths.ToArray(), diagnostics); } } return(true); }
public static int Run(string[] args) { DebugHelper.HandleDebugSwitch(ref args); CommandLineApplication app = new CommandLineApplication(); app.Name = "dotnet compile-csc-linq-rewrite"; app.FullName = ".NET C# Compiler with LINQ rewrite"; app.Description = "C# Compiler for the .NET Platform with LINQ rewrite optimizations"; app.HandleResponseFiles = true; app.HelpOption("-h|--help"); CommonCompilerOptionsCommandLine commonCompilerCommandLine = CommonCompilerOptionsCommandLine.AddOptions(app); AssemblyInfoOptionsCommandLine assemblyInfoCommandLine = AssemblyInfoOptionsCommandLine.AddOptions(app); CommandOption tempOutput = app.Option("--temp-output <arg>", "Compilation temporary directory", CommandOptionType.SingleValue); CommandOption outputName = app.Option("--out <arg>", "Name of the output assembly", CommandOptionType.SingleValue); CommandOption references = app.Option("--reference <arg>...", "Path to a compiler metadata reference", CommandOptionType.MultipleValue); CommandOption analyzers = app.Option("--analyzer <arg>...", "Path to an analyzer assembly", CommandOptionType.MultipleValue); CommandOption resources = app.Option("--resource <arg>...", "Resources to embed", CommandOptionType.MultipleValue); CommandArgument sources = app.Argument("<source-files>...", "Compilation sources", multipleValues: true); app.OnExecute(() => { if (!tempOutput.HasValue()) { Reporter.Error.WriteLine("Option '--temp-output' is required"); return(ExitFailed); } CommonCompilerOptions commonOptions = commonCompilerCommandLine.GetOptionValues(); AssemblyInfoOptions assemblyInfoOptions = assemblyInfoCommandLine.GetOptionValues(); var translated = TranslateCommonOptions(commonOptions, outputName.Value()); var allArgs = new List <string>(translated); allArgs.AddRange(GetDefaultOptions()); // Generate assembly info var assemblyInfo = Path.Combine(tempOutput.Value(), $"dotnet-compile.assemblyinfo.cs"); File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateCSharp(assemblyInfoOptions, sources.Values)); allArgs.Add($"\"{assemblyInfo}\""); if (outputName.HasValue()) { allArgs.Add($"-out:\"{outputName.Value()}\""); } allArgs.AddRange(analyzers.Values.Select(a => $"-a:\"{a}\"")); allArgs.AddRange(references.Values.Select(r => $"-r:\"{r}\"")); // Resource has two parts separated by a comma // Only the first should be quoted. This is handled // in dotnet-compile where the information is present. allArgs.AddRange(resources.Values.Select(resource => $"-resource:{resource}")); allArgs.AddRange(sources.Values.Select(s => $"\"{s}\"")); var rsp = Path.Combine(tempOutput.Value(), "dotnet-compile-csc.rsp"); File.WriteAllLines(rsp, allArgs, Encoding.UTF8); // Execute CSC! return(Microsoft.CodeAnalysis.CSharp.CommandLine.ProgramLinqRewrite.MainInternal(new string[] { $"-noconfig", "@" + $"{rsp}" })); }); try { return(app.Execute(args)); } catch (Exception ex) { //#if DEBUG Reporter.Error.WriteLine(ex.ToString()); //#else // Reporter.Error.WriteLine(ex.Message); ///#endif return(ExitFailed); } }
public override bool Compile(ProjectContext context, BuildCommandApp args) { // Set up Output Paths var outputPaths = context.GetOutputPaths(args.ConfigValue, args.BuildBasePathValue); var outputPath = outputPaths.CompilationOutputPath; var intermediateOutputPath = outputPaths.IntermediateOutputDirectoryPath; Directory.CreateDirectory(outputPath); Directory.CreateDirectory(intermediateOutputPath); // Create the library exporter var exporter = context.CreateExporter(args.ConfigValue, args.BuildBasePathValue); // Gather exports for the project var dependencies = exporter.GetDependencies().ToList(); Reporter.Output.WriteLine($"Compiling {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}"); var sw = Stopwatch.StartNew(); var diagnostics = new List <DiagnosticMessage>(); var missingFrameworkDiagnostics = new List <DiagnosticMessage>(); // Collect dependency diagnostics foreach (var diag in context.LibraryManager.GetAllDiagnostics()) { if (diag.ErrorCode == ErrorCodes.DOTNET1011 || diag.ErrorCode == ErrorCodes.DOTNET1012) { missingFrameworkDiagnostics.Add(diag); } diagnostics.Add(diag); } if (diagnostics.Any(d => d.Severity == DiagnosticMessageSeverity.Error)) { // We got an unresolved dependency or missing framework. Don't continue the compilation. PrintSummary(diagnostics, sw); return(false); } // Get compilation options var outputName = outputPaths.CompilationFiles.Assembly; // Assemble args var compilerArgs = new List <string>() { $"--temp-output:{intermediateOutputPath}", $"--out:{outputName}" }; var compilationOptions = context.ResolveCompilationOptions(args.ConfigValue); // Set default platform if it isn't already set and we're on desktop if (compilationOptions.EmitEntryPoint == true && string.IsNullOrEmpty(compilationOptions.Platform) && context.TargetFramework.IsDesktop()) { // See https://github.com/dotnet/cli/issues/2428 for more details. compilationOptions.Platform = RuntimeInformation.ProcessArchitecture == Architecture.X64 ? "x64" : "anycpu32bitpreferred"; } var languageId = CompilerUtil.ResolveLanguageId(context); var references = new List <string>(); // Add compilation options to the args compilerArgs.AddRange(compilationOptions.SerializeToArgs()); // Add metadata options compilerArgs.AddRange(AssemblyInfoOptions.SerializeToArgs(AssemblyInfoOptions.CreateForProject(context))); foreach (var dependency in dependencies) { references.AddRange(dependency.CompilationAssemblies.Select(r => r.ResolvedPath)); compilerArgs.AddRange(dependency.SourceReferences.Select(s => s.GetTransformedFile(intermediateOutputPath))); foreach (var resourceFile in dependency.EmbeddedResources) { var transformedResource = resourceFile.GetTransformedFile(intermediateOutputPath); var resourceName = ResourceManifestName.CreateManifestName( Path.GetFileName(resourceFile.ResolvedPath), compilationOptions.OutputName); compilerArgs.Add($"--resource:\"{transformedResource}\",{resourceName}"); } // Add analyzer references compilerArgs.AddRange(dependency.AnalyzerReferences .Where(a => a.AnalyzerLanguage == languageId) .Select(a => $"--analyzer:{a.AssemblyPath}")); } compilerArgs.AddRange(references.Select(r => $"--reference:{r}")); if (compilationOptions.PreserveCompilationContext == true) { var allExports = exporter.GetAllExports().ToList(); var dependencyContext = new DependencyContextBuilder().Build(compilationOptions, allExports, allExports, false, // For now, just assume non-portable mode in the legacy deps file (this is going away soon anyway) context.TargetFramework, context.RuntimeIdentifier ?? string.Empty); var writer = new DependencyContextWriter(); var depsJsonFile = Path.Combine(intermediateOutputPath, compilationOptions.OutputName + "dotnet-compile.deps.json"); using (var fileStream = File.Create(depsJsonFile)) { writer.Write(dependencyContext, fileStream); } compilerArgs.Add($"--resource:\"{depsJsonFile}\",{compilationOptions.OutputName}.deps.json"); } if (!AddNonCultureResources(context.ProjectFile, compilerArgs, intermediateOutputPath, compilationOptions)) { return(false); } // Add project source files var sourceFiles = CompilerUtil.GetCompilationSources(context, compilationOptions); compilerArgs.AddRange(sourceFiles); var compilerName = compilationOptions.CompilerName; // Write RSP file var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.rsp"); File.WriteAllLines(rsp, compilerArgs); // Run pre-compile event var contextVariables = new Dictionary <string, string>() { { "compile:TargetFramework", context.TargetFramework.GetShortFolderName() }, { "compile:FullTargetFramework", context.TargetFramework.DotNetFrameworkName }, { "compile:Configuration", args.ConfigValue }, { "compile:OutputFile", outputName }, { "compile:OutputDir", outputPath.TrimEnd('\\', '/') }, { "compile:ResponseFile", rsp } }; if (context.ProjectFile.HasRuntimeOutput(args.ConfigValue)) { var runtimeContext = args.Workspace.GetRuntimeContext(context, args.GetRuntimes()); var runtimeOutputPath = runtimeContext.GetOutputPaths(args.ConfigValue, args.BuildBasePathValue, args.OutputValue); contextVariables.Add( "compile:RuntimeOutputDir", runtimeOutputPath.RuntimeOutputPath.TrimEnd('\\', '/')); contextVariables.Add( "compile:RuntimeIdentifier", runtimeContext.RuntimeIdentifier); } _scriptRunner.RunScripts(context, ScriptNames.PreCompile, contextVariables); // Cache the reporters before invoking the command in case it is a built-in command, which replaces // the static Reporter instances. Reporter errorReporter = Reporter.Error; Reporter outputReporter = Reporter.Output; CommandResult result = _commandFactory.Create($"compile-{compilerName}", new[] { $"@{rsp}" }) .WorkingDirectory(context.ProjectDirectory) .OnErrorLine(line => HandleCompilerOutputLine(line, context, diagnostics, errorReporter)) .OnOutputLine(line => HandleCompilerOutputLine(line, context, diagnostics, outputReporter)) .Execute(); // Run post-compile event contextVariables["compile:CompilerExitCode"] = result.ExitCode.ToString(); _scriptRunner.RunScripts(context, ScriptNames.PostCompile, contextVariables); var success = result.ExitCode == 0; if (!success) { Reporter.Error.WriteLine($"{result.StartInfo.FileName} {result.StartInfo.Arguments} returned Exit Code {result.ExitCode}"); } if (success) { success &= GenerateCultureResourceAssemblies(context.ProjectFile, dependencies, outputPath, compilationOptions); } return(PrintSummary(diagnostics, sw, success)); }
public static int Main(string[] args) { DebugHelper.HandleDebugSwitch(ref args); CommonCompilerOptions commonOptions = null; AssemblyInfoOptions assemblyInfoOptions = null; string tempOutDir = null; IReadOnlyList <string> references = Array.Empty <string>(); IReadOnlyList <string> resources = Array.Empty <string>(); IReadOnlyList <string> sources = Array.Empty <string>(); string outputName = null; try { ArgumentSyntax.Parse(args, syntax => { commonOptions = CommonCompilerOptionsExtensions.Parse(syntax); assemblyInfoOptions = AssemblyInfoOptions.Parse(syntax); syntax.DefineOption("temp-output", ref tempOutDir, "Compilation temporary directory"); syntax.DefineOption("out", ref outputName, "Name of the output assembly"); syntax.DefineOptionList("reference", ref references, "Path to a compiler metadata reference"); syntax.DefineOptionList("resource", ref resources, "Resources to embed"); syntax.DefineParameterList("source-files", ref sources, "Compilation sources"); if (tempOutDir == null) { syntax.ReportError("Option '--temp-output' is required"); } }); } catch (ArgumentSyntaxException) { return(ExitFailed); } var translated = TranslateCommonOptions(commonOptions); var allArgs = new List <string>(translated); allArgs.AddRange(GetDefaultOptions()); // Generate assembly info var assemblyInfo = Path.Combine(tempOutDir, $"dotnet-compile.assemblyinfo.cs"); File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.Generate(assemblyInfoOptions, sources)); allArgs.Add($"\"{assemblyInfo}\""); if (outputName != null) { allArgs.Add($"-out:\"{outputName}\""); } allArgs.AddRange(references.Select(r => $"-r:\"{r}\"")); allArgs.AddRange(resources.Select(resource => $"-resource:{resource}")); allArgs.AddRange(sources.Select(s => $"\"{s}\"")); var rsp = Path.Combine(tempOutDir, "dotnet-compile-csc.rsp"); File.WriteAllLines(rsp, allArgs, Encoding.UTF8); // Execute CSC! var result = RunCsc($"-noconfig @\"{rsp}\"") .ForwardStdErr() .ForwardStdOut() .Execute(); return(result.ExitCode); }
internal bool CompileInternal(ProjectContext context, string config, string probingFolderPath) { // Check if ambient library if (AmbientLibraries.Contains(context.ProjectName())) { return(true); } bool compilationResult; // Check if already compiled if (_compiledLibraries.TryGetValue(context.ProjectName(), out compilationResult)) { return(compilationResult); } // Get compilation options and source files var compilationOptions = context.ResolveCompilationOptions(config); var projectSourceFiles = CompilerUtility.GetCompilationSources(context, compilationOptions); // Check if precompiled if (!projectSourceFiles.Any()) { return(_compiledLibraries[context.ProjectName()] = true); } // Set up Output Paths var outputPaths = context.GetOutputPaths(config); var outputPath = outputPaths.CompilationOutputPath; var intermediateOutputPath = outputPaths.IntermediateOutputDirectoryPath; Directory.CreateDirectory(outputPath); Directory.CreateDirectory(intermediateOutputPath); // Create the library exporter var exporter = context.CreateExporter(config); // Gather exports for the project var dependencies = exporter.GetDependencies().ToList(); // Get compilation options var outputName = outputPaths.CompilationFiles.Assembly; // Set default platform if it isn't already set and we're on desktop if (compilationOptions.EmitEntryPoint == true && String.IsNullOrEmpty(compilationOptions.Platform) && context.TargetFramework.IsDesktop()) { // See https://github.com/dotnet/cli/issues/2428 for more details. compilationOptions.Platform = RuntimeInformation.ProcessArchitecture == Architecture.X64 ? "x64" : "anycpu32bitpreferred"; } var references = new List <string>(); var sourceFiles = new List <string>(); var resources = new List <string>(); // Get the runtime directory var runtimeDirectory = Paths.GetParentFolderPath(EntryAssembly.Location); foreach (var dependency in dependencies) { sourceFiles.AddRange(dependency.SourceReferences.Select(s => s.GetTransformedFile(intermediateOutputPath))); foreach (var resourceFile in dependency.EmbeddedResources) { var transformedResource = resourceFile.GetTransformedFile(intermediateOutputPath); var resourceName = ResourceManifestName.CreateManifestName( Path.GetFileName(resourceFile.ResolvedPath), compilationOptions.OutputName); resources.Add($"\"{transformedResource}\",{resourceName}"); } var library = dependency.Library as ProjectDescription; var package = dependency.Library as PackageDescription; // Compile other referenced libraries if (library != null && !AmbientLibraries.Contains(library.Identity.Name) && dependency.CompilationAssemblies.Any()) { if (!_compiledLibraries.ContainsKey(library.Identity.Name)) { var projectContext = GetProjectContextFromPath(library.Project.ProjectDirectory); if (projectContext != null) { // Right now, if !success we try to use the last build var success = Compile(projectContext, config, probingFolderPath); } } } // Check for an unresolved library if (library != null && !library.Resolved) { var assetFileName = CompilerUtility.GetAssemblyFileName(library.Identity.Name); // Search in the runtime directory var assetResolvedPath = Path.Combine(runtimeDirectory, assetFileName); if (!File.Exists(assetResolvedPath)) { // Fallback to the project output path or probing folder assetResolvedPath = ResolveAssetPath(outputPath, probingFolderPath, assetFileName); if (String.IsNullOrEmpty(assetResolvedPath)) { // Fallback to this (possible) precompiled module bin folder var path = Path.Combine(Paths.GetParentFolderPath(library.Path), Constants.BinDirectoryName, assetFileName); assetResolvedPath = File.Exists(path) ? path : null; } } if (!String.IsNullOrEmpty(assetResolvedPath)) { references.Add(assetResolvedPath); } } // Check for an unresolved package else if (package != null && !package.Resolved) { var runtimeAssets = new HashSet <string>(package.RuntimeAssemblies.Select(x => x.Path), StringComparer.OrdinalIgnoreCase); string fallbackBinPath = null; foreach (var asset in package.CompileTimeAssemblies) { var assetFileName = Path.GetFileName(asset.Path); var isRuntimeAsset = runtimeAssets.Contains(asset.Path); // Search in the runtime directory var relativeFolderPath = isRuntimeAsset ? String.Empty : CompilerUtility.RefsDirectoryName; var assetResolvedPath = Path.Combine(runtimeDirectory, relativeFolderPath, assetFileName); if (!File.Exists(assetResolvedPath)) { // Fallback to the project output path or probing folder assetResolvedPath = ResolveAssetPath(outputPath, probingFolderPath, assetFileName, relativeFolderPath); } if (String.IsNullOrEmpty(assetResolvedPath)) { if (fallbackBinPath == null) { fallbackBinPath = String.Empty; // Fallback to a (possible) parent precompiled module bin folder var parentBinPaths = CompilerUtility.GetOtherParentProjectsLocations(context, package) .Select(x => Path.Combine(x, Constants.BinDirectoryName)); foreach (var binaryPath in parentBinPaths) { var path = Path.Combine(binaryPath, relativeFolderPath, assetFileName); if (File.Exists(path)) { assetResolvedPath = path; fallbackBinPath = binaryPath; break; } } } else if (!String.IsNullOrEmpty(fallbackBinPath)) { var path = Path.Combine(fallbackBinPath, relativeFolderPath, assetFileName); assetResolvedPath = File.Exists(path) ? path : null; } } if (!String.IsNullOrEmpty(assetResolvedPath)) { references.Add(assetResolvedPath); } } } // Check for a precompiled library else if (library != null && !dependency.CompilationAssemblies.Any()) { // Search in the project output path or probing folder var assetFileName = CompilerUtility.GetAssemblyFileName(library.Identity.Name); var assetResolvedPath = ResolveAssetPath(outputPath, probingFolderPath, assetFileName); if (String.IsNullOrEmpty(assetResolvedPath)) { // Fallback to this precompiled project output path var path = Path.Combine(CompilerUtility.GetAssemblyFolderPath(library.Project.ProjectDirectory, config, context.TargetFramework.DotNetFrameworkName), assetFileName); assetResolvedPath = File.Exists(path) ? path : null; } if (!String.IsNullOrEmpty(assetResolvedPath)) { references.Add(assetResolvedPath); } } // Check for a resolved but ambient library (compiled e.g by VS) else if (library != null && AmbientLibraries.Contains(library.Identity.Name)) { // Search in the regular project output path, fallback to the runtime directory references.AddRange(dependency.CompilationAssemblies.Select(r => File.Exists(r.ResolvedPath) ? r.ResolvedPath : Path.Combine(runtimeDirectory, r.FileName))); } else { references.AddRange(dependency.CompilationAssemblies.Select(r => r.ResolvedPath)); } } // Check again if already compiled, here through the dependency graph if (_compiledLibraries.TryGetValue(context.ProjectName(), out compilationResult)) { return(compilationResult); } var sw = Stopwatch.StartNew(); string depsJsonFile = null; DependencyContext dependencyContext = null; // Add dependency context as a resource if (compilationOptions.PreserveCompilationContext == true) { var allExports = exporter.GetAllExports().ToList(); var exportsLookup = allExports.ToDictionary(e => e.Library.Identity.Name); var buildExclusionList = context.GetTypeBuildExclusionList(exportsLookup); var filteredExports = allExports .Where(e => e.Library.Identity.Type.Equals(LibraryType.ReferenceAssembly) || !buildExclusionList.Contains(e.Library.Identity.Name)); dependencyContext = new DependencyContextBuilder().Build(compilationOptions, filteredExports, filteredExports, false, // For now, just assume non-portable mode in the legacy deps file (this is going away soon anyway) context.TargetFramework, context.RuntimeIdentifier ?? string.Empty); depsJsonFile = Path.Combine(intermediateOutputPath, compilationOptions.OutputName + "dotnet-compile.deps.json"); resources.Add($"\"{depsJsonFile}\",{compilationOptions.OutputName}.deps.json"); } // Add project source files sourceFiles.AddRange(projectSourceFiles); // Add non culture resources var resgenFiles = CompilerUtility.GetNonCultureResources(context.ProjectFile, intermediateOutputPath, compilationOptions); AddNonCultureResources(resources, resgenFiles); var translated = TranslateCommonOptions(compilationOptions, outputName); var allArgs = new List <string>(translated); allArgs.AddRange(GetDefaultOptions()); // Add assembly info var assemblyInfo = Path.Combine(intermediateOutputPath, $"dotnet-compile.assemblyinfo.cs"); allArgs.Add($"\"{assemblyInfo}\""); if (!String.IsNullOrEmpty(outputName)) { allArgs.Add($"-out:\"{outputName}\""); } allArgs.AddRange(references.Select(r => $"-r:\"{r}\"")); allArgs.AddRange(resources.Select(resource => $"-resource:{resource}")); allArgs.AddRange(sourceFiles.Select(s => $"\"{s}\"")); // Gather all compile IO var inputs = new List <string>(); var outputs = new List <string>(); inputs.Add(context.ProjectFile.ProjectFilePath); if (context.LockFile != null) { inputs.Add(context.LockFile.LockFilePath); } if (context.LockFile.ExportFile != null) { inputs.Add(context.LockFile.ExportFile.ExportFilePath); } inputs.AddRange(sourceFiles); inputs.AddRange(references); inputs.AddRange(resgenFiles.Select(x => x.InputFile)); var cultureResgenFiles = CompilerUtility.GetCultureResources(context.ProjectFile, outputPath, compilationOptions); inputs.AddRange(cultureResgenFiles.SelectMany(x => x.InputFileToMetadata.Keys)); outputs.AddRange(outputPaths.CompilationFiles.All()); outputs.AddRange(resgenFiles.Where(x => x.OutputFile != null).Select(x => x.OutputFile)); //outputs.AddRange(cultureResgenFiles.Where(x => x.OutputFile != null).Select(x => x.OutputFile)); // Locate RSP file var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile-csc.rsp"); // Check if there is no need to compile if (!CheckMissingIO(inputs, outputs) && !TimestampsChanged(inputs, outputs)) { if (File.Exists(rsp)) { // Check if the compilation context has been changed var prevInputs = new HashSet <string>(File.ReadAllLines(rsp)); var newInputs = new HashSet <string>(allArgs); if (!prevInputs.Except(newInputs).Any() && !newInputs.Except(prevInputs).Any()) { PrintMessage($"{context.ProjectName()}: Previously compiled, skipping dynamic compilation."); return(_compiledLibraries[context.ProjectName()] = true); } } else { // Write RSP file for the next time File.WriteAllLines(rsp, allArgs); PrintMessage($"{context.ProjectName()}: Previously compiled, skipping dynamic compilation."); return(_compiledLibraries[context.ProjectName()] = true); } } if (!CompilerUtility.GenerateNonCultureResources(context.ProjectFile, resgenFiles, Diagnostics)) { return(_compiledLibraries[context.ProjectName()] = false); } PrintMessage(String.Format($"{context.ProjectName()}: Dynamic compiling for {context.TargetFramework.DotNetFrameworkName}")); // Write the dependencies file if (dependencyContext != null) { var writer = new DependencyContextWriter(); using (var fileStream = File.Create(depsJsonFile)) { writer.Write(dependencyContext, fileStream); } } // Write assembly info and RSP files var assemblyInfoOptions = AssemblyInfoOptions.CreateForProject(context); File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateCSharp(assemblyInfoOptions, sourceFiles)); File.WriteAllLines(rsp, allArgs); // Locate runtime config files var runtimeConfigPath = Path.Combine(runtimeDirectory, EntryAssembly.GetName().Name + FileNameSuffixes.RuntimeConfigJson); var cscRuntimeConfigPath = Path.Combine(runtimeDirectory, "csc" + FileNameSuffixes.RuntimeConfigJson); // Automatically create the csc runtime config file if (Files.IsNewer(runtimeConfigPath, cscRuntimeConfigPath)) { lock (_syncLock) { if (Files.IsNewer(runtimeConfigPath, cscRuntimeConfigPath)) { File.Copy(runtimeConfigPath, cscRuntimeConfigPath, true); } } } // Locate csc.dll and the csc.exe asset var cscDllPath = Path.Combine(runtimeDirectory, CompilerUtility.GetAssemblyFileName("csc")); // Search in the runtime directory var cscRelativePath = Path.Combine("runtimes", "any", "native", "csc.exe"); var cscExePath = Path.Combine(runtimeDirectory, cscRelativePath); // Fallback to the packages storage if (!File.Exists(cscExePath) && !String.IsNullOrEmpty(context.PackagesDirectory)) { cscExePath = Path.Combine(context.PackagesDirectory, CscLibrary?.Name ?? String.Empty, CscLibrary?.Version ?? String.Empty, cscRelativePath); } // Automatically create csc.dll if (Files.IsNewer(cscExePath, cscDllPath)) { lock (_syncLock) { if (Files.IsNewer(cscExePath, cscDllPath)) { File.Copy(cscExePath, cscDllPath, true); } } } // Locate the csc dependencies file var cscDepsPath = Path.Combine(runtimeDirectory, "csc.deps.json"); // Automatically create csc.deps.json if (NativePDBWriter != null && Files.IsNewer(cscDllPath, cscDepsPath)) { lock (_syncLock) { if (Files.IsNewer(cscDllPath, cscDepsPath)) { // Only reference windows native pdb writers var runtimeLibraries = new List <RuntimeLibrary>(); runtimeLibraries.Add(NativePDBWriter); DependencyContext cscDependencyContext = new DependencyContext( DependencyContext.Default.Target, CompilationOptions.Default, new List <CompilationLibrary>(), runtimeLibraries, new List <RuntimeFallbacks>()); // Write the csc.deps.json file if (cscDependencyContext != null) { var writer = new DependencyContextWriter(); using (var fileStream = File.Create(cscDepsPath)) { writer.Write(cscDependencyContext, fileStream); } } // Windows native pdb writers are outputed on dotnet publish. // But not on dotnet build during development, we do it here. // Check if there is a packages storage if (!String.IsNullOrEmpty(context.PackagesDirectory)) { var assetPaths = NativePDBWriter.NativeLibraryGroups.SelectMany(l => l.AssetPaths); foreach (var assetPath in assetPaths) { // Resolve the pdb writer from the packages storage var pdbResolvedPath = Path.Combine(context.PackagesDirectory, NativePDBWriter.Name, NativePDBWriter.Version, assetPath); var pdbOutputPath = Path.Combine(runtimeDirectory, assetPath); // Store the pdb writer in the runtime directory if (Files.IsNewer(pdbResolvedPath, pdbOutputPath)) { Directory.CreateDirectory(Paths.GetParentFolderPath(pdbOutputPath)); File.Copy(pdbResolvedPath, pdbOutputPath, true); } } } } } } // Execute CSC! var result = Command.Create("csc.dll", new string[] { $"-noconfig", "@" + $"{rsp}" }) .WorkingDirectory(runtimeDirectory) .OnErrorLine(line => Diagnostics.Add(line)) .OnOutputLine(line => Diagnostics.Add(line)) .Execute(); compilationResult = result.ExitCode == 0; if (compilationResult) { compilationResult &= CompilerUtility.GenerateCultureResourceAssemblies(context.ProjectFile, cultureResgenFiles, references, Diagnostics); } PrintMessage(String.Empty); if (compilationResult && Diagnostics.Count == 0) { PrintMessage($"{context.ProjectName()}: Dynamic compilation succeeded."); PrintMessage($"0 Warning(s)"); PrintMessage($"0 Error(s)"); } else if (compilationResult && Diagnostics.Count > 0) { PrintMessage($"{context.ProjectName()}: Dynamic compilation succeeded but has warnings."); PrintMessage($"0 Error(s)"); } else { PrintMessage($"{context.ProjectName()}: Dynamic compilation failed."); } foreach (var diagnostic in Diagnostics) { PrintMessage(diagnostic); } PrintMessage($"Time elapsed {sw.Elapsed}"); PrintMessage(String.Empty); return(_compiledLibraries[context.ProjectName()] = compilationResult); }
public static int Main(string[] args) { DebugHelper.HandleDebugSwitch(ref args); var app = new CommandLineApplication(false); app.Name = "resgen"; app.FullName = "Resource compiler"; app.Description = "Microsoft (R) .NET Resource Generator"; app.HelpOption("-h|--help"); var ouputFile = app.Option("-o", "Output file name", CommandOptionType.SingleValue); var culture = app.Option("-c", "Ouput assembly culture", CommandOptionType.SingleValue); var version = app.Option("-v", "Ouput assembly version", CommandOptionType.SingleValue); var references = app.Option("-r", "Compilation references", CommandOptionType.MultipleValue); var inputFiles = app.Argument("<input>", "Input files", true); app.OnExecute(() => { if (!inputFiles.Values.Any()) { Reporter.Error.WriteLine("No input files specified"); return(1); } var intputResourceFiles = inputFiles.Values.Select(ParseInputFile).ToArray(); var outputResourceFile = ResourceFile.Create(ouputFile.Value()); switch (outputResourceFile.Type) { case ResourceFileType.Dll: using (var outputStream = outputResourceFile.File.Create()) { var metadata = new AssemblyInfoOptions(); metadata.Culture = culture.Value(); metadata.AssemblyVersion = version.Value(); ResourceAssemblyGenerator.Generate(intputResourceFiles, outputStream, metadata, Path.GetFileNameWithoutExtension(outputResourceFile.File.Name), references.Values.ToArray() ); } break; case ResourceFileType.Resources: using (var outputStream = outputResourceFile.File.Create()) { if (intputResourceFiles.Length > 1) { Reporter.Error.WriteLine("Only one input file required when generating .resource output"); return(1); } ResourcesFileGenerator.Generate(intputResourceFiles.Single().Resource, outputStream); } break; default: Reporter.Error.WriteLine("Resx output type not supported"); return(1); } return(0); }); try { return(app.Execute(args)); } catch (Exception ex) { #if DEBUG Reporter.Error.WriteLine(ex.ToString()); #else Reporter.Error.WriteLine(ex.Message); #endif return(1); } }
private static bool CompileProject(ProjectContext context, string configuration, string outputPath, string intermediateOutputPath, List <LibraryExport> dependencies, bool noHost) { Reporter.Output.WriteLine($"Compiling {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}"); var sw = Stopwatch.StartNew(); var diagnostics = new List <DiagnosticMessage>(); var missingFrameworkDiagnostics = new List <DiagnosticMessage>(); // Collect dependency diagnostics foreach (var diag in context.LibraryManager.GetAllDiagnostics()) { if (diag.ErrorCode == ErrorCodes.DOTNET1011 || diag.ErrorCode == ErrorCodes.DOTNET1012) { missingFrameworkDiagnostics.Add(diag); } diagnostics.Add(diag); } if (missingFrameworkDiagnostics.Count > 0) { // The framework isn't installed so we should short circuit the rest of the compilation // so we don't get flooded with errors PrintSummary(missingFrameworkDiagnostics, sw); return(false); } // Dump dependency data ShowDependencyInfo(dependencies); // Get compilation options var outputName = GetProjectOutput(context.ProjectFile, context.TargetFramework, configuration, outputPath); // Assemble args var compilerArgs = new List <string>() { $"--temp-output:{intermediateOutputPath}", $"--out:{outputName}" }; var compilationOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration); // Path to strong naming key in environment variable overrides path in project.json var environmentKeyFile = Environment.GetEnvironmentVariable(EnvironmentNames.StrongNameKeyFile); if (!string.IsNullOrWhiteSpace(environmentKeyFile)) { compilationOptions.KeyFile = environmentKeyFile; } else if (!string.IsNullOrWhiteSpace(compilationOptions.KeyFile)) { // Resolve full path to key file compilationOptions.KeyFile = Path.GetFullPath(Path.Combine(context.ProjectFile.ProjectDirectory, compilationOptions.KeyFile)); } // Add compilation options to the args compilerArgs.AddRange(compilationOptions.SerializeToArgs()); // Add metadata options compilerArgs.AddRange(AssemblyInfoOptions.SerializeToArgs(AssemblyInfoOptions.CreateForProject(context))); foreach (var dependency in dependencies) { var projectDependency = dependency.Library as ProjectDescription; if (projectDependency != null) { if (projectDependency.Project.Files.SourceFiles.Any()) { var projectOutputPath = GetProjectOutput(projectDependency.Project, projectDependency.Framework, configuration, outputPath); compilerArgs.Add($"--reference:{projectOutputPath}"); } } else { compilerArgs.AddRange(dependency.CompilationAssemblies.Select(r => $"--reference:{r.ResolvedPath}")); } compilerArgs.AddRange(dependency.SourceReferences); } if (!AddResources(context.ProjectFile, compilerArgs, intermediateOutputPath)) { return(false); } // Add project source files var sourceFiles = context.ProjectFile.Files.SourceFiles; compilerArgs.AddRange(sourceFiles); var compilerName = context.ProjectFile.CompilerName; compilerName = compilerName ?? "csc"; // Write RSP file var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.{context.ProjectFile.Name}.rsp"); File.WriteAllLines(rsp, compilerArgs); // Run pre-compile event var contextVariables = new Dictionary <string, string>() { { "compile:TargetFramework", context.TargetFramework.DotNetFrameworkName }, { "compile:Configuration", configuration }, { "compile:OutputFile", outputName }, { "compile:OutputDir", outputPath }, { "compile:ResponseFile", rsp } }; RunScripts(context, ScriptNames.PreCompile, contextVariables); var result = Command.Create($"dotnet-compile-{compilerName}", $"@\"{rsp}\"") .OnErrorLine(line => { var diagnostic = ParseDiagnostic(context.ProjectDirectory, line); if (diagnostic != null) { diagnostics.Add(diagnostic); } else { Reporter.Error.WriteLine(line); } }) .OnOutputLine(line => { var diagnostic = ParseDiagnostic(context.ProjectDirectory, line); if (diagnostic != null) { diagnostics.Add(diagnostic); } else { Reporter.Output.WriteLine(line); } }).Execute(); // Run post-compile event contextVariables["compile:CompilerExitCode"] = result.ExitCode.ToString(); RunScripts(context, ScriptNames.PostCompile, contextVariables); var success = result.ExitCode == 0; if (success) { success &= GenerateResourceAssemblies(context.ProjectFile, dependencies, outputPath, configuration); } if (success && !noHost && compilationOptions.EmitEntryPoint.GetValueOrDefault()) { var runtimeContext = ProjectContext.Create(context.ProjectDirectory, context.TargetFramework, new[] { RuntimeIdentifier.Current }); MakeRunnable(runtimeContext, outputPath, runtimeContext.CreateExporter(configuration)); } return(PrintSummary(diagnostics, sw, success)); }
public static void Generate(ResourceSource[] sourceFiles, Stream outputStream, AssemblyInfoOptions metadata, string assemblyName, string[] references) { if (sourceFiles == null) { throw new ArgumentNullException(nameof(sourceFiles)); } if (outputStream == null) { throw new ArgumentNullException(nameof(outputStream)); } if (!sourceFiles.Any()) { throw new InvalidOperationException("No source files specified"); } var resourceDescriptions = new List <ResourceDescription>(); foreach (var resourceInputFile in sourceFiles) { if (resourceInputFile.Resource.Type == ResourceFileType.Resx) { resourceDescriptions.Add(new ResourceDescription( resourceInputFile.MetadataName, () => GenerateResources(resourceInputFile.Resource), true)); } else if (resourceInputFile.Resource.Type == ResourceFileType.Resources) { resourceDescriptions.Add(new ResourceDescription(resourceInputFile.Resource.File.Name, () => resourceInputFile.Resource.File.OpenRead(), true)); } else { throw new InvalidOperationException("Generation of resource assemblies from dll not supported"); } } var compilationOptions = new CSharpCompilationOptions(outputKind: OutputKind.DynamicallyLinkedLibrary); var compilation = CSharpCompilation.Create(assemblyName, references: references.Select(reference => MetadataReference.CreateFromFile(reference)), options: compilationOptions); compilation = compilation.AddSyntaxTrees(new[] { CSharpSyntaxTree.ParseText(AssemblyInfoFileGenerator.Generate(metadata, Enumerable.Empty <string>())) }); var result = compilation.Emit(outputStream, manifestResources: resourceDescriptions); if (!result.Success) { foreach (var diagnostic in result.Diagnostics) { Reporter.Error.WriteLine(diagnostic.ToString()); } throw new InvalidOperationException("Error occured while emiting assembly"); } }
private static bool CompileProject(ProjectContext context, CompilerCommandApp args) { // Set up Output Paths string outputPath = context.GetOutputPath(args.ConfigValue, args.OutputValue); string intermediateOutputPath = context.GetIntermediateOutputPath(args.ConfigValue, args.IntermediateValue, outputPath); Directory.CreateDirectory(outputPath); Directory.CreateDirectory(intermediateOutputPath); // Create the library exporter var exporter = context.CreateExporter(args.ConfigValue); // Gather exports for the project var dependencies = exporter.GetDependencies().ToList(); Reporter.Output.WriteLine($"Compiling {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}"); var sw = Stopwatch.StartNew(); var diagnostics = new List <DiagnosticMessage>(); var missingFrameworkDiagnostics = new List <DiagnosticMessage>(); // Collect dependency diagnostics foreach (var diag in context.LibraryManager.GetAllDiagnostics()) { if (diag.ErrorCode == ErrorCodes.DOTNET1011 || diag.ErrorCode == ErrorCodes.DOTNET1012) { missingFrameworkDiagnostics.Add(diag); } diagnostics.Add(diag); } if (missingFrameworkDiagnostics.Count > 0) { // The framework isn't installed so we should short circuit the rest of the compilation // so we don't get flooded with errors PrintSummary(missingFrameworkDiagnostics, sw); return(false); } // Get compilation options var outputName = GetProjectOutput(context.ProjectFile, context.TargetFramework, args.ConfigValue, outputPath); // Assemble args var compilerArgs = new List <string>() { $"--temp-output:{intermediateOutputPath}", $"--out:{outputName}" }; var compilationOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, args.ConfigValue); // Path to strong naming key in environment variable overrides path in project.json var environmentKeyFile = Environment.GetEnvironmentVariable(EnvironmentNames.StrongNameKeyFile); if (!string.IsNullOrWhiteSpace(environmentKeyFile)) { compilationOptions.KeyFile = environmentKeyFile; } else if (!string.IsNullOrWhiteSpace(compilationOptions.KeyFile)) { // Resolve full path to key file compilationOptions.KeyFile = Path.GetFullPath(Path.Combine(context.ProjectFile.ProjectDirectory, compilationOptions.KeyFile)); } var references = new List <string>(); // Add compilation options to the args compilerArgs.AddRange(compilationOptions.SerializeToArgs()); // Add metadata options compilerArgs.AddRange(AssemblyInfoOptions.SerializeToArgs(AssemblyInfoOptions.CreateForProject(context))); foreach (var dependency in dependencies) { var projectDependency = dependency.Library as ProjectDescription; if (projectDependency != null) { if (projectDependency.Project.Files.SourceFiles.Any()) { var projectOutputPath = GetProjectOutput(projectDependency.Project, projectDependency.Framework, args.ConfigValue, outputPath); references.Add(projectOutputPath); } } else { references.AddRange(dependency.CompilationAssemblies.Select(r => r.ResolvedPath)); } compilerArgs.AddRange(dependency.SourceReferences); } compilerArgs.AddRange(references.Select(r => $"--reference:{r}")); if (compilationOptions.PreserveCompilationContext == true) { var dependencyContext = DependencyContextBuilder.Build(compilationOptions, exporter, args.ConfigValue, context.TargetFramework, context.RuntimeIdentifier); var writer = new DependencyContextWriter(); var depsJsonFile = Path.Combine(intermediateOutputPath, context.ProjectFile.Name + "dotnet-compile.deps.json"); using (var fileStream = File.Create(depsJsonFile)) { writer.Write(dependencyContext, fileStream); } compilerArgs.Add($"--resource:\"{depsJsonFile}\",{context.ProjectFile.Name}.deps.json"); var refsFolder = Path.Combine(outputPath, "refs"); if (Directory.Exists(refsFolder)) { Directory.Delete(refsFolder, true); } Directory.CreateDirectory(refsFolder); foreach (var reference in references) { File.Copy(reference, Path.Combine(refsFolder, Path.GetFileName(reference))); } } if (!AddNonCultureResources(context.ProjectFile, compilerArgs, intermediateOutputPath)) { return(false); } // Add project source files var sourceFiles = context.ProjectFile.Files.SourceFiles; compilerArgs.AddRange(sourceFiles); var compilerName = CompilerUtil.ResolveCompilerName(context); // Write RSP file var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.{context.ProjectFile.Name}.rsp"); File.WriteAllLines(rsp, compilerArgs); // Run pre-compile event var contextVariables = new Dictionary <string, string>() { { "compile:TargetFramework", context.TargetFramework.DotNetFrameworkName }, { "compile:Configuration", args.ConfigValue }, { "compile:OutputFile", outputName }, { "compile:OutputDir", outputPath }, { "compile:ResponseFile", rsp } }; RunScripts(context, ScriptNames.PreCompile, contextVariables); var result = Command.Create($"dotnet-compile-{compilerName}", $"@\"{rsp}\"") .OnErrorLine(line => { var diagnostic = ParseDiagnostic(context.ProjectDirectory, line); if (diagnostic != null) { diagnostics.Add(diagnostic); } else { Reporter.Error.WriteLine(line); } }) .OnOutputLine(line => { var diagnostic = ParseDiagnostic(context.ProjectDirectory, line); if (diagnostic != null) { diagnostics.Add(diagnostic); } else { Reporter.Output.WriteLine(line); } }).Execute(); // Run post-compile event contextVariables["compile:CompilerExitCode"] = result.ExitCode.ToString(); RunScripts(context, ScriptNames.PostCompile, contextVariables); var success = result.ExitCode == 0; if (success) { success &= GenerateCultureResourceAssemblies(context.ProjectFile, dependencies, outputPath); } if (success && !args.NoHostValue && compilationOptions.EmitEntryPoint.GetValueOrDefault()) { var rids = PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers(); var runtimeContext = ProjectContext.Create(context.ProjectDirectory, context.TargetFramework, rids); runtimeContext .MakeCompilationOutputRunnable(outputPath, args.ConfigValue); } return(PrintSummary(diagnostics, sw, success)); }
public static int Run(string[] args) { DebugHelper.HandleDebugSwitch(ref args); CommonCompilerOptions commonOptions = null; AssemblyInfoOptions assemblyInfoOptions = null; string tempOutDir = null; IReadOnlyList <string> references = Array.Empty <string>(); IReadOnlyList <string> resources = Array.Empty <string>(); IReadOnlyList <string> sources = Array.Empty <string>(); string outputName = null; var help = false; var returnCode = 0; string helpText = null; try { ArgumentSyntax.Parse(args, syntax => { syntax.HandleHelp = false; syntax.HandleErrors = false; commonOptions = CommonCompilerOptionsExtensions.Parse(syntax); assemblyInfoOptions = AssemblyInfoOptions.Parse(syntax); syntax.DefineOption("temp-output", ref tempOutDir, "Compilation temporary directory"); syntax.DefineOption("out", ref outputName, "Name of the output assembly"); syntax.DefineOptionList("reference", ref references, "Path to a compiler metadata reference"); syntax.DefineOptionList("resource", ref resources, "Resources to embed"); syntax.DefineOption("h|help", ref help, "Help for compile native."); syntax.DefineParameterList("source-files", ref sources, "Compilation sources"); helpText = syntax.GetHelpText(); if (tempOutDir == null) { syntax.ReportError("Option '--temp-output' is required"); } }); } catch (ArgumentSyntaxException exception) { Console.Error.WriteLine(exception.Message); help = true; returnCode = ExitFailed; } if (help) { Console.WriteLine(helpText); return(returnCode); } // TODO less hacky bool targetNetCore = commonOptions.Defines.Contains("DNXCORE50") || commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARDAPP1_")).Any() || commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARD1_")).Any(); // FSC arguments var allArgs = new List <string>(); //HACK fsc raise error FS0208 if target exe doesnt have extension .exe bool hackFS0208 = targetNetCore && commonOptions.EmitEntryPoint == true; string originalOutputName = outputName; if (outputName != null) { if (hackFS0208) { outputName = Path.ChangeExtension(outputName, ".exe"); } allArgs.Add($"--out:{outputName}"); } //let's pass debugging type only if options.DebugType is specified, until //portablepdb are confirmed to work. //so it's possibile to test portable pdb without breaking existing build if (string.IsNullOrEmpty(commonOptions.DebugType)) { //debug info (only windows pdb supported, not portablepdb) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { allArgs.Add("--debug"); //TODO check if full or pdbonly allArgs.Add("--debug:pdbonly"); } else { allArgs.Add("--debug-"); } } else { allArgs.Add("--debug"); allArgs.Add($"--debug:{commonOptions.DebugType}"); } // Default options allArgs.Add("--noframework"); allArgs.Add("--nologo"); allArgs.Add("--simpleresolution"); allArgs.Add("--nocopyfsharpcore"); // project.json compilationOptions if (commonOptions.Defines != null) { allArgs.AddRange(commonOptions.Defines.Select(def => $"--define:{def}")); } if (commonOptions.GenerateXmlDocumentation == true) { allArgs.Add($"--doc:{Path.ChangeExtension(outputName, "xml")}"); } if (commonOptions.KeyFile != null) { allArgs.Add($"--keyfile:{commonOptions.KeyFile}"); } if (commonOptions.Optimize == true) { allArgs.Add("--optimize+"); } //--resource doesnt expect " //bad: --resource:"path/to/file",name //ok: --resource:path/to/file,name allArgs.AddRange(resources.Select(resource => $"--resource:{resource.Replace("\"", "")}")); allArgs.AddRange(references.Select(r => $"-r:{r}")); if (commonOptions.EmitEntryPoint != true) { allArgs.Add("--target:library"); } else { allArgs.Add("--target:exe"); //HACK we need default.win32manifest for exe if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { var win32manifestPath = Path.Combine(AppContext.BaseDirectory, "default.win32manifest"); allArgs.Add($"--win32manifest:{win32manifestPath}"); } } if (commonOptions.SuppressWarnings != null) { allArgs.Add("--nowarn:" + string.Join(",", commonOptions.SuppressWarnings.ToArray())); } if (commonOptions.LanguageVersion != null) { // Not used in fsc } if (commonOptions.Platform != null) { allArgs.Add($"--platform:{commonOptions.Platform}"); } if (commonOptions.AllowUnsafe == true) { } if (commonOptions.WarningsAsErrors == true) { allArgs.Add("--warnaserror"); } //set target framework if (targetNetCore) { allArgs.Add("--targetprofile:netcore"); } if (commonOptions.DelaySign == true) { allArgs.Add("--delaysign+"); } if (commonOptions.PublicSign == true) { } if (commonOptions.AdditionalArguments != null) { // Additional arguments are added verbatim allArgs.AddRange(commonOptions.AdditionalArguments); } // Generate assembly info var assemblyInfo = Path.Combine(tempOutDir, $"dotnet-compile.assemblyinfo.fs"); File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateFSharp(assemblyInfoOptions)); //source files + assemblyInfo allArgs.AddRange(GetSourceFiles(sources, assemblyInfo).ToArray()); //TODO check the switch enabled in fsproj in RELEASE and DEBUG configuration var rsp = Path.Combine(tempOutDir, "dotnet-compile-fsc.rsp"); File.WriteAllLines(rsp, allArgs, Encoding.UTF8); // Execute FSC! var result = RunFsc(new List <string> { $"@{rsp}" }) .ForwardStdErr() .ForwardStdOut() .Execute(); bool successFsc = result.ExitCode == 0; if (hackFS0208 && File.Exists(outputName)) { if (File.Exists(originalOutputName)) { File.Delete(originalOutputName); } File.Move(outputName, originalOutputName); } //HACK dotnet build require a pdb (crash without), fsc atm cant generate a portable pdb, so an empty pdb is created string pdbPath = Path.ChangeExtension(outputName, ".pdb"); if (successFsc && !File.Exists(pdbPath)) { File.WriteAllBytes(pdbPath, Array.Empty <byte>()); } return(result.ExitCode); }
public static int Run(string[] args) { DebugHelper.HandleDebugSwitch(ref args); CommonCompilerOptions commonOptions = null; AssemblyInfoOptions assemblyInfoOptions = null; string tempOutDir = null; IReadOnlyList <string> references = Array.Empty <string>(); IReadOnlyList <string> resources = Array.Empty <string>(); IReadOnlyList <string> sources = Array.Empty <string>(); IReadOnlyList <string> analyzers = Array.Empty <string>(); string outputName = null; var help = false; var returnCode = 0; string helpText = null; try { ArgumentSyntax.Parse(args, syntax => { syntax.HandleHelp = false; syntax.HandleErrors = false; commonOptions = CommonCompilerOptionsExtensions.Parse(syntax); assemblyInfoOptions = AssemblyInfoOptions.Parse(syntax); syntax.DefineOption("temp-output", ref tempOutDir, "Compilation temporary directory"); syntax.DefineOption("out", ref outputName, "Name of the output assembly"); syntax.DefineOptionList("reference", ref references, "Path to a compiler metadata reference"); syntax.DefineOptionList("analyzer", ref analyzers, "Path to an analyzer assembly"); syntax.DefineOptionList("resource", ref resources, "Resources to embed"); syntax.DefineOption("h|help", ref help, "Help for compile native."); syntax.DefineParameterList("source-files", ref sources, "Compilation sources"); helpText = syntax.GetHelpText(); if (tempOutDir == null) { syntax.ReportError("Option '--temp-output' is required"); } }); } catch (ArgumentSyntaxException exception) { Console.Error.WriteLine(exception.Message); help = true; returnCode = ExitFailed; } if (help) { Console.WriteLine(helpText); return(returnCode); } var translated = TranslateCommonOptions(commonOptions, outputName); var allArgs = new List <string>(translated); allArgs.AddRange(GetDefaultOptions()); // Generate assembly info var assemblyInfo = Path.Combine(tempOutDir, $"dotnet-compile.assemblyinfo.cs"); File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateCSharp(assemblyInfoOptions, sources)); allArgs.Add($"\"{assemblyInfo}\""); if (outputName != null) { allArgs.Add($"-out:\"{outputName}\""); } allArgs.AddRange(analyzers.Select(a => $"-a:\"{a}\"")); allArgs.AddRange(references.Select(r => $"-r:\"{r}\"")); // Resource has two parts separated by a comma // Only the first should be quoted. This is handled // in dotnet-compile where the information is present. allArgs.AddRange(resources.Select(resource => $"-resource:{resource}")); allArgs.AddRange(sources.Select(s => $"\"{s}\"")); var rsp = Path.Combine(tempOutDir, "dotnet-compile-csc.rsp"); File.WriteAllLines(rsp, allArgs, Encoding.UTF8); // Execute CSC! var result = RunCsc(new string[] { $"-noconfig", "@" + $"{rsp}" }) .ForwardStdErr() .ForwardStdOut() .Execute(); return(result.ExitCode); }
public static int Main(string[] args) { DebugHelper.HandleDebugSwitch(ref args); CommandLineApplication app = new CommandLineApplication(); app.Name = "dotnet compile-vbc"; app.FullName = ".NET VB Compiler"; app.Description = "VB Compiler for the .NET Platform"; app.HandleResponseFiles = true; app.HelpOption("-h|--help"); CommonCompilerOptionsCommandLine commonCompilerCommandLine = CommonCompilerOptionsCommandLine.AddOptions(app); AssemblyInfoOptionsCommandLine assemblyInfoCommandLine = AssemblyInfoOptionsCommandLine.AddOptions(app); CommandOption tempOutput = app.Option("--temp-output <arg>", "Compilation temporary directory", CommandOptionType.SingleValue); CommandOption outputName = app.Option("--out <arg>", "Name of the output assembly", CommandOptionType.SingleValue); CommandOption references = app.Option("--reference <arg>...", "Path to a compiler metadata reference", CommandOptionType.MultipleValue); CommandOption analyzers = app.Option("--analyzer <arg>...", "Path to an analyzer assembly", CommandOptionType.MultipleValue); CommandOption resources = app.Option("--resource <arg>...", "Resources to embed", CommandOptionType.MultipleValue); CommandArgument sources = app.Argument("<source-files>...", "Compilation sources", multipleValues: true); app.OnExecute(() => { if (!tempOutput.HasValue()) { Reporter.Error.WriteLine("Option '--temp-output' is required"); return(ExitFailed); } CommonCompilerOptions commonOptions = commonCompilerCommandLine.GetOptionValues(); AssemblyInfoOptions assemblyInfoOptions = assemblyInfoCommandLine.GetOptionValues(); var translated = TranslateCommonOptions(commonOptions, outputName.Value()); var allArgs = new List <string>(translated); allArgs.AddRange(GetDefaultOptions()); // Generate assembly info /*DISABLED BECAUSE AssemblyInfoGenerator doesnt undertstand vb * just add something like https://github.com/dotnet/cli/blob/04f40f906dce2678d80fb9787e68de76ee6bf57e/src/Microsoft.DotNet.Compiler.Common/AssemblyInfoFileGenerator.cs#L19 * * var assemblyInfo = Path.Combine(tempOutput.Value(), $"dotnet-compile.assemblyinfo.vb"); * * File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateCSharp(assemblyInfoOptions, sources.Values)); * * allArgs.Add($"\"{assemblyInfo}\""); * */ if (outputName.HasValue()) { allArgs.Add($"-out:\"{outputName.Value()}\""); } allArgs.AddRange(analyzers.Values.Select(a => $"-a:\"{a}\"")); allArgs.AddRange(references.Values.Select(r => $"-r:\"{r}\"")); // Resource has two parts separated by a comma // Only the first should be quoted. This is handled // in dotnet-compile where the information is present. allArgs.AddRange(resources.Values.Select(resource => $"-resource:{resource}")); allArgs.AddRange(sources.Values.Select(s => $"\"{s}\"")); var rsp = Path.Combine(tempOutput.Value(), "dotnet-compile-vbc.rsp"); File.WriteAllLines(rsp, allArgs, Encoding.UTF8); // Execute VBC! var result = RunVbc(new string[] { $"-noconfig", "@" + $"{rsp}" }) .WorkingDirectory(Directory.GetCurrentDirectory()) .ForwardStdErr() .ForwardStdOut() .Execute(); // RENAME things // This is currently necessary as the BUILD task of the dotnet executable expects (at this stage) a .DLL (not an EXE). var outExe = outputName.Value(); outExe = outExe + ".exe"; if (!string.IsNullOrEmpty(outExe) && File.Exists(outExe)) { string outDll = outExe.Replace(".dll.exe", ".dll"); if (File.Exists(outDll)) { File.Delete(outDll); } System.IO.File.Move(outExe, outDll); string outPdbOrig = outExe.Replace(".dll.exe", ".dll.pdb"); string outPdb = outPdbOrig.Replace(".dll.pdb", ".pdb"); if (File.Exists(outPdb)) { File.Delete(outPdb); } System.IO.File.Move(outPdbOrig, outPdb); } return(result.ExitCode); }); try { return(app.Execute(args)); } catch (Exception ex) { #if DEBUG Reporter.Error.WriteLine(ex.ToString()); #else Reporter.Error.WriteLine(ex.Message); #endif return(ExitFailed); } }
public static int Main(string[] args) { DebugHelper.HandleDebugSwitch(ref args); CommandLineApplication app = new CommandLineApplication(); app.Name = "dotnet compile-fsc"; app.FullName = ".NET F# Compiler"; app.Description = "F# Compiler for the .NET Platform"; app.HandleResponseFiles = true; app.HelpOption("-h|--help"); CommonCompilerOptionsCommandLine commonCompilerCommandLine = CommonCompilerOptionsCommandLine.AddOptions(app); AssemblyInfoOptionsCommandLine assemblyInfoCommandLine = AssemblyInfoOptionsCommandLine.AddOptions(app); CommandOption tempOutputOption = app.Option("--temp-output <arg>", "Compilation temporary directory", CommandOptionType.SingleValue); CommandOption outputNameOption = app.Option("--out <arg>", "Name of the output assembly", CommandOptionType.SingleValue); CommandOption referencesOption = app.Option("--reference <arg>...", "Path to a compiler metadata reference", CommandOptionType.MultipleValue); CommandOption resourcesOption = app.Option("--resource <arg>...", "Resources to embed", CommandOptionType.MultipleValue); CommandArgument sourcesArgument = app.Argument("<source-files>...", "Compilation sources", multipleValues: true); app.OnExecute(() => { if (!tempOutputOption.HasValue()) { Reporter.Error.WriteLine("Option '--temp-output' is required"); return(ExitFailed); } CommonCompilerOptions commonOptions = commonCompilerCommandLine.GetOptionValues(); AssemblyInfoOptions assemblyInfoOptions = assemblyInfoCommandLine.GetOptionValues(); // TODO less hacky bool targetNetCore = commonOptions.Defines.Contains("DNXCORE50") || commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARDAPP1_")).Any() || commonOptions.Defines.Where(d => d.StartsWith("NETCOREAPP1_")).Any() || commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARD1_")).Any(); // Get FSC Path upfront to use it for win32manifest path string tempOutDir = tempOutputOption.Value(); var fscCommandSpec = ResolveFsc(null, tempOutDir); var fscExeFile = fscCommandSpec.FscExeFile; var fscExeDir = fscCommandSpec.FscExeDir; // FSC arguments var allArgs = new List <string>(); //HACK fsc raise error FS0208 if target exe doesnt have extension .exe bool hackFS0208 = targetNetCore && commonOptions.EmitEntryPoint == true; string outputName = outputNameOption.Value(); var originalOutputName = outputName; if (outputName != null) { if (hackFS0208) { outputName = Path.ChangeExtension(outputName, ".exe"); } allArgs.Add($"--out:{outputName}"); } //let's pass debugging type only if options.DebugType is specified, until //portablepdb are confirmed to work. //so it's possibile to test portable pdb without breaking existing build if (string.IsNullOrEmpty(commonOptions.DebugType)) { //debug info (only windows pdb supported, not portablepdb) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { allArgs.Add("--debug"); //TODO check if full or pdbonly allArgs.Add("--debug:pdbonly"); } else { allArgs.Add("--debug-"); } } else { allArgs.Add("--debug"); allArgs.Add($"--debug:{commonOptions.DebugType}"); } // Default options allArgs.Add("--noframework"); allArgs.Add("--nologo"); allArgs.Add("--simpleresolution"); allArgs.Add("--nocopyfsharpcore"); // project.json compilationOptions if (commonOptions.Defines != null) { allArgs.AddRange(commonOptions.Defines.Select(def => $"--define:{def}")); } if (commonOptions.GenerateXmlDocumentation == true) { allArgs.Add($"--doc:{Path.ChangeExtension(outputName, "xml")}"); } if (commonOptions.KeyFile != null) { allArgs.Add($"--keyfile:{commonOptions.KeyFile}"); } if (commonOptions.Optimize == true) { allArgs.Add("--optimize+"); } //--resource doesnt expect " //bad: --resource:"path/to/file",name //ok: --resource:path/to/file,name allArgs.AddRange(resourcesOption.Values.Select(resource => $"--resource:{resource.Replace("\"", "")}")); allArgs.AddRange(referencesOption.Values.Select(r => $"-r:{r}")); if (commonOptions.EmitEntryPoint != true) { allArgs.Add("--target:library"); } else { allArgs.Add("--target:exe"); //HACK we need default.win32manifest for exe var win32manifestPath = Path.Combine(fscExeDir, "..", "..", "runtimes", "any", "native", "default.win32manifest"); allArgs.Add($"--win32manifest:{win32manifestPath}"); } if (commonOptions.SuppressWarnings != null && commonOptions.SuppressWarnings.Any()) { allArgs.Add("--nowarn:" + string.Join(",", commonOptions.SuppressWarnings.ToArray())); } if (commonOptions.LanguageVersion != null) { // Not used in fsc } if (commonOptions.Platform != null) { allArgs.Add($"--platform:{commonOptions.Platform}"); } if (commonOptions.AllowUnsafe == true) { } if (commonOptions.WarningsAsErrors == true) { allArgs.Add("--warnaserror"); } //set target framework if (targetNetCore) { allArgs.Add("--targetprofile:netcore"); } if (commonOptions.DelaySign == true) { allArgs.Add("--delaysign+"); } if (commonOptions.PublicSign == true) { } if (commonOptions.AdditionalArguments != null) { // Additional arguments are added verbatim allArgs.AddRange(commonOptions.AdditionalArguments); } // Generate assembly info var assemblyInfo = Path.Combine(tempOutDir, $"dotnet-compile.assemblyinfo.fs"); File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateFSharp(assemblyInfoOptions)); //source files + assemblyInfo allArgs.AddRange(GetSourceFiles(sourcesArgument.Values, assemblyInfo).ToArray()); //TODO check the switch enabled in fsproj in RELEASE and DEBUG configuration var rsp = Path.Combine(tempOutDir, "dotnet-compile-fsc.rsp"); File.WriteAllLines(rsp, allArgs, Encoding.UTF8); // Execute FSC! var result = RunFsc(new List <string> { $"@{rsp}" }, tempOutDir) .ForwardStdErr() .ForwardStdOut() .Execute(); bool successFsc = result.ExitCode == 0; if (hackFS0208 && File.Exists(outputName)) { if (File.Exists(originalOutputName)) { File.Delete(originalOutputName); } File.Move(outputName, originalOutputName); } //HACK dotnet build require a pdb (crash without), fsc atm cant generate a portable pdb, so an empty pdb is created string pdbPath = Path.ChangeExtension(outputName, ".pdb"); if (successFsc && !File.Exists(pdbPath)) { File.WriteAllBytes(pdbPath, Array.Empty <byte>()); } return(result.ExitCode); }); try { return(app.Execute(args)); } catch (Exception ex) { #if DEBUG Reporter.Error.WriteLine(ex.ToString()); #else Reporter.Error.WriteLine(ex.Message); #endif return(ExitFailed); } }
public static int Main(string[] args) { DebugHelper.HandleDebugSwitch(ref args); CommonCompilerOptions commonOptions = null; AssemblyInfoOptions assemblyInfoOptions = null; string tempOutDir = null; IReadOnlyList <string> references = Array.Empty <string>(); IReadOnlyList <string> resources = Array.Empty <string>(); IReadOnlyList <string> sources = Array.Empty <string>(); string outputName = null; var help = false; var returnCode = 0; string helpText = null; try { ArgumentSyntax.Parse(args, syntax => { syntax.HandleHelp = false; syntax.HandleErrors = false; commonOptions = CommonCompilerOptionsExtensions.Parse(syntax); assemblyInfoOptions = AssemblyInfoOptions.Parse(syntax); syntax.DefineOption("temp-output", ref tempOutDir, "Compilation temporary directory"); syntax.DefineOption("out", ref outputName, "Name of the output assembly"); syntax.DefineOptionList("reference", ref references, "Path to a compiler metadata reference"); syntax.DefineOptionList("resource", ref resources, "Resources to embed"); syntax.DefineOption("h|help", ref help, "Help for compile native."); syntax.DefineParameterList("source-files", ref sources, "Compilation sources"); helpText = syntax.GetHelpText(); if (tempOutDir == null) { syntax.ReportError("Option '--temp-output' is required"); } }); } catch (ArgumentSyntaxException exception) { Console.Error.WriteLine(exception.Message); help = true; returnCode = ExitFailed; } if (help) { Console.WriteLine(helpText); return(returnCode); } var translated = TranslateCommonOptions(commonOptions, outputName); var allArgs = new List <string>(translated); allArgs.AddRange(GetDefaultOptions()); // Generate assembly info var assemblyInfo = Path.Combine(tempOutDir, $"dotnet-compile.assemblyinfo.fs"); File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateFSharp(assemblyInfoOptions)); allArgs.Add($"\"{assemblyInfo}\""); //HACK fsc raise error FS0208 if target exe doesnt have extension .exe bool hackFS0208 = commonOptions.EmitEntryPoint == true; string originalOutputName = outputName; if (outputName != null) { if (hackFS0208) { outputName = Path.ChangeExtension(outputName, ".exe"); } allArgs.Add($"--out:\"{outputName}\""); } allArgs.AddRange(references.Select(r => $"-r:\"{r}\"")); allArgs.AddRange(resources.Select(resource => $"--resource:{resource}")); allArgs.AddRange(sources.Select(s => $"\"{s}\"")); var rsp = Path.Combine(tempOutDir, "dotnet-compile-fsc.rsp"); File.WriteAllLines(rsp, allArgs, Encoding.UTF8); // Execute FSC! var result = RunFsc(string.Join(" ", allArgs)) .ForwardStdErr() .ForwardStdOut() .Execute(); if (hackFS0208 && File.Exists(outputName)) { if (File.Exists(originalOutputName)) { File.Delete(originalOutputName); } File.Move(outputName, originalOutputName); } return(result.ExitCode); }
public bool Compile(ProjectContext context, string config, string buildBasePath) { // Set up Output Paths var outputPaths = context.GetOutputPaths(config, buildBasePath); var outputPath = outputPaths.CompilationOutputPath; var intermediateOutputPath = outputPaths.IntermediateOutputDirectoryPath; Directory.CreateDirectory(outputPath); Directory.CreateDirectory(intermediateOutputPath); // Create the library exporter var exporter = context.CreateExporter(config, buildBasePath); // Gather exports for the project var dependencies = exporter.GetDependencies().ToList(); var diagnostics = new List <DiagnosticMessage>(); var missingFrameworkDiagnostics = new List <DiagnosticMessage>(); // Collect dependency diagnostics foreach (var diag in context.LibraryManager.GetAllDiagnostics()) { if (diag.ErrorCode == ErrorCodes.DOTNET1011 || diag.ErrorCode == ErrorCodes.DOTNET1012) { missingFrameworkDiagnostics.Add(diag); } diagnostics.Add(diag); } if (diagnostics.Any(d => d.Severity == DiagnosticMessageSeverity.Error)) { // We got an unresolved dependency or missing framework. Don't continue the compilation. return(false); } // Get compilation options var outputName = outputPaths.CompilationFiles.Assembly; var compilationOptions = context.ResolveCompilationOptions(config); // Set default platform if it isn't already set and we're on desktop if (compilationOptions.EmitEntryPoint == true && string.IsNullOrEmpty(compilationOptions.Platform) && context.TargetFramework.IsDesktop()) { // See https://github.com/dotnet/cli/issues/2428 for more details. compilationOptions.Platform = RuntimeInformation.ProcessArchitecture == Architecture.X64 ? "x64" : "anycpu32bitpreferred"; } var references = new List <string>(); var sourceFiles = new List <string>(); // Add metadata options var assemblyInfoOptions = AssemblyInfoOptions.CreateForProject(context); foreach (var dependency in dependencies) { references.AddRange(dependency.CompilationAssemblies.Select(r => r.ResolvedPath)); sourceFiles.AddRange(dependency.SourceReferences.Select(s => s.GetTransformedFile(intermediateOutputPath))); } var resources = new List <string>(); if (compilationOptions.PreserveCompilationContext == true) { var allExports = exporter.GetAllExports().ToList(); var dependencyContext = new DependencyContextBuilder().Build(compilationOptions, allExports, allExports, false, // For now, just assume non-portable mode in the legacy deps file (this is going away soon anyway) context.TargetFramework, context.RuntimeIdentifier ?? string.Empty); var writer = new DependencyContextWriter(); var depsJsonFile = Path.Combine(intermediateOutputPath, compilationOptions.OutputName + "dotnet-compile.deps.json"); using (var fileStream = File.Create(depsJsonFile)) { writer.Write(dependencyContext, fileStream); } resources.Add($"\"{depsJsonFile}\",{compilationOptions.OutputName}.deps.json"); } // Add project source files if (compilationOptions.CompileInclude == null) { sourceFiles.AddRange(context.ProjectFile.Files.SourceFiles); } else { var includeFiles = IncludeFilesResolver.GetIncludeFiles(compilationOptions.CompileInclude, "/", diagnostics: null); sourceFiles.AddRange(includeFiles.Select(f => f.SourcePath)); } if (String.IsNullOrEmpty(intermediateOutputPath)) { return(false); } var translated = TranslateCommonOptions(compilationOptions, outputName); var allArgs = new List <string>(translated); allArgs.AddRange(GetDefaultOptions()); // Generate assembly info var assemblyInfo = Path.Combine(intermediateOutputPath, $"dotnet-compile.assemblyinfo.cs"); File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateCSharp(assemblyInfoOptions, sourceFiles)); allArgs.Add($"\"{assemblyInfo}\""); if (!String.IsNullOrEmpty(outputName)) { allArgs.Add($"-out:\"{outputName}\""); } allArgs.AddRange(references.Select(r => $"-r:\"{r}\"")); allArgs.AddRange(resources.Select(resource => $"-resource:{resource}")); allArgs.AddRange(sourceFiles.Select(s => $"\"{s}\"")); allArgs.Prepend($"-noconfig"); // Execute CSC! var result = RunCsc(allArgs.ToArray()) .WorkingDirectory(Directory.GetCurrentDirectory()) .ForwardStdErr() .ForwardStdOut() .Execute(); return(result.ExitCode == 0); }
private static bool CompileProject(ProjectContext context, CompilerCommandApp args) { // Set up Output Paths var outputPathCalculator = context.GetOutputPathCalculator(args.OutputValue); var outputPath = outputPathCalculator.GetOutputDirectoryPath(args.ConfigValue); var intermediateOutputPath = outputPathCalculator.GetIntermediateOutputDirectoryPath(args.ConfigValue, args.IntermediateValue); Directory.CreateDirectory(outputPath); Directory.CreateDirectory(intermediateOutputPath); // Create the library exporter var exporter = context.CreateExporter(args.ConfigValue); // Gather exports for the project var dependencies = exporter.GetDependencies().ToList(); Reporter.Output.WriteLine($"Compiling {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}"); var sw = Stopwatch.StartNew(); var diagnostics = new List <DiagnosticMessage>(); var missingFrameworkDiagnostics = new List <DiagnosticMessage>(); // Collect dependency diagnostics foreach (var diag in context.LibraryManager.GetAllDiagnostics()) { if (diag.ErrorCode == ErrorCodes.DOTNET1011 || diag.ErrorCode == ErrorCodes.DOTNET1012) { missingFrameworkDiagnostics.Add(diag); } diagnostics.Add(diag); } if (missingFrameworkDiagnostics.Count > 0) { // The framework isn't installed so we should short circuit the rest of the compilation // so we don't get flooded with errors PrintSummary(missingFrameworkDiagnostics, sw); return(false); } // Get compilation options var outputName = outputPathCalculator.GetAssemblyPath(args.ConfigValue); // Assemble args var compilerArgs = new List <string>() { $"--temp-output:\"{intermediateOutputPath}\"", $"--out:\"{outputName}\"" }; var compilationOptions = CompilerUtil.ResolveCompilationOptions(context, args.ConfigValue); var languageId = CompilerUtil.ResolveLanguageId(context); var references = new List <string>(); // Add compilation options to the args compilerArgs.AddRange(compilationOptions.SerializeToArgs()); // Add metadata options compilerArgs.AddRange(AssemblyInfoOptions.SerializeToArgs(AssemblyInfoOptions.CreateForProject(context))); foreach (var dependency in dependencies) { references.AddRange(dependency.CompilationAssemblies.Select(r => r.ResolvedPath)); compilerArgs.AddRange(dependency.SourceReferences.Select(s => $"\"{s}\"")); // Add analyzer references compilerArgs.AddRange(dependency.AnalyzerReferences .Where(a => a.AnalyzerLanguage == languageId) .Select(a => $"--analyzer:\"{a.AssemblyPath}\"")); } compilerArgs.AddRange(references.Select(r => $"--reference:\"{r}\"")); if (compilationOptions.PreserveCompilationContext == true) { var dependencyContext = DependencyContextBuilder.Build(compilationOptions, exporter, args.ConfigValue, context.TargetFramework, context.RuntimeIdentifier); var writer = new DependencyContextWriter(); var depsJsonFile = Path.Combine(intermediateOutputPath, context.ProjectFile.Name + "dotnet-compile.deps.json"); using (var fileStream = File.Create(depsJsonFile)) { writer.Write(dependencyContext, fileStream); } compilerArgs.Add($"--resource:\"{depsJsonFile},{context.ProjectFile.Name}.deps.json\""); } if (!AddNonCultureResources(context.ProjectFile, compilerArgs, intermediateOutputPath)) { return(false); } // Add project source files var sourceFiles = CompilerUtil.GetCompilationSources(context); compilerArgs.AddRange(sourceFiles); var compilerName = CompilerUtil.ResolveCompilerName(context); // Write RSP file var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.rsp"); File.WriteAllLines(rsp, compilerArgs); // Run pre-compile event var contextVariables = new Dictionary <string, string>() { { "compile:TargetFramework", context.TargetFramework.DotNetFrameworkName }, { "compile:Configuration", args.ConfigValue }, { "compile:OutputFile", outputName }, { "compile:OutputDir", outputPath }, { "compile:ResponseFile", rsp } }; RunScripts(context, ScriptNames.PreCompile, contextVariables); var result = Command.CreateDotNet($"compile-{compilerName}", new[] { "@" + $"{rsp}" }) .OnErrorLine(line => { var diagnostic = ParseDiagnostic(context.ProjectDirectory, line); if (diagnostic != null) { diagnostics.Add(diagnostic); } else { Reporter.Error.WriteLine(line); } }) .OnOutputLine(line => { var diagnostic = ParseDiagnostic(context.ProjectDirectory, line); if (diagnostic != null) { diagnostics.Add(diagnostic); } else { Reporter.Output.WriteLine(line); } }).Execute(); // Run post-compile event contextVariables["compile:CompilerExitCode"] = result.ExitCode.ToString(); RunScripts(context, ScriptNames.PostCompile, contextVariables); var success = result.ExitCode == 0; if (!success) { Reporter.Error.WriteLine($"{result.StartInfo.FileName} {result.StartInfo.Arguments} returned Exit Code {result.ExitCode}"); } if (success) { success &= GenerateCultureResourceAssemblies(context.ProjectFile, dependencies, intermediateOutputPath, outputPath); } return(PrintSummary(diagnostics, sw, success)); }