Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Este artigo é sobre como criar e importar unidades de cabeçalho com o Visual Studio 2022. Para saber como importar cabeçalhos de biblioteca padrão C++ como unidades de cabeçalho, consulte Passo a passo: Importar bibliotecas STL como unidades de cabeçalho. Para obter uma maneira ainda mais rápida e robusta de importar a biblioteca padrão, consulte Tutorial: Importar a biblioteca padrão C++ usando módulos.
As unidades de cabeçalho são a alternativa recomendada aos arquivos de cabeçalho pré-compilados (PCH). As unidades de cabeçalho são mais fáceis de configurar e usar, são significativamente menores no disco, oferecem benefícios de desempenho semelhantes e são mais flexíveis do que uma PCH compartilhada.
Para contrastar unidades de cabeçalho com outras maneiras de incluir funcionalidade em seus programas, consulte Comparar unidades de cabeçalho, módulos e cabeçalhos pré-compilados.
Pré-requisitos
Para usar unidades de cabeçalho, você precisa do Visual Studio 2019 16.10 ou posterior.
O que é uma unidade de cabeçalho
Uma unidade de cabeçalho é uma representação binária de um arquivo de cabeçalho. Uma unidade de cabeçalho termina com a extensão .ifc. O mesmo formato é usado para módulos nomeados.
Uma diferença importante entre uma unidade de cabeçalho e um arquivo de cabeçalho é que uma unidade de cabeçalho não é afetada por definições de macro fora da unidade de cabeçalho. Ou seja, não é possível definir um símbolo de pré-processador que faça com que a unidade de cabeçalho se comporte de forma diferente. No momento em que você importa a unidade de cabeçalho, a unidade de cabeçalho já está compilada. Isso é diferente de como um #include arquivo é tratado. Um arquivo incluído pode ser afetado por uma definição de macro fora do arquivo de cabeçalho porque o arquivo de cabeçalho passa pelo pré-processador quando você compila o arquivo de origem que o inclui.
As unidades de cabeçalho podem ser importadas em qualquer ordem, o que não acontece com os arquivos de cabeçalho. A ordem do arquivo de cabeçalho é importante porque as definições de macro definidas em um arquivo de cabeçalho podem afetar um arquivo de cabeçalho subsequente. As definições de macro em uma unidade de cabeçalho não podem afetar outra unidade de cabeçalho.
Tudo o que é visível a partir de um ficheiro de cabeçalho também é visível a partir de uma unidade de cabeçalho, incluindo macros definidas dentro da unidade de cabeçalho.
Um arquivo de cabeçalho deve ser traduzido em uma unidade de cabeçalho antes de poder ser importado. Uma vantagem das unidades de cabeçalho sobre os arquivos de cabeçalho pré-compilados (PCH) é que eles podem ser usados em compilações distribuídas. Contanto que você compile o .ifc e o programa que o importa com o mesmo compilador e direcione a mesma plataforma e arquitetura, uma unidade de cabeçalho produzida em um computador pode ser consumida em outro. Ao contrário de uma PCH, quando uma unidade de cabeçalho muda, apenas ela e o que depende dela são reconstruídos. As unidades de cabeçalho podem ser até dez vezes menores do que um .pcharquivo.
As unidades de cabeçalho colocam menos restrições sobre as semelhanças necessárias entre as combinações de opções do compilador usadas para criar a unidade de cabeçalho e para compilar o código que a consome do que um PCH. No entanto, algumas combinações de switch e definições de macro podem criar violações da regra de uma definição (ODR) entre várias unidades de tradução.
Finalmente, as unidades de cabeçalho são mais flexíveis do que uma PCH. Com um PCH, você não pode optar por trazer apenas um dos cabeçalhos no PCH - o compilador processa todos eles. Com unidades de cabeçalho, mesmo quando você as compila juntas em uma biblioteca estática, você só traz o conteúdo da unidade de cabeçalho importada para seu aplicativo.
As unidades de cabeçalho são uma etapa entre os arquivos de cabeçalho e os módulos C++20. Eles fornecem alguns dos benefícios dos módulos. Eles são mais robustos porque as definições de macro externas não os afetam, então você pode importá-los em qualquer ordem. E o compilador pode processá-los mais rápido do que os arquivos de cabeçalho. Mas as unidades de cabeçalho não têm todas as vantagens dos módulos porque as unidades de cabeçalho expõem as macros definidas dentro delas (os módulos não). Ao contrário dos módulos, não há como ocultar a implementação privada em uma unidade de cabeçalho. Para indicar a implementação privada com arquivos de cabeçalho, diferentes técnicas são empregadas, como adicionar sublinhados principais a nomes ou colocar coisas em um namespace de implementação. Um módulo não expõe a implementação privada de forma alguma, então você não precisa fazer isso.
Considere substituir os cabeçalhos pré-compilados por unidades de cabeçalho. Você obtém a mesma vantagem de velocidade, mas com outros benefícios de higiene e flexibilidade de código também.
Maneiras de compilar uma unidade de cabeçalho
Há várias maneiras de compilar um arquivo em uma unidade de cabeçalho:
Crie um projeto de unidade de cabeçalho compartilhado. Recomendamos essa abordagem porque ela fornece mais controle sobre a organização e a reutilização das unidades de cabeçalho importadas. Crie um projeto de biblioteca estática que contenha as unidades de cabeçalho desejadas e, em seguida, faça referência a ele para importar as unidades de cabeçalho. Para obter um guia detalhado sobre esta abordagem, consulte Criar um projeto de biblioteca estática de unidade de cabeçalho para unidades de cabeçalho.
Escolha arquivos individuais para traduzir em unidades de cabeçalho. Essa abordagem oferece controle arquivo a arquivo sobre o que é tratado como uma unidade de cabeçalho. Também é útil quando você deve compilar um arquivo como uma unidade de cabeçalho que, por não ter a extensão padrão (
.ixx,.cppm,.h,.hpp), normalmente não seria compilada em uma unidade de cabeçalho. Essa abordagem é demonstrada neste passo a passo. Para começar, consulte Abordagem 1: traduzir um arquivo específico em uma unidade de cabeçalho.Analise e construa automaticamente unidades de cabeçalho. Essa abordagem é conveniente, mas é mais adequada para projetos menores porque não garante uma eficiência na construção ideal. Para obter detalhes sobre essa abordagem, consulte Abordagem 2: Verificar automaticamente unidades de cabeçalho.
Como mencionado na introdução, você pode criar e importar arquivos de cabeçalho STL como unidades de cabeçalho e tratar
#includeautomaticamente os cabeçalhos de biblioteca STL comoimportsem reescrever seu código. Para ver como, visite Passo a passo: Importar bibliotecas STL como unidades de cabeçalho.
Abordagem 1: Traduzir um arquivo específico em uma unidade de cabeçalho
Esta seção mostra como escolher um arquivo específico para traduzir em uma unidade de cabeçalho. Compile um arquivo de cabeçalho como uma unidade de cabeçalho usando as seguintes etapas no Visual Studio:
Crie um novo projeto de aplicativo de console C++.
Substitua o conteúdo do arquivo de origem da seguinte maneira:
#include "Pythagorean.h" int main() { PrintPythagoreanTriple(2,3); return 0; }Adicione um arquivo de cabeçalho chamado
Pythagorean.he, em seguida, substitua seu conteúdo por este código:#ifndef PYTHAGOREAN #define PYTHAGOREAN #include <iostream> inline void PrintPythagoreanTriple(int a, int b) { std::cout << "Pythagorean triple a:" << a << " b:" << b << " c:" << a*a + b*b << std::endl; } #endif
Definir propriedades do projeto
Para habilitar unidades de cabeçalho, primeiro defina o padrão de linguagem C++ para /std:c++20 ou posterior com as seguintes etapas:
- No Gerenciador de Soluções, clique com o botão direito do mouse no nome do projeto e escolha Propriedades.
- No painel esquerdo da janela de páginas de propriedades do projeto, selecione Propriedades>de configuração Geral.
- No menu suspenso Padrão de linguagem C++ , selecione ISO C++20 Standard (/std:c++20) ou posterior. Escolha Ok para fechar a caixa de diálogo.
Compile o arquivo de cabeçalho como uma unidade de cabeçalho:
No Gerenciador de Soluções, selecione o arquivo que você deseja compilar como uma unidade de cabeçalho (neste caso,
Pythagorean.h). Clique com o botão direito do mouse no arquivo e escolha Propriedades.Defina as Propriedades de Configuração>Geral>Tipo de Item da lista suspensa para compilador C/C++ e escolha Ok.
Quando este projeto for compilado mais tarde neste passo a passo, Pythagorean.h será traduzido para uma unidade de cabeçalho. Ele é traduzido em uma unidade de cabeçalho porque o tipo de item para esse arquivo de cabeçalho é definido como compilador C/C++ e porque a ação padrão para .h e .hpp arquivos definidos dessa maneira é traduzir o arquivo em uma unidade de cabeçalho.
Observação
Isso não é necessário para este passo a passo, mas é fornecido para suas informações. Para compilar um ficheiro como uma unidade de cabeçalho que não tem uma extensão de ficheiro de unidade de cabeçalho padrão, como .cpp por exemplo, defina as propriedades de configuração>C/C++>Avançadas>Compilar Como para Compilar como Unidade de Cabeçalho C++ (/exportHeader):
Altere o código para importar a unidade de cabeçalho
No arquivo de origem do projeto de exemplo, altere
#include "Pythagorean.h"paraimport "Pythagorean.h";. Não se esqueça do ponto-e-vírgula à direita. É obrigatório paraimportdeclarações. Como se trata de um ficheiro de cabeçalho numa diretoria local do projeto, utilizámos aspas com a instruçãoimport:import "file";. Em seus próprios projetos, para compilar uma unidade de cabeçalho a partir de um cabeçalho do sistema, use colchetes angulares:import <file>;Crie a solução selecionando Build>Build Solution no menu principal. Execute-o para ver se ele produz a saída esperada:
Pythagorean triple a:2 b:3 c:13
Em seus próprios projetos, repita esse processo para compilar os arquivos de cabeçalho que você deseja importar como unidades de cabeçalho.
Se você quiser converter apenas alguns arquivos de cabeçalho em unidades de cabeçalho, essa abordagem é boa. Mas se você tiver muitos arquivos de cabeçalho que deseja compilar e a perda potencial de desempenho de compilação for superada pela conveniência de ter o sistema de compilação manipulando-os automaticamente, consulte a seção a seguir.
Se você estiver interessado em importar especificamente cabeçalhos de biblioteca STL como unidades de cabeçalho, consulte Passo a passo: Importar bibliotecas STL como unidades de cabeçalho.
Abordagem 2: Procurar e construir unidades de cabeçalho automaticamente
Como leva tempo para verificar todos os seus arquivos de origem em busca de unidades de cabeçalho e tempo para criá-los, a abordagem a seguir é mais adequada para projetos menores. Não garante um desempenho de compilação ideal.
Essa abordagem combina duas configurações de projeto do Visual Studio:
-
Scan Sources for Module Dependencies faz com que o sistema de compilação chame o compilador para garantir que todos os módulos importados e unidades de cabeçalho sejam criados antes de compilar os arquivos que dependem deles. Quando combinado com Translate Includes to Imports, qualquer arquivo de cabeçalho incluído na sua fonte que também seja especificado num arquivo
header-units.jsonlocalizado no mesmo diretório do arquivo de cabeçalho, é compilado em unidades de cabeçalho. -
Translate Includes to Imports trata um arquivo de cabeçalho como um
importse o#includese refere a um arquivo de cabeçalho que pode ser compilado como uma unidade de cabeçalho (conforme especificado em umheader-units.jsonarquivo), e uma unidade de cabeçalho compilada está disponível para o arquivo de cabeçalho. Caso contrário, o arquivo de cabeçalho é tratado como um#include. Oheader-units.jsonarquivo é usado para construir automaticamente unidades de cabeçalho para cada#include, sem duplicação de símbolos.
Você pode ativar essas configurações nas propriedades do seu projeto. Para fazer isso, clique com o botão direito do mouse no projeto no Gerenciador de Soluções e escolha Propriedades. Em seguida, escolha Configuration Properties>C/C++>General.
As fontes de verificação para dependências de módulo podem ser definidas para todos os arquivos no projeto em Propriedades do projeto , conforme mostrado aqui, ou para arquivos individuais em Propriedades do arquivo. Os módulos e unidades de cabeçalho são sempre verificados. Defina essa opção quando tiver um .cpp arquivo que importe unidades de cabeçalho que você deseja criar automaticamente e que talvez ainda não tenha sido compilado.
Essas configurações funcionam juntas para criar e importar automaticamente unidades de cabeçalho sob estas condições:
-
Scan Sources for Module Dependencies verifica suas fontes em busca dos arquivos e suas dependências que podem ser tratados como unidades de cabeçalho. Os arquivos que têm a extensão
.ixx, e os arquivos que têm as suas propriedades de Ficheiro>C/C++>Compilar como definidas como Compile as C++ Header Unit (/export), são sempre analisados, independentemente dessa configuração. O compilador também procuraimportdeclarações para identificar dependências da unidade de cabeçalho. Se/translateIncludefor especificado, o compilador também verificará por diretivas#includeque estão também especificadas em um arquivoheader-units.jsonpara tratar como unidades de cabeçalho. Um gráfico de dependência é construído de todos os módulos e unidades de cabeçalho em seu projeto. -
Traduzir Includes para Imports Quando o compilador encontra uma
#includeinstrução, e existe um ficheiro de unidade de cabeçalho correspondente (.ifc) para o ficheiro de cabeçalho especificado, o compilador importa a unidade de cabeçalho em vez de tratar o ficheiro de cabeçalho como um#include. Quando combinado com Scan for dependencies, o compilador encontra todos os arquivos de cabeçalho que podem ser compilados em unidades de cabeçalho. Uma lista de permissões é consultada pelo compilador para decidir quais arquivos de cabeçalho podem ser compilados em unidades de cabeçalho. Essa lista é armazenada em umheader-units.jsonarquivo que deve estar no mesmo diretório que o arquivo incluído. Você pode ver um exemplo de umheader-units.jsonarquivo no diretório de instalação do Visual Studio. Por exemplo,%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.30.30705\include\header-units.jsoné usado pelo compilador para determinar se um cabeçalho da Biblioteca de Modelos Padrão pode ser compilado em uma unidade de cabeçalho. Esta função existe para servir como uma ponte com o código herdado para tirar partido de alguns benefícios das unidades de cabeçalho.
O header-units.json ficheiro tem duas finalidades. Além de especificar quais arquivos de cabeçalho podem ser compilados em unidades de cabeçalho, ele minimiza símbolos duplicados para aumentar a taxa de transferência de compilação. Para obter mais informações sobre duplicação de símbolos, consulte C++ header-units.json reference.
Estes interruptores e o header-unit.json fornecem alguns dos benefícios das unidades de cabeçalho. A conveniência tem o custo do desempenho de construção. Essa abordagem pode não ser a melhor para projetos maiores, porque não garante tempos de construção ideais. Além disso, os mesmos arquivos de cabeçalho podem ser reprocessados repetidamente, o que aumenta o tempo de compilação. No entanto, a conveniência pode valer a pena, dependendo do projeto.
Esses recursos são projetados para código legado. Para código novo, mova para módulos em vez de unidades de cabeçalho ou arquivos #include. Para obter um tutorial sobre como usar módulos, consulte Tutorial de módulos de nome (C++).
Para obter um exemplo de como essa técnica é usada para importar arquivos de cabeçalho STL como unidades de cabeçalho, consulte Passo a passo: Importar bibliotecas STL como unidades de cabeçalho.
Implicações do pré-processador
O pré-processador padrão em conformidade com C99/C++11 é necessário para criar e usar unidades de cabeçalho. O compilador habilita o novo pré-processador em conformidade com C99/C++11 ao compilar unidades de cabeçalho, adicionando /Zc:preprocessor implicitamente à linha de comando sempre que qualquer forma de /exportHeader é usada. Tentar desativá-lo resultará em um erro de compilação.
A ativação do novo pré-processador afeta o processamento de macros variádicas. Para mais informações, consulte a secção de comentários sobre macros variádicas.
Ver também
/translateInclude
/exportHeader
/headerUnit
header-units.json
Comparar unidades de cabeçalho, módulos e cabeçalhos pré-compilados
Visão geral dos módulos em C++
Tutorial: Importar a biblioteca padrão C++ usando módulos
Passo a passo: Importar bibliotecas STL como unidades de cabeçalho