我正在编写一个应用程序来评估(但不是构建) *.csproj和其他项目文件。
应用程序模拟MSBuild所做的事情。它使用由Microsoft.Build.dll实例公开的(有文档记录的)公共API,这些API安装在Visual文件夹中,例如:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\
C:\Program Files (x86)\Microsoft Visual Studio\2019\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\4.8@InstallationFolder)" />
<property name="MSBuildRuntimeVersion" value="4.0.30319" />
<property name="MSBuildFrameworkToolsPath" value="$(SystemRoot)\Microsoft.NET\Framework\v$(MSBuildRuntimeVersion)\" />
... etc ...这些条目定义了在计算*.csproj时设置的全局变量的值。
在dotnet/msbuild源代码中,我看到:
GetMSBuildSDKsPath()这样的函数是在IntrinsicFunctions类(在Microsoft.Build.Evaluation命名空间中)中定义的,它是一个internal static类。BuildEnvironmentHelper (在Microsoft.Build.Shared命名空间中),这也是一个internal类。在调用MSBuild时正确设置这些全局变量至关重要,例如,当调用ProjectCollection.LoadProject方法返回Project实例时(否则项目不会加载)。
设置这些变量的API是将它们通过globalProperties参数传递给ProjectCollection --但我不知道如何获取或计算这些属性的值,我应该设置这些属性。
我的问题是-- 如何读取这些变量(考虑到上面列出的类是内部的)?是否有一个公共API可以做到这一点?
如果有必要,我可以在MSBuild bin文件夹中运行我的应用程序,并/或复制MSBuild.exe.config文件。
发布于 2021-08-14 11:05:40
使用的方法:
MSBUILD_EXE_PATH环境变量BuildParametersGetToolset方法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 Studio\2017\Enterprise\MSBuild\15.0\Bin"},
{"Current" /*"16.0"*/, @"C:\Program Files (x86)\Microsoft Visual Studio\2019\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));
}
}https://stackoverflow.com/questions/68465375
复制相似问题