Olá pessoal, tudo certo?
No primeiro post dessa série mostrei alguns elementos fundamentais do MSBuild. Se você não sabe nada sobre esse assunto, por favor, considere dar uma conferida por lá.
Já sabemos que os arquivos .csproj são scripts para o MSBuild. Já sabemos, também, que o Visual Studio utiliza o arquivo .csproj e o MSBuild quando você “pressiona” F5. Hoje, vou tentar explicar um pouco da composição do conteúdo desse arquivo. Darei atenção a três tipos de elementos muito importantes: Tasks, Targets e Properties.
Depois de alguma introdução teórica, desenvolvo o post de hoje de forma prática. Espero que gostem.
Exemplos no GitHub
Todos os exemplos desenvolvidos nessa série estão disponíveis para download no GitHub. Se tiver interesse, acesse: https://github.com/ElemarJR/MSBuild101
Optei por não utilizar o Gist para postar os snippets por entender que você talvez deseje ter todos os arquivos, salvos em seu computador, em um único download.
Entendendo Tasks e Targets
O MSBuild tem dois elementos de execução: tasks e targets. Uma task é a menor unidade de trabalho que você pode encontrar dentro de um arquivo MSBuild e um Target é uma sequência de tasks. Tasks sempre estão definidas dentro de Targets.
Na pratica, você utiliza tasks para executar operações como:
-
copiar, mover, renomear, excluir arquivos;
-
compilar;
-
executar testes;
-
…
Ou seja, são as tasks que “fazem” o trabalho acontecer.
O MSBuild provê uma lista ampla de tasks.
No primeiro post dessa série, utilizamos a Task Message para imprimir um “Hello World” na tela. Entretanto, seu uso mais comum será enviar uma mensagem para algum logger que esteja “monitorando” nosso processo de build. No caso mais simples, nossas mensagens são impressas no Console.
Quando o MSBuild “aciona” uma task ele a provê com parâmetros que foram informamos nos atributos do nodo que configura a Task. A lista de atributos muda conforme o “tipo” de Task que estamos configurando. No caso da Task Message, sabemos que o atributo a ser “alimentado” chama-se Text.
Além de usar as Tasks providas no pacote do MSBuild, podemos utilizar Tasks desenvolvidas por teceiros. Também podemos construir Tasks sob-medida para nossas necessidades.
Targets são conjuntos de tasks. Pense em targets como “roteiros alternativos” de execução. Você pode construir quantas Targets (roteiros) forem necessárias. Por exemplo, você pode querer definir um target que apenas compila seu código e outro que, além de compilar, executa os testes e gera os pacotes de instalação. Considere o exemplo que segue:
1 <?xml version="1.0" encoding="utf-8"?> 2 <Project 3 xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 4 DefaultTarget="target1" 5 > 6 7 <Target Name="target1"> 8 <Message Text="Hello from Target1"/> 9 </Target> 10 11 <Target Name="target2"> 12 <Message Text="Hello from Target2"/> 13 </Target> 14 15 </Project>
Esse arquivo de configuração do msbuild possui dois targets: target1 e target2. Na linha 4, podemos observar o atributo DefaultTarget, que serve para definir qual será o target que deverá ser executado caso não isso não seja especificado na evocação do MSBuild.
Observe alguns exemplos de execução:
1 C:\git\MSBuild101>msbuild TwoTargets.proj /nologo 2 Build started 18/01/2011 17:04:58. 3 Project "C:\git\MSBuild101\TwoTargets.proj" on node 1 (default targets). 4 target1: 5 Hello from Target1 6 Done Building Project "C:\git\MSBuild101\TwoTargets.proj" (default targets). 7 8 9 Build succeeded. 10 0 Warning(s) 11 0 Error(s) 12 13 Time Elapsed 00:00:00.05
Observe, na linha 1, a chamada para o MSBuild. Observe que nenhum target foi especificado.
Agora, um exemplo evocando o target2. Observe:
1 C:\git\MSBuild101>msbuild TwoTargets.proj /t:target2 /nologo 2 Build started 18/01/2011 17:07:43. 3 Project "C:\git\MSBuild101\TwoTargets.proj" on node 1 (target2 target(s)). 4 target2: 5 Hello from Target2 6 Done Building Project "C:\git\MSBuild101\TwoTargets.proj" (target2 target(s)). 7 8 9 Build succeeded. 10 0 Warning(s) 11 0 Error(s) 12 13 Time Elapsed 00:00:00.04
Properties
Além das tasks e targets, há o conceito de propriedaes. Na prática, consiste de um dicionário chave-valor que podemos construir em nossos scripts de build.
Propriedades são sempre definidas dentro de um nodo PropertyGroup. O nome do nodo que define a chave que será utilizada para a propriedade, o valor do nodo é o valor da propriedade. Observe:
1 <?xml version="1.0" encoding="utf-8"?> 2 <Project 3 xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 4 DefaultTarget="build" 5 > 6 <PropertyGroup> 7 <Propriedade1>Essa é a propriedade 1</Propriedade1> 8 <Propriedade2>Essa é a propriedade 2</Propriedade2> 9 </PropertyGroup> 10 11 <Target Name="build"> 12 </Target> 13 </Project>
No exemplo foram definidas duas propriedades: Propriedade1 e Propriedade2.
Scripts MSBuild podem possuir diversos nodos PropertyGroup. Observe:
1 <?xml version="1.0" encoding="utf-8"?> 2 <Project 3 xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 4 DefaultTarget="build" 5 > 6 7 <PropertyGroup> 8 <Propriedade1>Essa é a propriedade 1</Propriedade1> 9 </PropertyGroup> 10 <PropertyGroup> 11 <Propriedade2>Essa é a propriedade 2</Propriedade2> 12 </PropertyGroup> 13 14 <Target Name="build"> 15 </Target> 16 </Project>
O resultado desse exemplo é identico ao anterior.
O valor das propriedades pode ser recuperado e utilizado em parâmetros para as Tasks. Observe:
1 <?xml version="1.0" encoding="utf-8"?> 2 <Project 3 xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 4 DefaultTarget="build" 5 > 6 7 <PropertyGroup> 8 <Name>Elemar Junior</Name> 9 </PropertyGroup> 10 11 <Target Name="build"> 12 <Message Text="Hello World, $(Name)!"/> 13 </Target> 14 15 </Project> 16
No exemplo, o valor da propriedade Name é recuperado na definição do parâmetro Text para a Task Message. Observe o resultado da execução desse script.
1 2 C:\git\MSBuild101>msbuild HelloWorldWithProperty.proj /nologo 3 Build started 18/01/2011 15:23:26. 4 Project "C:\git\MSBuild101\HelloWorldWithProperty.proj" on node 1 (default targ 5 ets). 6 build: 7 Hello World, Elemar Junior! 8 Done Building Project "C:\git\MSBuild101\HelloWorldWithProperty.proj" (default 9 targets). 10 11 12 Build succeeded. 13 0 Warning(s) 14 0 Error(s) 15 16 Time Elapsed 00:00:00.05
O valor de uma propriedade pode ser redefinido quantas vezes forem necessárias. Observe:
1 <?xml version="1.0" encoding="utf-8"?> 2 <Project 3 xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 4 DefaultTarget="build" 5 > 6 7 <PropertyGroup> 8 <Propriedade1>Essa é a propriedade 1</Propriedade1> 9 <Propriedade1>Essa é a propriedade 1 (redefinida)</Propriedade1> 10 </PropertyGroup> 11 12 <Target Name="build"> 13 <Message Text="$(Propriedade1)"/> 14 </Target> 15 16 </Project>
Observe a saída:
1 C:\git\MSBuild101>msbuild StaticPropertiesRedefined.proj /nologo 2 Build started 18/01/2011 17:29:41. 3 Project "C:\git\MSBuild101\StaticPropertiesRedefined.proj" on node 1 (default t 4 argets). 5 build: 6 Essa é a propriedade 1 (redefinida) 7 Done Building Project "C:\git\MSBuild101\StaticPropertiesRedefined.proj" (defau 8 lt targets). 9 10 11 Build succeeded. 12 0 Warning(s) 13 0 Error(s) 14 15 Time Elapsed 00:00:00.04
Outro aspecto é importante. Todas as definições de propriedade são carregadas antes de executar as tasks. Observe o código que segue:
1 <?xml version="1.0" encoding="utf-8"?> 2 <Project 3 xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 4 DefaultTarget="build" 5 > 6 7 <PropertyGroup> 8 <Propriedade1>Essa é a propriedade 1</Propriedade1> 9 </PropertyGroup> 10 11 <Target Name="build"> 12 <Message Text="$(Propriedade1)"/> 13 </Target> 14 15 <PropertyGroup> 16 <Propriedade1>Essa é a propriedade 1 (redefinida)</Propriedade1> 17 </PropertyGroup> 18 19 </Project>
O resultado da execução desse script é idêntica a anterior.
Reserved Properties
Além das propriedades que podemos definir em nossos scripts, podemos utilizar um conjunto extremamente rico de propriedades providas pelo ambiente do MSBuild. Aqui, não apresento a lista completa dessas propriedades (elas estão disponíveis no site do MSDN), nem explico seus propósitos pois acho que elas são compreensíveis pelo exemplo.
1 <?xml version="1.0" encoding="utf-8"?> 2 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 3 <Target Name="HelloWorld"> 4 <Message 5 Text= 6 "%24(MSBuildProjectDirectory)=$(MSBuildProjectDirectory)"/> 7 <Message 8 Text= 9 "%24(MSBuildProjectDirectoryNoRoot)=$(MSBuildProjectDirectoryNoRoot)"/> 10 <Message 11 Text= 12 "%24(MSBuildProjectFile)=$(MSBuildProjectFile)"/> 13 <Message 14 Text= 15 "%24(MSBuildProjectExtension)=$(MSBuildProjectExtension)"/> 16 <Message 17 Text= 18 "%24(MSBuildProjectFullPath)=$(MSBuildProjectFullPath)"/> 19 <Message 20 Text= 21 "%24(MSBuildProjectName)=$(MSBuildProjectName)"/> 22 <Message 23 Text= 24 "%24(MSBuildBinPath)=$(MSBuildBinPath)"/> 25 <Message 26 Text= 27 "%24(MSBuildExtensionsPath)=$(MSBuildExtensionsPath)"/> 28 <Message 29 Text= 30 "%24(MSBuildToolsVersion)=$(MSBuildToolsVersion)"/> 31 </Target> 32 </Project>
A execução desse script resulta na saída que segue:
1 2 C:\git\MSBuild101>msbuild ReservedProperties.proj /nologo 3 Build started 18/01/2011 15:45:24. 4 Project "C:\git\MSBuild101\ReservedProperties.proj" on node 1 (default targets) 5 . 6 HelloWorld: 7 $(MSBuildProjectDirectory)=C:\git\MSBuild101 8 $(MSBuildProjectDirectoryNoRoot)=git\MSBuild101 9 $(MSBuildProjectFile)=ReservedProperties.proj 10 $(MSBuildProjectExtension)=.proj 11 $(MSBuildProjectFullPath)=C:\git\MSBuild101\ReservedProperties.proj 12 $(MSBuildProjectName)=ReservedProperties 13 $(MSBuildBinPath)=C:\Windows\Microsoft.NET\Framework64\v2.0.50727 14 $(MSBuildExtensionsPath)=C:\Program Files (x86)\MSBuild 15 $(MSBuildToolsVersion)=2.0 16 Done Building Project "C:\git\MSBuild101\ReservedProperties.proj" (default targ 17 ets). 18 19 20 Build succeeded. 21 0 Warning(s) 22 0 Error(s) 23 24 Time Elapsed 00:00:00.05
Por hoje, é isso.
Por favor, comente, de ideiais e sugestões. Seu feedback é muito importante.
Se preferir, me contate pelo twitter.
![]()






janeiro 25th, 2011 → 21:21
[...] Parte 2 – Tasks, Targets e Properties; [...]
janeiro 28th, 2011 → 21:04
[...] Parte 2 – Tasks, Targets e Properties; [...]
março 4th, 2011 → 3:18
[...] Parte 2 – Tasks, Targets e Properties; [...]