зеркало из https://github.com/microsoft/BuildXL.git
Enable the MSBuildResolver to work under dotnet core (#561)
Enable the MSBuildResolver to work under dotnet core
This commit is contained in:
Родитель
eebb761925
Коммит
3733041e39
|
@ -4,7 +4,8 @@ namespace Helpers
|
|||
{
|
||||
export declare const qualifier : {};
|
||||
|
||||
function getToolTemplate() : Transformer.ExecuteArgumentsComposible {
|
||||
@@public
|
||||
export function getDotNetToolTemplate() : Transformer.ExecuteArgumentsComposible {
|
||||
const host = Context.getCurrentHost();
|
||||
|
||||
Contract.assert(host.cpuArchitecture === "x64", "The current DotNetCore Runtime package only has x64 version of Node. Ensure this runs on a 64-bit OS -or- update PowerShell.Core package to have other architectures embedded and fix this logic");
|
||||
|
@ -40,7 +41,7 @@ namespace Helpers
|
|||
};
|
||||
}
|
||||
|
||||
const toolTemplate = getToolTemplate();
|
||||
const toolTemplate = getDotNetToolTemplate();
|
||||
|
||||
@@public
|
||||
export function wrapInDotNetExeForCurrentOs(args: Transformer.ExecuteArguments) : Transformer.ExecuteArguments {
|
||||
|
|
|
@ -129,12 +129,12 @@ export interface LinkResource {
|
|||
}
|
||||
|
||||
@@public
|
||||
export function isBinary(item: Reference) : item is Binary {
|
||||
export function isBinary(item: any) : item is Binary {
|
||||
return item["binary"] !== undefined;
|
||||
}
|
||||
|
||||
@@public
|
||||
export function isAssembly(item: Reference) : item is Assembly {
|
||||
export function isAssembly(item: any) : item is Assembly {
|
||||
return item["name"] !== undefined &&
|
||||
(item["compile"] !== undefined || item["runtime"] !== undefined) &&
|
||||
item["contents"] === undefined; // Exclude nuget packages
|
||||
|
|
|
@ -47,6 +47,7 @@ const xunitNetStandardRuntimeConfigFiles: File[] = Managed.RuntimeConfigFiles.cr
|
|||
"xunit.console",
|
||||
Managed.Factory.createBinary(xunitNetCoreConsolePackage, r`/lib/netcoreapp2.0/xunit.console.dll`),
|
||||
xunitReferences,
|
||||
undefined, // runtimeContentToSkip
|
||||
undefined, // appconfig
|
||||
true);
|
||||
|
||||
|
@ -62,6 +63,7 @@ function additionalRuntimeContent(args: Managed.TestArguments) : Deployment.Depl
|
|||
"xunit.console",
|
||||
Managed.Factory.createBinary(xunitNetCoreConsolePackage, r`/lib/netcoreapp2.0/xunit.console.dll`),
|
||||
xunitReferences,
|
||||
args.runtimeContentToSkip,
|
||||
undefined, // appConfig
|
||||
true)),
|
||||
xunitConsolePackage.getFile(r`/tools/netcoreapp2.0/xunit.runner.utility.netcoreapp10.dll`),
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import * as Shared from "Sdk.Managed.Shared";
|
||||
import * as Csc from "Sdk.Managed.Tools.Csc";
|
||||
import * as Deployment from "Sdk.Deployment";
|
||||
|
||||
namespace Helpers {
|
||||
|
||||
|
@ -53,11 +54,13 @@ namespace Helpers {
|
|||
* You can control whether to follow the compile or the runtime axis using the optional compile argument.
|
||||
*/
|
||||
@@public
|
||||
export function computeTransitiveReferenceClosure(framework: Shared.Framework, references: Shared.Reference[], compile?: boolean) : Shared.Binary[] {
|
||||
export function computeTransitiveReferenceClosure(framework: Shared.Framework, references: Shared.Reference[], runtimeContentToSkip: Deployment.DeployableItem[], compile?: boolean) : Shared.Binary[] {
|
||||
return computeTransitiveClosure([
|
||||
...references,
|
||||
...framework.standardReferences
|
||||
], compile);
|
||||
],
|
||||
runtimeContentToSkip,
|
||||
compile);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,7 +68,7 @@ namespace Helpers {
|
|||
* You can control whether to follow the compile or the runtime axis using the optional compile argument.
|
||||
*/
|
||||
@@public
|
||||
export function computeTransitiveClosure(references: Shared.Reference[], compile?: boolean) : Shared.Binary[] {
|
||||
export function computeTransitiveClosure(references: Shared.Reference[], referencesToSkip: Deployment.DeployableItem[], compile?: boolean) : Shared.Binary[] {
|
||||
let results = MutableSet.empty<Shared.Binary>();
|
||||
let visitedReferences = MutableSet.empty<Shared.Reference>();
|
||||
|
||||
|
@ -75,14 +78,15 @@ namespace Helpers {
|
|||
|
||||
for (let ref of allReferences)
|
||||
{
|
||||
computeTransitiveReferenceClosureHelper(ref, results, visitedReferences, compile);
|
||||
const referencesToSkipSet = Set.empty<Deployment.DeployableItem>().add(...(referencesToSkip ? referencesToSkip : []));
|
||||
computeTransitiveReferenceClosureHelper(ref, referencesToSkipSet, results, visitedReferences, compile);
|
||||
}
|
||||
|
||||
return results.toArray();
|
||||
}
|
||||
|
||||
function computeTransitiveReferenceClosureHelper(ref: Shared.Reference, results: MutableSet<Shared.Binary>, visitedReferences: MutableSet<Shared.Reference>, compile?: boolean) {
|
||||
if (visitedReferences.contains(ref))
|
||||
function computeTransitiveReferenceClosureHelper(ref: Shared.Reference, referencesToSkip: Set<Deployment.DeployableItem>,results: MutableSet<Shared.Binary>, visitedReferences: MutableSet<Shared.Reference>, compile?: boolean) {
|
||||
if (visitedReferences.contains(ref) || referencesToSkip.contains(ref))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -95,17 +99,17 @@ namespace Helpers {
|
|||
}
|
||||
else if (Shared.isAssembly(ref))
|
||||
{
|
||||
if (compile && ref.compile) {
|
||||
if (compile && ref.compile && !referencesToSkip.contains(ref.compile)) {
|
||||
results.add(ref.compile);
|
||||
}
|
||||
if (!compile && ref.runtime) {
|
||||
if (!compile && ref.runtime && !referencesToSkip.contains(ref.runtime)) {
|
||||
results.add(ref.runtime);
|
||||
}
|
||||
if (ref.references)
|
||||
{
|
||||
for (let nestedRef of ref.references)
|
||||
{
|
||||
computeTransitiveReferenceClosureHelper(nestedRef, results, visitedReferences, compile);
|
||||
computeTransitiveReferenceClosureHelper(nestedRef, referencesToSkip, results, visitedReferences, compile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -113,18 +117,18 @@ namespace Helpers {
|
|||
{
|
||||
if (compile)
|
||||
{
|
||||
results.add(...ref.compile);
|
||||
results.add(...ref.compile.filter(c => !referencesToSkip.contains(c)));
|
||||
}
|
||||
else
|
||||
{
|
||||
results.add(...ref.runtime);
|
||||
results.add(...ref.runtime.filter(c => !referencesToSkip.contains(c)));
|
||||
}
|
||||
|
||||
for (let dependency of ref.dependencies)
|
||||
{
|
||||
if (Shared.isManagedPackage(dependency))
|
||||
{
|
||||
computeTransitiveReferenceClosureHelper(dependency, results, visitedReferences, compile);
|
||||
computeTransitiveReferenceClosureHelper(dependency, referencesToSkip, results, visitedReferences, compile);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ export function assembly(args: Arguments, targetType: Csc.TargetType) : Result {
|
|||
|
||||
if (targetType === "exe")
|
||||
{
|
||||
runtimeConfigFiles = RuntimeConfigFiles.createFiles(framework, name, runtimeBinary, references, appConfig);
|
||||
runtimeConfigFiles = RuntimeConfigFiles.createFiles(framework, name, runtimeBinary, references, args.runtimeContentToSkip, appConfig);
|
||||
if (framework.applicationDeploymentStyle === "selfContained")
|
||||
{
|
||||
const frameworkRuntimeFiles = framework.runtimeContentProvider(qualifier.targetRuntime);
|
||||
|
|
|
@ -5,6 +5,7 @@ import {Transformer} from "Sdk.Transformers";
|
|||
|
||||
import * as Json from "Sdk.Json";
|
||||
import * as Shared from "Sdk.Managed.Shared";
|
||||
import * as Deployment from "Sdk.Deployment";
|
||||
|
||||
namespace RuntimeConfigFiles {
|
||||
|
||||
|
@ -18,6 +19,7 @@ namespace RuntimeConfigFiles {
|
|||
assemblyName: string,
|
||||
runtimeBinary: Shared.Binary,
|
||||
references: Shared.Reference[],
|
||||
runtimeContentToSkip: Deployment.DeployableItem[],
|
||||
appConfig: File,
|
||||
testRunnerDeployment?: boolean
|
||||
) : File[] {
|
||||
|
@ -44,7 +46,7 @@ namespace RuntimeConfigFiles {
|
|||
}
|
||||
|
||||
return [
|
||||
createDependenciesJson(framework, assemblyName, runtimeBinary, references, testRunnerDeployment),
|
||||
createDependenciesJson(framework, assemblyName, runtimeBinary, references, runtimeContentToSkip, testRunnerDeployment),
|
||||
createRuntimeConfigJson(framework, assemblyName, runtimeConfigFolder, testRunnerDeployment),
|
||||
];
|
||||
case "none":
|
||||
|
@ -68,12 +70,13 @@ namespace RuntimeConfigFiles {
|
|||
assemblyName: string,
|
||||
runtimeBinary: Shared.Binary,
|
||||
references: Shared.Reference[],
|
||||
runtimeContentToSkip: Deployment.DeployableItem[],
|
||||
testRunnerDeployment?: boolean
|
||||
): File {
|
||||
|
||||
const specFileOutput = Context.getNewOutputDirectory("DotNetSpecFiles");
|
||||
|
||||
const runtimeReferences = Helpers.computeTransitiveReferenceClosure(framework, references, false);
|
||||
const runtimeReferences = Helpers.computeTransitiveReferenceClosure(framework, references, runtimeContentToSkip, false);
|
||||
|
||||
const dependencySpecExtension = `${assemblyName}.deps.json`;
|
||||
const dependencySpecPath = p`${specFileOutput}/${dependencySpecExtension}`;
|
||||
|
|
|
@ -136,12 +136,28 @@ interface MsBuildResolver extends ResolverBase, UntrackingSettings {
|
|||
runInContainer?: boolean;
|
||||
|
||||
/**
|
||||
* Collection of directories to search for the required MsBuild assemblies and MsBuild.exe (a.k.a. MSBuild toolset).
|
||||
* Collection of directories to search for the required MsBuild assemblies and MsBuild.exe/MSBuild.dll (a.k.a. MSBuild toolset).
|
||||
* If not specified, locations in %PATH% are used.
|
||||
* Locations are traversed in specification order.
|
||||
*/
|
||||
msBuildSearchLocations?: Directory[];
|
||||
|
||||
/**
|
||||
* Whether to use the full framework or dotnet core version of MSBuild. Selected runtime is used both for build evaluation and execution.
|
||||
* Default is full framework.
|
||||
* Observe that using the full framework version means that msbuild.exe is expected to be found in msbuildSearchLocations
|
||||
* (or PATH if not specified). If using the dotnet core version, the same logic applies but to msbuild.dll
|
||||
*/
|
||||
msBuildRuntime?: "FullFramework" | "DotNetCore";
|
||||
|
||||
/**
|
||||
* Collection of directories to search for dotnet.exe, when DotNetCore is specified as the msBuildRuntime. If not
|
||||
* specified, locations in %PATH% are used.
|
||||
* Locations are traversed in specification order.
|
||||
* It has no effect if the specified MSBuild runtime is full framework.
|
||||
*/
|
||||
dotNetSearchLocations?: Directory[];
|
||||
|
||||
/**
|
||||
* Optional file paths for the projects or solutions that should be used to start parsing. These are relative
|
||||
* paths with respect to the root traversal.
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
import {Transformer} from "Sdk.Transformers";
|
||||
import {createPublicDotNetRuntime} from "DotNet-Runtime.Common";
|
||||
|
||||
const v3 = <StaticDirectory>importFrom("DotNet-Runtime.linux-x64.3.0.0-preview5").extracted;
|
||||
const v2 = <StaticDirectory>importFrom("DotNet-Runtime.linux-x64.2.2.2").extracted;
|
||||
|
||||
@@public
|
||||
export const extracted = createPublicDotNetRuntime(v3, v2);
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
import {Transformer} from "Sdk.Transformers";
|
||||
import {createPublicDotNetRuntime} from "DotNet-Runtime.Common";
|
||||
|
||||
const v3 = <StaticDirectory>importFrom("DotNet-Runtime.osx-x64.3.0.0-preview5").extracted;
|
||||
const v2 = <StaticDirectory>importFrom("DotNet-Runtime.osx-x64.2.2.2").extracted;
|
||||
|
||||
@@public
|
||||
export const extracted = createPublicDotNetRuntime(v3, v2);
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
import {Transformer} from "Sdk.Transformers";
|
||||
import {createPublicDotNetRuntime} from "DotNet-Runtime.Common";
|
||||
|
||||
const v3 = <StaticDirectory>importFrom("DotNet-Runtime.win-x64.3.0.0-preview5").extracted;
|
||||
const v2 = <StaticDirectory>importFrom("DotNet-Runtime.win-x64.2.2.2").extracted;
|
||||
|
||||
@@public
|
||||
export const extracted = createPublicDotNetRuntime(v3, v2);
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
import {Transformer} from "Sdk.Transformers";
|
||||
|
||||
@@public
|
||||
export function createPublicDotNetRuntime(v3Runtime : StaticDirectory, v2Runtime: StaticDirectory) : StaticDirectory {
|
||||
const netCoreAppV2 = v2Runtime.contents.filter(file => file.path.isWithin(d`${v2Runtime.root}/shared`));
|
||||
|
||||
// We create a package that has dotnet executable and related SDK, plus the V2 SDK
|
||||
const dotNetRuntimeRoot = Context.getNewOutputDirectory("DotNet-Runtime");
|
||||
|
||||
const sealDirectory = Transformer.sealDirectory(
|
||||
dotNetRuntimeRoot,
|
||||
[
|
||||
...v3Runtime.contents.map(file => Transformer.copyFile(file, file.path.relocate(v3Runtime.root, dotNetRuntimeRoot))),
|
||||
...netCoreAppV2.map(file => Transformer.copyFile(file, file.path.relocate(v2Runtime.root, dotNetRuntimeRoot)))
|
||||
]
|
||||
);
|
||||
|
||||
return sealDirectory;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// These are the external versions of the architecture-specific DotNet-Runtime packages.
|
||||
// They are created from the 3.0.0-preview5 version, plus the 2.2 NetCore.App SDK, which is deployed side-by-side
|
||||
// The latter is required for MSBuild tests
|
||||
|
||||
module({
|
||||
name: "DotNet-Runtime.win-x64",
|
||||
nameResolutionSemantics: NameResolutionSemantics.implicitProjectReferences,
|
||||
projects: [f`DotNet-Runtime.win-x64.dsc`]
|
||||
});
|
||||
|
||||
module({
|
||||
name: "DotNet-Runtime.osx-x64",
|
||||
nameResolutionSemantics: NameResolutionSemantics.implicitProjectReferences,
|
||||
projects: [f`DotNet-Runtime.osx-x64.dsc`]
|
||||
});
|
||||
|
||||
module({
|
||||
name: "DotNet-Runtime.linux-x64",
|
||||
nameResolutionSemantics: NameResolutionSemantics.implicitProjectReferences,
|
||||
projects: [f`DotNet-Runtime.linux-x64.dsc`]
|
||||
});
|
||||
|
||||
module({
|
||||
name: "DotNet-Runtime.Common",
|
||||
nameResolutionSemantics: NameResolutionSemantics.implicitProjectReferences,
|
||||
projects: [f`common.dsc`]
|
||||
});
|
|
@ -3,16 +3,8 @@
|
|||
|
||||
import * as Managed from "Sdk.Managed";
|
||||
import * as BuildXLSdk from "Sdk.BuildXL";
|
||||
// import * as Deployment from "Sdk.Deployment";
|
||||
|
||||
@@public
|
||||
export interface MSBuildQualifier extends Qualifier {
|
||||
configuration: "debug" | "release";
|
||||
targetFramework: "net472" ;
|
||||
targetRuntime: "win-x64" | "osx-x64";
|
||||
};
|
||||
|
||||
export declare const qualifier : MSBuildQualifier;
|
||||
export declare const qualifier: BuildXLSdk.DefaultQualifier;
|
||||
|
||||
@@public
|
||||
export const msbuildReferences: Managed.ManagedNugetPackage[] = [
|
||||
|
@ -22,12 +14,16 @@ export const msbuildReferences: Managed.ManagedNugetPackage[] = [
|
|||
importFrom("Microsoft.Build.Tasks.Core").pkg,
|
||||
];
|
||||
|
||||
/** Runtime content for tests */
|
||||
@@public
|
||||
export const msbuildRuntimeContent = [
|
||||
BuildXLSdk.isDotNetCoreBuild ? importFrom("System.Threading.Tasks.Dataflow").pkg : importFrom("DataflowForMSBuild").pkg,
|
||||
importFrom("System.Numerics.Vectors").pkg,
|
||||
importFrom("DataflowForMSBuildRuntime").pkg,
|
||||
// importFrom("System.Collections.Immutable").pkg,
|
||||
...BuildXLSdk.isTargetRuntimeOsx ? [
|
||||
importFrom("Microsoft.Build.Runtime").pkg,
|
||||
...BuildXLSdk.isDotNetCoreBuild ? [
|
||||
importFrom("Microsoft.NETCore.App.210").pkg,
|
||||
importFrom("System.Text.Encoding.CodePages").withQualifier({targetFramework: "netstandard2.0"}).pkg,
|
||||
importFrom("Microsoft.Build.Tasks.Core").withQualifier({targetFramework: "netstandard2.0"}).pkg,
|
||||
importFrom("Microsoft.Build.Runtime").Contents.all.getFile(r`contentFiles/any/netcoreapp2.1/MSBuild.dll`),
|
||||
importFrom("Microsoft.Build.Runtime").Contents.all.getFile(r`contentFiles/any/netcoreapp2.1/MSBuild.runtimeconfig.json`),
|
||||
]
|
||||
|
@ -36,3 +32,20 @@ export const msbuildRuntimeContent = [
|
|||
importFrom("Microsoft.Build.Runtime").Contents.all.getFile(r`contentFiles/any/net472/MSBuild.exe.config`),
|
||||
],
|
||||
];
|
||||
|
||||
function getFrameworkFolder() {
|
||||
return BuildXLSdk.isDotNetCoreBuild ? "dotnetcore" : qualifier.targetFramework;
|
||||
}
|
||||
|
||||
@@public
|
||||
export const deployment = [
|
||||
{
|
||||
subfolder: a`msbuild`,
|
||||
contents: [{
|
||||
subfolder: getFrameworkFolder(),
|
||||
contents: [
|
||||
...msbuildRuntimeContent,
|
||||
...msbuildReferences,]
|
||||
}]
|
||||
},
|
||||
];
|
|
@ -17,7 +17,7 @@ export namespace CoreRT {
|
|||
@@public
|
||||
export function compileToNative(asm: Shared.Assembly): NativeExecutableResult {
|
||||
/** Compile to native object file */
|
||||
const referencesClosure = Managed.Helpers.computeTransitiveClosure(asm.references, /*compile*/ false);
|
||||
const referencesClosure = Managed.Helpers.computeTransitiveClosure(asm.references, asm.runtimeContentToSkip, /*compile*/ false);
|
||||
const ilcResult = Ilc.compile({
|
||||
out: `${asm.name}.o`,
|
||||
inputs: [
|
||||
|
|
|
@ -45,14 +45,7 @@ namespace BuildXL {
|
|||
).exe
|
||||
]
|
||||
} ] ),
|
||||
{
|
||||
subfolder: r`MsBuildGraphBuilder`,
|
||||
contents: BuildXLSdk.isDotNetCoreBuild ? [] : [
|
||||
// If the current qualifier is full framework, this tool has to be built with 472
|
||||
importFrom("BuildXL.Tools").MsBuildGraphBuilder.withQualifier(
|
||||
Object.merge<(typeof qualifier) & {targetFramework: "net472"}>(qualifier, {targetFramework: "net472"})).exe
|
||||
]
|
||||
},
|
||||
importFrom("BuildXL.Tools").MsBuildGraphBuilder.deployment,
|
||||
{
|
||||
subfolder: r`bvfs`,
|
||||
contents: qualifier.targetRuntime !== "win-x64" ? [] : [
|
||||
|
|
|
@ -59,6 +59,11 @@ namespace BuildXL.FrontEnd.MsBuild.Serialization
|
|||
/// </remarks>
|
||||
public bool AllowProjectsWithoutTargetProtocol { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the MSBuild runtime is DotNet core (as opposed to full framework)
|
||||
/// </summary>
|
||||
public bool MsBuildRuntimeIsDotNetCore { get; }
|
||||
|
||||
/// <nodoc/>
|
||||
public MSBuildGraphBuilderArguments(
|
||||
IReadOnlyCollection<string> projectsToParse,
|
||||
|
@ -67,7 +72,8 @@ namespace BuildXL.FrontEnd.MsBuild.Serialization
|
|||
IReadOnlyCollection<string> mSBuildSearchLocations,
|
||||
IReadOnlyCollection<string> entryPointTargets,
|
||||
IReadOnlyCollection<GlobalProperties> requestedQualifiers,
|
||||
bool allowProjectsWithoutTargetProtocol)
|
||||
bool allowProjectsWithoutTargetProtocol,
|
||||
bool msBuildRuntimeIsDotNetCore)
|
||||
{
|
||||
Contract.Requires(projectsToParse?.Count > 0);
|
||||
Contract.Requires(!string.IsNullOrEmpty(outputPath));
|
||||
|
@ -83,6 +89,7 @@ namespace BuildXL.FrontEnd.MsBuild.Serialization
|
|||
EntryPointTargets = entryPointTargets;
|
||||
RequestedQualifiers = requestedQualifiers;
|
||||
AllowProjectsWithoutTargetProtocol = allowProjectsWithoutTargetProtocol;
|
||||
MsBuildRuntimeIsDotNetCore = msBuildRuntimeIsDotNetCore;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -94,7 +101,8 @@ Serialized graph path: {OutputPath}
|
|||
Global properties: {string.Join(" ", GlobalProperties.Select(kvp => $"[{kvp.Key}]={kvp.Value}"))}
|
||||
Search locations: {string.Join(" ", MSBuildSearchLocations)}
|
||||
Requested qualifiers: {string.Join(" ", RequestedQualifiers.Select(qualifier => string.Join(";", qualifier.Select(kvp => $"[{kvp.Key}]={kvp.Value}"))))}
|
||||
Allow projects without target protocol: {AllowProjectsWithoutTargetProtocol}";
|
||||
Allow projects without target protocol: {AllowProjectsWithoutTargetProtocol}
|
||||
MSBuild runtime is DotNetCore: {MsBuildRuntimeIsDotNetCore}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,39 +29,57 @@ namespace BuildXL.FrontEnd.MsBuild.Serialization
|
|||
public IReadOnlyDictionary<string, TPathType> MsBuildAssemblyPaths { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Path to MsBuild.exe that was found
|
||||
/// Path to MsBuild that was found
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The path may not be valid if <see cref="Succeeded"/> is false.
|
||||
/// The last component of the path could be either MSBuild.exe or MSBuild.dll, depending on the selected runtime.
|
||||
/// </remarks>
|
||||
public TPathType PathToMsBuildExe { get; }
|
||||
public TPathType PathToMsBuild { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Path to dotnet.exe, if the dotnet core version of MSBuild was specified to run
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is not actually populated by the graph construction tool, but by bxl
|
||||
/// </remarks>
|
||||
public TPathType PathToDotNetExe { get; }
|
||||
|
||||
/// <nodoc/>
|
||||
public bool Succeeded { get; }
|
||||
|
||||
/// <nodoc/>
|
||||
public static ProjectGraphWithPredictionsResult<TPathType> CreateSuccessfulGraph(ProjectGraphWithPredictions<TPathType> projectGraphWithPredictions, IReadOnlyDictionary<string, TPathType> assemblyPathsToLoad, TPathType pathToMsBuildExe)
|
||||
public static ProjectGraphWithPredictionsResult<TPathType> CreateSuccessfulGraph(ProjectGraphWithPredictions<TPathType> projectGraphWithPredictions, IReadOnlyDictionary<string, TPathType> assemblyPathsToLoad, TPathType pathToMsBuild)
|
||||
{
|
||||
Contract.Requires(projectGraphWithPredictions != null);
|
||||
Contract.Requires(assemblyPathsToLoad != null);
|
||||
return new ProjectGraphWithPredictionsResult<TPathType>(projectGraphWithPredictions, failure: default, msBuildAssemblyPaths: assemblyPathsToLoad, pathToMsBuildExe: pathToMsBuildExe, succeeded: true);
|
||||
return new ProjectGraphWithPredictionsResult<TPathType>(projectGraphWithPredictions, failure: default, msBuildAssemblyPaths: assemblyPathsToLoad, pathToMsBuild: pathToMsBuild, pathToDotNetExe: default(TPathType), succeeded: true);
|
||||
}
|
||||
|
||||
/// <nodoc/>
|
||||
public static ProjectGraphWithPredictionsResult<TPathType> CreateFailure(GraphConstructionError failure, IReadOnlyDictionary<string, TPathType> assemblyPathsToLoad, TPathType pathToMsBuildExe)
|
||||
public static ProjectGraphWithPredictionsResult<TPathType> CreateFailure(GraphConstructionError failure, IReadOnlyDictionary<string, TPathType> assemblyPathsToLoad, TPathType pathToMsBuild)
|
||||
{
|
||||
Contract.Requires(failure != null);
|
||||
Contract.Requires(assemblyPathsToLoad != null);
|
||||
return new ProjectGraphWithPredictionsResult<TPathType>(default, failure, assemblyPathsToLoad, pathToMsBuildExe, succeeded: false);
|
||||
return new ProjectGraphWithPredictionsResult<TPathType>(default, failure, assemblyPathsToLoad, pathToMsBuild, pathToDotNetExe: default(TPathType), succeeded: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new instance of this with a specific path to dotnet.exe
|
||||
/// </summary>
|
||||
public ProjectGraphWithPredictionsResult<TPathType> WithPathToDotNetExe(TPathType pathToDotNetExe)
|
||||
{
|
||||
return new ProjectGraphWithPredictionsResult<TPathType>(Result, Failure, MsBuildAssemblyPaths, PathToMsBuild, pathToDotNetExe, Succeeded);
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
private ProjectGraphWithPredictionsResult(ProjectGraphWithPredictions<TPathType> result, GraphConstructionError failure, IReadOnlyDictionary<string, TPathType> msBuildAssemblyPaths, TPathType pathToMsBuildExe, bool succeeded)
|
||||
private ProjectGraphWithPredictionsResult(ProjectGraphWithPredictions<TPathType> result, GraphConstructionError failure, IReadOnlyDictionary<string, TPathType> msBuildAssemblyPaths, TPathType pathToMsBuild, TPathType pathToDotNetExe, bool succeeded)
|
||||
{
|
||||
Result = result;
|
||||
Failure = failure;
|
||||
Succeeded = succeeded;
|
||||
PathToMsBuildExe = pathToMsBuildExe;
|
||||
PathToMsBuild = pathToMsBuild;
|
||||
PathToDotNetExe = pathToDotNetExe;
|
||||
MsBuildAssemblyPaths = msBuildAssemblyPaths;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,11 +64,7 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
// If this is the first time a resolver is reporting the load of MsBuild assemblies, we just store the result
|
||||
if (m_loadedMsBuildAssemblyLocations.Count == 0)
|
||||
{
|
||||
foreach(var assembly in assemblyPathsToLoad)
|
||||
{
|
||||
m_loadedMsBuildAssemblyLocations.Add(assembly);
|
||||
}
|
||||
|
||||
m_loadedMsBuildAssemblyLocations.AddRange(assemblyPathsToLoad);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -158,7 +158,8 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
m_host,
|
||||
result.ModuleDefinition,
|
||||
m_msBuildResolverSettings,
|
||||
result.MsBuildExeLocation,
|
||||
result.MsBuildLocation,
|
||||
result.DotNetExeLocation,
|
||||
m_frontEndName,
|
||||
m_msBuildWorkspaceResolver.UserDefinedEnvironment,
|
||||
m_msBuildWorkspaceResolver.UserDefinedPassthroughVariables);
|
||||
|
|
|
@ -84,7 +84,10 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
/// <summary>
|
||||
/// Keep in sync with the BuildXL deployment spec that places the tool
|
||||
/// </summary>
|
||||
private RelativePath RelativePathToGraphConstructionTool => RelativePath.Create(m_context.StringTable, @"tools\MsBuildGraphBuilder\ProjectGraphBuilder.exe");
|
||||
private RelativePath RelativePathToGraphConstructionTool =>
|
||||
RelativePath.Create(m_context.StringTable, m_resolverSettings.ShouldRunDotNetCoreMSBuild() ?
|
||||
@"tools\MsBuildGraphBuilder\dotnetcore\ProjectGraphBuilder.dll" :
|
||||
@"tools\MsBuildGraphBuilder\net472\ProjectGraphBuilder.exe");
|
||||
|
||||
/// <summary>
|
||||
/// The result of computing the build graph
|
||||
|
@ -268,7 +271,7 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
if (m_projectGraph == null)
|
||||
{
|
||||
// Get the locations where the MsBuild assemblies should be searched
|
||||
if (!TryRetrieveMsBuildSearchLocations(out IEnumerable<AbsolutePath> searchLocations))
|
||||
if (!TryRetrieveMsBuildSearchLocations(out IEnumerable<AbsolutePath> msBuildSearchLocations))
|
||||
{
|
||||
// Errors should have been logged
|
||||
return new MsBuildGraphConstructionFailure(m_resolverSettings, m_context.PathTable);
|
||||
|
@ -280,9 +283,21 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
return new MsBuildGraphConstructionFailure(m_resolverSettings, m_context.PathTable);
|
||||
}
|
||||
|
||||
// If we should run the dotnet core version of MSBuild, let's retrieve the locations where dotnet.exe
|
||||
// should be found
|
||||
IEnumerable<AbsolutePath> dotNetSearchLocations = null;
|
||||
if (m_resolverSettings.ShouldRunDotNetCoreMSBuild())
|
||||
{
|
||||
if (!TryRetrieveDotNetSearchLocations(out dotNetSearchLocations))
|
||||
{
|
||||
// Errors should have been logged
|
||||
return new MsBuildGraphConstructionFailure(m_resolverSettings, m_context.PathTable);
|
||||
}
|
||||
}
|
||||
|
||||
BuildParameters.IBuildParameters buildParameters = RetrieveBuildParameters();
|
||||
|
||||
m_projectGraph = await TryComputeBuildGraphAsync(searchLocations, parsingEntryPoints, buildParameters);
|
||||
m_projectGraph = await TryComputeBuildGraphAsync(msBuildSearchLocations, dotNetSearchLocations, parsingEntryPoints, buildParameters);
|
||||
}
|
||||
|
||||
return m_projectGraph.Value;
|
||||
|
@ -352,7 +367,7 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
|
||||
}
|
||||
|
||||
private async Task<Possible<ProjectGraphResult>> TryComputeBuildGraphAsync(IEnumerable<AbsolutePath> searchLocations, IEnumerable<AbsolutePath> parsingEntryPoints, BuildParameters.IBuildParameters buildParameters)
|
||||
private async Task<Possible<ProjectGraphResult>> TryComputeBuildGraphAsync(IEnumerable<AbsolutePath> msBuildSearchLocations, IEnumerable<AbsolutePath> dotnetSearchLocations, IEnumerable<AbsolutePath> parsingEntryPoints, BuildParameters.IBuildParameters buildParameters)
|
||||
{
|
||||
// We create a unique output file on the obj folder associated with the current front end, and using a GUID as the file name
|
||||
AbsolutePath outputDirectory = m_host.GetFolderForFrontEnd(MsBuildFrontEnd.Name);
|
||||
|
@ -363,7 +378,7 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
// Make sure the directories are there
|
||||
FileUtilities.CreateDirectory(outputDirectory.ToString(m_context.PathTable));
|
||||
|
||||
Possible<ProjectGraphWithPredictionsResult<AbsolutePath>> maybeProjectGraphResult = await ComputeBuildGraphAsync(responseFile, parsingEntryPoints, outputFile, searchLocations, buildParameters);
|
||||
Possible<ProjectGraphWithPredictionsResult<AbsolutePath>> maybeProjectGraphResult = await ComputeBuildGraphAsync(responseFile, parsingEntryPoints, outputFile, msBuildSearchLocations, dotnetSearchLocations, buildParameters);
|
||||
|
||||
if (!maybeProjectGraphResult.Succeeded)
|
||||
{
|
||||
|
@ -409,7 +424,7 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
allowedModuleDependencies: null, // no module policies
|
||||
cyclicalFriendModules: null); // no whitelist of cycles
|
||||
|
||||
return new ProjectGraphResult(projectGraph, moduleDefinition, projectGraphResult.PathToMsBuildExe);
|
||||
return new ProjectGraphResult(projectGraph, moduleDefinition, projectGraphResult.PathToMsBuild, projectGraphResult.PathToDotNetExe);
|
||||
}
|
||||
|
||||
private void DeleteGraphBuilderRelatedFiles(AbsolutePath outputFile, AbsolutePath responseFile)
|
||||
|
@ -451,7 +466,26 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
m_host.Engine,
|
||||
m_resolverSettings.MsBuildSearchLocations?.SelectList(directoryLocation => directoryLocation.Path),
|
||||
out searchLocations,
|
||||
() => Tracing.Logger.Log.NoSearchLocationsSpecified(m_context.LoggingContext, m_resolverSettings.Location(m_context.PathTable)),
|
||||
() => Tracing.Logger.Log.NoSearchLocationsSpecified(m_context.LoggingContext, m_resolverSettings.Location(m_context.PathTable), "msBuildSearchLocations"),
|
||||
paths => Tracing.Logger.Log.CannotParseBuildParameterPath(m_context.LoggingContext, m_resolverSettings.Location(m_context.PathTable), paths)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a list of search locations for dotnet.exe
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// First inspects the resolver configuration to check if these are defined explicitly. Otherwise, uses PATH environment variable.
|
||||
/// </remarks>
|
||||
private bool TryRetrieveDotNetSearchLocations(out IEnumerable<AbsolutePath> searchLocations)
|
||||
{
|
||||
return FrontEndUtilities.TryRetrieveExecutableSearchLocations(
|
||||
MsBuildFrontEnd.Name,
|
||||
m_context,
|
||||
m_host.Engine,
|
||||
m_resolverSettings.DotNetSearchLocations?.SelectList(directoryLocation => directoryLocation.Path),
|
||||
out searchLocations,
|
||||
() => Tracing.Logger.Log.NoSearchLocationsSpecified(m_context.LoggingContext, m_resolverSettings.Location(m_context.PathTable), "dotnetSearchLocations"),
|
||||
paths => Tracing.Logger.Log.CannotParseBuildParameterPath(m_context.LoggingContext, m_resolverSettings.Location(m_context.PathTable), paths)
|
||||
);
|
||||
}
|
||||
|
@ -460,10 +494,21 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
AbsolutePath responseFile,
|
||||
IEnumerable<AbsolutePath> projectEntryPoints,
|
||||
AbsolutePath outputFile,
|
||||
IEnumerable<AbsolutePath> searchLocations,
|
||||
IEnumerable<AbsolutePath> msBuidSearchLocations,
|
||||
IEnumerable<AbsolutePath> dotnetSearchLocations,
|
||||
BuildParameters.IBuildParameters buildParameters)
|
||||
{
|
||||
SandboxedProcessResult result = await RunMsBuildGraphBuilderAsync(responseFile, projectEntryPoints, outputFile, searchLocations, buildParameters);
|
||||
AbsolutePath dotnetExeLocation = AbsolutePath.Invalid;
|
||||
if (m_resolverSettings.ShouldRunDotNetCoreMSBuild())
|
||||
{
|
||||
if (!TryFindDotNetExe(dotnetSearchLocations, out dotnetExeLocation, out string failure))
|
||||
{
|
||||
return ProjectGraphWithPredictionsResult<AbsolutePath>.CreateFailure(
|
||||
GraphConstructionError.CreateFailureWithoutLocation(failure),
|
||||
CollectionUtilities.EmptyDictionary<string, AbsolutePath>(), AbsolutePath.Invalid);
|
||||
}
|
||||
}
|
||||
SandboxedProcessResult result = await RunMsBuildGraphBuilderAsync(responseFile, projectEntryPoints, outputFile, msBuidSearchLocations, dotnetExeLocation, buildParameters);
|
||||
|
||||
string standardError = result.StandardError.CreateReader().ReadToEndAsync().GetAwaiter().GetResult();
|
||||
|
||||
|
@ -505,7 +550,7 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
var projectGraphWithPredictionsResult = serializer.Deserialize<ProjectGraphWithPredictionsResult<AbsolutePath>>(reader);
|
||||
|
||||
// A successfully constructed graph should always have a valid path to MsBuild
|
||||
Contract.Assert(!projectGraphWithPredictionsResult.Succeeded || projectGraphWithPredictionsResult.PathToMsBuildExe.IsValid);
|
||||
Contract.Assert(!projectGraphWithPredictionsResult.Succeeded || projectGraphWithPredictionsResult.PathToMsBuild.IsValid);
|
||||
// A successfully constructed graph should always have at least one project node
|
||||
Contract.Assert(!projectGraphWithPredictionsResult.Succeeded || projectGraphWithPredictionsResult.Result.ProjectNodes.Length > 0);
|
||||
// A failed construction should always have a failure set
|
||||
|
@ -515,12 +560,32 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
Tracing.Logger.Log.GraphConstructionToolCompleted(
|
||||
m_context.LoggingContext, m_resolverSettings.Location(m_context.PathTable),
|
||||
string.Join(",\n", projectGraphWithPredictionsResult.MsBuildAssemblyPaths.Select(kvp => I($"[{kvp.Key}]:{kvp.Value.ToString(m_context.PathTable)}"))),
|
||||
projectGraphWithPredictionsResult.PathToMsBuildExe.ToString(m_context.PathTable));
|
||||
projectGraphWithPredictionsResult.PathToMsBuild.ToString(m_context.PathTable));
|
||||
|
||||
return projectGraphWithPredictionsResult;
|
||||
return m_resolverSettings.ShouldRunDotNetCoreMSBuild() ? projectGraphWithPredictionsResult.WithPathToDotNetExe(dotnetExeLocation) : projectGraphWithPredictionsResult;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryFindDotNetExe(IEnumerable<AbsolutePath> dotnetSearchLocations, out AbsolutePath dotnetExeLocation, out string failure)
|
||||
{
|
||||
dotnetExeLocation = AbsolutePath.Invalid;
|
||||
failure = string.Empty;
|
||||
|
||||
foreach (AbsolutePath location in dotnetSearchLocations)
|
||||
{
|
||||
AbsolutePath dotnetExeCandidate = location.Combine(m_context.PathTable, "dotnet.exe");
|
||||
if (m_host.Engine.FileExists(dotnetExeCandidate))
|
||||
{
|
||||
dotnetExeLocation = dotnetExeCandidate;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
failure = $"Cannot find dotnet.exe. " +
|
||||
$"This is required because the dotnet core version of MSBuild was specified to run. Searched locations: [{string.Join(", ", dotnetSearchLocations.Select(location => location.ToString(m_context.PathTable)))}]";
|
||||
return false;
|
||||
}
|
||||
|
||||
private void TrackFilesAndEnvironment(ISet<ReportedFileAccess> fileAccesses, AbsolutePath frontEndFolder)
|
||||
{
|
||||
// Register all build parameters passed to the graph construction process
|
||||
|
@ -539,11 +604,13 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
AbsolutePath responseFile,
|
||||
IEnumerable<AbsolutePath> projectEntryPoints,
|
||||
AbsolutePath outputFile,
|
||||
IEnumerable<AbsolutePath> searchLocations,
|
||||
IEnumerable<AbsolutePath> msBuildSearchLocations,
|
||||
AbsolutePath dotnetExeLocation,
|
||||
BuildParameters.IBuildParameters buildParameters)
|
||||
{
|
||||
Contract.Assert(!m_resolverSettings.ShouldRunDotNetCoreMSBuild() || dotnetExeLocation.IsValid);
|
||||
|
||||
AbsolutePath toolDirectory = m_configuration.Layout.BuildEngineDirectory.Combine(m_context.PathTable, RelativePathToGraphConstructionTool).GetParent(m_context.PathTable);
|
||||
string pathToTool = m_configuration.Layout.BuildEngineDirectory.Combine(m_context.PathTable, RelativePathToGraphConstructionTool).ToString(m_context.PathTable);
|
||||
string outputDirectory = outputFile.GetParent(m_context.PathTable).ToString(m_context.PathTable);
|
||||
string outputFileString = outputFile.ToString(m_context.PathTable);
|
||||
IReadOnlyCollection<string> entryPointTargets = m_resolverSettings.InitialTargets ?? CollectionUtilities.EmptyArray<string>();
|
||||
|
@ -554,14 +621,30 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
projectEntryPoints.Select(entryPoint => entryPoint.ToString(m_context.PathTable)).ToList(),
|
||||
outputFileString,
|
||||
new GlobalProperties(m_resolverSettings.GlobalProperties ?? CollectionUtilities.EmptyDictionary<string, string>()),
|
||||
searchLocations.Select(location => location.ToString(m_context.PathTable)).ToList(),
|
||||
msBuildSearchLocations.Select(location => location.ToString(m_context.PathTable)).ToList(),
|
||||
entryPointTargets,
|
||||
requestedQualifiers,
|
||||
m_resolverSettings.AllowProjectsToNotSpecifyTargetProtocol == true);
|
||||
m_resolverSettings.AllowProjectsToNotSpecifyTargetProtocol == true,
|
||||
m_resolverSettings.ShouldRunDotNetCoreMSBuild());
|
||||
|
||||
var responseFilePath = responseFile.ToString(m_context.PathTable);
|
||||
SerializeResponseFile(responseFilePath, arguments);
|
||||
|
||||
string graphConstructionToolPath = m_configuration.Layout.BuildEngineDirectory.Combine(m_context.PathTable, RelativePathToGraphConstructionTool).ToString(m_context.PathTable);
|
||||
string pathToTool;
|
||||
string toolArguments;
|
||||
// if we should call the dotnet core version of MSBuild, we need to actually call dotnet.exe and pass the tool itself as its first argument
|
||||
if (m_resolverSettings.ShouldRunDotNetCoreMSBuild())
|
||||
{
|
||||
pathToTool = dotnetExeLocation.ToString(m_context.PathTable);
|
||||
toolArguments = I($"\"{graphConstructionToolPath}\" \"{responseFilePath}\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
pathToTool = graphConstructionToolPath;
|
||||
toolArguments = I($"\"{responseFilePath}\"");
|
||||
}
|
||||
|
||||
Tracing.Logger.Log.LaunchingGraphConstructionTool(m_context.LoggingContext, m_resolverSettings.Location(m_context.PathTable), arguments.ToString(), pathToTool);
|
||||
|
||||
// Just being defensive, make sure there is not an old output file lingering around
|
||||
|
@ -572,7 +655,7 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
pathToTool,
|
||||
buildStorageDirectory: outputDirectory,
|
||||
fileAccessManifest: GenerateFileAccessManifest(toolDirectory, outputFile),
|
||||
arguments: I($"\"{responseFilePath}\""),
|
||||
arguments: toolArguments,
|
||||
workingDirectory: outputDirectory,
|
||||
description: "MsBuild graph builder",
|
||||
buildParameters,
|
||||
|
|
|
@ -55,7 +55,8 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
|
||||
private AbsolutePath Root => m_resolverSettings.Root;
|
||||
|
||||
private readonly AbsolutePath m_msBuildExePath;
|
||||
private readonly AbsolutePath m_msBuildPath;
|
||||
private readonly AbsolutePath m_dotnetExePath;
|
||||
private readonly string m_frontEndName;
|
||||
private readonly IEnumerable<KeyValuePair<string, string>> m_userDefinedEnvironment;
|
||||
private readonly IEnumerable<string> m_userDefinedPassthroughVariables;
|
||||
|
@ -81,7 +82,8 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
FrontEndHost frontEndHost,
|
||||
ModuleDefinition moduleDefinition,
|
||||
IMsBuildResolverSettings resolverSettings,
|
||||
AbsolutePath pathToMsBuildExe,
|
||||
AbsolutePath pathToMsBuild,
|
||||
AbsolutePath pathToDotnetExe,
|
||||
string frontEndName,
|
||||
IEnumerable<KeyValuePair<string, string>> userDefinedEnvironment,
|
||||
IEnumerable<string> userDefinedPassthroughVariables)
|
||||
|
@ -90,7 +92,8 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
Contract.Requires(frontEndHost != null);
|
||||
Contract.Requires(moduleDefinition != null);
|
||||
Contract.Requires(resolverSettings != null);
|
||||
Contract.Requires(pathToMsBuildExe.IsValid);
|
||||
Contract.Requires(pathToMsBuild.IsValid);
|
||||
Contract.Requires(!resolverSettings.ShouldRunDotNetCoreMSBuild() || pathToDotnetExe.IsValid);
|
||||
Contract.Requires(!string.IsNullOrEmpty(frontEndName));
|
||||
Contract.Requires(userDefinedEnvironment != null);
|
||||
Contract.Requires(userDefinedPassthroughVariables != null);
|
||||
|
@ -99,7 +102,8 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
m_frontEndHost = frontEndHost;
|
||||
m_moduleDefinition = moduleDefinition;
|
||||
m_resolverSettings = resolverSettings;
|
||||
m_msBuildExePath = pathToMsBuildExe;
|
||||
m_msBuildPath = pathToMsBuild;
|
||||
m_dotnetExePath = pathToDotnetExe;
|
||||
m_frontEndName = frontEndName;
|
||||
m_userDefinedEnvironment = userDefinedEnvironment;
|
||||
m_userDefinedPassthroughVariables = userDefinedPassthroughVariables;
|
||||
|
@ -767,7 +771,17 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
ProcessBuilder processBuilder,
|
||||
ProjectWithPredictions project)
|
||||
{
|
||||
FileArtifact cmdExeArtifact = FileArtifact.CreateSourceFile(m_msBuildExePath);
|
||||
// If we should use the dotnet core version of msbuild, the executable for the pip is dotnet.exe instead of msbuild.exe, and
|
||||
// the first argument is msbuild.dll
|
||||
FileArtifact cmdExeArtifact;
|
||||
if (m_resolverSettings.ShouldRunDotNetCoreMSBuild())
|
||||
{
|
||||
cmdExeArtifact = FileArtifact.CreateSourceFile(m_dotnetExePath);
|
||||
processBuilder.ArgumentsBuilder.Add(PipDataAtom.FromAbsolutePath(m_msBuildPath));
|
||||
}
|
||||
else {
|
||||
cmdExeArtifact = FileArtifact.CreateSourceFile(m_msBuildPath);
|
||||
}
|
||||
|
||||
processBuilder.Executable = cmdExeArtifact;
|
||||
processBuilder.AddInputFile(cmdExeArtifact);
|
||||
|
@ -780,8 +794,6 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
// ensure environment value (and hence pip hash) consistency.
|
||||
processBuilder.EnableTempDirectory();
|
||||
|
||||
AbsolutePath toolDir = m_msBuildExePath.GetParent(PathTable);
|
||||
|
||||
processBuilder.ToolDescription = StringId.Create(m_context.StringTable, I($"{m_moduleDefinition.Descriptor.Name} - {project.FullPath.ToString(PathTable)}"));
|
||||
|
||||
return true;
|
||||
|
|
|
@ -35,7 +35,8 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
FrontEndHost frontEndHost,
|
||||
ModuleDefinition moduleDefinition,
|
||||
IMsBuildResolverSettings resolverSettings,
|
||||
AbsolutePath pathToMsBuildExe,
|
||||
AbsolutePath pathToMsBuild,
|
||||
AbsolutePath pathToDotnetExe,
|
||||
string frontEndName,
|
||||
IEnumerable<KeyValuePair<string, string>> userDefinedEnvironment,
|
||||
IEnumerable<string> userDefinedPassthroughVariables)
|
||||
|
@ -44,14 +45,15 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
Contract.Requires(frontEndHost != null);
|
||||
Contract.Requires(moduleDefinition != null);
|
||||
Contract.Requires(resolverSettings != null);
|
||||
Contract.Requires(pathToMsBuildExe.IsValid);
|
||||
Contract.Requires(pathToMsBuild.IsValid);
|
||||
Contract.Requires(!resolverSettings.ShouldRunDotNetCoreMSBuild() || pathToDotnetExe.IsValid);
|
||||
Contract.Requires(!string.IsNullOrEmpty(frontEndName));
|
||||
Contract.Requires(userDefinedEnvironment != null);
|
||||
Contract.Requires(userDefinedPassthroughVariables != null);
|
||||
|
||||
m_context = context;
|
||||
m_frontEndHost = frontEndHost;
|
||||
m_pipConstructor = new PipConstructor(context, frontEndHost, moduleDefinition, resolverSettings, pathToMsBuildExe, frontEndName, userDefinedEnvironment, userDefinedPassthroughVariables);
|
||||
m_pipConstructor = new PipConstructor(context, frontEndHost, moduleDefinition, resolverSettings, pathToMsBuild, pathToDotnetExe, frontEndName, userDefinedEnvironment, userDefinedPassthroughVariables);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -21,18 +21,22 @@ namespace BuildXL.FrontEnd.MsBuild
|
|||
public ModuleDefinition ModuleDefinition { get; }
|
||||
|
||||
/// <nodoc/>
|
||||
public AbsolutePath MsBuildExeLocation { get; }
|
||||
public AbsolutePath MsBuildLocation { get; }
|
||||
|
||||
/// <nodoc/>
|
||||
public ProjectGraphResult(ProjectGraphWithPredictions<AbsolutePath> projectGraphWithPredictions, ModuleDefinition moduleDefinition, AbsolutePath msBuildExeLocation)
|
||||
public AbsolutePath DotNetExeLocation { get; }
|
||||
|
||||
/// <nodoc/>
|
||||
public ProjectGraphResult(ProjectGraphWithPredictions<AbsolutePath> projectGraphWithPredictions, ModuleDefinition moduleDefinition, AbsolutePath msBuildLocation, AbsolutePath dotnetExeLocation)
|
||||
{
|
||||
Contract.Requires(projectGraphWithPredictions != null);
|
||||
Contract.Requires(moduleDefinition != null);
|
||||
Contract.Requires(msBuildExeLocation.IsValid);
|
||||
Contract.Requires(msBuildLocation.IsValid);
|
||||
|
||||
ProjectGraph = projectGraphWithPredictions;
|
||||
ModuleDefinition = moduleDefinition;
|
||||
MsBuildExeLocation = msBuildExeLocation;
|
||||
MsBuildLocation = msBuildLocation;
|
||||
DotNetExeLocation = dotnetExeLocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,9 +69,9 @@ namespace BuildXL.FrontEnd.MsBuild.Tracing
|
|||
EventGenerators = EventGenerators.LocalOnly,
|
||||
EventLevel = Level.Error,
|
||||
EventTask = (ushort)Tasks.Parser,
|
||||
Message = EventConstants.LabeledProvenancePrefix + "Build parameter 'PATH' is not specified, and no explicit locations were defined in the resolver settings via 'MsBuildAssemblyLocations'.",
|
||||
Message = EventConstants.LabeledProvenancePrefix + "Build parameter 'PATH' is not specified, and no explicit locations were defined in the resolver settings via '{specifiedVia}'.",
|
||||
Keywords = (int)(Keywords.UserMessage | Keywords.Diagnostics))]
|
||||
public abstract void NoSearchLocationsSpecified(LoggingContext context, Location location);
|
||||
public abstract void NoSearchLocationsSpecified(LoggingContext context, Location location, string specifiedVia);
|
||||
|
||||
[GeneratedEvent(
|
||||
(ushort)LogEventId.CannotParseBuildParameterPath,
|
||||
|
|
|
@ -122,6 +122,21 @@ interface MsBuildResolver {
|
|||
*/
|
||||
msBuildSearchLocations?: Directory[];
|
||||
|
||||
/**
|
||||
* Whether to use the full framework or dotnet core version of MSBuild. Selected runtime is used both for build evaluation and execution.
|
||||
* Default is full framework.
|
||||
* Observe that using the full framework version means that msbuild.exe is expected to be found in msbuildSearchLocations
|
||||
* (or PATH if not specified). If using the dotnet core version, the same logic applies but to msbuild.dll
|
||||
*/
|
||||
msBuildRuntime?: "FullFramework" | "DotNetCore";
|
||||
|
||||
/**
|
||||
* Collection of directories to search for dotnet.exe, when DotNetCore is specified as the msBuildRuntime. If not
|
||||
* specified, locations in %PATH% are used.
|
||||
* Locations are traversed in specification order.
|
||||
*/
|
||||
dotNetSearchLocations?: Directory[];
|
||||
|
||||
/**
|
||||
* Targets to execute on the entry point project.
|
||||
* If not provided, the default targets are used.
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BuildXL.Utilities.Configuration.Mutable;
|
||||
using BuildXL.Engine.Tracing;
|
||||
using BuildXL.Pips.Operations;
|
||||
using BuildXL.Scheduler.Graph;
|
||||
using Test.BuildXL.EngineTestUtilities;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using System;
|
||||
using BuildXL.Utilities;
|
||||
using BuildXL.Utilities.Configuration;
|
||||
|
||||
namespace Test.BuildXL.FrontEnd.MsBuild
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses an MSBuild resolver to schedule and execute pips based on MSBuild.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// These tests actually execute pips, and are therefore expensive
|
||||
/// </remarks>
|
||||
public class MsBuildDotNetRuntimeTests : MsBuildPipExecutionTestBase
|
||||
{
|
||||
public MsBuildDotNetRuntimeTests(ITestOutputHelper output)
|
||||
: base(output)
|
||||
{
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("DotNetCore")]
|
||||
[InlineData("FullFramework")]
|
||||
public void RuntimeSelectionIsEffective(string msBuildRuntime)
|
||||
{
|
||||
const string TestProj1 = "test1.csproj";
|
||||
var pathToTestProj1 = R("public", "dir1", TestProj1);
|
||||
|
||||
const string Dirs = "dirs.proj";
|
||||
var config = (CommandLineConfiguration)Build(
|
||||
msBuildRuntime: msBuildRuntime,
|
||||
dotnetSearchLocations: $"[d`{TestDeploymentDir}/{RelativePathToDotnetExe}`]")
|
||||
.AddSpec(Dirs, CreateDirsProject(pathToTestProj1))
|
||||
.AddSpec(pathToTestProj1, CreateEmptyProject())
|
||||
.PersistSpecsAndGetConfiguration();
|
||||
|
||||
config.Sandbox.FileSystemMode = FileSystemMode.RealAndMinimalPipGraph;
|
||||
|
||||
var engineResult = RunEngineWithConfig(config);
|
||||
Assert.True(engineResult.IsSuccess);
|
||||
|
||||
var pipGraph = engineResult.EngineState.PipGraph;
|
||||
|
||||
var processPips = pipGraph.RetrievePipsOfType(PipType.Process).ToList();
|
||||
var testProj1 = (Process)processPips.Find(pip => pip.Provenance.OutputValueSymbol.ToString(engineResult.EngineState.SymbolTable).Contains(TestProj1));
|
||||
Assert.True(testProj1 != null);
|
||||
|
||||
if (msBuildRuntime == "DotNetCore")
|
||||
{
|
||||
// The main executable has to be dotnet.exe (or dotnet in the mac/unix case)
|
||||
Assert.Contains("DOTNET", testProj1.Executable.Path.ToString(PathTable).ToUpperInvariant());
|
||||
}
|
||||
else
|
||||
{
|
||||
// The main executable has to be msbuild.exe
|
||||
Assert.Contains("MSBUILD.EXE", testProj1.Executable.Path.ToString(PathTable).ToUpperInvariant());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -136,7 +136,9 @@ namespace Test.BuildXL.FrontEnd.MsBuild
|
|||
runInContainer: false,
|
||||
environment: environment,
|
||||
globalProperties: null,
|
||||
filenameEntryPoint: pathToTestProj1)
|
||||
filenameEntryPoint: pathToTestProj1,
|
||||
msBuildRuntime: null,
|
||||
dotnetSearchLocations: null)
|
||||
.AddSpec(pathToTestProj1, CreateWriteFileTestProject("MyFile"))
|
||||
.PersistSpecsAndGetConfiguration();
|
||||
|
||||
|
|
|
@ -36,6 +36,16 @@ namespace Test.BuildXL.FrontEnd.MsBuild
|
|||
// By default the engine runs e2e
|
||||
protected virtual EnginePhases Phase => EnginePhases.Execute;
|
||||
|
||||
// Keep the paths below in sync with Public\Src\FrontEnd\UnitTests\MsBuild\Test.BuildXL.FrontEnd.MsBuild.dsc
|
||||
/// <nodoc/>
|
||||
protected string RelativePathToFullframeworkMSBuild => "msbuild/net472";
|
||||
|
||||
/// <nodoc/>
|
||||
protected string RelativePathToDotnetCoreMSBuild => "msbuild/dotnetcore";
|
||||
|
||||
/// <nodoc/>
|
||||
protected string RelativePathToDotnetExe => "dotnet";
|
||||
|
||||
protected MsBuildPipExecutionTestBase(ITestOutputHelper output) : base(output, true)
|
||||
{
|
||||
RegisterEventSource(global::BuildXL.Engine.ETWLogger.Log);
|
||||
|
@ -59,19 +69,40 @@ namespace Test.BuildXL.FrontEnd.MsBuild
|
|||
return base.Build().Configuration(DefaultMsBuildPrelude(runInContainer: false, environment));
|
||||
}
|
||||
|
||||
protected SpecEvaluationBuilder Build(bool runInContainer = false, Dictionary<string, string> environment = null, Dictionary<string, string> globalProperties = null, string filenameEntryPoint = null)
|
||||
protected SpecEvaluationBuilder Build(
|
||||
bool runInContainer = false,
|
||||
Dictionary<string, string> environment = null,
|
||||
Dictionary<string, string> globalProperties = null,
|
||||
string filenameEntryPoint = null,
|
||||
string msBuildRuntime = null,
|
||||
string dotnetSearchLocations = null)
|
||||
{
|
||||
return Build(runInContainer,
|
||||
environment != null? environment.ToDictionary(kvp => kvp.Key, kvp => new DiscriminatingUnion<string, UnitValue>(kvp.Value)) : null,
|
||||
globalProperties,
|
||||
filenameEntryPoint);
|
||||
filenameEntryPoint,
|
||||
msBuildRuntime,
|
||||
dotnetSearchLocations);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected SpecEvaluationBuilder Build(bool runInContainer, Dictionary<string, DiscriminatingUnion<string, UnitValue>> environment, Dictionary<string, string> globalProperties, string filenameEntryPoint)
|
||||
protected SpecEvaluationBuilder Build(
|
||||
bool runInContainer,
|
||||
Dictionary<string, DiscriminatingUnion<string, UnitValue>> environment,
|
||||
Dictionary<string, string> globalProperties,
|
||||
string filenameEntryPoint,
|
||||
string msBuildRuntime,
|
||||
string dotnetSearchLocations)
|
||||
{
|
||||
// Let's explicitly pass an empty environment, so the process environment won't affect tests by default
|
||||
return base.Build().Configuration(DefaultMsBuildPrelude(runInContainer, environment: environment ?? new Dictionary<string, DiscriminatingUnion<string, UnitValue>>(), globalProperties, filenameEntryPoint: filenameEntryPoint));
|
||||
return base.Build().Configuration(
|
||||
DefaultMsBuildPrelude(
|
||||
runInContainer,
|
||||
environment: environment ?? new Dictionary<string, DiscriminatingUnion<string, UnitValue>>(),
|
||||
globalProperties,
|
||||
filenameEntryPoint: filenameEntryPoint,
|
||||
msBuildRuntime: msBuildRuntime,
|
||||
dotnetSearchLocations: dotnetSearchLocations));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -111,6 +142,18 @@ namespace Test.BuildXL.FrontEnd.MsBuild
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an empty project
|
||||
/// </summary>
|
||||
protected string CreateEmptyProject()
|
||||
{
|
||||
return
|
||||
$@"<?xml version='1.0' encoding='utf-8'?>
|
||||
<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
|
||||
<Target Name='Build'/>
|
||||
</Project>";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a project that just echoes 'Hello World'
|
||||
/// </summary>
|
||||
|
@ -180,7 +223,7 @@ $@"<?xml version='1.0' encoding='utf-8'?>
|
|||
private string GetWriteFileTask()
|
||||
{
|
||||
return
|
||||
$@"<UsingTask TaskName='WriteFile' TaskFactory='CodeTaskFactory' AssemblyFile='{TestDeploymentDir}\Microsoft.Build.Tasks.Core.dll'>
|
||||
$@"<UsingTask TaskName='WriteFile' TaskFactory='CodeTaskFactory' AssemblyFile='{TestDeploymentDir}\{RelativePathToFullframeworkMSBuild}\Microsoft.Build.Tasks.Core.dll'>
|
||||
<ParameterGroup>
|
||||
<Path ParameterType='System.String' Required='true' />
|
||||
<Content ParameterType ='System.String' Required='true' />
|
||||
|
@ -229,14 +272,16 @@ $@"<?xml version='1.0' encoding='utf-8'?>
|
|||
bool enableEngineTracing = false,
|
||||
string logVerbosity = null,
|
||||
bool allowProjectsToNotSpecifyTargetProtocol = true,
|
||||
string filenameEntryPoint = null) => $@"
|
||||
string filenameEntryPoint = null,
|
||||
string msBuildRuntime = null,
|
||||
string dotnetSearchLocations = null) => $@"
|
||||
config({{
|
||||
disableDefaultSourceResolver: true,
|
||||
resolvers: [
|
||||
{{
|
||||
kind: 'MsBuild',
|
||||
moduleName: 'Test',
|
||||
msBuildSearchLocations: [d`{TestDeploymentDir}`],
|
||||
msBuildSearchLocations: [d`{TestDeploymentDir}/{(msBuildRuntime == "DotNetCore" ? RelativePathToDotnetCoreMSBuild : RelativePathToFullframeworkMSBuild)}`],
|
||||
root: d`.`,
|
||||
allowProjectsToNotSpecifyTargetProtocol: {(allowProjectsToNotSpecifyTargetProtocol ? "true" : "false")},
|
||||
runInContainer: {(runInContainer ? "true" : "false")},
|
||||
|
@ -246,6 +291,8 @@ config({{
|
|||
enableEngineTracing: {(enableEngineTracing? "true" : "false")},
|
||||
{(logVerbosity != null ? $"logVerbosity: {logVerbosity}," : string.Empty)}
|
||||
{(filenameEntryPoint != null ? $"fileNameEntryPoints: [r`{filenameEntryPoint}`]," : string.Empty)}
|
||||
{(msBuildRuntime != null ? $"msBuildRuntime: \"{msBuildRuntime}\"," : string.Empty)}
|
||||
{(dotnetSearchLocations != null ? $"dotNetSearchLocations: {dotnetSearchLocations}," : string.Empty)}
|
||||
}},
|
||||
],
|
||||
}});";
|
||||
|
@ -258,7 +305,7 @@ config({{
|
|||
{{
|
||||
kind: 'MsBuild',
|
||||
moduleName: 'Test',
|
||||
msBuildSearchLocations: [d`{TestDeploymentDir}`],
|
||||
msBuildSearchLocations: [d`{TestDeploymentDir}/{RelativePathToFullframeworkMSBuild}`],
|
||||
root: d`.`,
|
||||
allowProjectsToNotSpecifyTargetProtocol: true,
|
||||
{DictionaryToExpression("environment", new Dictionary<string, string>())}
|
||||
|
|
|
@ -40,6 +40,19 @@ namespace Test.BuildXL.FrontEnd.MsBuild.Infrastructure
|
|||
|
||||
protected AbsolutePath TestPath { get; }
|
||||
|
||||
// Keep the paths below in sync with Public\Src\FrontEnd\UnitTests\MsBuild\Test.BuildXL.FrontEnd.MsBuild.dsc
|
||||
private AbsolutePath FullframeworkMSBuild => AbsolutePath.Create(PathTable, TestDeploymentDir)
|
||||
.Combine(PathTable, "msbuild")
|
||||
.Combine(PathTable, "net472")
|
||||
.Combine(PathTable, "MSBuild.exe");
|
||||
private AbsolutePath DotnetCoreMSBuild => AbsolutePath.Create(PathTable, TestDeploymentDir)
|
||||
.Combine(PathTable, "msbuild")
|
||||
.Combine(PathTable, "dotnetcore")
|
||||
.Combine(PathTable, "MSBuild.dll");
|
||||
private AbsolutePath DotnetExe => AbsolutePath.Create(PathTable, TestDeploymentDir)
|
||||
.Combine(PathTable, "dotnet")
|
||||
.Combine(PathTable, OperatingSystemHelper.IsUnixOS ? "dotnet" : "dotnet.exe");
|
||||
|
||||
/// <nodoc/>
|
||||
public MsBuildPipSchedulingTestBase(ITestOutputHelper output, bool usePassThroughFileSystem = false) : base(output, usePassThroughFileSystem)
|
||||
{
|
||||
|
@ -134,7 +147,8 @@ namespace Test.BuildXL.FrontEnd.MsBuild.Infrastructure
|
|||
controller,
|
||||
m_testModule,
|
||||
resolverSettings,
|
||||
AbsolutePath.Create(PathTable, TestDeploymentDir).Combine(PathTable, "MSBuild.exe"),
|
||||
resolverSettings.ShouldRunDotNetCoreMSBuild()? DotnetCoreMSBuild : FullframeworkMSBuild,
|
||||
resolverSettings.ShouldRunDotNetCoreMSBuild()? DotnetExe : AbsolutePath.Invalid,
|
||||
nameof(MsBuildFrontEnd),
|
||||
trackedEnv,
|
||||
passthroughVars);
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
|
||||
import * as Managed from "Sdk.Managed";
|
||||
import * as MSBuild from "Sdk.Selfhost.MSBuild";
|
||||
import * as Frameworks from "Sdk.Managed.Frameworks";
|
||||
|
||||
namespace Test.MsBuild {
|
||||
export declare const qualifier: MSBuild.MSBuildQualifier;
|
||||
export declare const qualifier: BuildXLSdk.DefaultQualifier;
|
||||
|
||||
@@public
|
||||
export const dll = BuildXLSdk.test({
|
||||
|
@ -38,21 +39,19 @@ namespace Test.MsBuild {
|
|||
importFrom("BuildXL.Utilities.Instrumentation").Common.dll,
|
||||
...BuildXLSdk.tplPackages,
|
||||
],
|
||||
|
||||
// We need both the full framework and dotnet core versions of MSBuild, plus dotnet.exe for the dotnet core case
|
||||
runtimeContent: [
|
||||
...MSBuild.msbuildRuntimeContent,
|
||||
...MSBuild.msbuildReferences,
|
||||
...importFrom("Sdk.Selfhost.MSBuild").withQualifier(Object.merge<BuildXLSdk.DefaultQualifier>(qualifier, {targetFramework: "net472"})).deployment,
|
||||
...importFrom("Sdk.Selfhost.MSBuild").withQualifier(Object.merge<BuildXLSdk.DefaultQualifier>(qualifier, {targetFramework: "netcoreapp3.0"})).deployment,
|
||||
{
|
||||
subfolder: "dotnet",
|
||||
contents: Frameworks.Helpers.getDotNetToolTemplate().dependencies
|
||||
},
|
||||
{
|
||||
subfolder: a`tools`,
|
||||
contents: [{
|
||||
subfolder: a`MsBuildGraphBuilder`,
|
||||
contents: [
|
||||
importFrom("BuildXL.Tools").MsBuildGraphBuilder.exe,
|
||||
]}
|
||||
]
|
||||
contents: [importFrom("BuildXL.Tools").MsBuildGraphBuilder.deployment]
|
||||
}
|
||||
],
|
||||
runtimeContentToSkip : [
|
||||
importFrom("System.Threading.Tasks.Dataflow").pkg
|
||||
]
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,6 +19,11 @@ namespace MsBuildGraphBuilderTool
|
|||
/// <param name="searchLocations">A collection of full paths to directories, representing search locations on disk</param>
|
||||
/// <param name="failureReason">On failure, the reason for why the assemblies were not found</param>
|
||||
/// <param name="locatedAssemblyPaths">A dictionary from assembly names to paths to the required assemblies that were found. May not be complete if the invocation failed.</param>
|
||||
bool TryLoadMsBuildAssemblies(IEnumerable<string> searchLocations, GraphBuilderReporter reporter, out string failureReason, out IReadOnlyDictionary<string, string> locatedAssemblyPaths, out string locatedMsBuildExePath);
|
||||
bool TryLoadMsBuildAssemblies(
|
||||
IEnumerable<string> searchLocations,
|
||||
GraphBuilderReporter reporter,
|
||||
out string failureReason,
|
||||
out IReadOnlyDictionary<string, string> locatedAssemblyPaths,
|
||||
out string locatedMsBuildExePath);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Microsoft.Build.Tasks;
|
||||
|
||||
namespace MsBuildGraphBuilderTool
|
||||
{
|
||||
|
@ -31,12 +32,29 @@ namespace MsBuildGraphBuilderTool
|
|||
private const string SystemCollectionsImmutable = "System.Collections.Immutable.dll";
|
||||
private const string SystemThreadingDataflow = "System.Threading.Tasks.Dataflow.dll";
|
||||
|
||||
// MsBuild.exe is not a required to be loaded but is required to be found
|
||||
private const string MsBuildExe = "MsBuild.exe";
|
||||
// MsBuild is not a required to be loaded but is required to be found
|
||||
// Under DotNetCore there is not an msbuild.exe but a msbuild.dll
|
||||
private string m_msbuild;
|
||||
|
||||
private static readonly string[] s_assemblyNamesToLoad = new[]
|
||||
private readonly string[] m_assemblyNamesToLoad;
|
||||
|
||||
/// <summary>
|
||||
/// The expected public token for each required assembly
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, string> m_assemblyPublicTokens;
|
||||
|
||||
private static ResolveEventHandler s_msBuildHandler;
|
||||
|
||||
// Assembly resolution is multi-threaded
|
||||
private readonly ConcurrentDictionary<string, Assembly> m_loadedAssemblies;
|
||||
|
||||
public MsBuildAssemblyLoader(bool msBuildRuntimeIsDotNetCore)
|
||||
{
|
||||
m_msbuild = msBuildRuntimeIsDotNetCore ? "MSBuild.dll" : "MSBuild.exe";
|
||||
|
||||
m_assemblyNamesToLoad = new[]
|
||||
{
|
||||
MsBuildExe,
|
||||
m_msbuild,
|
||||
MicrosoftBuild,
|
||||
MicrosoftBuildFramework,
|
||||
MicrosoftBuildUtilities,
|
||||
|
@ -44,35 +62,26 @@ namespace MsBuildGraphBuilderTool
|
|||
SystemThreadingDataflow
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The expected public token for each required assembly
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, string> s_assemblyPublicTokens = new Dictionary<string, string>
|
||||
{
|
||||
[MsBuildExe] = MSBuildPublicKeyToken,
|
||||
[MicrosoftBuild] = MSBuildPublicKeyToken,
|
||||
[MicrosoftBuildFramework] = MSBuildPublicKeyToken,
|
||||
[MicrosoftBuildUtilities] = MSBuildPublicKeyToken,
|
||||
[SystemCollectionsImmutable] = DotNetPublicToken,
|
||||
[SystemThreadingDataflow] = DotNetPublicToken,
|
||||
};
|
||||
m_assemblyPublicTokens = new Dictionary<string, string>
|
||||
{
|
||||
[m_msbuild] = MSBuildPublicKeyToken,
|
||||
[MicrosoftBuild] = MSBuildPublicKeyToken,
|
||||
[MicrosoftBuildFramework] = MSBuildPublicKeyToken,
|
||||
[MicrosoftBuildUtilities] = MSBuildPublicKeyToken,
|
||||
[SystemCollectionsImmutable] = DotNetPublicToken,
|
||||
[SystemThreadingDataflow] = DotNetPublicToken,
|
||||
};
|
||||
|
||||
private static ResolveEventHandler s_msBuildHandler;
|
||||
|
||||
// Assembly resolution is multi-threaded
|
||||
private readonly ConcurrentDictionary<string, Assembly> m_loadedAssemblies = new ConcurrentDictionary<string, Assembly>(5, s_assemblyNamesToLoad.Length, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private static readonly Lazy<MsBuildAssemblyLoader> s_singleton = new Lazy<MsBuildAssemblyLoader>(() => new MsBuildAssemblyLoader());
|
||||
|
||||
private MsBuildAssemblyLoader()
|
||||
{
|
||||
m_loadedAssemblies = new ConcurrentDictionary<string, Assembly>(5, m_assemblyNamesToLoad.Length, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <nodoc/>
|
||||
public static MsBuildAssemblyLoader Instance => s_singleton.Value;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryLoadMsBuildAssemblies(IEnumerable<string> searchLocations, GraphBuilderReporter reporter, out string failureReason, out IReadOnlyDictionary<string, string> locatedAssemblyPaths, out string locatedMsBuildExePath)
|
||||
public bool TryLoadMsBuildAssemblies(
|
||||
IEnumerable<string> searchLocations,
|
||||
GraphBuilderReporter reporter,
|
||||
out string failureReason,
|
||||
out IReadOnlyDictionary<string, string> locatedAssemblyPaths,
|
||||
out string locatedMsBuildExePath)
|
||||
{
|
||||
// We want to make sure the provided locations actually contain all the needed assemblies
|
||||
if (!TryGetAssemblyLocations(searchLocations, reporter, out locatedAssemblyPaths, out IReadOnlyDictionary<string, string> missingAssemblyNames, out locatedMsBuildExePath))
|
||||
|
@ -104,7 +113,7 @@ namespace MsBuildGraphBuilderTool
|
|||
|
||||
// Automatically un-register the handler once all supported assemblies have been loaded.
|
||||
// No need to synchronize threads here, if the handler was already removed, nothing bad happens
|
||||
if (m_loadedAssemblies.Count == s_assemblyNamesToLoad.Length)
|
||||
if (m_loadedAssemblies.Count == m_assemblyNamesToLoad.Length)
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyResolve -= s_msBuildHandler;
|
||||
}
|
||||
|
@ -128,10 +137,10 @@ namespace MsBuildGraphBuilderTool
|
|||
out IReadOnlyDictionary</* assembly name */ string, /* not found reason */ string> missingAssemblies,
|
||||
out string locatedMsBuildExePath)
|
||||
{
|
||||
var foundAssemblies = new Dictionary<string, string>(s_assemblyNamesToLoad.Length, StringComparer.OrdinalIgnoreCase);
|
||||
var notFoundAssemblies = new Dictionary<string, string>(s_assemblyNamesToLoad.Length, StringComparer.OrdinalIgnoreCase);
|
||||
var foundAssemblies = new Dictionary<string, string>(m_assemblyNamesToLoad.Length, StringComparer.OrdinalIgnoreCase);
|
||||
var notFoundAssemblies = new Dictionary<string, string>(m_assemblyNamesToLoad.Length, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var assembliesToFind = new HashSet<string>(s_assemblyNamesToLoad, StringComparer.OrdinalIgnoreCase);
|
||||
var assembliesToFind = new HashSet<string>(m_assemblyNamesToLoad, StringComparer.OrdinalIgnoreCase);
|
||||
locatedMsBuildExePath = string.Empty;
|
||||
|
||||
foreach (var location in locations)
|
||||
|
@ -142,7 +151,7 @@ namespace MsBuildGraphBuilderTool
|
|||
try
|
||||
{
|
||||
var dlls = Directory.EnumerateFiles(location, "*.dll", SearchOption.TopDirectoryOnly);
|
||||
var msBuildExe = Directory.EnumerateFiles(location, MsBuildExe, SearchOption.TopDirectoryOnly);
|
||||
var msBuildExe = Directory.EnumerateFiles(location, m_msbuild, SearchOption.TopDirectoryOnly);
|
||||
|
||||
foreach (string fullPath in dlls.Union(msBuildExe))
|
||||
{
|
||||
|
@ -158,7 +167,7 @@ namespace MsBuildGraphBuilderTool
|
|||
|
||||
// If the file found is msbuild.exe, we update the associated location but don't store the path
|
||||
// in foundAssemblies, since this is not an assembly we really want to load
|
||||
if (file.Equals(MsBuildExe, StringComparison.OrdinalIgnoreCase))
|
||||
if (file.Equals(m_msbuild, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
locatedMsBuildExePath = fullPath;
|
||||
}
|
||||
|
@ -222,7 +231,7 @@ namespace MsBuildGraphBuilderTool
|
|||
return assembliesToFind.Count == 0;
|
||||
}
|
||||
|
||||
private static bool IsMsBuildAssembly(AssemblyName assemblyName, string fullPathToAssembly, out string notFoundReason)
|
||||
private bool IsMsBuildAssembly(AssemblyName assemblyName, string fullPathToAssembly, out string notFoundReason)
|
||||
{
|
||||
if (string.Equals($"{assemblyName.Name}.dll", MicrosoftBuild, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
@ -258,7 +267,7 @@ namespace MsBuildGraphBuilderTool
|
|||
sb.Append($"{b:x2}");
|
||||
}
|
||||
|
||||
if (s_assemblyPublicTokens.TryGetValue(assemblyName.Name, out string publicToken) && !sb.ToString().Equals(publicToken, StringComparison.OrdinalIgnoreCase))
|
||||
if (m_assemblyPublicTokens.TryGetValue(assemblyName.Name, out string publicToken) && !sb.ToString().Equals(publicToken, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
notFoundReason = $"The assembly under '{fullPathToAssembly}' is expected to contain public token '{publicToken}' but '{sb}' was found.";
|
||||
return false;
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace MsBuildGraphBuilderTool
|
|||
// The output file is used as a unique name to identify the pipe
|
||||
using (var reporter = new GraphBuilderReporter(Path.GetFileName(arguments.OutputPath)))
|
||||
{
|
||||
DoBuildGraphAndSerialize(MsBuildAssemblyLoader.Instance, reporter, arguments);
|
||||
DoBuildGraphAndSerialize(new MsBuildAssemblyLoader(arguments.MsBuildRuntimeIsDotNetCore), reporter, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,10 +6,11 @@ import * as BuildXLSdk from "Sdk.BuildXL";
|
|||
import {Transformer} from "Sdk.Transformers";
|
||||
import * as Deployment from "Sdk.Deployment";
|
||||
import * as MSBuild from "Sdk.Selfhost.MSBuild";
|
||||
import * as Frameworks from "Sdk.Managed.Frameworks";
|
||||
import * as Shared from "Sdk.Managed.Shared";
|
||||
|
||||
namespace MsBuildGraphBuilder {
|
||||
// TODO: We want this to be netstandard too but since Build Prediction is not, we have to keep it net47 only
|
||||
export declare const qualifier: MSBuild.MSBuildQualifier;
|
||||
export declare const qualifier: BuildXLSdk.DefaultQualifier;
|
||||
|
||||
@@public
|
||||
export const exe = BuildXLSdk.executable({
|
||||
|
@ -23,8 +24,8 @@ namespace MsBuildGraphBuilder {
|
|||
importFrom("BuildXL.Utilities").Collections.dll,
|
||||
importFrom("BuildXL.Utilities").Native.dll,
|
||||
importFrom("BuildXL.Utilities.Instrumentation").Common.dll,
|
||||
importFrom("System.Collections.Immutable").pkg,
|
||||
importFrom("DataflowForMSBuildRuntime").pkg,
|
||||
...addIf(BuildXLSdk.isFullFramework, importFrom("System.Collections.Immutable").pkg),
|
||||
...addIf(BuildXLSdk.isFullFramework, importFrom("System.Threading.Tasks.Dataflow").pkg),
|
||||
importFrom("Microsoft.Build.Prediction").pkg,
|
||||
NetFx.System.Threading.Tasks.dll,
|
||||
...MSBuild.msbuildReferences,
|
||||
|
@ -35,10 +36,30 @@ namespace MsBuildGraphBuilder {
|
|||
runtimeContentToSkip: [
|
||||
// don't add msbuild dlls because assembly resolvers will resolve msbuild from other MSBuild installations
|
||||
...MSBuild.msbuildReferences,
|
||||
importFrom("System.Threading.Tasks.Dataflow").pkg
|
||||
],
|
||||
internalsVisibleTo: [
|
||||
"Test.Tool.ProjectGraphBuilder",
|
||||
]
|
||||
});
|
||||
|
||||
@@public
|
||||
export const deployment : Deployment.Definition = { contents: [{
|
||||
subfolder: r`MsBuildGraphBuilder`,
|
||||
contents: [
|
||||
{
|
||||
subfolder: r`net472`,
|
||||
contents: [
|
||||
$.withQualifier(Object.merge<BuildXLSdk.DefaultQualifier>(qualifier, {targetFramework: "net472"}))
|
||||
.MsBuildGraphBuilder.exe
|
||||
]
|
||||
},
|
||||
{
|
||||
subfolder: r`dotnetcore`,
|
||||
contents: [
|
||||
$.withQualifier(Object.merge<BuildXLSdk.DefaultQualifier>(qualifier, {targetFramework: "netcoreapp3.0"}))
|
||||
.MsBuildGraphBuilder.exe
|
||||
]
|
||||
}
|
||||
]
|
||||
}]};
|
||||
}
|
||||
|
|
|
@ -5,12 +5,13 @@ using System;
|
|||
using System.Linq;
|
||||
using MsBuildGraphBuilderTool;
|
||||
using Test.BuildXL.TestUtilities.Xunit;
|
||||
using Test.ProjectGraphBuilder.Utilities;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Test.ProjectGraphBuilder
|
||||
{
|
||||
public class MsBuildAssemblyLoaderTests : XunitBuildXLTest
|
||||
public class MsBuildAssemblyLoaderTests : GraphBuilderToolTestBase
|
||||
{
|
||||
public MsBuildAssemblyLoaderTests(ITestOutputHelper output): base(output)
|
||||
{
|
||||
|
@ -21,8 +22,7 @@ namespace Test.ProjectGraphBuilder
|
|||
{
|
||||
using (var reporter = new GraphBuilderReporter(Guid.NewGuid().ToString()))
|
||||
{
|
||||
var assemblyLoader = MsBuildAssemblyLoader.Instance;
|
||||
var succeed = assemblyLoader.TryLoadMsBuildAssemblies(
|
||||
var succeed = AssemblyLoader.TryLoadMsBuildAssemblies(
|
||||
// The test deployment dir should have all assemblies needed by the loader
|
||||
new [] {TestDeploymentDir},
|
||||
reporter,
|
||||
|
@ -44,8 +44,7 @@ namespace Test.ProjectGraphBuilder
|
|||
{
|
||||
using (var reporter = new GraphBuilderReporter(Guid.NewGuid().ToString()))
|
||||
{
|
||||
var assemblyLoader = MsBuildAssemblyLoader.Instance;
|
||||
var succeed = assemblyLoader.TryLoadMsBuildAssemblies(
|
||||
var succeed = AssemblyLoader.TryLoadMsBuildAssemblies(
|
||||
// An empty location should result in not finding any of the required assemblies
|
||||
new string[] {},
|
||||
reporter,
|
||||
|
|
|
@ -14,7 +14,7 @@ using Xunit.Abstractions;
|
|||
|
||||
namespace Test.ProjectGraphBuilder
|
||||
{
|
||||
public class MsBuildGraphConstructionTests : TemporaryStorageTestBase
|
||||
public class MsBuildGraphConstructionTests : GraphBuilderToolTestBase
|
||||
{
|
||||
private readonly MsBuildProjectBuilder m_builder;
|
||||
|
||||
|
@ -233,14 +233,13 @@ namespace Test.ProjectGraphBuilder
|
|||
{
|
||||
string outputFile = Path.Combine(TemporaryDirectory, Guid.NewGuid().ToString());
|
||||
|
||||
var arguments = new MSBuildGraphBuilderArguments(
|
||||
projectEntryPoints,
|
||||
outputFile,
|
||||
globalProperties: GlobalProperties.Empty,
|
||||
mSBuildSearchLocations: new[] {TestDeploymentDir},
|
||||
entryPointTargets: new string[0],
|
||||
requestedQualifiers: new GlobalProperties[] { GlobalProperties.Empty },
|
||||
allowProjectsWithoutTargetProtocol: true);
|
||||
var arguments = GetStandardBuilderArguments(
|
||||
projectEntryPoints,
|
||||
outputFile,
|
||||
GlobalProperties.Empty,
|
||||
new string[0],
|
||||
new GlobalProperties[] { GlobalProperties.Empty },
|
||||
allowProjectsWithoutTargetProtocol: true);
|
||||
|
||||
return BuildGraphAndDeserialize(arguments);
|
||||
|
||||
|
@ -249,14 +248,14 @@ namespace Test.ProjectGraphBuilder
|
|||
private MSBuildGraphBuilderArguments CreateBuilderArguments(string entryPointPath, GlobalProperties[] requestedQualifiers = null, GlobalProperties globalProperties = null, bool allowProjectsWithoutTargetProtocol = true)
|
||||
{
|
||||
string outputFile = Path.Combine(TemporaryDirectory, Guid.NewGuid().ToString());
|
||||
var arguments = new MSBuildGraphBuilderArguments(
|
||||
var arguments = GetStandardBuilderArguments(
|
||||
new string[] { entryPointPath },
|
||||
outputFile,
|
||||
globalProperties: globalProperties ?? GlobalProperties.Empty,
|
||||
mSBuildSearchLocations: new[] { TestDeploymentDir },
|
||||
entryPointTargets: new string[0],
|
||||
requestedQualifiers: requestedQualifiers ?? new GlobalProperties[] { GlobalProperties.Empty },
|
||||
allowProjectsWithoutTargetProtocol: allowProjectsWithoutTargetProtocol);
|
||||
|
||||
return arguments;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace Test.ProjectGraphBuilder
|
|||
/// <summary>
|
||||
/// Tests related to the decorations associated to the project graph (e.g. failures, location of assemblies, etc.)
|
||||
/// </summary>
|
||||
public class MsBuildGraphDecorationTests : TemporaryStorageTestBase
|
||||
public class MsBuildGraphDecorationTests : GraphBuilderToolTestBase
|
||||
{
|
||||
public MsBuildGraphDecorationTests(ITestOutputHelper output): base(output)
|
||||
{
|
||||
|
@ -56,13 +56,13 @@ namespace Test.ProjectGraphBuilder
|
|||
// We expect the result to succeed
|
||||
Assert.True(projectGraphWithPredictionsResult.Succeeded);
|
||||
// The locations for MSBuild.exe and its assemblies should be properly set
|
||||
Assert.Contains(TestDeploymentDir, projectGraphWithPredictionsResult.PathToMsBuildExe);
|
||||
Assert.Contains(TestDeploymentDir, projectGraphWithPredictionsResult.PathToMsBuild);
|
||||
Assert.All(projectGraphWithPredictionsResult.MsBuildAssemblyPaths.Values, assemblyPath => assemblyPath.Contains(TestDeploymentDir));
|
||||
}
|
||||
|
||||
private ProjectGraphWithPredictionsResult<string> BuildGraphAndDeserialize(string projectEntryPointContent = null)
|
||||
{
|
||||
return BuildGraphAndDeserialize(MsBuildAssemblyLoader.Instance, projectEntryPointContent);
|
||||
return BuildGraphAndDeserialize(AssemblyLoader, projectEntryPointContent);
|
||||
}
|
||||
|
||||
private ProjectGraphWithPredictionsResult<string> BuildGraphAndDeserialize(IMsBuildAssemblyLoader assemblyLoader, string projectEntryPointContent = null)
|
||||
|
@ -77,11 +77,10 @@ namespace Test.ProjectGraphBuilder
|
|||
|
||||
using (var reporter = new GraphBuilderReporter(Guid.NewGuid().ToString()))
|
||||
{
|
||||
var arguments = new MSBuildGraphBuilderArguments(
|
||||
var arguments = GetStandardBuilderArguments(
|
||||
new[] { entryPoint },
|
||||
outputFile,
|
||||
globalProperties: GlobalProperties.Empty,
|
||||
mSBuildSearchLocations: new string[] {TestDeploymentDir},
|
||||
entryPointTargets: new string[0],
|
||||
requestedQualifiers: new GlobalProperties[] { GlobalProperties.Empty},
|
||||
allowProjectsWithoutTargetProtocol: false);
|
||||
|
|
|
@ -8,14 +8,13 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using BuildXL.FrontEnd.MsBuild.Serialization;
|
||||
using MsBuildGraphBuilderTool;
|
||||
using Test.BuildXL.TestUtilities.Xunit;
|
||||
using Test.ProjectGraphBuilder.Utilities;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Test.ProjectGraphBuilder
|
||||
{
|
||||
public class MsBuildGraphProgressTests : TemporaryStorageTestBase
|
||||
public class MsBuildGraphProgressTests : GraphBuilderToolTestBase
|
||||
{
|
||||
private readonly string m_entryPoint;
|
||||
|
||||
|
@ -69,16 +68,15 @@ namespace Test.ProjectGraphBuilder
|
|||
private bool BuildAndReport(GraphBuilderReporter reporter, out string failure)
|
||||
{
|
||||
string outputFile = Path.Combine(TemporaryDirectory, Guid.NewGuid().ToString());
|
||||
var arguments = new MSBuildGraphBuilderArguments(
|
||||
var arguments = GetStandardBuilderArguments(
|
||||
new[] { m_entryPoint },
|
||||
outputFile,
|
||||
globalProperties: GlobalProperties.Empty,
|
||||
mSBuildSearchLocations: new[] {TestDeploymentDir},
|
||||
entryPointTargets: new string[0],
|
||||
requestedQualifiers: new GlobalProperties[] { GlobalProperties.Empty },
|
||||
allowProjectsWithoutTargetProtocol: false);
|
||||
|
||||
MsBuildGraphBuilder.BuildGraphAndSerializeForTesting(MsBuildAssemblyLoader.Instance, reporter, arguments);
|
||||
MsBuildGraphBuilder.BuildGraphAndSerializeForTesting(AssemblyLoader, reporter, arguments);
|
||||
var result = SimpleDeserializer.Instance.DeserializeGraph(outputFile);
|
||||
|
||||
failure = string.Empty;
|
||||
|
@ -117,6 +115,5 @@ namespace Test.ProjectGraphBuilder
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ namespace Test.ProjectGraphBuilder
|
|||
/// <summary>
|
||||
/// Makes sure that project predictions are plumbed through and serialized into the project graph. The actual predictions are not tested here.
|
||||
/// </summary>
|
||||
public class MsBuildGraphProjectPredictionTests : TemporaryStorageTestBase
|
||||
public class MsBuildGraphProjectPredictionTests : GraphBuilderToolTestBase
|
||||
{
|
||||
public MsBuildGraphProjectPredictionTests(ITestOutputHelper output): base(output)
|
||||
{
|
||||
|
@ -44,11 +44,10 @@ namespace Test.ProjectGraphBuilder
|
|||
");
|
||||
|
||||
MsBuildGraphBuilder.BuildGraphAndSerialize(
|
||||
new MSBuildGraphBuilderArguments(
|
||||
GetStandardBuilderArguments(
|
||||
new[] { entryPoint },
|
||||
outputFile,
|
||||
globalProperties: GlobalProperties.Empty,
|
||||
mSBuildSearchLocations: new[] { TestDeploymentDir },
|
||||
entryPointTargets: new string[0],
|
||||
requestedQualifiers: new GlobalProperties[] { GlobalProperties.Empty },
|
||||
allowProjectsWithoutTargetProtocol: false));
|
||||
|
@ -72,17 +71,16 @@ namespace Test.ProjectGraphBuilder
|
|||
|
||||
using (var reporter = new GraphBuilderReporter(Guid.NewGuid().ToString()))
|
||||
{
|
||||
var arguments = new MSBuildGraphBuilderArguments(
|
||||
var arguments = GetStandardBuilderArguments(
|
||||
new[] { entryPoint },
|
||||
outputFile,
|
||||
globalProperties: GlobalProperties.Empty,
|
||||
mSBuildSearchLocations: new[] { TestDeploymentDir },
|
||||
entryPointTargets: new string[0],
|
||||
requestedQualifiers: new GlobalProperties[] { GlobalProperties.Empty },
|
||||
allowProjectsWithoutTargetProtocol: false);
|
||||
|
||||
MsBuildGraphBuilder.BuildGraphAndSerializeForTesting(
|
||||
MsBuildAssemblyLoader.Instance,
|
||||
AssemblyLoader,
|
||||
reporter,
|
||||
arguments,
|
||||
new IProjectPredictor[] { new ThrowOnPredictionPredictor() });
|
||||
|
|
|
@ -68,7 +68,7 @@ namespace Test.ProjectGraphBuilder
|
|||
var predictionFailures = new ConcurrentQueue<(string predictorName, string failure)>();
|
||||
var collector = new MsBuildPredictionCollector(inputFilePredictions, outputFolderPredictions, predictionFailures);
|
||||
|
||||
collector.AddInputFile("!@#$%^&*()", TemporaryDirectory, "Mock");
|
||||
collector.AddInputFile("!@#$%^&*()\0", TemporaryDirectory, "Mock");
|
||||
|
||||
Assert.Equal(0, inputFilePredictions.Count);
|
||||
|
||||
|
@ -76,7 +76,7 @@ namespace Test.ProjectGraphBuilder
|
|||
|
||||
Assert.Equal(1, predictionFailures.Count);
|
||||
Assert.Equal("Mock", predictionFailures.Single().predictorName);
|
||||
Assert.Contains("!@#$%^&*()", predictionFailures.Single().failure);
|
||||
Assert.Contains("!@#$%^&*()\0", predictionFailures.Single().failure);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -160,7 +160,7 @@ namespace Test.ProjectGraphBuilder
|
|||
var predictionFailures = new ConcurrentQueue<(string predictorName, string failure)>();
|
||||
var collector = new MsBuildPredictionCollector(inputFilePredictions, outputFolderPredictions, predictionFailures);
|
||||
|
||||
collector.AddInputDirectory("!@#$%^&*()", TemporaryDirectory, "Mock");
|
||||
collector.AddInputDirectory("!@#$%^&*()\0", TemporaryDirectory, "Mock");
|
||||
|
||||
Assert.Equal(0, inputFilePredictions.Count);
|
||||
|
||||
|
@ -168,7 +168,7 @@ namespace Test.ProjectGraphBuilder
|
|||
|
||||
Assert.Equal(1, predictionFailures.Count);
|
||||
Assert.Equal("Mock", predictionFailures.Single().predictorName);
|
||||
Assert.Contains("!@#$%^&*()", predictionFailures.Single().failure);
|
||||
Assert.Contains("!@#$%^&*()\0", predictionFailures.Single().failure);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -222,7 +222,7 @@ namespace Test.ProjectGraphBuilder
|
|||
var predictionFailures = new ConcurrentQueue<(string predictorName, string failure)>();
|
||||
var collector = new MsBuildPredictionCollector(inputFilePredictions, outputFolderPredictions, predictionFailures);
|
||||
|
||||
collector.AddOutputFile("!@#$%^&*()", TemporaryDirectory, "Mock");
|
||||
collector.AddOutputFile("!@#$%^&*()\0", TemporaryDirectory, "Mock");
|
||||
|
||||
Assert.Equal(0, inputFilePredictions.Count);
|
||||
|
||||
|
@ -230,7 +230,7 @@ namespace Test.ProjectGraphBuilder
|
|||
|
||||
Assert.Equal(1, predictionFailures.Count);
|
||||
Assert.Equal("Mock", predictionFailures.Single().predictorName);
|
||||
Assert.Contains("!@#$%^&*()", predictionFailures.Single().failure);
|
||||
Assert.Contains("!@#$%^&*()\0", predictionFailures.Single().failure);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -282,7 +282,7 @@ namespace Test.ProjectGraphBuilder
|
|||
var predictionFailures = new ConcurrentQueue<(string predictorName, string failure)>();
|
||||
var collector = new MsBuildPredictionCollector(inputFilePredictions, outputFolderPredictions, predictionFailures);
|
||||
|
||||
collector.AddOutputDirectory("!@#$%^&*()", TemporaryDirectory, "Mock");
|
||||
collector.AddOutputDirectory("!@#$%^&*()\0", TemporaryDirectory, "Mock");
|
||||
|
||||
Assert.Equal(0, inputFilePredictions.Count);
|
||||
|
||||
|
|
|
@ -6,20 +6,15 @@ import * as MSBuild from "Sdk.Selfhost.MSBuild";
|
|||
|
||||
namespace Test.Tool.MsBuildGraphBuilder {
|
||||
|
||||
export declare const qualifier: MSBuild.MSBuildQualifier;
|
||||
|
||||
// If the current qualifier is full framework, this tool has to be built with 472
|
||||
const msBuildGraphBuilderReference : Managed.Assembly =
|
||||
importFrom("BuildXL.Tools").MsBuildGraphBuilder.withQualifier(to472(qualifier)).exe;
|
||||
export declare const qualifier: BuildXLSdk.DefaultQualifier;
|
||||
|
||||
@@public
|
||||
export const dll = BuildXLSdk.test({
|
||||
assemblyName: "Test.Tool.ProjectGraphBuilder",
|
||||
sources: globR(d`.`, "*.cs"),
|
||||
// TODO: QTest
|
||||
testFramework: importFrom("Sdk.Managed.Testing.XUnit").framework,
|
||||
references:[
|
||||
msBuildGraphBuilderReference,
|
||||
importFrom("BuildXL.Tools").MsBuildGraphBuilder.exe,
|
||||
importFrom("Microsoft.Build.Prediction").pkg,
|
||||
importFrom("Newtonsoft.Json").pkg,
|
||||
importFrom("BuildXL.FrontEnd").MsBuild.Serialization.dll,
|
||||
|
@ -29,12 +24,8 @@ namespace Test.Tool.MsBuildGraphBuilder {
|
|||
...MSBuild.msbuildRuntimeContent,
|
||||
...MSBuild.msbuildReferences,
|
||||
],
|
||||
runtimeContentToSkip : [
|
||||
runtimeContentToSkip: [
|
||||
importFrom("System.Threading.Tasks.Dataflow").pkg
|
||||
]
|
||||
});
|
||||
|
||||
function to472(aQualifier: (typeof qualifier)) : (typeof qualifier) & {targetFramework: "net472"} {
|
||||
return Object.merge<(typeof qualifier) & {targetFramework: "net472"}>(aQualifier, {targetFramework: "net472"});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using BuildXL.FrontEnd.MsBuild.Serialization;
|
||||
using MsBuildGraphBuilderTool;
|
||||
using Test.BuildXL.TestUtilities.Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Test.ProjectGraphBuilder.Utilities
|
||||
{
|
||||
public abstract class GraphBuilderToolTestBase : TemporaryStorageTestBase
|
||||
{
|
||||
/// <nodoc/>
|
||||
public GraphBuilderToolTestBase(ITestOutputHelper output) : base(output) {}
|
||||
|
||||
#if FEATURE_CORECLR
|
||||
/// <nodoc/>
|
||||
protected bool RunningUnderDotNetCore => true;
|
||||
#else
|
||||
/// <nodoc/>
|
||||
protected bool RunningUnderDotNetCore => false;
|
||||
#endif
|
||||
/// <nodoc/>
|
||||
protected MsBuildAssemblyLoader AssemblyLoader => new MsBuildAssemblyLoader(RunningUnderDotNetCore);
|
||||
|
||||
/// <nodoc/>
|
||||
protected MSBuildGraphBuilderArguments GetStandardBuilderArguments(
|
||||
IReadOnlyCollection<string> projectsToParse,
|
||||
string outputFile,
|
||||
GlobalProperties globalProperties,
|
||||
IReadOnlyCollection<string> entryPointTargets,
|
||||
IReadOnlyCollection<GlobalProperties> requestedQualifiers,
|
||||
bool allowProjectsWithoutTargetProtocol)
|
||||
{
|
||||
return new MSBuildGraphBuilderArguments(
|
||||
projectsToParse,
|
||||
outputFile,
|
||||
globalProperties,
|
||||
mSBuildSearchLocations: new[] {TestDeploymentDir},
|
||||
entryPointTargets,
|
||||
requestedQualifiers,
|
||||
allowProjectsWithoutTargetProtocol,
|
||||
RunningUnderDotNetCore);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,6 +56,26 @@ namespace BuildXL.Utilities.Configuration
|
|||
/// </remarks>
|
||||
IReadOnlyList<DirectoryArtifact> MsBuildSearchLocations { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use the full framework or dotnet core version of MSBuild.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Selected runtime is used both for build evaluation and execution.
|
||||
/// Default is full framework.
|
||||
/// Observe that using the full framework version means that msbuild.exe is expected to be found in msbuildSearchLocations
|
||||
/// (or PATH if not specified). If using the dotnet core version, the same logic applies but to msbuild.dll
|
||||
/// </remarks>
|
||||
string MsBuildRuntime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Collection of directories to search for dotnet.exe, when DotNetCore is specified as the msBuildRuntime.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If not specified, locations in %PATH% are used.
|
||||
/// Locations are traversed in specification order.
|
||||
/// </remarks>
|
||||
IReadOnlyList<DirectoryArtifact> DotNetSearchLocations { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional file paths for the projects or solutions that should be used to start parsing. These are relative
|
||||
/// paths with respect to the root traversal.
|
||||
|
@ -193,5 +213,14 @@ namespace BuildXL.Utilities.Configuration
|
|||
trackedEnv = trackedList;
|
||||
passthroughEnv = passthroughList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether MSBuildRuntime is DotNetCore.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Keep in sync with Public\Sdk\Public\Prelude\Prelude.Configuration.Resolvers.dsc
|
||||
/// If not specified, the default is full framework, so this function returns false in that case.
|
||||
/// </remarks>
|
||||
public static bool ShouldRunDotNetCoreMSBuild(this IMsBuildResolverSettings msBuildResolverSettings) => msBuildResolverSettings.MsBuildRuntime == "DotNetCore";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@ namespace BuildXL.Utilities.Configuration.Mutable
|
|||
UseLegacyProjectIsolation = resolverSettings.UseLegacyProjectIsolation;
|
||||
DoubleWritePolicy = resolverSettings.DoubleWritePolicy;
|
||||
AllowProjectsToNotSpecifyTargetProtocol = resolverSettings.AllowProjectsToNotSpecifyTargetProtocol;
|
||||
MsBuildRuntime = resolverSettings.MsBuildRuntime;
|
||||
DotNetSearchLocations = resolverSettings.DotNetSearchLocations;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -109,5 +111,11 @@ namespace BuildXL.Utilities.Configuration.Mutable
|
|||
|
||||
/// <inheritdoc/>
|
||||
public bool? AllowProjectsToNotSpecifyTargetProtocol { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string MsBuildRuntime { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IReadOnlyList<DirectoryArtifact> DotNetSearchLocations { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
37
config.dsc
37
config.dsc
|
@ -127,7 +127,6 @@ config({
|
|||
{ id: "System.Data.SQLite.Linq", version: "1.0.102.0" },
|
||||
{ id: "System.Reflection.Metadata", version: "1.6.0" },
|
||||
{ id: "System.Threading.Tasks.Dataflow", version: "4.9.0" },
|
||||
{ id: "System.Threading.Tasks.Dataflow", version: "4.5.24", alias: "DataflowForMSBuildRuntime"},
|
||||
|
||||
// Nuget
|
||||
{ id: "NuGet.Commandline", version: "4.7.1" },
|
||||
|
@ -370,7 +369,6 @@ config({
|
|||
{ id: "System.Security.Principal.Windows", version: "4.6.0-preview5.19224.8" },
|
||||
{ id: "System.Security.SecureString", version: "4.3.0" },
|
||||
{ id: "System.Text.Encoding", version: "4.3.0" },
|
||||
{ id: "System.Text.Encoding.CodePages", version: "4.3.0" },
|
||||
{ id: "System.Text.Encoding.Extensions", version: "4.3.0" },
|
||||
{ id: "System.Text.RegularExpressions", version: "4.3.0" },
|
||||
{ id: "System.Threading", version: "4.3.0" },
|
||||
|
@ -443,6 +441,9 @@ config({
|
|||
// Extra dependencies to make MSBuild work
|
||||
{ id: "Microsoft.VisualStudio.Setup.Configuration.Interop", version: "1.16.30"},
|
||||
{ id: "System.CodeDom", version: "4.4.0"},
|
||||
{ id: "System.Text.Encoding.CodePages", version: "4.5.1", dependentPackageIdsToSkip: ["System.Runtime.CompilerServices.Unsafe"]},
|
||||
{ id: "System.Threading.Tasks.Dataflow", version: "4.5.24", alias: "DataflowForMSBuild" },
|
||||
{ id: "Microsoft.NETCore.App", version: "2.1.0", alias: "Microsoft.NETCore.App.210" },
|
||||
|
||||
// Used for MSBuild input/output prediction
|
||||
{ id: "Microsoft.Build.Prediction", version: "0.3.0" },
|
||||
|
@ -481,6 +482,10 @@ config({
|
|||
|
||||
importFile(f`config.microsoftInternal.dsc`).resolver,
|
||||
|
||||
{
|
||||
kind: "SourceResolver",
|
||||
modules: [f`Public\Sdk\SelfHost\Libraries\Dotnet-Runtime-External\module.config.dsc`],
|
||||
},
|
||||
{
|
||||
kind: "Download",
|
||||
downloads: [
|
||||
|
@ -506,24 +511,42 @@ config({
|
|||
|
||||
// DotNet Core Runtime
|
||||
{
|
||||
moduleName: "DotNet-Runtime.win-x64",
|
||||
moduleName: "DotNet-Runtime.win-x64.3.0.0-preview5",
|
||||
url: "https://download.visualstudio.microsoft.com/download/pr/9459ede1-e223-40c7-a4c5-2409e789121a/46d4eb6067bda9f412a472f7286ffd94/dotnet-runtime-3.0.0-preview5-27626-15-win-x64.zip",
|
||||
hash: "VSO0:6DBFE7BC9FA24D33A46A3A0732164BD5A4F5984E8FCE091D305FA635CD876AA700",
|
||||
archiveType: "zip",
|
||||
},
|
||||
{
|
||||
moduleName: "DotNet-Runtime.osx-x64",
|
||||
moduleName: "DotNet-Runtime.osx-x64.3.0.0-preview5",
|
||||
url: "https://download.visualstudio.microsoft.com/download/pr/85024962-5dee-4f64-ab29-a903f3749f85/6178bfacc58f4d9a596b5e3facc767ab/dotnet-runtime-3.0.0-preview5-27626-15-osx-x64.tar.gz",
|
||||
hash: "VSO0:C6AB5808D30BFF857263BC467FE8D818F35486763F673F79CA5A758727CEF3A900",
|
||||
archiveType: "tgz",
|
||||
},
|
||||
{
|
||||
moduleName: "DotNet-Runtime.linux-x64",
|
||||
moduleName: "DotNet-Runtime.linux-x64.3.0.0-preview5",
|
||||
url: "https://download.visualstudio.microsoft.com/download/pr/f15ad9ab-7bd2-4ff5-87b6-b1a08f062ea2/6fdd314c16c17ba22934cd0ac6b4d343/dotnet-runtime-3.0.0-preview5-27626-15-linux-x64.tar.gz",
|
||||
hash: "VSO0:C6AB5808D30BFF857263BC467FE8D818F35486763F673F79CA5A758727CEF3A900",
|
||||
hash: "VSO0:00F83B929904F647BD8FB22361052BB347A1E5FA9A3A32A67EE1569DE443D92700",
|
||||
archiveType: "tgz",
|
||||
},
|
||||
// The following are needed for dotnet core MSBuild test deployments
|
||||
{
|
||||
moduleName: "DotNet-Runtime.win-x64.2.2.2",
|
||||
url: "https://download.visualstudio.microsoft.com/download/pr/b10d0a68-b720-48ae-bab8-4ac39bd1b5d3/f32b8b41dff5c1488c2b915a007fc4a6/dotnet-runtime-2.2.2-win-x64.zip",
|
||||
hash: "VSO0:6BBAE77F9BA0231C90ABD9EA720FF886E8613CE8EF29D8B657AF201E2982829600",
|
||||
archiveType: "zip",
|
||||
},
|
||||
{
|
||||
moduleName: "DotNet-Runtime.osx-x64.2.2.2",
|
||||
url: "https://download.visualstudio.microsoft.com/download/pr/d1f0dfb3-b6bd-42ae-895f-f149bf1d90ca/9b1fb91a9692fc31d6fc83e97caba4cd/dotnet-runtime-2.2.2-osx-x64.tar.gz",
|
||||
hash: "VSO0:88B2B6E8CEF711E108FDE529E781F555516634CD442B3503B712D22947F0788700",
|
||||
archiveType: "tgz",
|
||||
},
|
||||
{
|
||||
moduleName: "DotNet-Runtime.linux-x64.2.2.2",
|
||||
url: "https://download.visualstudio.microsoft.com/download/pr/97b97652-4f74-4866-b708-2e9b41064459/7c722daf1a80a89aa8c3dec9103c24fc/dotnet-runtime-2.2.2-linux-x64.tar.gz",
|
||||
hash: "VSO0:6E5172671364C65B06C9940468A62BAF70EE27392CB2CA8B2C8BFE058CCD088300",
|
||||
archiveType: "tgz",
|
||||
},
|
||||
|
||||
// NodeJs
|
||||
{
|
||||
moduleName: "NodeJs.win-x64",
|
||||
|
|
Загрузка…
Ссылка в новой задаче