什么 API 来获取或评估 MSBuild.exe.config 中定义的全局变量?
What API to get or evaluate the global variables defined in MSBuild.exe.config?
我正在编写一个应用程序来评估(但不是构建)*.csproj 和其他项目文件。
该应用程序模拟 MSBuild 的功能。它使用 Microsoft.Build.dll
实例公开的(记录的)public APIs,这些实例安装在 Visual Studio 文件夹中,例如:
C:\Program Files (x86)\Microsoft Visual Studio17\Enterprise\MSBuild.0\Bin\
C:\Program Files (x86)\Microsoft Visual Studio19\Enterprise\MSBuild\Current\Bin\
在这些目录中有一个 MSBuild.exe.config
文件,其中包含一个 msbuildToolsets
部分,如下所示:
<msbuildToolsets default="Current">
<toolset toolsVersion="Current">
<property name="MSBuildToolsPath" value="$([MSBuild]::GetCurrentToolsDirectory())" />
<property name="MSBuildToolsPath32" value="$([MSBuild]::GetToolsDirectory32())" />
<property name="MSBuildToolsPath64" value="$([MSBuild]::GetToolsDirectory64())" />
<property name="MSBuildSDKsPath" value="$([MSBuild]::GetMSBuildSDKsPath())" />
<property name="FrameworkSDKRoot" value="$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\NETFXSDK.8@InstallationFolder)" />
<property name="MSBuildRuntimeVersion" value="4.0.30319" />
<property name="MSBuildFrameworkToolsPath" value="$(SystemRoot)\Microsoft.NET\Framework\v$(MSBuildRuntimeVersion)\" />
... etc ...
这些条目定义了评估 *.csproj 时设置的全局变量的值。
在 the dotnet/msbuild source code 我看到了:
- 像
GetMSBuildSDKsPath()
这样的函数定义在IntrinsicFunctions
class(在Microsoft.Build.Evaluation
命名空间中),它是一个internal static
class.
- 这个函数的实现委托给了
BuildEnvironmentHelper
(在Microsoft.Build.Shared
命名空间),它也是一个internal
class.
在调用 MSBuild 时正确设置这些全局变量至关重要,例如在将 ProjectCollection.LoadProject
方法调用到 return 一个 Project
实例时(否则项目将无法加载).
设置这些变量的 API 是通过 globalProperties
参数将它们传递给 ProjectCollection
-- 但我不知道如何获取或评估这些变量的值我应该设置这些属性。
我的问题是——我如何读取这些变量(假定上面列出的 classes 是“内部的”)?有 public API 可以做到这一点吗?
如有必要,我可以 运行 我的应用程序在 MSBuild bin 文件夹中,and/or 复制 MSBuild.exe.config
文件。
使用方法:
- 设置
MSBUILD_EXE_PATH
环境变量
- 实例化一个
BuildParameters
- 调用其
GetToolset
方法
- 参数在工具集
Properties
中
目录路径(例如 Enterprise
)可能因机器而异。
为了更加稳健,您可以实施 运行 时间探测来发现它,而不是对其进行硬编码。
private readonly string _toolsPath;
private readonly string _toolsVersion;
public EvaluateCondition(string solutionPath)
{
var toolsets = new Dictionary<string, string>
{
{"2.0", @"C:\WINDOWS\Microsoft.Net\Framework\v2.0.50727"},
{"3.5", @"C:\WINDOWS\Microsoft.Net\Framework\v3.5"},
{"4.0", @"C:\WINDOWS\Microsoft.Net\Framework\v4.0.30319"},
{"15.0", @"C:\Program Files (x86)\Microsoft Visual Studio17\Enterprise\MSBuild.0\Bin"},
{"Current" /*"16.0"*/, @"C:\Program Files (x86)\Microsoft Visual Studio19\Enterprise\MSBuild\Current\Bin"}
};
// specify which version of the toolset we want to use
// this is a compile-time definition but could have been a function parameter
#if X2017
_toolsVersion = "15.0";
#endif
#if X2019
_toolsVersion = "Current";
#endif
var toolsPath = toolsets[_toolsVersion];
_toolsPath = toolsPath;
// Use BuildParameters to load the settings which are defined in the MSBuild.exe.config and which would be loaded
// if we specified ToolsetDefinitionLocations.ConfigurationFile as a ProjectCollection constructor parameter.
Environment.SetEnvironmentVariable("MSBUILD_EXE_PATH", CombineFullPath(toolsPath, "MSBuild.exe"));
var buildParameters = new BuildParameters();
var toolset = buildParameters.GetToolset(_toolsVersion);
var toolsetProperties = toolset.Properties;
GlobalProperties = new Dictionary<string, string>();
foreach (var kvp in toolsetProperties)
{
if (kvp.Key != kvp.Value.Name)
{
throw new ArgumentException();
}
GlobalProperties.Add(kvp.Key, kvp.Value.EvaluatedValue);
}
Environment.SetEnvironmentVariable("MSBuildExtensionsPath", GlobalProperties["MSBuildExtensionsPath"]);
Environment.SetEnvironmentVariable("MSBuildSDKsPath", GlobalProperties["MSBuildSDKsPath"]);
// QED: pass the global variables to the ProjectCollection
ProjectCollection = new ProjectCollection(GlobalProperties);
foreach (var kvp in toolsets)
{
// this sets $(MSBuildToolsPath)
ProjectCollection.AddToolset(new Toolset(kvp.Key, kvp.Value, ProjectCollection, string.Empty));
}
}
我正在编写一个应用程序来评估(但不是构建)*.csproj 和其他项目文件。
该应用程序模拟 MSBuild 的功能。它使用 Microsoft.Build.dll
实例公开的(记录的)public APIs,这些实例安装在 Visual Studio 文件夹中,例如:
C:\Program Files (x86)\Microsoft Visual Studio17\Enterprise\MSBuild.0\Bin\
C:\Program Files (x86)\Microsoft Visual Studio19\Enterprise\MSBuild\Current\Bin\
在这些目录中有一个 MSBuild.exe.config
文件,其中包含一个 msbuildToolsets
部分,如下所示:
<msbuildToolsets default="Current">
<toolset toolsVersion="Current">
<property name="MSBuildToolsPath" value="$([MSBuild]::GetCurrentToolsDirectory())" />
<property name="MSBuildToolsPath32" value="$([MSBuild]::GetToolsDirectory32())" />
<property name="MSBuildToolsPath64" value="$([MSBuild]::GetToolsDirectory64())" />
<property name="MSBuildSDKsPath" value="$([MSBuild]::GetMSBuildSDKsPath())" />
<property name="FrameworkSDKRoot" value="$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\NETFXSDK.8@InstallationFolder)" />
<property name="MSBuildRuntimeVersion" value="4.0.30319" />
<property name="MSBuildFrameworkToolsPath" value="$(SystemRoot)\Microsoft.NET\Framework\v$(MSBuildRuntimeVersion)\" />
... etc ...
这些条目定义了评估 *.csproj 时设置的全局变量的值。
在 the dotnet/msbuild source code 我看到了:
- 像
GetMSBuildSDKsPath()
这样的函数定义在IntrinsicFunctions
class(在Microsoft.Build.Evaluation
命名空间中),它是一个internal static
class. - 这个函数的实现委托给了
BuildEnvironmentHelper
(在Microsoft.Build.Shared
命名空间),它也是一个internal
class.
在调用 MSBuild 时正确设置这些全局变量至关重要,例如在将 ProjectCollection.LoadProject
方法调用到 return 一个 Project
实例时(否则项目将无法加载).
设置这些变量的 API 是通过 globalProperties
参数将它们传递给 ProjectCollection
-- 但我不知道如何获取或评估这些变量的值我应该设置这些属性。
我的问题是——我如何读取这些变量(假定上面列出的 classes 是“内部的”)?有 public API 可以做到这一点吗?
如有必要,我可以 运行 我的应用程序在 MSBuild bin 文件夹中,and/or 复制 MSBuild.exe.config
文件。
使用方法:
- 设置
MSBUILD_EXE_PATH
环境变量 - 实例化一个
BuildParameters
- 调用其
GetToolset
方法 - 参数在工具集
Properties
中
目录路径(例如 Enterprise
)可能因机器而异。
为了更加稳健,您可以实施 运行 时间探测来发现它,而不是对其进行硬编码。
private readonly string _toolsPath;
private readonly string _toolsVersion;
public EvaluateCondition(string solutionPath)
{
var toolsets = new Dictionary<string, string>
{
{"2.0", @"C:\WINDOWS\Microsoft.Net\Framework\v2.0.50727"},
{"3.5", @"C:\WINDOWS\Microsoft.Net\Framework\v3.5"},
{"4.0", @"C:\WINDOWS\Microsoft.Net\Framework\v4.0.30319"},
{"15.0", @"C:\Program Files (x86)\Microsoft Visual Studio17\Enterprise\MSBuild.0\Bin"},
{"Current" /*"16.0"*/, @"C:\Program Files (x86)\Microsoft Visual Studio19\Enterprise\MSBuild\Current\Bin"}
};
// specify which version of the toolset we want to use
// this is a compile-time definition but could have been a function parameter
#if X2017
_toolsVersion = "15.0";
#endif
#if X2019
_toolsVersion = "Current";
#endif
var toolsPath = toolsets[_toolsVersion];
_toolsPath = toolsPath;
// Use BuildParameters to load the settings which are defined in the MSBuild.exe.config and which would be loaded
// if we specified ToolsetDefinitionLocations.ConfigurationFile as a ProjectCollection constructor parameter.
Environment.SetEnvironmentVariable("MSBUILD_EXE_PATH", CombineFullPath(toolsPath, "MSBuild.exe"));
var buildParameters = new BuildParameters();
var toolset = buildParameters.GetToolset(_toolsVersion);
var toolsetProperties = toolset.Properties;
GlobalProperties = new Dictionary<string, string>();
foreach (var kvp in toolsetProperties)
{
if (kvp.Key != kvp.Value.Name)
{
throw new ArgumentException();
}
GlobalProperties.Add(kvp.Key, kvp.Value.EvaluatedValue);
}
Environment.SetEnvironmentVariable("MSBuildExtensionsPath", GlobalProperties["MSBuildExtensionsPath"]);
Environment.SetEnvironmentVariable("MSBuildSDKsPath", GlobalProperties["MSBuildSDKsPath"]);
// QED: pass the global variables to the ProjectCollection
ProjectCollection = new ProjectCollection(GlobalProperties);
foreach (var kvp in toolsets)
{
// this sets $(MSBuildToolsPath)
ProjectCollection.AddToolset(new Toolset(kvp.Key, kvp.Value, ProjectCollection, string.Empty));
}
}