Перед прочтением этого ответа вы, вероятно, захотите посмотреть:
Старый способ расширения MSBuild и упомянутый в справочнике, который я имею, по сути, основан на переопределении пустых целей по умолчанию, поставляемых Microsoft.Новый способ, как указано во второй ссылке выше, состоит в том, чтобы определить собственную произвольную цель и использовать свойства «BeforeTargets» и «AfterTargets», чтобы заставить вашу цель запускаться до или после вашей целевой цели.
В моем конкретном случае мне требовалось, чтобы задача ANTLR Grammars выполнялась до цели CLCompile, которая фактически создает файлы C ++, поскольку задача ANTLR Grammars создает файлы .cpp.Следовательно, XML выглядит следующим образом:
<Project ...
<!-- Other things put in by VS2010 ... this is the bottom of the file -->
<UsingTask TaskName="ANTLR.MSBuild.AntlrGrammar"
AssemblyName = "ANTLR.MSBuild, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d50cc80512acc876" />
<Target Name="AntlrGrammars"
Inputs="Configuration.g"
Outputs="ConfigurationParser.h;ConfigurationParser.cpp;ConfigurationLexer.h;ConfigurationLexer.cpp"
BeforeTargets="ClCompile">
<AntlrGrammar
AntlrLocation="$(MSBuildProjectDirectory)\Antlr.jar"
Grammar="Configuration.g"
RenameToCpp="true" />
</Target>
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
Что касается того, почему он превосходит PreBuildEvent и / или PostBuildEvent;это достаточно умно, чтобы не перестраивать .cpps, когда сама грамматика не обновляется.Вы получите что-то вроде:
1>AntlrGrammars:
1>Skipping target "AntlrGrammars" because all output files are up-to-date with respect to the input files.
1>ClCompile:
1> All outputs are up-to-date.
1> All outputs are up-to-date.
Это также заставляет непрекращающиеся жалобы Visual Studio каждый раз, когда вы запускаете программу, что ей нужно пересобрать вещи, как это происходит с простыми шагами до и после сборки.
Надеюсь, это кому-нибудь поможет - у меня ушло на дерьмо, чтобы понять.