【问题标题】:How to generate files during build using msbuild如何在构建期间使用 msbuild 生成文件
【发布时间】:2015-09-19 15:40:40
【问题描述】:

有谁知道如何修改 csproj 文件以在构建期间生成代码文件而不实际引用文件?

类似的过程:

  • 创建文件,
  • 在构建期间动态引用临时文件
  • 编译后的程序集有其他成员,具体取决于构建期间创建的文件

这样做的目的是创建一种使用 roslyn 而不是使用 t4 模板生成代码文件的方法,一旦您尝试根据属性执行某些操作,使用起来非常尴尬。

因此我计划提供一种方法来使用特殊的 csharp 文件(以获得完整的语法支持)根据该特殊文件的内容以编程方式生成文件。

我花了几个星期在互联网上查找资源(主题为 msbuild),但直到现在我似乎没有使用正确的关键字。

这个对我来说是最有见地的一个: https://www.simple-talk.com/dotnet/.net-tools/extending-msbuild/

我的猜测是,为了我的目的,正确的构建目标应该是“BeforeCompile”,以便以某种方式使用自定义代码文件填充构建过程。

是否有人对我的问题有经验,或者知道处理该任务的任何特定资源?

我得到了它的解决方案:

<UsingTask TaskName="DynamicCodeGenerator.DynamicFileGeneratorTask" AssemblyFile="..\DynamicCodeGenerator\bin\Debug\DynamicCodeGenerator.dll" />
<Target Name="DynamicCodeGeneratorTarget" BeforeTargets="BeforeBuild;BeforeRebuild">
    <DynamicFileGeneratorTask>
        <Output ItemName="Generated" TaskParameter="GeneratedFilePaths" />
    </DynamicFileGeneratorTask>
    <ItemGroup>
        <Compile Include="@(Generated)" />
        <FileWrites Include="@(Generated)" />
        <!-- For clean to work properly -->
    </ItemGroup>
</Target>

不幸的是,我没有按照建议使用属性组覆盖

更新:这个链接也很有趣:https://github.com/firstfloorsoftware/xcc/blob/master/FirstFloor.Xcc/Targets/Xcc.targets

【问题讨论】:

  • BeforeTargets="BeforeBuild;BeforeRebuild" - 这是改变游戏规则的部分。

标签: msbuild


【解决方案1】:

生成代码文件可以通过msbuild taskmsbuild inline task来实现。生成正确的代码取决于您。您必须注意的一件事是创建输出项参数,以便将其附加到 @(Compile) 项。您可以使用 $(IntDir) 位置来定位新生成的文件,并将它们添加到 @(FileWrites) 项目组,以便 Clean 目标正常工作。

当你写完你的任务后,你必须像这样在你的项目中使用它:

<UsingTask TaskName="TaskTypeFullName" AssemblyFile="YourAssembly.dll"/>
<PropertyGroup>
<!-- Here you need to experiment with [Build/Compile/SomeOther]DependsOn property -->
    <BuildDependsOn>
        MyCodeGenerator;
        $(BuildDependsOn)
    </BuildDependsOn>
</PropertyGroup>

<Target Name="MyCodeGenerator">
    <YourTaskName>
        <Output ItemName="Generated" TaskParameter="GeneratedFiles" />
    </YourTaskName>
    <ItemGroup>
        <Compile Include="@(Generated)" /> 
        <FileWrites Include="@(Generated)" /> <!-- For clean to work properly -->
    </ItemGroup>
</Target>

【讨论】:

  • 不错!不久前我已经开始进入 UsingTask 方向,但我没有将它与您的 Output + Compile 声明结合起来。那应该做的工作。一旦我验证了这一点,我会检查+赞成你的答案。它当然看起来很有希望。感谢您的帮助
  • 另请注意,为了正确执行目标 - 您必须在导入项目特定目标(即 Microsoft.CSharp.targets)后声明属性 BuildDependsOn。跨度>
  • 我回家后会测试这个。从我读过的内容中,我可以猜到这应该是如何工作的,但还有一个确认问题:@(Generated) 支持像“subfolder1/file.cs;subfolder2/file.cs”这样的语法,并且取决于我根据生成的文件到 csproj 的相对路径(就像编译包含一样)?如果我做对了,则必须将文件复制到那里,因为它们将在构建周期的后期移动。对吗?
  • 是的。这完全取决于您在 @(Generated) 项目中放入的内容。一旦将其包含在编译项目中,它们将作为 Sources 参数传递给 Csc 任务。此外,物品支持wildcards
【解决方案2】:

我想使用 bash 脚本为在 Linux 上使用 dotnet core 的项目生成代码。这对我有用。感谢@stukselbax,我根据您的回答构建了这个。

  <Target Name="GenerateProtocolBuffers" BeforeTargets="BeforeBuild;BeforeRebuild">
    <Exec Command="./generatecode.sh" Outputs="proto/*.cs">
      <Output ItemName="Generated" TaskParameter="Outputs" />
    </Exec>
    <ItemGroup>
      <Compile Include="@(Generated)" />
      <FileWrites Include="@(Generated)" />
    </ItemGroup>
  </Target>

请注意,我用来生成代码的脚本称为 generatecode.sh。用你自己的替换它。

【讨论】:

  • 我最终选择使用 CoreCompile &lt;Target Name="PreBuild" BeforeTargets="CoreCompile"&gt;,而不是尝试使用输出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-12
相关资源
最近更新 更多