Passo a passo: Compilar e importar unidades de cabeçalho no Microsoft Visual C++
Este artigo trata da criação e importação de 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 para arquivos de cabeçalho pré-compilado (PCH). As unidades de cabeçalho são mais fáceis de configurar e usar, são significativamente menores em disco, fornecem benefícios de desempenho semelhantes e são mais flexíveis que um PCH compartilhado.
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, é necessário o 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 uma 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 dela. Ou seja, você não pode definir um símbolo de pré-processador que faça com que a unidade de cabeçalho se comporte de maneira diferente. Quando você importa a unidade de cabeçalho, ela já estará 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 é verdade para 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 visível de um arquivo de cabeçalho também é visível de uma unidade de cabeçalho, incluindo macros definidas dentro da unidade de cabeçalho.
Um arquivo de cabeçalho deve ser convertido em uma unidade de cabeçalho antes de ser importado. Uma vantagem das unidades de cabeçalho sobre os arquivos de cabeçalho pré-compilados (PCH) é que elas podem ser usadas 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 um 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é uma ordem de magnitude menor em tamanho do que um .pch
.
As unidades de cabeçalho impõem menos restrições às semelhanças necessárias das combinações de comutadores do compilador usadas para criar a unidade de cabeçalho e 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 definição única (ODR) entre várias unidades de tradução.
Por fim, as unidades de cabeçalho são mais flexíveis que um PCH. Com um PCH, você não pode optar por colocar apenas um dos cabeçalhos no PCH — o compilador processa todos eles. Com unidades de cabeçalho, mesmo quando você as compila em uma biblioteca estática, somente é importado para o aplicativo o conteúdo da unidade de cabeçalho.
As unidades de cabeçalho são uma etapa entre arquivos de cabeçalho e módulos C++20. Elas fornecem alguns dos benefícios dos módulos. Eles são mais robustos porque as definições de macro externas não os afetam, portanto, você pode importá-los em qualquer ordem. E o compilador pode processá-las mais rápido que 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 particular com arquivos de cabeçalho, diferentes técnicas são empregadas, como adicionar sublinhados à esquerda dos nomes ou colocar coisas em um namespace de implementação. Um módulo não expõe a implementação privada de nenhuma forma, portanto, você não precisa fazer isso.
Considere substituir seus cabeçalhos pré-compilados por unidades de cabeçalho. Você obtém a mesma vantagem de velocidade, mas também com outros benefícios de higiene e flexibilidade de código.
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 faça referência a ele para importar as unidades de cabeçalho. Para obter um passo a passo dessa 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 fornece controle arquivo por arquivo sobre o que é tratado como uma unidade de cabeçalho. Também é útil quando você precisa compilar um arquivo como uma unidade de cabeçalho que, como ele não tem a extensão padrão (
.ixx
,.cppm
,.h
,.hpp
), normalmente não seria compilado em uma unidade de cabeçalho. Essa abordagem é demonstrada neste passo a passo. Para começar, consulte Abordagem 1: Converter um arquivo específico em uma unidade de cabeçalho.Examinar e criar automaticamente unidades de cabeçalho. Essa abordagem é conveniente, mas é mais adequada para projetos menores porque não garante a taxa de transferência de build ideal. Para obter detalhes sobre essa abordagem, consulte a Abordagem 2: examinar automaticamente as unidades de cabeçalho.
Conforme mencionado na introdução, você pode criar e importar arquivos de cabeçalho STL como unidades de cabeçalho e tratar
#include
automaticamente os cabeçalhos da biblioteca STL semimport
reescrever seu código. Para ver como, acesse 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 etapas a seguir 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.h
e 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++ como /std:c++20
ou posterior com as seguintes etapas:
- No Gerenciador de Soluções, clique com o botão direito do mouse no projeto e escolha Propriedades.
- No painel esquerdo da janela páginas de propriedades do projeto, selecione Propriedades de Configuração>Geral.
- Na lista suspensa Padrão de linguagem C++ , selecione Padrão ISO C++20 (/std:c++20) ou posterior. Escolha Ok para fechar o diálogo.
Compile o arquivo de cabeçalho como uma unidade de cabeçalho:
Em Gerenciador de Soluções, selecione o arquivo que deseja compilar como uma unidade de cabeçalho (nesse caso,
Pythagorean.h
). Clique com o botão direito do mouse no arquivo e escolha Propriedades.Defina a lista suspensa Propriedades de configuração>Geral>Tipo de item para Compilador C/C++ e escolha Ok.
Quando você criar esse projeto posteriormente neste passo a passo, Pythagorean.h
será convertido em uma unidade de cabeçalho. Ele é convertido 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
files definida dessa maneira é converter 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 arquivo como uma unidade de cabeçalho que não tem uma extensão de arquivo de unidade de cabeçalho padrão, como.cpp
, por exemplo, defina as propriedades>de configuração C/C++>Advanced>Compile As para compilar como unidade de cabeçalho C++ (/exportHeader):
Alterar seu 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. É necessário paraimport
declarações. Por ser um arquivo de cabeçalho em um diretório local para o projeto, usamos aspas com aimport
instrução: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>;
Compile a solução selecionando Compilar>Compilar Solução no menu principal. Execute-a para ver se ela 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 quiser converter apenas alguns arquivos de cabeçalho em unidades de cabeçalho, essa será uma boa abordagem. Mas se você tiver muitos arquivos de cabeçalho que deseja compilar e a perda potencial de desempenho de build for superada pela conveniência de fazer com que o sistema de build os manipule automaticamente, consulte a seção a seguir.
Se você estiver interessado especificamente em importar cabeçalhos da biblioteca STL como unidades de cabeçalho, confira Passo a passo: importar bibliotecas STL como unidades de cabeçalho.
Abordagem 2: examinar e criar automaticamente unidades de cabeçalho
Como leva tempo para verificar todos os arquivos de origem em busca de unidades de cabeçalho e tempo para criá-los, a abordagem a seguir é mais adequada para projetos menores. Ele não garante a taxa de transferência de build ideal.
Essa abordagem combina duas configurações de projeto do Visual Studio:
- Verificar fontes de dependências de módulo faz com que o sistema de build 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 combinados com Translate Includes to Imports, todos os arquivos de cabeçalho incluídos em sua origem que também são especificados em um
header-units.json
arquivo localizado no mesmo diretório que o arquivo de cabeçalho são compilados em unidades de cabeçalho. - Translate Includes to Imports trata um arquivo de cabeçalho como um
import
, caso#include
se refira a um arquivo de cabeçalho que pode ser compilado como uma unidade de cabeçalho (conforme especificado em um arquivoheader-units.json
) e uma unidade de cabeçalho compilado está disponível para o arquivo de cabeçalho. Caso contrário, o arquivo de cabeçalho é tratado como#include
normal. Oheader-units.json
arquivo é 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 projeto. Para fazer isso, clique no projeto com o botão direito do mouse no Gerenciador de Soluções e escolha Propriedades. Em seguida, escolha Propriedades de Configuração>C/C++>Geral.
Verificar fontes de dependências de módulo podem ser definidas para todos os arquivos no projeto nas Propriedades do Projeto, conforme mostrado aqui, ou para arquivos individuais nas Propriedades do Arquivo. Módulos e unidades de cabeçalho são sempre verificados. Defina essa opção quando você tiver um arquivo .cpp
que importe unidades de cabeçalho que quer que sejam criadas automaticamente e talvez ainda não tenham sido criadas.
Essas configurações funcionam juntas para compilar e importar automaticamente unidades de cabeçalho nessas condições:
- Verificar fontes para dependências de módulo 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 suas propriedades>de arquivo C/C++>Compilar como propriedade definida como Compilar como Unidade de Cabeçalho C++ (/export) são sempre verificados, independentemente dessa configuração. O compilador também procura instruçõesimport
para identificar dependências de unidade de cabeçalho. Se/translateInclude
for especificado, o compilador também examinará as diretivas de#include
que também são especificadas em um arquivoheader-units.json
para tratar como unidades de cabeçalho. É criado um grafo de dependência a partir de todos os módulos e unidades de cabeçalho em seu projeto. - Traduzir Inclui para Importações. Quando o compilador encontra uma instrução
#include
e existir um arquivo de unidade de cabeçalho correspondente (.ifc
) para o arquivo de cabeçalho especificado, o compilador importará a unidade de cabeçalho em vez de tratar o arquivo de cabeçalho como um#include
. Quando combinado com Verificar dependências, o compilador localiza 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 um arquivoheader-units.json
que deve estar no mesmo diretório que o arquivo incluído. Você poderá ver um exemplo de um arquivoheader-units.json
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. Essa funcionalidade existe para servir como uma ponte com código herdado para obter alguns benefícios das unidades de cabeçalho.
O arquivo header-units.json
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 build. Para obter mais informações sobre a duplicação de símbolo, consulte Referência de header-units.json do C++.
Esses switches e header-unit.json
fornecem alguns dos benefícios das unidades de cabeçalho. A conveniência vem ao custo da taxa de transferência de build. Essa abordagem pode não ser a melhor para projetos maiores porque não garante tempos de build ideais. Além disso, os mesmos arquivos de cabeçalho podem ser reprocessados repetidamente, o que aumenta o tempo de build. No entanto, a conveniência pode valer a pena dependendo do projeto.
Esses recursos foram projetados para código herdado. Para um novo código, mova para módulos em vez de unidades de cabeçalho ou arquivos #include
. Para obter um tutorial sobre como usar módulos, consulte o 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 para o pré-processador
O pré-processador padrão C99/C++11 em conformidade é necessário para criar e usar unidades de cabeçalho. O compilador habilita o novo pré-processador C99/C++11 em conformidade ao compilar unidades de cabeçalho adicionando /Zc:preprocessor
implicitamente à linha de comando sempre que qualquer forma de /exportHeader
seja usada. Tentar desativá-lo resultará em um erro de compilação.
Habilitar o novo pré-processador afeta o processamento de macros variádicas. Para obter mais informações, consulte a seção comentários sobre Macros variádicas.
Confira 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 no C++
Tutorial: Importar a biblioteca padrão C++ usando módulos
Passo a passo: Importar bibliotecas STL como unidades de cabeçalho