MSBuild自定义任务取决于另一个项目

时间:2016-11-08 22:46:30

标签: c# visual-studio-2015 msbuild csproj

我有一个奇怪的解决方案,我需要其中一个项目来“编译”另一个文件。

编译器(这里显示一个最小的例子)如下(MSBuild自定义任务):

public class MyCompileTask : Task
{
    [Required]
    public ITaskItem[] InputFiles { get; set; }

    [Output]
    public ITaskItem[] OutputFiles { get; set; }

    public override bool Execute()
    {
        var generatedFileNames = new List<string>();

        foreach (var inputFile in this.InputFiles)
        {
            var inputFileName = inputFile.ItemSpec;
            var outputFileName = Path.ChangeExtension(inputFileName, ".res.txt");

            var source = File.ReadAllText(inputFileName);
            var compiled = source.ToUpper();
            File.WriteAllText(outputFileName, compiled + "\n\n" + DateTime.Now);

            generatedFileNames.Add(outputFileName);
        }

        this.OutputFiles = generatedFileNames.Select(name => new TaskItem(name)).ToArray();

        return true;
    }
}

如您所见,它只会改变输入文件的内容。

这是项目A - “编译器”库。

项目B,现在是主应用程序,有一个文件“lorem.txt”需要“编译”成“lorem.res.txt”并作为EmbeddedResource放在B.exe / B.dll中。 / p>

在B.csproj中我添加了以下内容:

<PropertyGroup>
<CoreCompileDependsOn>$(CoreCompileDependsOn);InvokeMyCompile</CoreCompileDependsOn>
</PropertyGroup>
<UsingTask TaskName="MyCompiler.MyCompileTask" AssemblyFile="$(MSBuildProjectDirectory)\..\MyCompiler\bin\$(Configuration)\MyCompiler.dll" />
<Target Name="MyCompile" Inputs="lorem.txt" Outputs="lorem.res.txt">
  <MyCompileTask InputFiles="lorem.txt">
    <Output TaskParameter="OutputFiles" PropertyName="OutputFiles" />
  </MyCompileTask>
</Target>
<Target Name="InvokeMyCompile" Inputs="lorem.txt" Outputs="lorem.res.txt">
  <Exec Command="&quot;$(MSBuildBinPath)\MSBuild.exe&quot; /t:MyCompile &quot;$(ProjectDir)$(ProjectFileName)&quot;" />
</Target>

(2层目标和一个明确的msbuild.exe调用是一种解决方法to another problem。实际上,这个例子的大部分都是从那个Q中偷来的。)

最重要的部分是有效的,即当我更改lorem.txt和build时,lorem.res.txt会重新生成。

然而

  • 当lorem.res.txt被物理删除时,构建什么都不做(说它是最新的),直到我真正刷新VS中的项目。因此,MSBuild并不“知道”构建项目实际上需要lorem.res.txt。
  • 更重要的是,当我更改项目A中的任何内容时,项目B会重新编译,但不会重新运行编译lorem.txt - &gt; lorem.res.txt。所以MSBuild并不“知道”转换依赖于另一个项目。

如何在csproj文件中声明这些依赖项?

Bonus问题:如何将输出文件(lorem.res.txt)标记为生成的EmbeddedResource,这样我就不必在VS中跟踪它,但它仍然被放入程序集中?

1 个答案:

答案 0 :(得分:0)

  

•当物理删除lorem.res.txt时,构建什么也不做(说它是最新的),直到我真正刷新VS中的项目。因此,MSBuild并不“知道”构建项目实际上需要lorem.res.txt。

我创建了一个演示并在我身边重现了你的问题,你可以使用msbuild命令行来避免它。

  

•更重要的是,当我更改项目A中的任何内容时,项目B会重新编译,但不会重新运行编译lorem.txt - &gt; lorem.res.txt。所以MSBuild并不“知道”转换依赖于另一个项目。

因为自定义任务引用了DLL文件,所以在更改项目A中的任何内容时,需要重建项目以生成更新的DLL文件。

  

Bonus问题:如何将输出文件(lorem.res.txt)标记为生成的EmbeddedResource,这样我就不必在VS中跟踪它,但它仍然被放入程序集中?

您可以在BeforeBuild目标中添加自定义ItemGroup来实现它。

 <Target Name="BeforeBuild" DependsOnTargets="MyCompile">
    <ItemGroup>
      <Content Include="lorem.res.txt">
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      </Content>
    </ItemGroup>
  </Target>