2016-11-08 3 views
3

У меня есть странное решение, где мне нужен один из проектов для «компиляции» файлов в другом.MSBuild пользовательская задача в зависимости от другого проекта

Компилятор (показать здесь минимальный пример) выглядит следующим образом (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; 
    } 
} 

Как вы видите, это uppercases только содержание входных файлов.

Это был проект A - библиотека «компилятор».

Проект B, на данный момент основное приложение, имеет файл «lorem.txt», который должен быть «скомпилирован» в «lorem.res.txt» и помещен как EmbeddedResource в B.exe/B.dll.

В 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 и строю, lorem.res.txt восстанавливается.

Однако:

  • Когда lorem.res.txt физически удален, накопление ничего не делает (говорит, что это уточненный), пока я на самом деле обновить проект в VS. Таким образом, MSBuild не «знает», что для создания проекта на самом деле требуется lorem.res.txt.
  • Что еще более важно, когда я меняю что-либо в проекте A, проект B перекомпилирует, но не перезапускает компиляцию lorem.txt -> lorem.res.txt. Поэтому MSBuild не «знает», что преобразование зависит от другого проекта.

Как объявить эти зависимости в файле csproj?

Бонусный вопрос: как пометить выходной файл (lorem.res.txt) как сгенерированный EmbeddedResource, поэтому мне не нужно отслеживать его в VS, но он все еще помещается в сборку?

+0

Добавление MyCompiler.dll к входам может иметь дело с последней точкой. Кроме того, вместо использования CoreCompileDependsOn вы можете просто добавить * BeforeTargets = "Build" * к цели, поэтому выполнение не зависит от возможных других механизмов, определяющих, является ли проект актуальным или нет. – stijn

+0

Что вы подразумеваете под «Как объявить эти зависимости в файле csproj?» –

+0

Вы решаете проблему, если проблема все еще существует, пожалуйста, сообщите мне об этом. –

ответ

0

• Когда lorem.res.txt физически удален, сборка ничего не делает (говорит, что она актуальна), пока я не обновляю проект в VS. Таким образом, MSBuild не «знает», что для создания проекта на самом деле требуется lorem.res.txt.

Я создаю демоверсию и воспроизведу вашу проблему на своей стороне, вы можете использовать командную строку msbuild, чтобы избежать ее.

• Что еще более важно, когда я меняю что-либо в проекте A, проект B перекомпилирует, но не перезапускает компиляцию lorem.txt -> lorem.res.txt. Поэтому MSBuild не «знает», что преобразование зависит от другого проекта.

Поскольку ссылка на заказ задает файл DLL при изменении чего-либо в проекте A, вам необходимо перестроить проект для создания более нового DLL-файла.

Бонусный вопрос: как пометить выходной файл (lorem.res.txt) как сгенерированный EmbeddedResource, поэтому мне не нужно отслеживать его в VS, но он все еще помещается в сборку?

Вы можете добавить пользовательскую ItemGroup в цель BeforeBuild для ее достижения.

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