Add --no-dependency flag to build

This commit is contained in:
Mihai Codoban 2016-02-05 15:29:34 -08:00
parent 41fd92222d
commit a0990a518c
7 changed files with 109 additions and 47 deletions

View file

@ -8,15 +8,18 @@ namespace Microsoft.DotNet.Tools.Build
internal class BuilderCommandApp : CompilerCommandApp
{
public const string BuildProfileFlag = "--build-profile";
public const string ForceUnsafeFlag = "--no-incremental";
public const string NoIncrementalFlag = "--no-incremental";
public const string NoDependenciesFlag = "--no-dependencies";
public bool BuildProfileValue => OptionHasValue(BuildProfileFlag);
public bool ForceUnsafeValue => OptionHasValue(ForceUnsafeFlag);
public bool ShouldPrintIncrementalPreconditions => OptionHasValue(BuildProfileFlag);
public bool ShouldNotUseIncrementality => OptionHasValue(NoIncrementalFlag);
public bool ShouldSkipDependencies => OptionHasValue(NoDependenciesFlag);
public BuilderCommandApp(string name, string fullName, string description) : base(name, fullName, description)
{
AddNoValueOption(BuildProfileFlag, "Set this flag to print the incremental safety checks that prevent incremental compilation");
AddNoValueOption(ForceUnsafeFlag, "Set this flag to turn off incremental build");
AddNoValueOption(NoIncrementalFlag, "Set this flag to turn off incremental build");
AddNoValueOption(NoDependenciesFlag, "Set this flag to ignore project to project references and only build the root project");
}
}
}

View file

@ -23,9 +23,9 @@ namespace Microsoft.DotNet.Tools.Build
public static readonly string[] KnownCompilers = { "csc", "vbc", "fsc" };
private readonly ProjectContext _rootProject;
private readonly ProjectDependenciesFacade _rootProjectDependencies;
private readonly BuilderCommandApp _args;
private readonly IncrementalPreconditions _preconditions;
private readonly ProjectDependenciesFacade _dependencies;
public bool IsSafeForIncrementalCompilation => !_preconditions.PreconditionsDetected();
@ -36,12 +36,9 @@ namespace Microsoft.DotNet.Tools.Build
// Cleaner to clone the args and mutate the clone than have separate CompileContext fields for mutated args
// and then reasoning which ones to get from args and which ones from fields.
_args = (BuilderCommandApp)args.ShallowCopy();
_args.OutputValue = _args.OutputValue;
_args.BuildBasePathValue = _args.BuildBasePathValue;
// Set up dependencies
_dependencies = new ProjectDependenciesFacade(_rootProject, _args.ConfigValue);
_rootProjectDependencies = new ProjectDependenciesFacade(_rootProject, _args.ConfigValue);
// gather preconditions
_preconditions = GatherIncrementalPreconditions();
@ -51,17 +48,36 @@ namespace Microsoft.DotNet.Tools.Build
{
CreateOutputDirectories();
// compile dependencies
foreach (var dependency in Sort(_dependencies.ProjectDependenciesWithSources))
{
if (incremental)
{
var dependencyProjectContext = ProjectContext.Create(dependency.Path, dependency.Framework, new[] { _rootProject.RuntimeIdentifier });
return CompileDendencies(incremental) && CompileRootProject(incremental);
}
if (!NeedsRebuilding(dependencyProjectContext, new ProjectDependenciesFacade(dependencyProjectContext, _args.ConfigValue)))
{
continue;
}
private bool CompileRootProject(bool incremental)
{
if (incremental && !NeedsRebuilding(_rootProject, _rootProjectDependencies))
{
// todo: what if the previous build had errors / warnings and nothing changed? Need to propagate them in case of incremental
return true;
}
var success = InvokeCompileOnRootProject();
PrintSummary(success);
return success;
}
private bool CompileDendencies(bool incremental)
{
if (_args.ShouldSkipDependencies)
{
return true;
}
foreach (var dependency in Sort(_rootProjectDependencies.ProjectDependenciesWithSources))
{
if (incremental && !DependencyNeedsRebuilding(dependency))
{
continue;
}
if (!InvokeCompileOnDependency(dependency))
@ -70,28 +86,18 @@ namespace Microsoft.DotNet.Tools.Build
}
}
if (incremental && !NeedsRebuilding(_rootProject, _dependencies))
{
// todo: what if the previous build had errors / warnings and nothing changed? Need to propagate them in case of incremental
return true;
}
return true;
}
// compile project
var success = InvokeCompileOnRootProject();
PrintSummary(success);
return success;
private bool DependencyNeedsRebuilding(ProjectDescription dependency)
{
var dependencyProjectContext = ProjectContext.Create(dependency.Path, dependency.Framework, new[] { _rootProject.RuntimeIdentifier });
return NeedsRebuilding(dependencyProjectContext, new ProjectDependenciesFacade(dependencyProjectContext, _args.ConfigValue));
}
private bool NeedsRebuilding(ProjectContext project, ProjectDependenciesFacade dependencies)
{
return NeedsRebuilding(project, dependencies, _args.BuildBasePathValue);
}
private bool NeedsRebuilding(ProjectContext project, ProjectDependenciesFacade dependencies, string baseBuildPath)
{
var compilerIO = GetCompileIO(project, _args.ConfigValue, baseBuildPath, _args.OutputValue, dependencies, project == _rootProject);
var compilerIO = GetCompileIO(project, _args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue, dependencies, project == _rootProject);
// rebuild if empty inputs / outputs
if (!(compilerIO.Outputs.Any() && compilerIO.Inputs.Any()))
@ -195,9 +201,9 @@ namespace Microsoft.DotNet.Tools.Build
private IncrementalPreconditions GatherIncrementalPreconditions()
{
var preconditions = new IncrementalPreconditions(_args.BuildProfileValue);
var preconditions = new IncrementalPreconditions(_args.ShouldPrintIncrementalPreconditions);
if (_args.ForceUnsafeValue)
if (_args.ShouldNotUseIncrementality)
{
preconditions.AddForceUnsafePrecondition();
}
@ -217,11 +223,16 @@ namespace Microsoft.DotNet.Tools.Build
// check the entire project tree that needs to be compiled, duplicated for each framework
private List<ProjectContext> GetProjectsToCheck()
{
if (_args.ShouldSkipDependencies)
{
return new List<ProjectContext>(1) { _rootProject };
}
// include initial root project
var contextsToCheck = new List<ProjectContext>(1 + _dependencies.ProjectDependenciesWithSources.Count) { _rootProject };
var contextsToCheck = new List<ProjectContext>(1 + _rootProjectDependencies.ProjectDependenciesWithSources.Count) { _rootProject };
// convert ProjectDescription to ProjectContext
var dependencyContexts = _dependencies.ProjectDependenciesWithSources.Select
var dependencyContexts = _rootProjectDependencies.ProjectDependenciesWithSources.Select
(keyValuePair => ProjectContext.Create(keyValuePair.Value.Path, keyValuePair.Value.Framework));
contextsToCheck.AddRange(dependencyContexts);

View file

@ -36,7 +36,7 @@ namespace Microsoft.DotNet.Tools.Build
public void AddForceUnsafePrecondition()
{
_preconditions.Add($"[Forced Unsafe] The build was marked as unsafe. Remove the {BuilderCommandApp.ForceUnsafeFlag} flag to enable incremental compilation");
_preconditions.Add($"[Forced Unsafe] The build was marked as unsafe. Remove the {BuilderCommandApp.NoIncrementalFlag} flag to enable incremental compilation");
}
public bool PreconditionsDetected()

View file

@ -33,3 +33,6 @@ Prints out the incremental safety checks that users need to address in order for
--no-incremental
Marks the build as unsafe for incrementality. This turns off incremental compilation and forces a clean rebuild of the project dependency graph.
--no-dependencies
Ignore project to project references and only build the root project specified to build.

View file

@ -26,6 +26,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
private string _cppCompilerFlags;
private bool _buildProfile;
private bool _noIncremental;
private bool _noDependencies;
private string OutputOption
{
@ -166,6 +167,16 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
}
}
private string NoDependencies
{
get
{
return _noDependencies ?
"--no-dependencies" :
"";
}
}
public BuildCommand(
string projectPath,
string output="",
@ -181,11 +192,11 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
bool nativeCppMode=false,
string cppCompilerFlags="",
bool buildProfile=true,
bool noIncremental=false
bool noIncremental=false,
bool noDependencies=false
)
: base("dotnet")
{
_projectPath = projectPath;
_project = ProjectReader.GetProject(projectPath);
@ -203,6 +214,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
_cppCompilerFlags = cppCompilerFlags;
_buildProfile = buildProfile;
_noIncremental = noIncremental;
_noDependencies = noDependencies;
}
public override CommandResult Execute(string args = "")
@ -226,7 +238,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
private string BuildArgs()
{
return $"{BuildProfile} {NoIncremental} \"{_projectPath}\" {OutputOption} {BuildBasePathOption} {ConfigurationOption} {FrameworkOption} {NoHostOption} {NativeOption} {ArchitectureOption} {IlcArgsOption} {IlcPathOption} {AppDepSDKPathOption} {NativeCppModeOption} {CppCompilerFlagsOption}";
return $"{BuildProfile} {NoDependencies} {NoIncremental} \"{_projectPath}\" {OutputOption} {BuildBasePathOption} {ConfigurationOption} {FrameworkOption} {NoHostOption} {NativeOption} {ArchitectureOption} {IlcArgsOption} {IlcPathOption} {AppDepSDKPathOption} {NativeCppModeOption} {CppCompilerFlagsOption}";
}
}
}

View file

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FluentAssertions;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Test.Utilities;
using Xunit;
@ -13,7 +14,7 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
{
public class ProjectToProjectDependenciesIncrementalTest : IncrementalTestBase
{
private string[] _projects = new[] { "L0", "L11", "L12", "L21", "L22" };
private readonly string[] _projects = new[] { "L0", "L11", "L12", "L21", "L22" };
public ProjectToProjectDependenciesIncrementalTest() : base(
Path.Combine(AppContext.BaseDirectory, "TestAssets", "TestProjects", "TestProjectToProjectDependencies"),
@ -48,6 +49,38 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
AssertRebuilt(result3, expectedRebuiltProjects);
}
[Fact]
public void TestNoDependencyFlag()
{
var dependencies = new[] { "L11", "L12", "L21", "L22" };
// first clean build; all projects required compilation
var result1 = BuildProject();
AssertRebuilt(result1, _projects);
// modify the source code of a leaf dependency
TouchSourcesOfProject("L22");
// second build with no dependencies and no incremental; only the root rebuilds
var result2 = BuildProject(noDependencies: true, noIncremental: true);
result2.Should().StdOutMatchPattern("Compiling.*L0.*");
AssertResultDoesNotContainStrings(result2, dependencies);
// third build with no dependencies but incremental; nothing rebuilds
var result3 = BuildProject(noDependencies: true);
result3.Should().HaveSkippedProjectCompilation("L0");
AssertResultDoesNotContainStrings(result3, dependencies);
}
private static void AssertResultDoesNotContainStrings(CommandResult commandResult, string[] strings)
{
foreach (var s in strings)
{
commandResult.StdOut.Should().NotContain(s);
}
}
// compute A - B
private T[] SetDifference<T>(T[] A, T[] B)
{

View file

@ -46,11 +46,11 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
File.SetLastWriteTimeUtc(file, DateTime.UtcNow);
}
protected CommandResult BuildProject(bool noIncremental = false, bool expectBuildFailure = false)
protected CommandResult BuildProject(bool noDependencies = false, bool noIncremental = false, bool expectBuildFailure = false)
{
var mainProjectFile = GetProjectFile(MainProject);
var buildCommand = new BuildCommand(mainProjectFile, output: GetBinRoot(), framework: "dnxcore50", noIncremental : noIncremental);
var buildCommand = new BuildCommand(mainProjectFile, output: GetBinRoot(), framework: "dnxcore50", noIncremental : noIncremental, noDependencies : noDependencies);
var result = buildCommand.ExecuteWithCapturedOutput();
if (!expectBuildFailure)