Example #1
0
        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}");
                }
            }
        }
Example #3
0
        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;
        }
Example #5
0
        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);
            }

        }
Example #6
0
        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;
        }