如何使用MSBuild在输出目录之间复制文件?

时间:2018-05-08 15:39:40

标签: visual-studio msbuild visual-studio-2017

我有一个C#库,它有一种在构建时生成输出的复杂方法,我无法将正确的输出复制到引用它的项目中。

解决方案结构

MySolution
├─ MyConsoleApp           (c# console)
│  └─ Program.cs
└─ MyNodeServices         (c# library)
   ├─ node_modules**
   ├─ NodeProgram
   │  ├─ build**
   │  │  ├─ tsCode.js**
   │  │  └─ tsCode.map**
   │  └─ src
   │     └─ tsCode.ts     (TypeScriptCompile)
   ├─ package.json
   ├─ tsconfig.json
   └─ CodeThatReferencesNodeProgram.cs

** indicates files are not included in project

在构建时,我希望 MyNodeServices NodeProgram 文件夹完全复制到输出目录(src以及build),然后复制 node_modules 进入 NodeProgram 。这将是我使用NodeServices时的执行上下文。

MyConsoleApp 引用 MyNodeServices ,我想将 MyNodeServices 中的 NodeProgram 目录复制到输出目录构建 MyConsoleApp

约束

  • MyNodeServices 将被多个项目引用,因此我希望避免将后构建副本添加到 MyConsoleApp 和其他引用项目。
  • 我不想在项目中的node_modules和NodeProgram / build中包含单个文件,因为内容是在构建时生成的。
  • 我不希望NodeProgram / src中的每个文件都在解决方案中列出两次。

我尝试了什么

将NodeProgram包含为内容

<TypeScriptCompile Include="NodeProgram\src\tsCode.ts">
<Content Include="$(ProjectDir)NodeProgram\**" />

这适用于将代码包含在MyConsoleApp的输出中,但.ts文件在解决方案资源管理器中显示两次。这也不涉及node_modules。

构建副本后

<Target Name="AfterBuild">
  <ItemGroup>
    <ProgramCode Include="$(ProjectDir)NodeProgram\**" />
    <NodeModules Include="$(ProjectDir)node_modules\**" />
  </ItemGroup>
  <MakeDir Directories="$(TargetDir)\NodeProgram" Condition=" !Exists('$(TargetDir\NodeProgram') " />
  <MakeDir Directories="$(TargetDir)\NodeProgram\node_modules" Condition=" !Exists('$(TargetDir\NodeProgram\node_modules') " />
  <Copy SourceFiles="@(ProgramCode)" DestinationFiles="@(ProgramCode->'$(TargetDir)\NodeProgram\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
  <Copy SourceFiles="@(NodeModules)" DestinationFiles="@(NodeModules->'$(TargetDir)\NodeProgram\node_modules\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
</Target>

这使我的解决方案保持干净并将正确的文件复制到输出目录,但之后似乎忽略了这些文件。如果我清理解决方案,则复制的文件夹将保留在输出目录中,并且不会将内容复制到引用项目。

问题

  • 有没有办法指定输出目录中哪些文件很重要?
  • 有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

我想出了一个似乎可以解决我的问题的解决方案。我已将以下内容添加到 MyNodeServices

的项目文件中
<!-- Specify the files to be included in the output directory -->
<ItemGroup>
  <NodeFile Include="NodePrograms\**">
    <InProject>false</InProject>
  </NodeFile>

  <NodeModule Include="node_modules\**">
    <InProject>false</InProject>
  </NodeModule>
</ItemGroup>


<!-- Copy files from the project directory into the output directory -->
<Target Name="BeforeBuild"
        Inputs="@(NodeFile);@(NodeModules)"
        Outputs="@(NodeFile->'$(OutputPath)%(RelativeDir)%(Filename)%(Extension)');@(NodeModule->'$(OutputPath)NodePrograms\%(RelativeDir)%(Filename)%(Extension)')">

  <Copy SourceFiles="@(NodeFile)"
        DestinationFiles="$(OutputPath)%(NodeFile.RelativeDir)%(NodeFile.Filename)%(NodeFile.Extension)" />

  <Copy SourceFiles="@(NodeModule)"
        DestinationFiles="$(OutputPath)NodePrograms\%(NodeModule.RelativeDir)%(NodeModule.Filename)%(NodeModule.Extension)" />

  <ItemGroup>
    <!-- Specify files that were written to the output directory so the clean task knows to remove them -->
    <FileWrites Include="@(NodeFile->'$(OutputPath)%(RelativeDir)%(Filename)%(Extension)')"/>
    <FileWrites Include="@(NodeModule->'$(OutputPath)NodePrograms\%(RelativeDir)%(Filename)%(Extension)')"/>
  </ItemGroup>

</Target>


<!-- Include the files from the output directory when other projects reference this -->
<Target Name="IncludeNodeFiles"
        BeforeTargets="GetCopyToOutputDirectoryItems">

  <ItemGroup>
    <OutputNodeFiles Include="@(NodeFile->'$(OutputPath)%(RelativeDir)%(Filename)%(Extension)')">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <TargetPath>%(RelativeDir)%(FileName)%(Extension)</TargetPath>
    </OutputNodeFiles>

    <OutputNodeModules Include="@(NodeModule->'$(OutputPath)NodePrograms\%(RelativeDir)%(Filename)%(Extension)')">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <TargetPath>NodePrograms\%(RelativeDir)%(FileName)%(Extension)</TargetPath>
    </OutputNodeModules>

    <AllItemsFullPathWithTargetPath Include="@(OutputNodeFiles->'%(FullPath)')"  />
    <AllItemsFullPathWithTargetPath Include="@(OutputNodeModules->'%(FullPath)')"  />
  </ItemGroup>
</Target>