MsBuild Target с несколькими выходами

Есть ли способ преодолеть целевые соответствия один-к-одному, когда у вас есть несколько выходов? Кажется, это возможно, но я не могу понять, как, учитывая, что я довольно новичок в MsBuild, я, вероятно, что-то упускаю.

Следующий фрагмент скрипта msbuild взят из документации Microsoft. Что я должен изменить, если у меня есть несколько папок для резервных копий? Итак, список @(BackupFolders), и я хотел бы сохранить пошаговое поведение сборки?

<Target Name="Backup" Inputs="@(Compile)"   
    Outputs="@(Compile->'$(BackupFolder)%(Identity).bak')">  
    <Copy SourceFiles="@(Compile)" DestinationFiles=  
        "@(Compile->'$(BackupFolder)%(Identity).bak')" />  
</Target>  

1 ответ

Решение

Прежде всего, атрибуты Inputs и Outputs на узле Target предназначены для инкрементных сборок. Они должны иметь одинаковое количество записей, чтобы msbuild понимал, какие элементы должны быть отфильтрованы при сборке. MSBuild проверяет, имеются ли выходные данные и являются ли они актуальными, и, если это так, соответствующий элемент ввода отфильтровывается из списка ввода. Если вас не интересует пошаговое построение, вы можете вообще пропустить этот механизм. Если входы и выходы не совпадают (или не присутствуют), msbuild всегда выполняет цель со всеми элементами, потому что не может решить, какие элементы ведут к какому выходу.

Во-вторых, эти атрибуты ожидают списка элементов. Это не должен быть один список, это может быть произвольный список. Так что совершенно справедливо расширить ваш пример так:

<Target Name="Backup" Inputs="@(Compile);@(Compile2)"   
  Outputs="@(Compile->'$(BackupFolder)%(Identity).bak');@(Compile2->'$(BackupFolder)%(Identity).bak')">  
  <Copy SourceFiles="@(Compile)" DestinationFiles=  
     "@(Compile->'$(BackupFolder)%(Identity).bak')" />  
  <Copy SourceFiles="@(Compile2)" DestinationFiles=  
     "@(Compile2->'$(BackupFolder)%(Identity).bak')" />  
</Target>

Но вы хотите скопировать одни и те же элементы в разные папки резервных копий, верно? Так что-то вроде этого должно сделать:

<Target Name="Backup">  
  <Copy SourceFiles="@(Compile)" DestinationFiles=  
      "@(Compile->'$(BackupFolder)%(Identity).bak')" />  
  <Copy SourceFiles="@(Compile)" DestinationFiles=  
      "@(Compile->'$(BackupFolder2)%(Identity).bak')" />  
</Target>

С двумя папками резервных копий, элемент может фактически быть обновленным в одной папке, но отсутствовать в другой. Вы можете определить его в качестве "основной" резервной папки и указать MSBuild использовать его в качестве ссылки для инкрементных сборок.

Редактировать: Для инкрементных сборок в двух местах, вероятно, самое простое решение - объединить две цели, обе построены постепенно:

<Target Name="Backup" DependsOnTargets="_Backup1;_Backup2">
</Target>

<Target Name="_Backup1" Inputs="@(Compile)"   
  Outputs="@(Compile->'$(BackupFolder)%(Identity).bak')">  
  <Copy SourceFiles="@(Compile)" DestinationFiles=  
     "@(Compile->'$(BackupFolder)%(Identity).bak')" />    
</Target>

<Target Name="_Backup2" Inputs="@(Compile)"   
  Outputs="@(Compile->'$(BackupFolder2)%(Identity).bak')">  
  <Copy SourceFiles="@(Compile)" DestinationFiles=  
     "@(Compile->'$(BackupFolder2)%(Identity).bak')" />  
</Target>
Другие вопросы по тегам