msbuild $(SolutionDir)在运行msbuild / t:restore时错误地解析为c:\

时间:2017-10-02 13:26:48

标签: .net msbuild continuous-integration visual-studio-2017 .net-standard-2.0

我有 foo.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup Label="Globals">
            <ExtPath>$(SolutionDir)\WpfNetStandardSample\CustomProjectSystem\</ExtPath>
  </PropertyGroup>

  <Import Project="$(ExtPath)CustomProject.props" />

</Project>

从解决方案文件 bar.sln

引用

从我运行的CI服务器恢复我的nuget包

msbuild /t:restore bar.sln

我收到了错误

  

“C:\ Users \ phelan \ workspace \ bar \ bar.sln”(恢复目标)(1) - &gt;   “C:\ Users \用户费伦\工作空间\条\ FOO \ foo.csproj”   (_IsProjectRestoreSupported target)(11) - &gt;
  C:\ Users \ phelan \ workspace \ bar \ foo \ foo.csproj(7,3):错误   MSB4019:导入的项目   “C:\ WpfNetStandardSample \ CustomProjectSystem \ CustomProject.props”是   未找到。确认声明中的路径是   正确,并且该文件存在于磁盘上。

主要问题

SolutionDir 如何/为何解析为 c:\ 而不是解决方案文件所在的目录。

注释

  • 整个解决方案都是在visual studio中构建的。
  • 运行msbuild foo.sln构建整个解决方案(假设nuget包已全部恢复)
  • msbuild版本为15.3.409.57025
  • 解决方案是项目的混合,一些使用packages.config,一些使用PackageReference。一些使用PackageReference的项目是dotnetstandard库,一些是net461库
  • 关于如何恢复nuget包似乎有各种各样的建议
    • dotnet restore
    • nuget restore enter image description here
    • msbuild / t:restore
    • dotnet msbuild / t:restore foo.sln

我的混合设置类型的正确流程是什么?

用于重现错误的Github存储库

https://github.com/bradphelan/msbuildbug

2 个答案:

答案 0 :(得分:1)

这是因为对于解决方案的Restore目标,SolutionDir不会传递给生成的项目引用。

运行时可以看到:

MSBuildEmitSolution=1 dotnet msbuild /t:Restore

对于foo.sln,这将生成一个foo.sln.metaproj文件,其中包含解决方案格式的实际msbuild解释,以及添加的扩展(例如我们的15.0/SolutionFile/ImportAfter/Microsoft.NuGet.ImportAfter.targets)。

生成的Build目标包含以下内容:

  <Target Name="Build" Outputs="@(CollectedBuildOutput)">
    <MSBuild Projects="@(ProjectReference)" BuildInParallel="True" Properties="BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" SkipNonexistentProjects="%(ProjectReference.SkipNonexistentProjects)">
      <Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
    </MSBuild>
  </Target>

您可以看到这显式设置了SolutionDir和其他与解决方案相关的属性。这同样适用于解决方案中生成的众多其他目标。

然而,NuGet目标不会这样做(技术原因是它们共享相同的项目和解决方案的MSBuild代码)。在检查由nuget创建的<MSBuild>项时,它们不会设置这些属性,因此在评估期间它们在项目中不可用。

作为一种解决方法,我建议使用MSBuild 15的Directory.Build.props逻辑,该逻辑会将具有此名称的文件自动导入到使用公共props / targets的所有项目中。 (几乎所有项目类型)。

在此文件中,放置在解决方案目录或其应用的项目上方的任何目录中,您可以设置要在项目中使用的变量(ExtPath)或直接设置所需的公共属性:

<Project>
  <PropertyGroup>
    <ExtPath>$(MSBuildThisFileDirectory)</ExtPath>
    <VersionPrefix>1.2.3</VersionPrefix>
  </PropertyGroup>
  <Import Project="$(ExtPath)Some\other.props" />
</Project>

答案 1 :(得分:0)

这是解决方法而非解决方案。使用相对路径

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup Label="Globals">
            <ExtPath>..\WpfNetStandardSample\CustomProjectSystem\</ExtPath>
  </PropertyGroup>

  <Import Project="$(ExtPath)CustomProject.props" />

</Project>