Compartilhar via


Extensibilidade do sistema de projeto do Visual Studio C++ e integração de ferramentas de build

O sistema de projetos do Visual C++ é usado para arquivos .vcxproj. Ele se baseia no CPS (Common Project System) do Visual Studio e fornece pontos de extensibilidade específicos do C++ adicionais para facilitar a integração do novo sistema de projetos do MSBuild C++, arquiteturas de build e plataformas de destino.

Estrutura de alvos do MSBuild do C++

Todos os arquivos .vcxproj importam estes arquivos:

<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

Esses arquivos, por si só, definem muito pouco. Em vez disso, eles importam outros arquivos com base nesses valores de propriedade:

  • $(ApplicationType)

    Exemplos: Windows Store, Android, Linux

  • $(ApplicationTypeRevision)

    Essa deve ser uma string de versão válida no formato major.minor[.build[.revision]].

    Exemplos: 1.0, 10.0.0.0

  • $(Platform)

    A arquitetura de build, chamada "Plataforma" por motivos históricos.

    Exemplos: Win32, x86, x64, ARM

  • $(PlatformToolset)

    Exemplos: v140, v141, v141_xp, llvm

Esses valores de propriedade especificam nomes de pasta na $(VCTargetsPath) pasta raiz:

$(VCTargetsPath)\
     Tipo de aplicativo\
        $(ApplicationType)\
            $(ApplicationTypeRevision)\
                 Plataformas\
                    $(Platform)\
                         PlatformToolsets\
                            $(PlatformToolset)
     Plataformas\
        $(Platform)\
             PlatformToolsets\
                $(PlatformToolset)

A $(VCTargetsPath)\ pasta Platforms\ é usada quando $(ApplicationType) está vazia, para projetos da Área de Trabalho do Windows.

Adicionar um novo conjunto de ferramentas de plataforma

Para adicionar um novo conjunto de ferramentas, por exemplo, "MyToolset" para a plataforma Win32 existente, crie uma pasta MyToolset em $(VCTargetsPath)\Platforms\Win32\PlatformToolsets\e crie arquivos Toolset.props e Toolset.targets nele.

Cada nome de pasta em PlatformToolsets aparece na caixa de diálogo Propriedades do Projeto como um conjunto de ferramentas de plataforma disponível para a plataforma especificada, conforme mostrado aqui:

A propriedade Platform Toolset na caixa de diálogo Páginas de Propriedades do projeto

Crie pastas MyToolset semelhantes e arquivos Toolset.props e Toolset.targets em cada pasta de plataforma existente compatível com este conjunto de ferramentas.

Adicionar uma nova plataforma

Para adicionar uma nova plataforma, por exemplo, "MyPlatform", crie uma pasta MyPlatform em $(VCTargetsPath)\Platforms\e crie arquivos Platform.default.props, Platform.props e Platform.targets nela. Crie também uma $(VCTargetsPath) pasta \Platforms\MyPlatform\PlatformToolsets\ e crie pelo menos um conjunto de ferramentas nela.

Todos os nomes de pasta sob a pasta Plataformas para cada $(ApplicationType) e $(ApplicationTypeRevision) aparecem no IDE como opções de Plataforma disponíveis para um projeto.

A opção Nova plataforma na caixa de diálogo Nova Plataforma de Projeto

Adicionar um novo tipo de aplicativo

Para adicionar um novo tipo de aplicativo, crie uma pasta MyApplicationType em $(VCTargetsPath)\Application Type\ e crie um arquivo Defaults.props nele. Pelo menos uma revisão é necessária para um tipo de aplicativo, portanto, crie também uma $(VCTargetsPath) pasta \Application Type\MyApplicationType\1.0 e crie um arquivo Defaults.props nela. Você também deve criar uma $(VCTargetsPath) pasta \ApplicationType\MyApplicationType\1.0\Platforms e criar pelo menos uma plataforma nela.

$(ApplicationType) e $(ApplicationTypeRevision) as propriedades não estão visíveis na interface do usuário. Eles são definidos nos modelos de projeto e não podem ser alterados após a criação do projeto.

A árvore de importação .vcxproj

Uma árvore simplificada de importações para arquivos de propriedades e alvos do Microsoft C++ é semelhante a:

$(VCTargetsPath) \ Microsoft.Cpp.Default.props
     $(MSBuildExtensionsPath) \ $(MSBuildToolsVersion) \ Microsoft.Common.props
     $(VCTargetsPath) \ ImportBefore\Default\*. props
     $(VCTargetsPath) \ Tipo de aplicativo\$(ApplicationType)\Default.props
     $(VCTargetsPath) \ Tipo de Aplicativo\$(ApplicationType)\$(ApplicationTypeRevision)\Default.props
     $(VCTargetsPath) \ Tipo de Aplicativo\$(ApplicationType)\$(ApplicationTypeRevision)\Plataformas\$(Platform)\Platform.default.props
     $(VCTargetsPath) \ ImportAfter\Default\*. props

Os projetos da Área de Trabalho do Windows não definem $(ApplicationType), portanto, eles só importam

$(VCTargetsPath) \ Microsoft.Cpp.Default.props
     $(MSBuildExtensionsPath) \ $(MSBuildToolsVersion) \ Microsoft.Common.props
     $(VCTargetsPath) \ ImportBefore\Default\*. props
     $(VCTargetsPath) \ Plataformas\$(Platform)\Platform.default.props
     $(VCTargetsPath) \ ImportAfter\Default\*. props

Usaremos a propriedade $(_PlatformFolder) para armazenar os locais das pastas da plataforma $(Platform). Esta propriedade é

$(VCTargetsPath) \ Plataformas\$(Platform)

para aplicativos de desktop do Windows e

$(VCTargetsPath) \ Tipo\$(ApplicationType)\$(ApplicationTypeRevision)\ de aplicativoPlataformas\$(Platform)

para todo o resto.

Os arquivos de props são importados nesta ordem:

$(VCTargetsPath) \ Microsoft.Cpp.props
     $(_PlatformFolder) \ Platform.props
         $(VCTargetsPath) \ Microsoft.Cpp.Platform.props
             $(_PlatformFolder) \ ImportBefore\*. Adereços
             $(_PlatformFolder) \ PlatformToolsets\$(PlatformToolset)\Toolset.props
             $(_PlatformFolder) \ ImportAfter\*. props

Os arquivos de destino são importados nesta ordem:

$(VCTargetsPath) \ Microsoft.Cpp.targets
     $(VCTargetsPath) \ Microsoft.Cpp.Current.targets
         $(_PlatformFolder) \ Platform.targets
             $(VCTargetsPath) \ Microsoft.Cpp.Platform.targets
                 $(_PlatformFolder) \ ImportBefore\*.targets
                 $(_PlatformFolder) \ PlatformToolsets\$(PlatformToolset)\Toolset.target
                 $(_PlatformFolder) \ ImportAfter\*.targets

Se você precisar definir algumas propriedades padrão para o conjunto de ferramentas, poderá adicionar arquivos às pastas ImportBefore e ImportAfter apropriadas.

Criar arquivos Toolset.props e Toolset.targets

Os arquivos Toolset.props e Toolset.targets têm controle total sobre o que acontece durante um build quando esse conjunto de ferramentas é usado. Eles também podem controlar os depuradores disponíveis, alguns da interface do usuário do IDE, como o conteúdo na caixa de diálogo Páginas de Propriedades e alguns outros aspectos do comportamento do projeto.

Embora um conjunto de ferramentas possa substituir todo o processo de build, geralmente você deseja apenas que seu conjunto de ferramentas modifique ou adicione algumas etapas de build ou use ferramentas de build diferentes, como parte de um processo de build existente. Para atingir essa meta, há uma série de arquivos comuns de props e destinos que seu conjunto de ferramentas pode importar. Dependendo do que você deseja que seu conjunto de ferramentas faça, esses arquivos podem ser úteis para usar como importações ou como exemplos:

  • $(VCTargetsPath) \ Microsoft.CppCommon.targets

    Esse arquivo define as principais partes do processo de build nativo e também importa:

    • $(VCTargetsPath) \ Microsoft.CppBuild.targets

    • $(VCTargetsPath) \ Microsoft.BuildSteps.targets

    • $(MSBuildToolsPath) \ Microsoft.Common.Targets

  • $(VCTargetsPath) \ Microsoft.Cpp.Common.props

    Define padrões para conjuntos de ferramentas que usam os compiladores da Microsoft e o Windows de destino.

  • $(VCTargetsPath) \ Microsoft.Cpp.WindowsSDK.props

    Este arquivo determina o local do SDK do Windows e define algumas propriedades importantes para aplicativos direcionados ao Windows.

Integrar destinos específicos do conjunto de ferramentas ao processo de build padrão do C++

O processo de build padrão do C++ é definido em Microsoft.CppCommon.targets. Os alvos não chamam nenhuma ferramenta de construção específica; eles especificam as principais etapas de construção, sua ordem e dependências.

A compilação do C++ tem três etapas principais, que são representadas pelos seguintes alvos:

  • BuildGenerateSources

  • BuildCompile

  • BuildLink

Como cada etapa de build pode ser executada de forma independente, os destinos em execução em uma etapa não podem contar com os grupos de itens e as propriedades definidas nos destinos que são executados como parte de uma etapa diferente. Essa divisão permite otimizações específicas no desempenho do build. Embora não seja usado por padrão, você ainda é incentivado a honrar essa separação.

Os alvos executados em cada etapa são controlados por estas propriedades.

  • $(BuildGenerateSourcesTargets)

  • $(BuildCompileTargets)

  • $(BeforeBuildLinkTargets)

Cada etapa também tem as propriedades "Antes" e "Depois".

<Target
  Name="_BuildGenerateSourcesAction"
  DependsOnTargets="$(CommonBuildOnlyTargets);$(BeforeBuildGenerateSourcesTargets);$(BuildGenerateSourcesTargets);$(AfterBuildGenerateSourcesTargets)" />

<Target
  Name="\_BuildCompileAction"
  DependsOnTargets="$(CommonBuildOnlyTargets);$(BeforeBuildCompileTargets);$(BuildCompileTargets);$(AfterBuildCompileTargets)" />

<Target
  Name="\_BuildLinkAction"
  DependsOnTargets="$(CommonBuildOnlyTargets);$(BeforeBuildLinkTargets);$(BuildLinkTargets);$(AfterBuildLinkTargets)" />

Consulte o arquivo Microsoft.CppBuild.targets para obter exemplos dos destinos incluídos em cada etapa:

<BuildCompileTargets Condition="'$(ConfigurationType)'\!='Utility'">
  $(BuildCompileTargets);
  _ClCompile;
  _ResGen;
  _ResourceCompile;
  $(BuildLibTargets);
</BuildCompileTargets>

Se você olhar para os alvos, como _ClCompile, verá que eles não fazem nada diretamente, mas dependem de outros alvos, incluindo ClCompile:

<Target Name="_ClCompile"
  DependsOnTargets="$(BeforeClCompileTargets);$(ComputeCompileInputsTargets);MakeDirsForCl;ClCompile;$(AfterClCompileTargets)" >
</Target>

ClCompile e outros destinos específicos da ferramenta de build são definidos como destinos vazios em Microsoft.CppBuild.targets:

<Target Name="ClCompile"/>

Como o ClCompile destino está vazio, a menos que seja substituído por um conjunto de ferramentas, nenhuma ação de build real é executada. Os destinos do conjunto de ferramentas podem substituir o ClCompile destino, ou seja, eles podem conter outra ClCompile definição depois de importar Microsoft.CppBuild.targets:

<Target Name="ClCompile"
  Condition="'@(ClCompile)' != ''"
  DependsOnTargets="SelectClCompile">
  <!-- call some MSBuild tasks -->
</Target>

Apesar do nome, que foi criado antes do Visual Studio implementar suporte multiplataforma, o alvo ClCompile não precisa chamar o CL.exe. Ele também pode chamar Clang, gcc ou outros compiladores usando tarefas apropriadas do MSBuild.

O ClCompile destino não deve ter nenhuma dependência, exceto o SelectClCompile destino, que é necessário para que o comando de compilação de arquivo único funcione no IDE.

Tarefas do MSBuild para uso em alvos do conjunto de ferramentas

Para invocar uma ferramenta de build real, o destino precisa chamar uma tarefa do MSBuild. Há uma tarefa exec básica que permite que você especifique uma linha de comando a ser executada. No entanto, as ferramentas de build geralmente têm muitas opções, entradas e saídas para acompanhar builds incrementais, portanto, faz mais sentido ter tarefas especiais para elas. Por exemplo, a tarefa do CL traduz as propriedades do MSBuild em opções do CL.exe, grava essas informações em um arquivo de resposta e chama o CL.exe. Ele também rastreia todos os arquivos de entrada e saída para builds incrementais posteriores. Para obter mais informações, consulte builds incrementais e verificações de atualidade.

O Microsoft.Cpp.Common.Tasks.dll implementa estas tarefas:

  • BSCMake

  • CL

  • ClangCompile (comutadores clang-gcc)

  • LIB

  • LINK

  • MIDL

  • Mt

  • RC

  • XDCMake

  • CustomBuild (como Exec, mas com controle de entrada e saída)

  • SetEnv

  • GetOutOfDateItems

Se você tiver uma ferramenta que execute a mesma ação que uma ferramenta existente e que tenha comutadores de linha de comando semelhantes (como clang-cl e CL fazem), você poderá usar a mesma tarefa para ambos.

Se você precisar criar uma nova tarefa para uma ferramenta de build, poderá escolher entre as seguintes opções:

  1. Se você usar essa tarefa raramente ou se alguns segundos não forem importantes para seu build, você poderá usar tarefas 'embutidas' do MSBuild:

    • Tarefa Xaml (uma regra de build personalizada)

      Para obter um exemplo de uma declaração de tarefa Xaml, consulte $(VCTargetsPath)\BuildCustomizations\masm.xmle, para seu uso, consulte $(VCTargetsPath)\BuildCustomizations\masm.targets.

    • Tarefa de código

  2. Se você quiser melhorar o desempenho da tarefa ou apenas precisar de uma funcionalidade mais complexa, use o processo regular de gravação de tarefas do MSBuild.

    Se nem todas as entradas e saídas da ferramenta estiverem listadas na linha de comando da ferramenta, como no CL, MIDLe RC nos casos, e se você quiser o acompanhamento automático de arquivos de entrada e saída e a criação de arquivos .tlog, derive sua tarefa da Microsoft.Build.CPPTasks.TrackedVCToolTask classe. No momento, embora haja documentação para a classe ToolTask base, não há exemplos ou documentação para os detalhes da TrackedVCToolTask classe. Se isso for de particular interesse, adicione sua voz a uma solicitação na Comunidade de Desenvolvedores.

Builds incrementais e verificações de atualização

Os destinos de build incrementais padrão do MSBuild usam os atributos Inputs e Outputs. Se você especificá-las, o MSBuild chamará o alvo somente se alguma das entradas tiver uma data/hora mais recente do que todas as saídas. Como os arquivos de origem geralmente incluem ou importam outros arquivos e as ferramentas de build produzem saídas diferentes dependendo das opções de ferramenta, é difícil especificar todas as entradas e saídas possíveis nos destinos do MSBuild.

Para gerenciar esse problema, o build do C++ usa uma técnica diferente para dar suporte a builds incrementais. A maioria dos alvos não especifica entradas e saídas e, como resultado, são sempre executados durante o build. As tarefas chamadas por destinos gravam informações sobre todas as entradas e saídas em arquivos tlog que têm uma extensão .tlog. Os arquivos .tlog são usados por compilações posteriores para verificar o que foi alterado e precisa ser recriado e o que está atualizado. Os arquivos .tlog também são a única fonte para a verificação de atualidade da build padrão no IDE.

Para determinar todas as entradas e saídas, as tarefas de ferramenta nativa usam tracker.exe e a classe FileTracker fornecida pelo MSBuild.

Microsoft.Build.CPPTasks.Common.dll define a classe base abstrata pública. A maioria das tarefas de ferramenta nativa é derivada dessa classe.

A partir da Atualização 15.8 do Visual Studio 2017, você pode usar a tarefa GetOutOfDateItems implementada em Microsoft.Cpp.Common.Tasks.dll para produzir arquivos .tlog para destinos personalizados com conhecidas entradas e saídas. Como alternativa, você pode criá-los usando a WriteLinesToFile tarefa. Veja o _WriteMasmTlogs alvo em $(VCTargetsPath)\BuildCustomizations\masm.targets como exemplo.

Arquivos .tlog

Há três tipos de arquivos .tlog: leitura, gravação e linha de comando. Os arquivos .tlog de leitura e gravação são usados por compilações incrementais e pela verificação de atualização na IDE. Os arquivos .tlog de linha de comando são usados apenas em builds incrementais.

O MSBuild fornece estas classes auxiliares para ler e gravar arquivos .tlog:

A classe FlatTrackingData pode ser usada para acessar arquivos .tlog de leitura e gravação e identificar entradas mais recentes que saídas ou se uma saída estiver ausente. Ele é usado na verificação de atualização.

Os arquivos .tlog de linha de comando contêm informações sobre linhas de comando usadas no build. Eles são usados apenas para builds incrementais, não para verificações de atualização, assim, o formato interno é determinado pela tarefa MSBuild que os produz.

Ler o formato .tlog

Os arquivos .tlog de leitura (*.read.*.tlog) contêm informações sobre arquivos de origem e suas dependências.

Um cursor (^) no início de uma linha indica uma ou mais fontes. As fontes que compartilham as mesmas dependências são separadas por uma barra vertical (|).

Os arquivos de dependência são listados após os arquivos fonte, cada um em sua própria linha. Todos os nomes de arquivo são caminhos completos.

Por exemplo, suponha que as fontes do projeto sejam encontradas em F:\test\ConsoleApplication1\ConsoleApplication1. Se o arquivo de origem, Class1.cpp, tiver esses inclusões,

#include "stdafx.h" //precompiled header
#include "Class1.h"

em seguida, o arquivo CL.read.1.tlog contém o arquivo de origem seguido por suas duas dependências:

^F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\CLASS1.CPP
F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.PCH
F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\CLASS1.H

Não é necessário gravar nomes de arquivo em maiúsculas, mas é uma conveniência para algumas ferramentas.

Formato de gravação .tlog

Os arquivos .tlog de 'write' (*.write.*.tlog) conectam fontes e saídas.

Um cursor (^) no início de uma linha indica uma ou mais fontes. Várias fontes são separadas por uma barra vertical (|).

Os arquivos de saída criados a partir das fontes devem ser listados após as fontes, cada uma em sua própria linha. Todos os nomes de arquivo devem ser caminhos completos.

Por exemplo, para um projeto consoleapplication simples que tem um arquivo de origem adicional Class1.cpp, o arquivo link.write.1.tlog pode conter:

^F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\DEBUG\CLASS1.OBJ|F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.OBJ|F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\DEBUG\STDAFX.OBJ
F:\TEST\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.ILK
F:\TEST\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.EXE
F:\TEST\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.PDB

Construção em design

Na IDE, projetos .vcxproj usam um conjunto de alvos do MSBuild para obter informações adicionais do projeto e regenerar arquivos de saída. Alguns desses alvos são usados apenas em builds em tempo de projeto, mas muitos deles são usados tanto em builds regulares quanto em builds em tempo de projeto.

Para informações gerais sobre builds em tempo de design, consulte a documentação do CPS para builds em tempo de design. Esta documentação só é parcialmente aplicável a projetos do Visual C++.

Os alvos CompileDesignTime e Compile mencionados na documentação de builds em tempo de design nunca são executados para projetos .vcxproj. Os projetos .vcxproj do Visual C++ usam diferentes alvos de design-time para obter informações do IntelliSense.

Destinos de tempo de design para informações do IntelliSense

Os alvos de tempo de design usados em projetos .vcxproj são definidos em $(VCTargetsPath)\Microsoft.Cpp.DesignTime.targets.

O GetClCommandLines destino coleta opções do compilador para o IntelliSense:

<Target
  Name="GetClCommandLines"
  Returns="@(ClCommandLines)"
  DependsOnTargets="$(DesignTimeBuildInitTargets);$(ComputeCompileInputsTargets)">
  • DesignTimeBuildInitTargets – destinos somente de design-time, necessários para a inicialização de compilação em design-time. Entre outras coisas, esses alvos desabilitam algumas das funcionalidades de Build regulares para melhorar o desempenho.

  • ComputeCompileInputsTargets – um conjunto de destinos que modifica itens e opções do compilador. Esses alvos são executados tanto em tempo de projeto quanto em builds regulares.

O destino chama a CLCommandLine tarefa para criar a linha de comando a ser usada para o IntelliSense. Novamente, apesar de seu nome, ele pode lidar não apenas com opções cl, mas também com opções Clang e gcc. O tipo das opções do compilador é controlado pela propriedade ClangMode.

Atualmente, a linha de comando produzida pela tarefa CLCommandLine sempre usa opções CL (mesmo no modo Clang), porque são mais fáceis para o mecanismo do IntelliSense analisar.

Se você estiver adicionando um alvo executado antes da compilação, seja em tempo de execução regular ou em tempo de design, certifique-se de que ele não interrompa os builds em tempo de design ou afete o desempenho. A maneira mais simples de testar seu alvo é abrir um prompt de comando do desenvolvedor e executar este comando:

msbuild /p:SolutionDir=*solution-directory-with-trailing-backslash*;Configuration=Debug;Platform=Win32;BuildingInsideVisualStudio=true;DesignTimebuild=true /t:\_PerfIntellisenseInfo /v:d /fl /fileloggerparameters:PerformanceSummary \*.vcxproj

Esse comando produz um log detalhado de build, msbuild.log, que contém um resumo de desempenho para os alvos e tarefas no final.

Certifique-se de usar Condition ="'$(DesignTimeBuild)' != 'true'" em todas as operações que só fazem sentido para builds regulares e não para builds de design.

Destinos de tempo de design que geram fontes

Esse recurso está desabilitado por padrão para projetos nativos da Área de Trabalho e atualmente não tem suporte em projetos armazenados em cache.

Se GeneratorTarget os metadados forem definidos para um item de projeto, o destino será executado automaticamente quando o projeto for carregado e quando o arquivo de origem for alterado.

Por exemplo, para gerar automaticamente arquivos .cpp ou .h de arquivos .xaml, os $(VSInstallDir)\ arquivos MSBuild\Microsoft\WindowsXaml\v16.0\*\Microsoft.Windows.UI.Xaml.CPP.Targets definem essas entidades:

<ItemDefinitionGroup>
  <Page>
    <GeneratorTarget>DesignTimeMarkupCompilation</GeneratorTarget>
  </Page>
  <ApplicationDefinition>
    <GeneratorTarget>DesignTimeMarkupCompilation</GeneratorTarget>
  </ApplicationDefinition>
</ItemDefinitionGroup>
<Target Name="DesignTimeMarkupCompilation">
  <!-- BuildingProject is used in Managed builds (always true in Native) -->
  <!-- DesignTimeBuild is used in Native builds (always false in Managed) -->
  <CallTarget Condition="'$(BuildingProject)' != 'true' Or $(DesignTimeBuild) == 'true'" Targets="DesignTimeMarkupCompilationCT" />
</Target>

Para usar Task.HostObject para obter o conteúdo não salvo dos arquivos de origem, os destinos e a tarefa devem ser registrados como MsbuildHostObjects para os projetos especificados em um pkgdef:

\[$RootKey$\\Projects\\{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\MSBuildHostObjects\]
\[$RootKey$\\Projects\\{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\MSBuildHostObjects\\DesignTimeMarkupCompilationCT;CompileXaml\]
@="{83046B3F-8984-444B-A5D2-8029DEE2DB70}"

Extensibilidade de projeto do Visual C++ no IDE do Visual Studio

O sistema de projetos do Visual C++ baseia-se no SISTEMA de Projeto do VS e usa seus pontos de extensibilidade. No entanto, a implementação da hierarquia de projeto é específica do Visual C++ e não se baseia no CPS, portanto, a extensibilidade da hierarquia é limitada a itens de projeto.

Páginas de propriedades do projeto

Para obter informações gerais sobre design, consulte Estrutura multi-direcionamento para projetos VC++.

Em termos simples, as páginas de propriedades que você vê na caixa de diálogo Propriedades do Projeto para um projeto C++ são definidas por arquivos de regra . Um arquivo de regra especifica um conjunto de propriedades a serem mostradas em uma página de propriedade e como e onde elas devem ser salvas no arquivo de projeto. Os arquivos de regra são .xml arquivos que usam o formato Xaml. Os tipos usados para serializá-los são descritos em Microsoft.Build.Framework.XamlTypes. Para obter mais informações sobre o uso de arquivos de regra em projetos, consulte arquivos de regra XML da Página de Propriedades.

Os arquivos de regra devem ser adicionados ao PropertyPageSchema grupo de itens:

<ItemGroup>
  <PropertyPageSchema Include="$(VCTargetsPath)$(LangID)\general.xml;"/>
  <PropertyPageSchema Include="$(VCTargetsPath)$(LangID)\general_file.xml">
    <Context>File</Context>
  </PropertyPageSchema>
</ItemGroup>

Context os metadados limitam a visibilidade da regra, que também é controlada pelo tipo de regra e pode ter um destes valores:

Project | File | PropertySheet

O CPS dá suporte a outros valores para o tipo de contexto, mas eles não são usados em projetos do Visual C++.

Se a regra deve estar visível em mais de um contexto, use ponto e vírgula (;) para separar os valores de contexto, conforme mostrado aqui:

<PropertyPageSchema Include="$(MyFolder)\MyRule.xml">
  <Context>Project;PropertySheet</Context>
</PropertyPageSchema>

Formato de regra e tipos principais

O formato de regra é simples, portanto, esta seção descreve apenas os atributos que afetam a aparência da regra na interface do usuário.

<Rule
  Name="ConfigurationGeneral"
  DisplayName="General"
  PageTemplate="generic"
  Description="General"
  xmlns="http://schemas.microsoft.com/build/2009/properties">

O PageTemplate atributo define como a regra é exibida na caixa de diálogo Páginas de Propriedades . O atributo pode ter um destes valores:

Attribute Description
generic Todas as propriedades são mostradas em uma página em títulos de categoria
A regra pode ser visível para Project e PropertySheet contextos, mas não File.

Exemplo: $(VCTargetsPath)\1033\general.xml
tool As categorias são mostradas como subpáginas.
A regra pode ser visível em todos os contextos: ProjectPropertySheet e File.
A regra ficará visível nas Propriedades do Projeto somente se o projeto tiver itens com o ItemType definido em Rule.DataSource, a menos que o nome da regra seja incluído no grupo de itens ProjectTools.

Exemplo: $(VCTargetsPath)\1033\clang.xml
debugger A página é mostrada como parte da página Depuração.
No momento, as categorias são ignoradas.
O nome da regra deve corresponder ao atributo do Inicializador de Lançamento de Depuração do objeto MEF ExportDebugger.

Exemplo: $(VCTargetsPath)\1033\debugger_local_windows.xml
personalizado Modelo personalizado. O nome do modelo deve corresponder ao ExportPropertyPageUIFactoryProvider atributo do PropertyPageUIFactoryProvider objeto MEF. Consulte Microsoft.VisualStudio.ProjectSystem.Designers.Properties.IPropertyPageUIFactoryProvider.

Exemplo: $(VCTargetsPath)\1033\userMacros.xml

Se a regra usar um dos modelos baseados na Grade de Propriedades, ela poderá usar esses pontos de extensibilidade para suas propriedades:

Estender uma regra

Se você quiser usar uma regra existente, mas precisar adicionar ou remover (ou seja, ocultar) apenas algumas propriedades, poderá criar uma regra de extensão.

Substituir uma regra

Talvez você queira que seu conjunto de ferramentas use a maioria das regras padrão do projeto, mas para substituir apenas uma ou algumas delas. Por exemplo, digamos que você só queira alterar a regra C/C++ para mostrar diferentes opções de compilador. Você pode fornecer uma nova regra com o mesmo nome e nome de exibição que a regra existente e incluí-la no PropertyPageSchema grupo de itens após a importação de destinos de cpp padrão. Somente uma regra com um determinado nome é usada no projeto e a última incluída no PropertyPageSchema grupo de itens vence.

Itens do projeto

O arquivo ProjectItemsSchema.xml define os valores ContentType e ItemType para os Itens que são tratados como Itens de Projeto e define elementos FileExtension para determinar a qual grupo de item um novo arquivo é adicionado.

O arquivo ProjectItemsSchema padrão é encontrado em $(VCTargetsPath)\1033\ProjectItemsSchema.xml. Para estendê-lo, você deve criar um arquivo de esquema com um novo nome, como MyProjectItemsSchema.xml:

<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties">

  <ItemType Name="MyItemType" DisplayName="C/C++ compiler"/>

  <ContentType
    Name="MyItems"
    DisplayName="My items"
    ItemType=" MyItemType ">
  </ContentType>

  <FileExtension Name=".abc" ContentType=" MyItems"/>

</ProjectSchemaDefinitions>

Em seguida, no arquivo de destinos, adicione:

<ItemGroup>
  <PropertyPageSchema Include="MyProjectItemsSchema.xml"/>
</ItemGroup>

Exemplo: $(VCTargetsPath)\BuildCustomizations\masm.xml

Depuradores

O serviço de depuração no Visual Studio dá suporte à extensibilidade para o mecanismo de depuração. Para obter mais informações, confira estes exemplos:

Para especificar os mecanismos de depuração e outras propriedades para a sessão de depuração, você deve implementar um componente MEF do Inicializador de Depuração e adicionar uma debugger regra. Para obter um exemplo, consulte o $(VCTargetsPath) arquivo\1033\debugger_local_windows.xml.

Deploy

Projetos .vcxproj usam a extensibilidade do Sistema de Projetos do Visual Studio para Fornecedores de Implantação.

Executar verificação de atualização

Por padrão, a verificação de atualização da build requer que arquivos .tlog de leitura e gravação sejam criados na pasta $(TlogLocation) durante o build para todas as entradas e saídas de build.

Para usar uma verificação de atualização personalizada:

  1. Desabilite a verificação padrão de atualização adicionando o NoVCDefaultBuildUpToDateCheckProvider recurso no arquivo Toolset.targets:

    <ItemGroup>
      <ProjectCapability Include="NoVCDefaultBuildUpToDateCheckProvider" />
    </ItemGroup>
    
  2. Implemente seu próprio IBuildUpToDateCheckProvider.

Atualização do projeto

Upgrader de projeto de .vcxproj padrão

O atualizador padrão do projeto .vcxproj altera o PlatformToolset, ApplicationTypeRevision, a versão do conjunto de ferramentas do MSBuild e o .NET Framework. Os dois últimos são sempre alterados para os padrões de versão do Visual Studio, mas PlatformToolset e ApplicationTypeRevision podem ser controlados por propriedades especiais do MSBuild.

O atualizador usa esses critérios para decidir se um projeto pode ser atualizado ou não:

  1. Para projetos que definem ApplicationType e ApplicationTypeRevision, há uma pasta com um número de revisão maior que o atual.

  2. A propriedade _UpgradePlatformToolsetFor_<safe_toolset_name> é definida para o conjunto de ferramentas atual e seu valor não é igual ao conjunto de ferramentas atual.

    Nesses nomes de propriedade, <safe_toolset_name> representa o nome do conjunto de ferramentas com todos os caracteres não alfanuméricos substituídos por um sublinhado (_).

Quando um projeto pode ser atualizado, ele participa do Retargeting de Solução. Para obter mais informações, consulte IVsTrackProjectRetargeting2.

Se você quiser adornar nomes de projeto no Gerenciador de Soluções quando os projetos usarem um conjunto de ferramentas específico, defina uma _PlatformToolsetShortNameFor_<safe_toolset_name> propriedade.

Para obter exemplos das definições de propriedade _UpgradePlatformToolsetFor_<safe_toolset_name> e _PlatformToolsetShortNameFor_<safe_toolset_name>, consulte o arquivo Microsoft.Cpp.Default.props. Para obter exemplos de uso, consulte o $(VCTargetPath)\ arquivo Microsoft.Cpp.Platform.targets.

Atualizador de projeto personalizado

Para usar um objeto personalizado do upgrader de projeto, implemente um componente MEF, conforme mostrado aqui:

/// </summary>
[Export("MyProjectUpgrader", typeof(IProjectRetargetHandler))]
[Export(typeof(IProjectRetargetHandler))]
[ExportMetadata("Name", "MyProjectUpgrader")]
[OrderPrecedence(20)]
[PartMetadata(ProjectCapabilities.Requires, ProjectCapabilities.VisualC)]

internal class MyProjectUpgrader: IProjectRetargetHandler
{
    // ...
}

Seu código pode importar e chamar o objeto padrão para atualização de .vcxproj:

// ...
[Import("VCDefaultProjectUpgrader")]
// ...
    IProjectRetargetHandler Lazy<IProjectRetargetHandler>
    VCDefaultProjectUpgrader { get; set; }
// ...

IProjectRetargetHandler é definido em Microsoft.VisualStudio.ProjectSystem.VS.dll e é semelhante a IVsRetargetProjectAsync.

Defina a propriedade VCProjectUpgraderObjectName para informar ao sistema de projeto a usar o seu objeto de atualização personalizado.

<PropertyGroup>
  <VCProjectUpgraderObjectName>MyProjectUpgrader</VCProjectUpgraderObjectName>
</PropertyGroup>

Desabilitar a atualização do projeto

Para desabilitar atualizações de projeto, use um valor NoUpgrade:

<PropertyGroup>
  <VCProjectUpgraderObjectName>NoUpgrade</VCProjectUpgraderObjectName>
</PropertyGroup>

Cache e extensibilidade do projeto

Para melhorar o desempenho ao trabalhar com grandes soluções C++ no Visual Studio 2017, o cache do projeto foi introduzido. Ele é implementado como um banco de dados SQLite preenchido com dados do projeto e usado para carregar projetos sem carregar projetos MSBuild ou CPS na memória.

Como não há objetos CPS presentes para projetos .vcxproj carregados do cache, os componentes MEF da extensão que importam UnconfiguredProject ou ConfiguredProject não podem ser criados. Para dar suporte à extensibilidade, o cache de projeto não é usado quando o Visual Studio detecta se um projeto usa (ou provavelmente usará) extensões MEF.

Esses tipos de projeto são sempre totalmente carregados e têm objetos CPS na memória, portanto, todas as extensões MEF são criadas para eles:

  • Projetos de startup

  • Projetos que têm um upgrader de projeto personalizado, ou seja, definem uma VCProjectUpgraderObjectName propriedade

  • Projetos que não têm como destino o Windows Desktop, ou seja, definem uma ApplicationType propriedade

  • Projetos de Itens Compartilhados (.vcxitems) e todos os projetos que os referenciam importando projetos .vcxitems.

Se nenhuma dessas condições for detectada, um cache de projeto será criado. O cache inclui todos os dados do projeto MSBuild necessários para responder get a consultas em VCProjectEngine interfaces. Isso significa que todas as modificações no nível de arquivo de props e destinos do MSBuild feitas por uma extensão devem funcionar apenas em projetos carregados do cache.

Enviando sua extensão

Para obter informações sobre como criar arquivos VSIX, consulte Envio de extensões do Visual Studio. Para obter informações sobre como adicionar arquivos a locais de instalação especiais, por exemplo, para adicionar arquivos em $(VCTargetsPath), consulte Instalando fora da pasta de extensões.

Recursos adicionais

O MSBuild (Microsoft Build System) fornece o mecanismo de build e o formato extensível baseado em XML para arquivos de projeto. Você deve estar familiarizado com os conceitos básicos do MSBuild e com como o MSBuild para Visual C++ funciona para estender o sistema de projetos do Visual C++.

O MEF (Managed Extensibility Framework) fornece as APIs de extensão usadas pelo CPS e pelo sistema de projetos do Visual C++. Para obter uma visão geral de como o MEF é utilizado pelo CPS, consulte CPS e MEF na seção visão geral do MEF no VSProjectSystem.

Você pode personalizar o sistema de build existente para adicionar etapas de build ou novos tipos de arquivo. Para obter mais informações, consulte a Visão geral do MSBuild (Visual C++) e trabalhando com as propriedades do projeto.