Udostępnij za pośrednictwem


Rozszerzalność systemu projektów visual Studio C++ i integracja zestawu narzędzi

System projektu Visual C++ jest używany do .vcxproj plików. Jest ona oparta na programie Visual Studio Common Project System (CPS) i udostępnia dodatkowe punkty rozszerzalności specyficzne dla języka C++ umożliwiające łatwą integrację nowych zestawów narzędzi, architektur kompilacji i platform docelowych.

Struktura obiektów docelowych programu MSBuild w języku C++

Wszystkie pliki .vcxproj są importowane:

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

Te pliki definiują niewiele samodzielnie. Zamiast tego importują inne pliki na podstawie tych wartości właściwości:

  • $(ApplicationType)

    Przykłady: Sklep Windows, Android, Linux

  • $(ApplicationTypeRevision)

    Musi to być prawidłowy ciąg wersji formularza major.minor[.build[.revision]].

    Przykłady: 1.0, 10.0.0.0

  • $(Platform)

    Architektura kompilacji o nazwie "Platforma" ze względów historycznych.

    Przykłady: Win32, x86, x64, ARM

  • $(PlatformToolset)

    Przykłady: v140, v141, v141_xp, llvm

Te wartości właściwości określają nazwy folderów w folderze $(VCTargetsPath) głównym:

$(VCTargetsPath)\
    Typ aplikacji\
        $(ApplicationType)\
            $(ApplicationTypeRevision)\
                Platformy\
                    $(Platform)\
                        Zestawy narzędzi platformy\
                            $(PlatformToolset)
    Platformy\
        $(Platform)\
            Zestawy narzędzi platformy\
                $(PlatformToolset)

Folder $(VCTargetsPath)\Platformy\ jest używany, gdy $(ApplicationType) jest pusty, w przypadku projektów klasycznych systemu Windows.

Dodawanie nowego zestawu narzędzi platformy

Aby dodać nowy zestaw narzędzi, na przykład "MyToolset" dla istniejącej platformy Win32, utwórz folder MyToolset w folderze $(VCTargetsPath)\Platforms\Win32\PlatformToolsets\, a następnie utwórz w nim pliki Toolset.props i Toolset.targets.

Każda nazwa folderu w obszarze PlatformToolsets jest wyświetlana w oknie dialogowym Właściwości projektu jako dostępny zestaw narzędzi platformy dla określonej platformy, jak pokazano poniżej:

Właściwość Zestaw narzędzi platformy w oknie dialogowym Strony właściwości projektu

Utwórz podobne foldery MyToolset i pliki Toolset.props i Toolset.targets w każdym istniejącym folderze platformy, który obsługuje ten zestaw narzędzi.

Dodawanie nowej platformy

Aby dodać nową platformę, na przykład "MyPlatform", utwórz folder MyPlatform w folderze $(VCTargetsPath)\Platforms\, a następnie utwórz w nim pliki Platform.default.props, Platform.props i Platform.targets. $(VCTargetsPath)Utwórz również folder \Platforms\MyPlatform\PlatformToolsets\ i utwórz w nim co najmniej jeden zestaw narzędzi.

Wszystkie nazwy folderów w folderze Platformy dla każdego $(ApplicationType) i $(ApplicationTypeRevision) są wyświetlane w środowisku IDE jako dostępne opcje platformy dla projektu.

Wybór nowej platformy w oknie dialogowym Nowa platforma projektu

Dodawanie nowego typu aplikacji

Aby dodać nowy typ aplikacji, utwórz folder MyApplicationType w folderze $(VCTargetsPath)\Application Type\ i utwórz w nim plik Defaults.props. Co najmniej jedna poprawka jest wymagana dla typu aplikacji, dlatego utwórz $(VCTargetsPath)w nim również folder \Application Type\MyApplicationType\1.0 i utwórz w nim plik Defaults.props . Należy również utworzyć $(VCTargetsPath)folder \ApplicationType\MyApplicationType\1.0\Platforms i utworzyć w nim co najmniej jedną platformę.

$(ApplicationType) właściwości i $(ApplicationTypeRevision) nie są widoczne w interfejsie użytkownika. Są one definiowane w szablonach projektów i nie można ich zmienić po utworzeniu projektu.

Drzewo importu .vcxproj

Uproszczone drzewo importów dla rekwizytów i plików docelowych języka Microsoft C++ wygląda następująco:

$(VCTargetsPath)\Microsoft.Cpp.Default.props
    $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props
    $(VCTargetsPath)\ImportBefore\Default\*.Rekwizyty
    $(VCTargetsPath)\Typ\\$(ApplicationType)aplikacji Default.props
    $(VCTargetsPath)\Typ$(ApplicationTypeRevision)\$(ApplicationType)\\aplikacji Default.props
    $(VCTargetsPath)\Platformy\$(Platform)\typów$(ApplicationType)\\$(ApplicationTypeRevision)\aplikacji Platform.default.props
    $(VCTargetsPath)\ImportAfter\Default\*.Rekwizyty

Projekty pulpitu z systemem Windows nie definiują $(ApplicationType)elementu , więc importują je tylko

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

Użyjemy $(_PlatformFolder) właściwości do przechowywania $(Platform) lokalizacji folderów platformy. Ta właściwość jest

$(VCTargetsPath)\Platformy\$(Platform)

dla aplikacji klasycznych systemu Windows i

$(VCTargetsPath)\Platformy typów$(ApplicationTypeRevision)\$(ApplicationType)\\aplikacji\$(Platform)

dla wszystkiego innego.

Pliki props są importowane w tej kolejności:

$(VCTargetsPath)\Microsoft.Cpp.props
    $(_PlatformFolder)\Platform.props
        $(VCTargetsPath)\Microsoft.Cpp.Platform.props
            $(_PlatformFolder)\ImportBefore\*.Rekwizyty
            $(_PlatformFolder)\Zestaw narzędzi PlatformToolsets.props\$(PlatformToolset)\
            $(_PlatformFolder)\ImportAfter\*.Rekwizyty

Pliki docelowe są importowane w następującej kolejności:

$(VCTargetsPath)\Microsoft.Cpp.targets
    $(VCTargetsPath)\Microsoft.Cpp.Current.targets
        $(_PlatformFolder)\Platform.targets
            $(VCTargetsPath)\Microsoft.Cpp.Platform.targets
                $(_PlatformFolder)\ImportBefore\*.Cele
                $(_PlatformFolder)\Zestaw narzędzi PlatformToolsets.target\$(PlatformToolset)\
                $(_PlatformFolder)\ImportAfter\*.Cele

Jeśli musisz zdefiniować niektóre domyślne właściwości zestawu narzędzi, możesz dodać pliki do odpowiednich folderów ImportBefore i ImportAfter.

Pliki Author Toolset.props i Toolset.targets

Pliki Toolset.props i Toolset.targets mają pełną kontrolę nad tym, co się dzieje podczas kompilacji, gdy ten zestaw narzędzi jest używany. Mogą również kontrolować dostępne debugery, niektóre interfejsy użytkownika IDE, takie jak zawartość w oknie dialogowym Strony właściwości i niektóre inne aspekty zachowania projektu.

Mimo że zestaw narzędzi może zastąpić cały proces kompilacji, zwykle zestaw narzędzi ma modyfikować lub dodawać kilka kroków kompilacji lub używać różnych narzędzi kompilacji w ramach istniejącego procesu kompilacji. Aby osiągnąć ten cel, istnieje wiele typowych rekwizytów i plików docelowych, które zestaw narzędzi może zaimportować. W zależności od tego, co chcesz zrobić w zestawie narzędzi, te pliki mogą być przydatne do użycia jako import lub jako przykłady:

  • $(VCTargetsPath)\Microsoft.CppCommon.targets

    Ten plik definiuje główne części natywnego procesu kompilacji, a także importuje:

    • $(VCTargetsPath)\Microsoft.CppBuild.targets

    • $(VCTargetsPath)\Microsoft.BuildSteps.targets

    • $(MSBuildToolsPath)\Microsoft.Common.Targets

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

    Ustawia wartości domyślne dla zestawów narzędzi korzystających z kompilatorów firmy Microsoft i docelowego systemu Windows.

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

    Ten plik określa lokalizację zestawu Windows SDK i definiuje niektóre ważne właściwości dla aplikacji przeznaczonych dla systemu Windows.

Integrowanie elementów docelowych specyficznych dla zestawu narzędzi z domyślnym procesem kompilacji języka C++

Domyślny proces kompilacji języka C++ jest zdefiniowany w pliku Microsoft.CppCommon.targets. Te obiekty docelowe nie wywołają żadnych konkretnych narzędzi kompilacji; określają główne kroki kompilacji, ich kolejność i zależności.

Kompilacja języka C++ ma trzy główne kroki, które są reprezentowane przez następujące cele:

  • BuildGenerateSources

  • BuildCompile

  • BuildLink

Ponieważ każdy krok kompilacji może być wykonywany niezależnie, obiekty docelowe uruchomione w jednym kroku nie mogą polegać na grupach elementów i właściwościach zdefiniowanych w obiektach docelowych uruchamianych w ramach innego kroku. Ten podział umożliwia pewne optymalizacje wydajności kompilacji. Mimo że nie jest on używany domyślnie, nadal zachęcamy do honorowania tej separacji.

Obiekty docelowe, które są uruchamiane wewnątrz każdego kroku, są kontrolowane przez następujące właściwości:

  • $(BuildGenerateSourcesTargets)

  • $(BuildCompileTargets)

  • $(BeforeBuildLinkTargets)

Każdy krok ma również właściwości Przed i Po.

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

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

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

Zobacz plik Microsoft.CppBuild.targets, aby zapoznać się z przykładami obiektów docelowych uwzględnionych w każdym kroku:

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

Jeśli przyjrzysz się obiektom docelowym, takim jak _ClCompile, zobaczysz, że nie robią nic bezpośrednio samodzielnie, ale zamiast tego zależą od innych celów, w tym ClCompile:

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

ClCompile i inne obiekty docelowe specyficzne dla narzędzi kompilacji są definiowane jako puste obiekty docelowe w pliku Microsoft.CppBuild.targets:

<Target Name="ClCompile"/>

Ponieważ element docelowy ClCompile jest pusty, chyba że jest zastępowany przez zestaw narzędzi, nie jest wykonywana żadna rzeczywista akcja kompilacji. Obiekty docelowe zestawu narzędzi mogą zastąpić ClCompile element docelowy, czyli mogą zawierać inną ClCompile definicję po zaimportowaniu elementu Microsoft.CppBuild.targets:

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

Pomimo nazwy, która została utworzona przed zaimplementowaniem obsługi międzyplatformowej programu Visual Studio, ClCompile element docelowy nie musi wywoływać CL.exe. Może również wywoływać język Clang, gcc lub inne kompilatory przy użyciu odpowiednich zadań MSBuild.

Obiekt ClCompile docelowy nie powinien mieć żadnych zależności z wyjątkiem SelectClCompile obiektu docelowego, który jest wymagany do działania polecenia kompilacji pojedynczego pliku w środowisku IDE.

Zadania programu MSBuild do użycia w elementach docelowych zestawu narzędzi

Aby wywołać rzeczywiste narzędzie kompilacji, element docelowy musi wywołać zadanie MSBuild. Istnieje podstawowe zadanie Exec, które umożliwia określenie wiersza polecenia do uruchomienia. Jednak narzędzia kompilacji zwykle mają wiele opcji, danych wejściowych i wyjściowych do śledzenia kompilacji przyrostowych, więc warto mieć specjalne zadania dla nich. Na przykład CL zadanie tłumaczy właściwości msBuild na przełączniki CL.exe, zapisuje je w pliku odpowiedzi i wywołuje CL.exe. Śledzi również wszystkie pliki wejściowe i wyjściowe na potrzeby kolejnych kompilacji przyrostowych. Aby uzyskać więcej informacji, zobacz Incremental builds and up-to-date checks (Kompilacje przyrostowe i aktualne testy).

Microsoft.Cpp.Common.Tasks.dll implementuje następujące zadania:

  • BSCMake

  • CL

  • ClangCompile (przełączniki clang-gcc)

  • LIB

  • LINK

  • MIDL

  • Mt

  • RC

  • XDCMake

  • CustomBuild (na przykład Exec, ale ze śledzeniem danych wejściowych i wyjściowych)

  • SetEnv

  • GetOutOfDateItems

Jeśli masz narzędzie, które wykonuje tę samą akcję co istniejące narzędzie i ma podobne przełączniki wiersza polecenia (co clang-cl i CL do), możesz użyć tego samego zadania dla obu z nich.

Jeśli musisz utworzyć nowe zadanie dla narzędzia kompilacji, możesz wybrać jedną z następujących opcji:

  1. Jeśli używasz tego zadania rzadko lub jeśli kilka sekund nie ma znaczenia dla kompilacji, możesz użyć zadań msBuild "wbudowanych":

    • Zadanie Xaml (niestandardowa reguła kompilacji)

      Aby zapoznać się z jednym przykładem deklaracji zadania Xaml, zobacz $(VCTargetsPath)\BuildCustomizations\masm.xml i aby uzyskać informacje o jego użyciu, zobacz $(VCTargetsPath)\BuildCustomizations\masm.targets.

    • Zadanie kodu

  2. Jeśli chcesz uzyskać lepszą wydajność zadań lub po prostu potrzebujesz bardziej złożonych funkcji, użyj zwykłego procesu pisania zadań MSBuild.

    Jeśli nie wszystkie dane wejściowe i wyjściowe narzędzia są wyświetlane w wierszu polecenia narzędzia, tak jak w CLwierszach poleceń , MIDLi RC przypadkach, a jeśli chcesz automatyczne śledzenie plików wejściowych i wyjściowych oraz tworzenie pliku tlog, należy utworzyć zadanie z Microsoft.Build.CPPTasks.TrackedVCToolTask klasy . Obecnie w dokumentacji podstawowej klasy ToolTask nie ma przykładów ani dokumentacji dotyczącej szczegółów TrackedVCToolTask klasy. Jeśli jest to szczególnie interesujące, dodaj swój głos do żądania w społeczności deweloperów.

Kompilacje przyrostowe i aktualne kontrole

Domyślne obiekty docelowe kompilacji przyrostowej MSBuild używają Inputs atrybutów i Outputs . Jeśli je określisz, program MSBuild wywołuje element docelowy tylko wtedy, gdy którykolwiek z danych wejściowych ma nowszy znacznik czasu niż wszystkie dane wyjściowe. Ponieważ pliki źródłowe często zawierają lub importują inne pliki, a narzędzia kompilacji generują różne dane wyjściowe w zależności od opcji narzędzia, trudno jest określić wszystkie możliwe dane wejściowe i wyjściowe w celach programu MSBuild.

Aby zarządzać tym problemem, kompilacja języka C++ używa innej techniki do obsługi kompilacji przyrostowych. Większość obiektów docelowych nie określa danych wejściowych i wyjściowych, a w rezultacie zawsze uruchamiane podczas kompilacji. Zadania wywoływane przez obiekty docelowe zapisują informacje o wszystkich danych wejściowych i wyjściowych w plikach tlog , które mają rozszerzenie tlog. Pliki tlog są używane przez późniejsze kompilacje, aby sprawdzić, co się zmieniło i które należy ponownie skompilować oraz co jest aktualne. Pliki .tlog są również jedynym źródłem domyślnej kompilacji aktualnej ewidencjonowania w środowisku IDE.

Aby określić wszystkie dane wejściowe i wyjściowe, zadania narzędzi natywnych używają tracker.exe i klasy FileTracker dostarczonej przez program MSBuild.

Microsoft.Build.CPPTasks.Common.dll definiuje publiczną abstrakcyjną klasę TrackedVCToolTask bazową. Większość zadań natywnych narzędzi pochodzi z tej klasy.

Począwszy od programu Visual Studio 2017 update 15.8, można użyć GetOutOfDateItems zadania zaimplementowanego w Microsoft.Cpp.Common.Tasks.dll w celu utworzenia plików tlog dla obiektów docelowych niestandardowych ze znanymi danymi wejściowymi i wyjściowymi. Alternatywnie można je utworzyć przy użyciu WriteLinesToFile zadania . Zobacz element docelowy w $(VCTargetsPath)\pliku _WriteMasmTlogs BuildCustomizations\masm.targets jako przykład.

Pliki .tlog

Istnieją trzy typy plików tlog: odczyt, zapis i wiersz polecenia. Pliki tlog odczytu i zapisu są używane przez kompilacje przyrostowe i aktualne sprawdzanie w środowisku IDE. Pliki tlog wiersza polecenia są używane tylko w kompilacjach przyrostowych.

Program MSBuild udostępnia te klasy pomocnicze do odczytywania i zapisywania plików tlog:

Klasa FlatTrackingData może służyć do uzyskiwania dostępu zarówno do odczytu, jak i zapisu plików tlog oraz identyfikowania danych wejściowych, które są nowsze niż dane wyjściowe, lub jeśli brakuje danych wyjściowych. Jest on używany w aktualnym czeku.

Pliki .tlog wiersza polecenia zawierają informacje o wierszach polecenia używanych w kompilacji. Są one używane tylko do kompilacji przyrostowych, a nie aktualnych testów, więc format wewnętrzny jest określany przez zadanie MSBuild, które je generuje.

Odczytywanie formatu tlog

Odczytywanie plików tlog (*.read.*.tlog) zawiera informacje o plikach źródłowych i ich zależnościach.

Daszek (^) na początku wiersza wskazuje co najmniej jedno źródło. Źródła, które współużytkują te same zależności, są oddzielone pionowym paskiem (|).

Pliki zależności są wyświetlane po źródłach, z których każda znajduje się w osobnym wierszu. Wszystkie nazwy plików to pełne ścieżki.

Załóżmy na przykład, że źródła projektu znajdują się w folderze F:\test\ConsoleApplication1\ConsoleApplication1. Jeśli plik źródłowy, Class1.cpp, zawiera następujące elementy:

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

następnie plik CL.read.1.tlog zawiera plik źródłowy, a następnie jego dwie zależności:

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

Nie jest to wymagane do pisania nazw plików w wielkim przypadku, ale jest to wygoda dla niektórych narzędzi.

Zapis formatu tlog

Zapisuj pliki .tlog (*.write.*.tlog) łączące źródła i dane wyjściowe.

Daszek (^) na początku wiersza wskazuje co najmniej jedno źródło. Wiele źródeł jest rozdzielonych pionowym paskiem (|).

Pliki wyjściowe skompilowane ze źródeł powinny być wyświetlane po źródłach, z których każda znajduje się we własnym wierszu. Wszystkie nazwy plików muszą być pełne ścieżki.

Na przykład w przypadku prostego projektu ConsoleApplication z dodatkowym plikiem źródłowym Class1.cpp plik link.write.1.tlog może zawierać następujące elementy:

^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

Kompilacja w czasie projektowania

W środowisku IDE projekty .vcxproj używają zestawu obiektów docelowych MSBuild do uzyskiwania dodatkowych informacji z projektu i ponownego generowania plików wyjściowych. Niektóre z tych celów są używane tylko w kompilacjach w czasie projektowania, ale wiele z nich jest używanych zarówno w zwykłych kompilacjach, jak i kompilacjach w czasie projektowania.

Aby uzyskać ogólne informacje na temat kompilacji w czasie projektowania, zobacz dokumentację CPS dotyczącą kompilacji w czasie projektowania. Ta dokumentacja ma zastosowanie tylko częściowo do projektów Visual C++.

Obiekty CompileDesignTime docelowe i Compile wymienione w dokumentacji kompilacji w czasie projektowania nigdy nie są uruchamiane dla projektów .vcxproj. Projekty visual C++ .vcxproj używają różnych celów czasu projektowania, aby uzyskać informacje o funkcji IntelliSense.

Cele czasu projektowania dla informacji funkcji IntelliSense

Cele czasu projektowania używane w projektach .vcxproj są zdefiniowane w $(VCTargetsPath)\pliku Microsoft.Cpp.DesignTime.targets.

Obiekt GetClCommandLines docelowy zbiera opcje kompilatora dla funkcji IntelliSense:

<Target
  Name="GetClCommandLines"
  Returns="@(ClCommandLines)"
  DependsOnTargets="$(DesignTimeBuildInitTargets);$(ComputeCompileInputsTargets)">
  • DesignTimeBuildInitTargets — cele tylko w czasie projektowania, wymagane do inicjowania kompilacji w czasie projektowania. Między innymi te cele wyłączają niektóre z regularnych funkcji kompilacji, aby zwiększyć wydajność.

  • ComputeCompileInputsTargets — zestaw obiektów docelowych, który modyfikuje opcje i elementy kompilatora. Te obiekty docelowe są uruchamiane zarówno w czasie projektowania, jak i w regularnych kompilacjach.

Element docelowy CLCommandLine wywołuje zadanie, aby utworzyć wiersz polecenia do użycia dla funkcji IntelliSense. Ponownie, pomimo nazwy, może obsługiwać nie tylko opcje CL, ale także Clang i gcc opcje. Typ przełączników kompilatora jest kontrolowany ClangMode przez właściwość .

Obecnie wiersz polecenia generowany przez CLCommandLine zadanie zawsze używa przełączników CL (nawet w trybie Clang), ponieważ są one łatwiejsze dla aparatu IntelliSense do analizowania.

Jeśli dodasz element docelowy uruchamiany przed kompilacją, niezależnie od tego, czy jest to regularne, czy projektowe, upewnij się, że nie przerywa kompilacji czasu projektowania ani nie wpływa na wydajność. Najprostszym sposobem testowania docelowego jest otwarcie wiersza polecenia dla deweloperów i uruchomienie tego polecenia:

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

To polecenie tworzy szczegółowy dziennik kompilacji, msbuild.log, który zawiera podsumowanie wydajności dla celów i zadań na końcu.

Pamiętaj, aby używać Condition ="'$(DesignTimeBuild)' != 'true'" we wszystkich operacjach, które mają sens tylko w przypadku zwykłych kompilacji, a nie kompilacji w czasie projektowania.

Cele czasu projektowania, które generują źródła

Ta funkcja jest domyślnie wyłączona dla projektów natywnych dla komputerów stacjonarnych i nie jest obecnie obsługiwana w projektach buforowanych.

Jeśli GeneratorTarget metadane są zdefiniowane dla elementu projektu, element docelowy jest uruchamiany automatycznie zarówno po załadowaniu projektu, jak i po zmianie pliku źródłowego.

Na przykład aby automatycznie generować pliki .cpp lub h z plików xaml, $(VSInstallDir)\pliki MSBuild\Microsoft\WindowsXaml\v16.0\*\Microsoft.Windows.UI.Xaml.CPP.Targets definiują następujące jednostki:

<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>

Task.HostObject Aby uzyskać niezapisaną zawartość plików źródłowych, obiekty docelowe i zadanie powinny być zarejestrowane jako msbuildHostObjects dla danych projektów w pliku pkgdef:

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

Rozszerzalność projektu Visual C++ w środowisku IDE programu Visual Studio

System projektu Visual C++ jest oparty na systemie programu VS Project i używa jego punktów rozszerzalności. Jednak implementacja hierarchii projektu jest specyficzna dla języka Visual C++ i nie jest oparta na cpS, więc rozszerzalność hierarchii jest ograniczona do elementów projektu.

Strony właściwości projektu

Ogólne informacje o projekcie można znaleźć w temacie Framework Multi-Targeting for VC++ Projects (Wielowersyjność struktury dla projektów VC++).

Mówiąc prosto, strony właściwości widoczne w oknie dialogowym Właściwości projektu dla projektu języka C++ są definiowane przez pliki reguł . Plik reguły określa zestaw właściwości do wyświetlenia na stronie właściwości oraz sposób i miejsce ich zapisania w pliku projektu. Pliki reguł to pliki .xml, które używają formatu Xaml. Typy używane do serializacji są opisane w artykule Microsoft.Build.Framework.XamlTypes. Aby uzyskać więcej informacji na temat używania plików reguł w projektach, zobacz Pliki reguł XML strony właściwości.

Pliki reguł muszą zostać dodane do PropertyPageSchema grupy elementów:

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

Context Widoczność reguły limitów metadanych, która jest również kontrolowana przez typ reguły i może mieć jedną z następujących wartości:

Project | File | PropertySheet

Usługa CPS obsługuje inne wartości dla typu kontekstu, ale nie są używane w projektach Visual C++.

Jeśli reguła powinna być widoczna w więcej niż jednym kontekście, użyj średników (;), aby oddzielić wartości kontekstu, jak pokazano poniżej:

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

Format reguły i typy główne

Format reguły jest prosty, dlatego w tej sekcji opisano tylko atrybuty wpływające na wygląd reguły w interfejsie użytkownika.

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

Atrybut PageTemplate określa sposób wyświetlania reguły w oknie dialogowym Strony właściwości. Atrybut może mieć jedną z następujących wartości:

Atrybut opis
generic Wszystkie właściwości są wyświetlane na jednej stronie w obszarze Nagłówki kategorii
Reguła może być widoczna dla Project kontekstów i PropertySheet , ale nie File.

Przykład: $(VCTargetsPath)\1033\general.xml
tool Kategorie są wyświetlane jako podstrony.
Reguła może być widoczna we wszystkich kontekstach: Project, PropertySheet i File.
Reguła jest widoczna we właściwościach projektu tylko wtedy, gdy projekt zawiera elementy ze ItemType zdefiniowanymi w elemencie Rule.DataSource, chyba że nazwa reguły jest uwzględniona w ProjectTools grupie elementów.

Przykład: $(VCTargetsPath)\1033\clang.xml
debugger Strona jest wyświetlana jako część strony Debugowanie.
Kategorie są obecnie ignorowane.
Nazwa reguły powinna być zgodna z atrybutem obiektu MEF uruchamiania ExportDebugger debugowania.

Przykład: $(VCTargetsPath)\1033\debugger_local_windows.xml
custom Szablon niestandardowy. Nazwa szablonu powinna być zgodna z ExportPropertyPageUIFactoryProvider atrybutem PropertyPageUIFactoryProvider obiektu MEF. Zobacz Microsoft.VisualStudio.ProjectSystem.Designers.Properties.IPropertyPageUIFactoryProvider.

Przykład: $(VCTargetsPath)\1033\userMacros.xml

Jeśli reguła używa jednego z szablonów opartych na siatce właściwości, może użyć tych punktów rozszerzalności dla jego właściwości:

Rozszerzanie reguły

Jeśli chcesz użyć istniejącej reguły, ale musisz dodać lub usunąć (czyli ukryć) tylko kilka właściwości, możesz utworzyć regułę rozszerzenia.

Zastępowanie reguły

Być może chcesz, aby zestaw narzędzi używał większości reguł domyślnych projektu, ale zastąpić tylko jedną lub kilka z nich. Załóżmy na przykład, że chcesz zmienić regułę języka C/C++, aby wyświetlić różne przełączniki kompilatora. Możesz podać nową regułę o tej samej nazwie i nazwie wyświetlanej co istniejąca reguła i dołączyć ją do PropertyPageSchema grupy elementów po zaimportowaniu domyślnych obiektów docelowych cpp. W projekcie jest używana tylko jedna reguła o podanej nazwie, a ostatnia zawarta w PropertyPageSchema grupie elementów wygrywa.

Towary w ramach projektu

Plik ProjectItemsSchema.xml definiuje ContentType wartości i ItemType dla elementów, które są traktowane jako elementy projektu, i definiuje FileExtension elementy w celu określenia, do której grupy elementów jest dodawany nowy plik.

Domyślny plik ProjectItemsSchema znajduje się w $(VCTargetsPath)\ProjectItemsSchema.xml 1033.\ Aby go rozszerzyć, należy utworzyć plik schematu o nowej nazwie, na przykład 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>

Następnie w pliku targets dodaj:

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

Przykład: $(VCTargetsPath)\BuildCustomizations\masm.xml

Debugery

Usługa Debugowanie w programie Visual Studio obsługuje rozszerzalność aparatu debugowania. Aby uzyskać więcej informacji, zobacz następujące przykłady:

Aby określić aparaty debugowania i inne właściwości sesji debugowania, należy zaimplementować składnik MEF debugowania i dodać regułę debugger . Na przykład zobacz $(VCTargetsPath)plik \1033\debugger_local_windows.xml.

Wdróż

.vcxproj projekty używają rozszerzalności programu Visual Studio Project System dla dostawców wdrażania.

Tworzenie aktualnego sprawdzania

Domyślnie funkcja sprawdzania kompilacji wymaga utworzenia plików tlog i zapisu tlog w $(TlogLocation) folderze podczas kompilacji dla wszystkich danych wejściowych i wyjściowych kompilacji.

Aby użyć niestandardowego sprawdzania aktualności:

  1. Wyłącz domyślne sprawdzanie aktualne, dodając NoVCDefaultBuildUpToDateCheckProvider funkcję w pliku Toolset.targets :

    <ItemGroup>
      <ProjectCapability Include="NoVCDefaultBuildUpToDateCheckProvider" />
    </ItemGroup>
    
  2. Zaimplementuj własny IBuildUpToDateCheckProvider.

Uaktualnianie projektu

Domyślny program uaktualniania projektu .vcxproj

Domyślny .vcxproj uaktualniania projektu zmienia PlatformToolsetApplicationTypeRevisionwersję zestawu narzędzi MSBuild i .NET Framework. Ostatnie dwa są zawsze zmieniane na domyślne wersje programu Visual Studio, ale PlatformToolset mogą ApplicationTypeRevision być kontrolowane przez specjalne właściwości programu MSBuild.

Uaktualnianie używa tych kryteriów, aby zdecydować, czy projekt można uaktualnić, czy nie:

  1. W przypadku projektów definiujących ApplicationType wartości i ApplicationTypeRevisionistnieje folder o wyższym numerze poprawki niż bieżący.

  2. Właściwość _UpgradePlatformToolsetFor_<safe_toolset_name> jest zdefiniowana dla bieżącego zestawu narzędzi, a jego wartość nie jest równa bieżącemu zestawowi narzędzi.

    W tych nazwach <właściwości safe_toolset_name> reprezentuje nazwę zestawu narzędzi ze wszystkimi znakami innych niż alfanumeryczne zastąpione znakiem podkreślenia (_).

Po uaktualnieniu projektu uczestniczy on w retargetingu rozwiązań. Aby uzyskać więcej informacji, zobacz IVsTrackProjectRetargeting2.

Jeśli chcesz ozdobić nazwy projektów w Eksplorator rozwiązań, gdy projekty używają określonego zestawu narzędzi, zdefiniuj _PlatformToolsetShortNameFor_<safe_toolset_name> właściwość.

_UpgradePlatformToolsetFor_<safe_toolset_name> Przykłady definicji właściwości i _PlatformToolsetShortNameFor_<safe_toolset_name> można znaleźć w pliku Microsoft.Cpp.Default.props. Przykłady użycia można znaleźć w $(VCTargetPath)\pliku Microsoft.Cpp.Platform.targets.

Niestandardowy moduł uaktualniania projektu

Aby użyć niestandardowego obiektu uaktualniania projektu, zaimplementuj składnik MEF, jak pokazano poniżej:

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

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

Kod może importować i wywoływać domyślny obiekt .vcxproj upgrader:

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

IProjectRetargetHandler jest zdefiniowany w Microsoft.VisualStudio.ProjectSystem.VS.dll i jest podobny do IVsRetargetProjectAsync.

Zdefiniuj VCProjectUpgraderObjectName właściwość , aby poinformować system projektu o użyciu niestandardowego obiektu uaktualniania:

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

Wyłączanie uaktualniania projektu

Aby wyłączyć uaktualnienia projektu, użyj NoUpgrade wartości:

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

Pamięć podręczna i rozszerzalność projektu

Aby zwiększyć wydajność podczas pracy z dużymi rozwiązaniami języka C++ w programie Visual Studio 2017, wprowadzono pamięć podręczną projektu. Jest implementowana jako baza danych SQLite wypełniona danymi projektu, a następnie używana do ładowania projektów bez ładowania projektów MSBuild lub CPS do pamięci.

Ponieważ nie ma żadnych obiektów CPS dla projektów .vcxproj załadowanych z pamięci podręcznej, składniki MEF rozszerzenia, które importują UnconfiguredProject lub ConfiguredProject nie można ich utworzyć. Aby zapewnić rozszerzalność, pamięć podręczna projektu nie jest używana, gdy program Visual Studio wykryje, czy projekt używa (lub prawdopodobnie używa) rozszerzeń MEF.

Te typy projektów są zawsze w pełni ładowane i mają obiekty CPS w pamięci, więc wszystkie rozszerzenia MEF są tworzone dla nich:

  • Projekty startowe

  • Projekty z niestandardowym uaktualnieniem VCProjectUpgraderObjectName projektu, czyli definiują właściwość

  • Projekty, które nie są przeznaczone dla systemu Windows pulpitu, czyli definiują ApplicationType właściwość

  • Projekty elementów udostępnionych (vcxitems) i wszystkie projekty odwołujące się do nich przez zaimportowanie projektów vcxitems.

Jeśli żaden z tych warunków nie zostanie wykryty, zostanie utworzona pamięć podręczna projektu. Pamięć podręczna zawiera wszystkie dane z projektu MSBuild wymagane do odpowiadania na get zapytania dotyczące VCProjectEngine interfejsów. Oznacza to, że wszystkie modyfikacje na poziomie plików msBuild i docelowych wykonywane przez rozszerzenie powinny działać tylko w projektach załadowanych z pamięci podręcznej.

Wysyłanie rozszerzenia

Aby uzyskać informacje na temat tworzenia plików VSIX, zobacz Wysyłanie rozszerzeń programu Visual Studio. Aby uzyskać informacje na temat dodawania plików do specjalnych lokalizacji instalacji, na przykład w celu dodania plików w obszarze $(VCTargetsPath), zobacz Instalowanie poza folderem rozszerzeń.

Dodatkowe zasoby

System Microsoft Build System (MSBuild) udostępnia aparat kompilacji i rozszerzalny format XML dla plików projektu. Należy zapoznać się z podstawowymi pojęciami programu MSBuild i sposobem działania programu MSBuild dla języka Visual C++ w celu rozszerzenia systemu projektu Visual C++.

Platforma Managed Extensibility Framework (MEF) udostępnia interfejsy API rozszerzeń, które są używane przez cpS i system projektu Visual C++. Aby zapoznać się z omówieniem sposobu, w jaki meF jest używany przez cpS, zobacz CPS i MEF w temacie VSProjectSystem overview of MEF (Omówienie interfejsu MEF w programie VSProjectSystem).

Możesz dostosować istniejący system kompilacji, aby dodać kroki kompilacji lub nowe typy plików. Aby uzyskać więcej informacji, zobacz MSBuild (Visual C++) Overview and Working with project properties (Omówienie programu MSBuild (Visual C++) i Praca z właściwościami projektu.