Estendendo o processo de compilação com o MSBuild

O objetivo do artigo é falar um pouco sobre o MSBuild, mostrar quais são os destinos e tarefas no MSBuild, aprender a trabalhar com um arquivo .csproj e fornecer links úteis. Se você tem um título mais adequado para o artigo, terei prazer em discutir nos comentários.

Menu



Conceitos básicos ( Menu )


O MSBuild é projetado de tal maneira que a montagem do projeto é dividida em várias etapas.

O destino é um determinado estágio (evento) que ocorre durante a montagem de um projeto. Você pode usar destinos padrão ou definir seus próprios.

Tarefa é uma tarefa que pode ser executada em um determinado estágio. Você pode usar tarefas padrão ou criar suas próprias.

Cite a documentação de segmentação ( https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-targets ):
Os destinos agrupam tarefas em uma ordem específica e permitem que o processo de construção seja fatorado em unidades menores.
Por exemplo, um destino pode excluir todos os arquivos no diretório de saída para se preparar para a compilação, enquanto outro
compila as entradas para o projeto e as coloca no diretório vazio.

Ciclo de Vida da Construção do MSBuild ( Menu )


Para o MSBuild, a Microsoft definiu vários destinos padrão (nos arquivos Microsoft.Common.targets, Microsoft.CSharp.targets, etc.). Um grande número de destinos diferentes é definido, mas neste artigo não vamos nos aprofundar nisso em detalhes. Alguns destinos padrão (pedidos):

Lista de Alvos (Spoiler)
  • Beforerebuild
  • Limpo
  • Beforebuild
  • BuildOnlySettings
  • PrepareForBuild
  • PreBuildEvent
  • ResolveReferences
  • PrepareResources
  • ResolveKeySource
  • Compilar
  • UnmanagedUnregistration
  • GenerateSerializationAssemblies
  • CreateSatAssemblies
  • GenerateManifests
  • GetTargetPath
  • PrepareForRun
  • Registro não gerenciado
  • Incrementalclean
  • PostBuildEvent
  • Afterbuild
  • Afterrebuild


Os destinos BeforeBuild e AfterBuild são projetados especificamente para serem substituídos e podem ser usados. Não recomendo o uso dos demais alvos da lista para que nada quebre .

Para uma visão mais detalhada da lista de destinos, você pode usar a opção / pp: Graças a esse parâmetro, será gerado um arquivo no qual todas as importações serão incluídas (incluindo arquivos .targets). Você pode encontrar muitos alvos e variáveis ​​(obrigado aikixd pela dica).


Preparando o ambiente para exemplos ( Menu )


Para exemplos, você precisa:

  • Ambiente de Desenvolvimento Instalado do Visual Studio
  • Crie um projeto do tipo Aplicativo de Console chamado MSBuildExample
  • Abra a pasta do projeto e encontre o arquivo MSBuildExample.csproj lá
  • Abra o arquivo MSBuildExample.csproj no bloco de notas ou em outro editor

Em todos os exemplos deste artigo, você precisará editar o arquivo MSBuildExample.csproj. Cada exemplo envolve remover o código do exemplo anterior e adicionar um novo. O código deve ser adicionado no final do arquivo .csproj à última linha que contém a tag de fechamento do projeto.

imagem

Atenção! Em um arquivo .csproj, o caso é importante .
Para executar o exemplo, você deve executar a compilação no ambiente de desenvolvimento do Visual Studio. Para alguns exemplos, você precisará escolher uma configuração de solução.

imagem

O resultado será exibido na janela Saída no Visual Studio (abaixo). Caso contrário, abra-o nos itens de menu Exibir => Saída.

imagem


Segmentação no MSBuild ( Menu )


Por exemplo, usaremos a tarefa Mensagem , que exibirá informações na janela Saída no Visual Studio. Como mencionado anteriormente, existem destinos padrão BeforeBuild e AfterBuild, nós os usaremos. Para treinamento, leia a seção Preparando o ambiente para obter exemplos .

Exemplo de uso de destino (spoiler)
Código de exemplo:

<Target Name="AfterBuild"> <Message Text="AfterBuild event" Importance="high"></Message> </Target> <Target Name="BeforeBuild"> <Message Text="BeforeBuild event" Importance="high"></Message> </Target> 

Resultado da execução (desnecessário excluído):
...
Evento antes da construção
...
Evento Afterbuild
...


Como você pode ver, a tarefa Message foi executada, que exibia o texto que especificamos no momento do BeforeBuild e AfterBuild na janela Output no Visual Studio.
Ao definir um destino com o mesmo nome, ele é substituído!

Exemplo de reescrita de destino (spoiler)
Código de exemplo:

 <Target Name="BeforeBuild"> <Message Text="First message" Importance="high"></Message> </Target> <Target Name="BeforeBuild"> <Message Text="Second message" Importance="high"></Message> </Target> 

Resultado da execução (desnecessário excluído):
...
Segunda mensagem
...


Somente a segunda mensagem foi exibida, porque eles usaram destinos com o mesmo nome e foram substituídos pelo segundo valor.

Criando seu próprio destino MSBuild ( Menu )


Se os destinos BeforeBuild e AfterBuild não forem suficientes ou você desejar que as tarefas sejam executadas em outro estágio do ciclo de vida da montagem, você poderá definir seu próprio destino. Para esses propósitos, existem parâmetros BeforeTargets e AfterTargets.

Exemplo de definição de seus próprios destinos (spoiler)
Código de exemplo:

  <Target Name="BeforeBuild"> <Message Text="BeforeBuild event" Importance="high"></Message> </Target> <Target Name="MyCustomBeforeTarget" BeforeTargets="BeforeBuild"> <Message Text="MyCustomBeforeTarget event" Importance="high"></Message> </Target> <Target Name="MyCustomAfterTarget" AfterTargets="BeforeBuild"> <Message Text="MyCustomAfterTarget event" Importance="high"></Message> </Target> 

Resultado da execução (desnecessário excluído):
...
Evento MyCustomBeforeTarget
Evento antes da construção
Evento MyCustomAfterTarget
...


Dois destinos personalizados foram definidos - MyCustomBeforeTarget e MyCustomAfterTarget.
O destino MyCustomBeforeTarget é executado antes do destino BeforeBuild porque especificamos:

 BeforeTargets="BeforeBuild" 

O destino MyCustomAfterTarget é executado após o destino BeforeBuild porque especificamos:

 AfterTargets="BeforeBuild" 

Tarefas no MSBuild ( Menu )


Este artigo não discute como você pode escrever suas próprias tarefas, mas antes de escrevê- las, confira a lista de tarefas fornecidas pela Microsoft .

Vejamos alguns exemplos de uso de tarefas e macros.

Parâmetro de condição (spoiler)
O parâmetro Condition está presente em todas as tarefas. Cite a documentação docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-task-reference :
Uma expressão booleana que o mecanismo MSBuild usa para determinar se esta tarefa será executada.
Código de exemplo:

 <Target Name="BeforeBuild"> <Message Text="Current configuration is Debug" Condition="'$(Configuration)' == 'Debug'" Importance="high"></Message> <Message Text="Current configuration is Release" Condition="'$(Configuration)' == 'Release'" Importance="high"></Message> </Target> 

Se a solução de configuração Debug estiver selecionada, o resultado será semelhante a este (desnecessário excluído):
...
A configuração atual é Debug
...
Se a versão de configuração da solução for selecionada, o resultado será semelhante a este (desnecessário excluído):
...
A configuração atual é Release
...
Você pode encontrar informações sobre a macro $ (Configuração) e outras macros na seção sobre variáveis ​​e macros em .csproj .

Informações sobre a sintaxe das condições podem ser encontradas em https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-conditions

Definição de variável em csproj (spoiler)
No exemplo acima, temos um texto que pode ser unificado. Para evitar duplicação, colocaremos o texto da mensagem em uma variável separada.

Código de exemplo:

 <PropertyGroup> <MessageText>Current configuration is $(Configuration)</MessageText> </PropertyGroup> <Target Name="BeforeBuild"> <Message Text="$(MessageText)" Condition="'$(Configuration)' == 'Debug'" Importance="high"></Message> <Message Text="$(MessageText)" Condition="'$(Configuration)' == 'Release'" Importance="high"></Message> </Target> 

Para definir sua própria variável, use o elemento PropertyGroup .


Verificando a existência de um arquivo, emitindo um erro (spoiler)
Neste exemplo, fazemos uma tarefa que verifica se o arquivo App.Debug.config foi criado. Se não for criado, lançamos um erro. Em caso de erro, a compilação será interrompida e o erro será exibido como erros de compilação na janela Lista de Erros.
Usamos a tarefa Erro e o parâmetro de condição que já nos é familiar.

Código de exemplo:

 <Target Name="BeforeBuild"> <Error Condition="!Exists('App.Debug.config')" Text="File App.Debug.config not found"></Error> </Target> 

Resultado:
imagem

A cláusula Exists usa o caminho relativo da pasta na qual o arquivo .csproj está localizado. Para acessar a pasta acima da atual, use '../'. Se você precisar acessar a subpasta, use o formato '[DirectoryName] /App.Debug.config'.

Copiando arquivos (spoiler)
Neste exemplo, usaremos a tarefa Copiar . Usando a tarefa, copie o arquivo App.config para a pasta bin / [Configuration] / Config nos dois arquivos App.config e App.test.config.

Código de exemplo:

 <Target Name="BeforeBuild"> <Copy SourceFiles="App.config;App.config" DestinationFiles="$(OutputPath)/Test/App.config;$(OutputPath)/Test/App.test.config"></Copy> </Target> 

A propriedade SourceFiles é uma matriz de arquivos a serem baixados. Indique sem aspas, separado por ponto e vírgula.

A propriedade DestinationFiles é uma matriz de arquivos onde os arquivos serão copiados. Indique sem aspas, separado por ponto e vírgula.

Leia mais sobre a macro $ (OutputPath) na seção Variáveis ​​e macros em .csproj .

Variáveis ​​e macros em .csproj ( Menu )


Várias macros padrão podem ser usadas no arquivo .csproj, uma lista delas pode ser encontrada aqui https://msdn.microsoft.com/en-us/library/c02as0cs.aspx e aqui https://msdn.microsoft.com/en-us/ library / bb629394.aspx . Considere algumas macros úteis:

  • $ (MSBuildToolsPath) - indica o caminho para a pasta MSBuild. Por exemplo, C: \ Arquivos de Programas (x86) \ MSBuild \ 14.0 \ Bin. Ao combinar um caminho, use essa macro com uma barra. Por exemplo, $ (MSBuildToolsPath) \ Microsoft.Web.Publishing.Tasks.dll. Caso contrário, ele pode formar o caminho incorretamente e dar um erro que o arquivo não foi encontrado.
  • $ (OutputPath) - caminho relativo para a pasta de saída. Por exemplo, bin \ Stage. Use esta macro com uma barra, por exemplo, $ (OutputPath) \ $ (TargetFileName) .config.
  • $ (TargetFileName) - o nome do arquivo de saída com a extensão. Por exemplo, MSBuildExample.exe. A extensão e o formato do nome do arquivo de saída podem diferir dos diferentes tipos de projetos. Usando essa macro, você pode determinar com segurança qual será o nome do arquivo de configuração. Pode ser útil para transformações de configuração.
  • $ (Configuração) é o nome da configuração atual. Por exemplo, Liberar, Depurar
  • $ (IntermediateOutputPath) - caminho para a pasta obj. Por exemplo, obj \ Stage.

Para definir seus próprios parâmetros, use o PropertyGroup . Um exemplo de definição de sua própria variável pode ser encontrado na seção de tarefas no MSBuild .

Links ( Menu )


Source: https://habr.com/ru/post/pt414969/


All Articles