MSBuild 项可以使用目标设置的 属性 吗?

Can an MSBuild Item use a Property set by a Target?

我正在尝试使用 MSBuild 实现以下目标:我的主项目 (MyProject.csproj) 应该包括几个 Reference 项,但是其中一个 Reference 的路径是 SomeProperty 属性 的值,由 Target 设置。具体来说,SomeProperty 的值是使用 ReadLinesFromFileTask 从文件中解析出来的。

这里是MyProject.csproj的高层结构:

<Project>
  <Target Name="CreateSomeProperty">
    <!-- Tasks that ultimately set $(SomeProperty) by parsing a value with ReadLinesFromFileTask -->
  </Target>
  <ItemGroup>
    <Reference Include="$(SomeProperty)" />
    <!-- Other Reference items -->
  </ItemGroup>
</Project>

很遗憾,此设置无效。我在 VS 解决方案资源管理器中的 MyProjectDependencies 节点下看到了那些黄色小三角形,因为该项目正在寻找缺少字符的路径中的 DLL。同样,当我构建项目时,我得到了一堆 The type or namespace name could not be found 错误,即使我仍然在我的目标中看到 Message 任务的输出。据推测,CreatePathProperty 目标在执行阶段是 运行,在 Reference 项在评估阶段加载失败后。

有没有办法让这样的设置工作?我已经尝试在 Target 元素中设置 BeforeTargets="Build",并在 Project 元素中设置 InitialTargets="CreateSomeProperty",但似乎没有任何效果。任何帮助将不胜感激!

Can an MSBuild Item use a Property set by a Target?

是的,如果你在 .net framework project with old csproj format 并且你想要的是 VS2017 中支持的场景(仅在 VS2017 中进行了测试),我相信这是可能的。

提示:

通常 msbuild 在执行您的自定义目标之前读取 PropertiesItems。所以我们应该使用 BeforeTargets="BeforeResolveReferences" 之类的东西来确保在这种情况下正确的顺序是 custom target runs=>create the property=>msbuild reads the info about references and the property.

否则顺序(BeforeTargets="Build" 或什么时候顺序错误)应该是:Msbuild reads the info about references(now the property is not defined yet)=>the target runs and creates the property.

解法: 将此脚本添加到 xx.csproj.

的底部
  <!-- Make sure it executes before msbuild reads the ItemGroup above and loads the references -->
  <Target Name="MyTest" BeforeTargets="BeforeResolveReferences">
    <ItemGroup>
      <!-- Define a TestFile to represent the file I read -->
      <TestFile Include="D:\test.txt" />
    </ItemGroup>
    <!-- Pass the file to read to the ReadLinesFromFile task -->
    <ReadLinesFromFile File="@(TestFile)">
      <!--Create the Property that represents the normal hintpath(SomePath\DLLName.dll)-->
      <Output TaskParameter="Lines" PropertyName="HintPathFromFile" />
    </ReadLinesFromFile>
    <!-- Output the HintPath in output log to check if the path is right -->
    <Message Text="$(HintPathFromFile)" Importance="high" />
    <ItemGroup>
      <Reference Include="TestReference">
        <!--It actually equals:<HintPath>D:\AssemblyFolder\TestReference.dll</HintPath>-->
        <HintPath>$(HintPathFromFile)</HintPath>
      </Reference>
    </ItemGroup>
  </Target>

另外:

我用 test.txt 文件做了测试,其内容是:

我不确定你的文件的实际内容(和格式),但如果你的文件中只有像 D:\AssemblyFolder\ 这样的路径,你应该将 D:\AssemblyFolder\+YourAssemblyName.dll 传递给 <HintPath>元数据。导致带有 hintpathdefault reference 格式如下所示:

  <Reference Include="ClassLibrary1">
      <HintPath>path\ClassLibrary1.dll</HintPath>
  </Reference>

注意路径格式!希望我的回答对您有所帮助:)

在 msbuild 中,static 项目无法根据设计依赖于 dynamic 属性。

接受的答案提供了一个解决方法:使用动态项目,这自然可以依赖于动态属性。但是动态项不会显示在 IDE.

处理文件时,更 IDE 友好的方法是静态创建项目并在目标运行时更新它:

<!-- Static item definition -->
<ItemGroup>
  <SomeItem Include="item_file" />
</ItemGroup>
<Target Name="...">
  <!-- When the target runs, find the static item using Condition and change its properties -->
  <ItemGroup>
    <SomeItem Condition="'%(SomeItem.Identity)' == 'item_file'">
      <SomeProperty>New Value</SomeProperty>
    </SomeItem>
  </ItemGroup>
</Target>

还有一个未解决的 msbuild 问题 (#889) 以支持为此改进的语法:

<Target Name="...">
  <ItemGroup>
    <!-- Update has the same syntax as Include -->
    <SomeItem Update="item_file">
      <SomeProperty>New Value</SomeProperty>
    </SomeItem>
  </ItemGroup>
</Target>