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 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)); var 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); 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); }
// Need to unit test this, so public public void GenerateDepsJsonFile( LockFile toolLockFile, string depsPath) { Reporter.Verbose.WriteLine($"Generating deps.json at: {depsPath}"); var projectContext = new ProjectContextBuilder() .WithLockFile(toolLockFile) .WithTargetFramework(s_toolPackageFramework.ToString()) .Build(); var exporter = projectContext.CreateExporter(Constants.DefaultConfiguration); var dependencyContext = new DependencyContextBuilder() .Build(null, null, exporter.GetAllExports(), true, s_toolPackageFramework, string.Empty); var tempDepsFile = Path.GetTempFileName(); using (var fileStream = File.Open(tempDepsFile, FileMode.Open, FileAccess.Write)) { var dependencyContextWriter = new DependencyContextWriter(); dependencyContextWriter.Write(dependencyContext, fileStream); } try { File.Copy(tempDepsFile, depsPath); } catch (Exception e) { Reporter.Verbose.WriteLine($"unable to generate deps.json, it may have been already generated: {e.Message}"); } finally { try { File.Delete(tempDepsFile); } catch (Exception e2) { Reporter.Verbose.WriteLine($"unable to delete temporary deps.json file: {e2.Message}"); } } }
public override bool Compile(ProjectContext context, CompilerCommandApp 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 (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 = outputPaths.CompilationFiles.Assembly; // Assemble args var compilerArgs = new List<string>() { $"--temp-output:{intermediateOutputPath}", $"--out:{outputName}" }; var compilationOptions = context.ResolveCompilationOptions(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.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)) { return false; } // Add project source files var sourceFiles = CompilerUtil.GetCompilationSources(context); compilerArgs.AddRange(sourceFiles); var compilerName = context.ProjectFile.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 = context.CreateRuntimeContext(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); var result = _commandFactory.Create($"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(); _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, intermediateOutputPath, outputPath); } return PrintSummary(diagnostics, sw, success); }
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 = Path.GetDirectoryName(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 fileName = GetAssemblyFileName(library.Identity.Name); // Search in the runtime directory var path = Path.Combine(runtimeDirectory, fileName); if (!File.Exists(path)) { // Fallback to the project output path or probing folder path = ResolveAssetPath(outputPath, probingFolderPath, fileName); } if (!String.IsNullOrEmpty(path)) { references.Add(path); } } // Check for an unresolved package else if (package != null && !package.Resolved) { var runtimeAssets = new HashSet<string>(package.RuntimeAssemblies.Select(x => x.Path), StringComparer.OrdinalIgnoreCase); foreach (var asset in package.CompileTimeAssemblies) { var assetFileName = Path.GetFileName(asset.Path); var isRuntimeAsset = runtimeAssets.Contains(asset.Path); // Search in the runtime directory var path = isRuntimeAsset ? Path.Combine(runtimeDirectory, assetFileName) : Path.Combine(runtimeDirectory, CompilerUtility.RefsDirectoryName, assetFileName); if (!File.Exists(path)) { // Fallback to the project output path or probing folder var relativeFolderPath = isRuntimeAsset ? String.Empty : CompilerUtility.RefsDirectoryName; path = ResolveAssetPath(outputPath, probingFolderPath, assetFileName, relativeFolderPath); } if (!String.IsNullOrEmpty(path)) { references.Add(path); } } } // Check for a precompiled library else if (library != null && !dependency.CompilationAssemblies.Any()) { var projectContext = GetProjectContextFromPath(library.Project.ProjectDirectory); if (projectContext != null) { var fileName = GetAssemblyFileName(library.Identity.Name); // Search in the precompiled project output path var path = Path.Combine(projectContext.GetOutputPaths(config).CompilationOutputPath, fileName); if (!File.Exists(path)) { // Fallback to this project output path or probing folder path = ResolveAssetPath(outputPath, probingFolderPath, fileName); } if (!String.IsNullOrEmpty(path)) { references.Add(path); } } } // 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 bin folder, 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, 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 (File.Exists(runtimeConfigPath) && (!File.Exists(cscRuntimeConfigPath) || File.GetLastWriteTimeUtc(runtimeConfigPath) > File.GetLastWriteTimeUtc(cscRuntimeConfigPath))) { lock (_syncLock) { if (!File.Exists(cscRuntimeConfigPath) || File.GetLastWriteTimeUtc(runtimeConfigPath) > File.GetLastWriteTimeUtc(cscRuntimeConfigPath)) { File.Copy(runtimeConfigPath, cscRuntimeConfigPath, true); } } } // Locate csc.dll and the csc.exe asset var cscDllPath = Path.Combine(runtimeDirectory, 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 (File.Exists(cscExePath) && (!File.Exists(cscDllPath) || File.GetLastWriteTimeUtc(cscExePath) > File.GetLastWriteTimeUtc(cscDllPath))) { lock (_syncLock) { if (!File.Exists(cscDllPath) || File.GetLastWriteTimeUtc(cscExePath) > File.GetLastWriteTimeUtc(cscDllPath)) { File.Copy(cscExePath, cscDllPath, 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 void WriteDeps(LibraryExporter exporter) { var path = Path.Combine(_runtimeOutputPath, _context.ProjectFile.Name + FileNameSuffixes.Deps); CreateDirectoryIfNotExists(path); File.WriteAllLines(path, exporter .GetDependencies(LibraryType.Package) .SelectMany(GenerateLines)); var compilerOptions = _context.ResolveCompilationOptions(_configuration); var includeCompile = compilerOptions.PreserveCompilationContext == true; var exports = exporter.GetAllExports().ToArray(); var dependencyContext = new DependencyContextBuilder().Build( compilerOptions: includeCompile? compilerOptions: null, compilationExports: includeCompile ? exports : null, runtimeExports: exports, portable: string.IsNullOrEmpty(_context.RuntimeIdentifier), target: _context.TargetFramework, runtime: _context.RuntimeIdentifier ?? string.Empty); var writer = new DependencyContextWriter(); var depsJsonFile = Path.Combine(_runtimeOutputPath, _context.ProjectFile.Name + FileNameSuffixes.DepsJson); using (var fileStream = File.Create(depsJsonFile)) { writer.Write(dependencyContext, fileStream); } }
public void WriteDeps(LibraryExporter exporter) { Directory.CreateDirectory(_runtimeOutputPath); var includeCompile = _compilerOptions.PreserveCompilationContext == true; var exports = exporter.GetAllExports().ToArray(); var dependencyContext = new DependencyContextBuilder().Build( compilerOptions: includeCompile ? _compilerOptions : null, compilationExports: includeCompile ? exports : null, runtimeExports: exports, portable: string.IsNullOrEmpty(_context.RuntimeIdentifier), target: _context.TargetFramework, runtime: _context.RuntimeIdentifier ?? string.Empty); var writer = new DependencyContextWriter(); var depsJsonFilePath = Path.Combine(_runtimeOutputPath, _compilerOptions.OutputName + FileNameSuffixes.DepsJson); using (var fileStream = File.Create(depsJsonFilePath)) { writer.Write(dependencyContext, fileStream); } }
private void EnsureToolJsonDepsFileExists( LibraryRange toolLibrary, LockFile toolLockFile, string depsPath) { if (!File.Exists(depsPath)) { var projectContext = new ProjectContextBuilder() .WithLockFile(toolLockFile) .WithTargetFramework(s_toolPackageFramework.ToString()) .Build(); var exporter = projectContext.CreateExporter(Constants.DefaultConfiguration); var dependencyContext = new DependencyContextBuilder() .Build(null, null, exporter.GetAllExports(), true, s_toolPackageFramework, string.Empty); using (var fileStream = File.Create(depsPath)) { var dependencyContextWriter = new DependencyContextWriter(); dependencyContextWriter.Write(dependencyContext, fileStream); } } }
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; }