Dela via


Genomgång: Importera STL-bibliotek som rubrikenheter

Den här genomgången visar hur du importerar STL-bibliotek (C++ Standard Template Library) som rubrikenheter i Visual Studio. Ett ännu snabbare och mer robust sätt att importera standardbiblioteket finns i Självstudie: Importera C++-standardbiblioteket med hjälp av moduler.

Det är enklare att importera en STL-rubrik som en rubrikenhet än att använda förkompilerade huvudfiler. Rubrikenheter är enklare att konfigurera och använda, är betydligt mindre på disk, ger liknande prestandafördelar och är mer flexibla än en delad PCH.

Mer detaljerad information om vilka rubrikenheter som är och vilka fördelar de ger finns i Vad är en rubrikenhet?. Om du vill kontrastera rubrikenheter med andra sätt att importera standardbiblioteket kan du läsa Jämför rubrikenheter, moduler och förkompilerade rubriker.

Förutsättningar

Om du vill använda rubrikenheter använder du Visual Studio 2022 eller senare, eller Visual Studio 2019 version 16.11 eller senare. Alternativet /std:c++20 (eller senare) krävs för att använda rubrikenheter.

Två metoder för att importera STL-huvuden som rubrikenheter

Innan du kan importera en STL-rubrik måste den kompileras till en rubrikenhet. En rubrikenhet är en binär representation av en rubrikfil. Den har ett .ifc tillägg.

Den rekommenderade metoden är att skapa ett statiskt bibliotek som innehåller de skapade huvudenheterna för de STL-huvuden som du vill använda. Referera sedan till biblioteket och import dess header-enheter. Den här metoden kan resultera i snabbare versioner och bättre återanvändning. Om du vill prova den här metoden kan du läsa Metod 1: Skapa ett statiskt bibliotek med STL-bibliotekshuvudenheter.

En annan metod är att låta Visual Studio söka efter DE STL-huvuden som du #include har i projektet, kompilera dem till rubrikenheter och import i stället #include för dessa rubriker. Den här metoden är användbar om du har en stor kodbas eftersom du inte behöver ändra källkoden. Den här metoden är mindre flexibel än metoden för statiskt bibliotek eftersom den inte lämpar sig för återanvändning av de skapade huvudenheterna i andra projekt. Men du får fortfarande prestandafördelarna med att importera enskilda STL-bibliotek som rubrikenheter. Om du vill prova den här metoden kan du läsa Metod 2: Sök igenom inklusive STL-huvuden för import.

Metod 1: Skapa ett statiskt bibliotek med STL-bibliotekshuvudenheter

Det rekommenderade sättet att använda STL-bibliotek som rubrikenheter är att skapa ett eller flera statiska biblioteksprojekt. Dessa projekt bör bestå av de STL-bibliotekshuvudenheter som du vill använda. Referera sedan till biblioteksprojekten för att använda dessa STL-huvudenheter. Det liknar att använda delade förkompilerade rubriker, men enklare.

Rubrikenheter (och moduler) som är inbyggda i ett statiskt biblioteksprojekt är automatiskt tillgängliga för att referera till projekt eftersom projektsystemet automatiskt lägger till lämpligt /headerUnit kommandoradsalternativ i kompilatorn så att refererande projekt kan importera rubrikenheterna.

Den här metoden säkerställer att rubrikenheten för en viss rubrik bara skapas en gång. Det gör att du kan importera vissa eller alla rubrikenheter, vilket inte är möjligt med en PCH. Du kan inkludera rubrikenheter i valfri ordning.

I följande exempel skapar du ett statiskt biblioteksprojekt som består av huvudenheterna <iostream> och <vector> . När lösningen har skapats refererar du till det delade huvudenhetsprojektet från ett annat C++-projekt. Varhelst import <iostream>; eller import <vector>; finns används den byggda huvudenheten för det biblioteket i stället för att översätta huvudet med förprocessorn. Det förbättrar byggprestanda, som PCH-filer gör, när samma rubrik ingår i flera filer. Rubriken behöver inte bearbetas om och om av de filer som innehåller den. I stället importeras den redan bearbetade kompilerade rubrikenheten.

Om du vill skapa ett statiskt bibliotek som innehåller STL-biblioteken <iostream> och <vector>följer du dessa steg:

  1. Skapa ett tomt C++-projekt. Ge den namnet SharedPrj.
    Välj Tomt projekt för C++ från de projekttyper som är tillgängliga i fönstret Skapa ett nytt projekt : Skärmbild som visar hur du skapar ett nytt tomt C++-projekt.

  2. Lägg till en ny C++-fil i projektet. Ändra filens innehåll till:

    import <iostream>;
    import <vector>;
    

Ange projektegenskaper

Ange projektegenskaper för att dela huvudenheterna från det här projektet:

  1. På huvudmenyn i Visual Studio väljer du Egenskaper för Project>SharedPrj för att öppna dialogrutan Egenskapssidor för projektet: Skärmbild som visar inställningar för konfigurationstyp och C++Language Standard.
  2. Välj Alla konfigurationer i listrutan Konfiguration och välj sedan Alla plattformar i listrutan Plattform . De här inställningarna säkerställer att ändringarna gäller oavsett om du skapar för felsökning eller lansering.
  3. I den vänstra rutan i dialogrutan Egenskapssidor för projektet väljer du Konfigurationsegenskaper>Allmänt.
  4. Ändra alternativet Konfigurationstyp till Statiskt bibliotek (.lib).
  5. Ändra C++ Language Standard till ISO C++20 Standard (/std:c++20) (eller senare).
  6. I den vänstra rutan i dialogrutan Egenskapssidor för projektet väljer du Konfigurationsegenskaper>C/C++>Allmänt.
  7. I listrutan Genomsök källor för modulberoenden väljer du Ja. (Det här alternativet gör att kompilatorn söker igenom koden efter beroenden som kan byggas in i rubrikenheter): Skärmbild som visar egenskapsinställningen för genomsökningsmodulens beroenden.
  8. Välj OK för att stänga dialogrutan Egenskapssidor för projektet. Skapa lösningen genom att välja Skapa>bygglösning på huvudmenyn.

Referera till huvudenhetsbiblioteket

Om du vill importera <iostream> och <vector> som rubrikenheter från det statiska biblioteket skapar du ett projekt som refererar till det statiska biblioteket på följande sätt:

  1. När den aktuella lösningen fortfarande är öppen går du till Visual Studio-menyn och väljer Arkiv>Lägg till>nytt projekt.

  2. I guiden Skapa ett nytt projekt väljer du mallen C++ Konsolapp och väljer Nästa.

  3. Ge det nya projektet namnet Walkthrough. Ändra listrutan Lösning till Lägg till i lösning. Välj Skapa för att skapa projektet och lägg till det i din lösning.

  4. Ändra innehållet i Walkthrough.cpp källfilen enligt följande:

    import <iostream>;
    import <vector>;
    
    int main()
    {
        std::vector<int> numbers = {0, 1, 2};
        std::cout << numbers[1];
    }
    

Rubrikenheter kräver /std:c++20 alternativet (eller senare). Ange språkstandarden med hjälp av följande steg:

  1. I Solution Explorerhögerklickar du på projektet Genomgång och väljer Egenskaper för att öppna dialogrutan Egenskapssidor för projektet: Skärmbild som visar hur du ställer in språkstandarden på förhandsversionen.
  2. I den vänstra rutan i dialogrutan Genomgångsprojektegenskapssidor väljer du Allmänna konfigurationsegenskaper>.
  3. I listrutan C++ Language Standard väljer du ISO C++20 Standard (/std:c++20) (eller senare).
  4. Välj OK för att stänga dialogrutan Egenskapssidor för projektet.

I walkthrough-projektet lägger du till en referens till SharedPrj-projektet med följande steg:

  1. I projektet Genomgång väljer du noden Referenser och väljer sedan Lägg till referens. Välj SharedPrj i listan över projekt: Skärmbild som visar dialogrutan Lägg till referens. Den används för att lägga till en referens till genomgångsprojektet. Om du lägger till den här referensen används huvudenheterna som skapats av SharedPrj när en import i walkthrough-projektet matchar en av de inbyggda rubrikenheterna i SharedPrj.
  2. Välj OK för att stänga dialogrutan Lägg till referens .
  3. Högerklicka på genomgångsprojektet och välj Ange som startprojekt.
  4. Skapa lösningen. (Använd build>Skapa lösning på huvudmenyn.) Kör den för att se att den genererar förväntade utdata: 1

Fördelen med den här metoden är att du kan referera till det statiska biblioteksprojektet från alla projekt för att återanvända rubrikenheterna i det. I det här exemplet innehåller det statiska biblioteket headerenheterna <vector> och <iostream>.

Du kan skapa ett monolitiskt statiskt biblioteksprojekt som innehåller alla vanliga STL-huvuden som du vill importera från dina olika projekt. Du kan också skapa mindre delade biblioteksprojekt för de olika grupperingar av STL-bibliotek som du vill importera som rubrikenheter. Referera sedan till de delade huvudenhetsprojekten efter behov.

Resultatet bör öka build-dataflödet eftersom import av en rubrikenhet avsevärt minskar det arbete som kompilatorn måste utföra.

När du använder den här metoden med dina egna projekt skapar du det statiska biblioteksprojektet med kompilatoralternativ som är kompatibla med det projekt som refererar till det. Till exempel bör STL-projekt skapas med kompilatoralternativet /EHsc för att aktivera undantagshantering, och det bör även de projekt som refererar till det statiska biblioteksprojektet.

Använd /translateInclude

Kompileringsalternativet /translateInclude (tillgängligt i dialogrutan Egenskapssidor för projekt under C/C++>Allmänt>Översätt Inkluderar till Importer) gör det enklare för dig att använda ett rubrikenhetsbibliotek i äldre projekt som #include STL-biblioteken. Det gör det onödigt att ändra #include direktiv till import i projektet, samtidigt som du får fördelen att importera rubrikenheterna i stället för att inkludera dem.

Om du till exempel har #include <vector> i projektet och refererar till ett statiskt bibliotek som innehåller en rubrikenhet för <vector>behöver du inte ändra #include <vector> till import <vector>; i källkoden manuellt. Kompilatorn behandlar #include <vector> i stället automatiskt som import <vector>;. För mer information om detta tillvägagångssätt, se Tillvägagångssätt 2: Sökning i inkluderade STL-rubriker som ska importeras. Alla STL-huvudfiler kan inte kompileras till en rubrikenhet. Den header-units.json som levereras med Visual Studio visar vilka STL-huvudfiler som kan kompileras till rubrikenheter. En header som förlitar sig på makron för att ange dess funktion kan inte ofta kompileras till en header-enhet.

En #include instruktion som inte refererar till en rubrikenhet behandlas som en normal #include.

Återanvända rubrikenheter mellan projekt

Rubrikenheter som skapats av ett statiskt biblioteksprojekt är automatiskt tillgängliga för alla direkt och indirekt refererande projekt. Det finns projektinställningar som gör att du kan välja vilka rubrikenheter som ska vara automatiskt tillgängliga för alla refererande projekt. Inställningarna finns i projektinställningar under VC++ Kataloger.

  1. Högerklicka på projektet i Solution Explorer och välj Egenskaper för att öppna dialogrutan Egenskapssidor för projektet.
  2. I den vänstra rutan i dialogrutan väljer du Konfigurationsegenskaper>VC++ Kataloger: Skärmbild som visar egenskaper för offentligt projektinnehåll, till exempel Offentliga inkluderingskataloger och Alla rubrikfiler är offentliga.

Följande egenskaper styr synligheten för header-enheter i byggsystemet:

  • Offentliga inkluderingskataloger anger projektkataloger för rubrikenheter som automatiskt ska läggas till i inkluderingssökvägen i refererande projekt.
  • Offentliga C++-modulkataloger anger vilka projektkataloger som innehåller rubrikenheter som ska vara tillgängliga för att referera till projekt. Med den här egenskapen kan du göra vissa rubrikenheter offentliga. Det är synligt för andra projekt, så placera rubrikenheter som du vill dela här. Om du använder den här inställningen anger du för enkelhetens skull offentliga inkluderingskataloger för att automatiskt lägga till dina offentliga rubriker i sökvägen Inkludera i refererande projekt.
  • Alla moduler är offentliga: när du använder rubrikenheter som skapats som en del av ett DLL-projekt måste symbolerna exporteras från DLL:en. Om du vill exportera modulsymboler automatiskt anger du den här egenskapen till Ja.

Använda en fördefinierad modulfil

Det enklaste sättet att återanvända huvudfiler mellan lösningar är vanligtvis att referera till ett projekt med delade huvudfiler från varje lösning.

Om du måste använda en inbyggd rubrikenhet som du inte har projektet för kan du ange var den skapade .ifc filen finns så att du kan importera den i din lösning. Så här kommer du åt den här inställningen:

  1. På huvudmenyn väljer du Projektegenskaper> för att öppna dialogrutan Egenskapssidor för projektet.
  2. I den vänstra rutan i dialogrutan väljer du Konfigurationsegenskaper>C/C++>Allmänt.
  3. I Ytterligare modulberoenden lägger du till modulerna som ska refereras, avgränsade med semikolon. Här är ett exempel på det format som ska användas för Ytterligare modulberoenden: ModuleName1=Path\To\ModuleName1.ifc; ModuleName2=Path\To\ModuleName2.ifcSkärmbild som visar egenskaper för projektegenskapssidor under Konfigurationsegenskaper, C/C++, Allmänt, med ytterligare modulberoenden valda.

Välj bland flera kopior av en rubrikenhet

Om du refererar till projekt som skapar flera rubrikenheter, antingen med samma namn eller för samma rubrikfil, måste du ange vilken som ska användas. Du kan ha olika versioner av rubrikenheten som skapats med olika kompilatorinställningar, till exempel och måste ange den som matchar dina projektinställningar.

Använd projektets additional header unit dependencies-egenskap för att lösa kollisioner genom att ange vilken rubrikenhet som ska användas. Annars går det inte att förutsäga vilken som väljs.

Så här anger du egenskapen Ytterligare beroenden för rubrikenhet :

  1. På huvudmenyn väljer du Projektegenskaper> för att öppna dialogrutan Egenskapssidor för projektet.
  2. I den vänstra rutan i dialogrutan väljer du Konfigurationsegenskaper>C/C++>Allmänt.
  3. Ange vilka moduler eller huvudenhetsfiler som ska användas i Ytterligare beroenden för rubrikenhet för att lösa kollisioner. Använd det här formatet för Ytterligare beroenden för rubrikenhet: Path\To\Header1.h= Path\To\HeaderUnit1.ifc;Path\To\Header2.h= Path\To\ HeaderUnit2.ifcSkärmbild som visar inställningen Ytterligare beroenden för rubrikenheter i dialogrutan Egenskapssidor för projekt.

Viktigt!

Se till att projekt som delar rubrikenheter skapas med kompatibla kompileringsalternativ. Om du använder kompileringsalternativ när du implementerar rubrikenheten som skiljer sig från de som du använde när du skapade den, utfärdar kompilatorn varningar.

Anmärkning

Om du vill använda rubrikenheter som skapats som en del av ett DLL-projekt anger du Alla moduler är offentliga till Ja.

Metod 2: Genomsökning innehåller stl-huvuden som ska importeras

Ett annat sätt att importera STL-bibliotek är att låta Visual Studio söka efter de STL-huvudfiler du #include har i projektet och kompilera dem till huvudenheter. Kompilatorn importerar sedan i stället för att inkludera dessa rubriker.

Det här alternativet är praktiskt när projektet innehåller många STL-huvudfiler i många filer, eller när byggdataflödet inte är kritiskt. Det här alternativet garanterar inte att en rubrikenhet för en viss rubrikfil bara skapas en gång. Det är dock användbart om du har en stor kodbas: Du behöver inte ändra källkoden för att dra nytta av fördelarna med rubrikenheter för många av de STL-bibliotek som du använder.

Den här metoden är mindre flexibel än metoden för statiskt bibliotek, eftersom den inte lämpar sig för återanvändning av de skapade huvudenheterna i andra projekt. Den här metoden kanske inte är lämplig för större projekt: Den garanterar inte optimal byggtid eftersom alla källor måste genomsökas efter #include instruktioner.

Alla huvudfiler kan inte konverteras automatiskt till rubrikenheter. Till exempel bör rubriker som är beroende av villkorlig kompilering via makron inte konverteras till rubrikenheter. Det finns en tillåtelselista i form av en header-units.json-fil för de STL-headerfiler som kompilatorn använder när /translateInclude anges. Den avgör vilka STL-huvuden som kan kompileras till rubrikenheter. Filen header-units.json finns under installationskatalogen för Visual Studio. Till exempel %ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.30.30705\include\header-units.json. Om STL-huvudfilen inte finns med i listan behandlas den som en normal #include fil i stället för att importera den som en rubrikenhet. En annan fördel med header-units.json-filen är att den förhindrar symbolduplicering i genererade huvudeneheter. Om kompileringen av en rubrikenhet inkluderar ett bibliotekshuvud flera gånger, kommer inte symbolerna att dupliceras.

Om du vill prova den här metoden skapar du ett projekt som innehåller två STL-bibliotek. Ändra sedan projektets egenskaper så att det importerar biblioteken som rubrikenheter i stället för att inkludera dem, enligt beskrivningen i nästa avsnitt.

Skapa ett C++-konsolappprojekt

Följ de här stegen för att skapa ett projekt som innehåller två STL-bibliotek: <iostream> och <vector>.

  1. Skapa ett nytt C++-konsolappprojekt i Visual Studio.

  2. Ersätt innehållet i källfilen på följande sätt:

    #include <iostream>
    #include <vector>
    
    int main()
    {
        std::vector<int> numbers = {0, 1, 2};
        std::cout << numbers[1];
    }
    

Ange projektalternativ och kör projektet

Följande steg anger det alternativ som gör att kompilatorn söker efter inkluderade rubriker som översätts till rubrikenheter. De anger också det alternativ som gör att kompilatorn behandlar #include som om du hade skrivit import för huvudfiler som kan behandlas som rubrikenheter.

  1. På huvudmenyn väljer du Projektegenskaper> för att öppna dialogrutan Egenskapssidor för projektet.
  2. Välj Alla konfigurationer i listrutan Konfiguration och välj sedan Alla plattformar i listrutan Plattform . De här inställningarna säkerställer att ändringarna gäller oavsett om du skapar för felsökning eller lansering och andra konfigurationer.
  3. I den vänstra rutan i dialogrutan väljer du Konfigurationsegenskaper>C/C++>Allmänt.
  4. Ställ in Sök källor för modulberoendenJa. Den här inställningen säkerställer att alla kompatibla huvudfiler kompileras till rubrikenheter.
  5. Ange Översätt 'Inkludera' till 'Importera' till Ja. Den här inställningen kompilerar de STL-huvudfiler som anges i header-unit.json-filen som rubrikenheter och importerar dem i stället för att använda förprocessorn till att #include dem. Skärmbild som visar egenskapsinställningen för genomsökningsmodulens beroenden i projektets egenskapssidor.
  6. Välj OK för att spara ändringarna och stäng dialogrutan Egenskapssidor för projektet.

Alternativet /std:c++20 eller senare krävs för att använda rubrikenheter. Så här ändrar du C++-språkstandarden som används av kompilatorn:

  1. På huvudmenyn väljer du Projektegenskaper> för att öppna dialogrutan Egenskapssidor för projektet.
  2. Välj Alla konfigurationer i listrutan Konfiguration och välj sedan Alla plattformar i listrutan Plattform . De här inställningarna säkerställer att ändringarna gäller oavsett om du skapar för felsökning eller lansering och andra konfigurationer.
  3. I den vänstra rutan i dialogrutan Egenskapssidor för projektet väljer du Konfigurationsegenskaper>Allmänt.
  4. I listrutan C++ Language Standard väljer du ISO C++20 Standard (/std:c++20) (eller senare).
  5. Välj OK för att spara ändringarna och stäng dialogrutan Egenskapssidor för projektet.
  6. På huvudmenyn skapar du lösningen genom att välja Skapa>bygglösning.

Kör lösningen för att kontrollera att den genererar förväntade utdata: 1

Huvudövervägandet för att använda den här metoden är balansen mellan bekvämlighet och kostnaden för att genomsöka alla dina filer för att avgöra vilka huvudfiler som ska skapas som rubrikenheter.

Se även

Jämför rubrikenheter, moduler och förkompilerade rubriker
Självstudie: Importera C++-standardbiblioteket med hjälp av moduler
Genomgång: Skapa och importera rubrikenheter i dina Visual C++-projekt
/translateInclude