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 plików .vcxproj. Jest ona oparta na Visual Studio Common Project System (CPS) i udostępnia dodatkowe, specyficzne dla języka C++ punkty rozszerzalności umożliwiające łatwą integrację nowych zestawów narzędzi, architektur kompilacji i platform docelowych.

Struktura celów MSBuild w języku C++

Wszystkie pliki .vcxproj importują te pliki:

<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 w formacie major.minor[.build[.revision]].

    Przykłady: 1.0, 10.0.0.0

  • $(Platform)

    Architektura zwana "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 głównym $(VCTargetsPath):

$(VCTargetsPath)\
     typu aplikacji\
        $(ApplicationType)\
            $(ApplicationTypeRevision)\
                 platformy\
                    $(Platform)\
                         PlatformToolsets\
                            $(PlatformToolset)
     platformy\
        $(Platform)\
             PlatformToolsets\
                $(PlatformToolset)

Folder platformy $(VCTargetsPath)\\ jest używany, gdy $(ApplicationType) jest pusta 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\i utwórz w nim pliki Toolset.prop s i Toolset.targets.

Każda nazwa folderu w PlatformToolsets jest wyświetlana w oknie dialogowym właściwości projektu jako dostępny zestaw narzędzi platformy 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 oraz pliki Toolset.props i Toolset.targets w każdym istniejącym folderze platformy obsługiwanym przez ten zestaw narzędzi.

Dodawanie nowej platformy

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

Wszystkie nazwy folderów w folderze Platforms dla wszystkich $(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 obszarze $(VCTargetsPath)\Application Type\ i utwórz w nim plik Defaults.props. Co najmniej jedna poprawka jest wymagana dla typu aplikacji, dlatego utwórz folder $(VCTargetsPath)\Application Type\MyApplicationType\1.0, a następnie utwórz w nim plik Defaults.props. Należy również utworzyć folder $(VCTargetsPath)\ApplicationType\MyApplicationType\1.0\Platforms i utworzyć w nim co najmniej jedną platformę.

$(ApplicationType) i właściwości $(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\domyślne\*.props
     $(VCTargetsPath) \ typ aplikacji\$(ApplicationType)\Default.props
     $(VCTargetsPath) \ typ aplikacji\$(ApplicationType)\$(ApplicationTypeRevision)\Default.props
     $(VCTargetsPath) \ typ aplikacji\$(ApplicationType)\$(ApplicationTypeRevision)\Platformy\$(Platform)\Platform.default.props
     $(VCTargetsPath) \ ImportAfter\domyślne\*.props

Projekty pulpitów systemu Windows nie definiują $(ApplicationType), więc importują tylko

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

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

$(VCTargetsPath) \ platformy\$(Platform)

dla aplikacji na pulpit systemu Windows i

$(VCTargetsPath) \ typ aplikacji\$(ApplicationType)\$(ApplicationTypeRevision)\platformy\$(Platform)

na wszystko inne.

Pliki props są importowane w tej kolejności:

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

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\*.obiektów docelowych
                 $(_PlatformFolder) \ PlatformToolsets\$(PlatformToolset)\Toolset.target
                 $(_PlatformFolder) \ ImportAfter\*.obiektów docelowych

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 podczas korzystania z tego zestawu narzędzi. Mogą również kontrolować dostępne debugery, niektóre elementy interfejsu użytkownika środowiska IDE, takie jak zawartość w oknie dialogowym strony właściwości, a także inne aspekty działania 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 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. Chociaż nie jest używana domyślnie, nadal zachęcamy do respektowania 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ę celom, takim jak _ClCompile, zobaczysz, że nie wykonują bezpośrednio żadnych działań, 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 Microsoft.CppBuild.targets:

<Target Name="ClCompile"/>

Ponieważ obiekt 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ć obiekt docelowy ClCompile, czyli mogą zawierać inną definicję ClCompile po zaimportowaniu 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, obiekt docelowy ClCompile 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 docelowy ClCompile nie powinien mieć żadnych zależności, z wyjątkiem obiektu docelowego SelectClCompile, który jest wymagany do działania polecenia kompilacji pojedynczego pliku w środowisku IDE.

Zadania programu MSBuild do użycia w celach 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 zadanie CL 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 kompilacje przyrostowe i up-to-date checks.

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 to samo działanie, co istniejące narzędzie i ma podobne przełączniki wiersza poleceń (podobnie jak clang-cl i CL), możesz użyć tej samej czynności 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 uzyskać przykład deklaracji zadania Xaml, zobacz $(VCTargetsPath)\BuildCustomizations\masm.xml, a aby uzyskać informacje o jego użyciu, zobacz $(VCTargetsPath)\BuildCustomizations\masm.targets.

    • zadanie

  2. Jeśli chcesz uzyskać lepszą wydajność zadań lub 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 CL, MIDLi RC przypadkach, a jeśli chcesz automatyczne śledzenie plików wejściowych i wyjściowych oraz tworzenie plików tlog, należy utworzyć zadanie z klasy Microsoft.Build.CPPTasks.TrackedVCToolTask. Obecnie, chociaż istnieje dokumentacja dla podstawowej klasy ToolTask, nie ma przykładów ani dokumentacji dotyczącej szczegółów klasy TrackedVCToolTask. Jeśli jest to szczególnie interesujące, dodaj swój głos do prośby w witrynie Developer Community.

Kompilacje przyrostowe i kontrole daty up-to

Domyślne obiekty docelowe kompilacji przyrostowej programu MSBuild używają atrybutów Inputs 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ść celów nie określa danych wejściowych i wyjściowych, a w rezultacie są zawsze uruchamiane podczas kompilacji. Zadania wywoływane przez obiekty docelowe zapisują informacje o wszystkich danych wejściowych i wyjściowych do plików tlog, które mają rozszerzenie tlog. Pliki .tlog są używane przez późniejsze kompilacje do sprawdzania, co się zmieniło i co wymaga ponownej kompilacji, oraz jakie są zmiany oznaczone jako up-to-date. Pliki .tlog są również jedynym źródłem do domyślnego sprawdzania kompilacji up-to-date 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ę bazową TrackedVCToolTask. Większość zadań natywnych narzędzi pochodzi z tej klasy.

Począwszy od programu Visual Studio 2017 update 15.8, można użyć zadania GetOutOfDateItems 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 zadania WriteLinesToFile. Zobacz element docelowy _WriteMasmTlogs w $(VCTargetsPath)\BuildCustomizations\masm.targets jako przykład.

Pliki .tlog

Istnieją trzy typy plików .tlog: plik odczytu, plik zapisuoraz plik wiersza polecenia. Pliki .tlog do odczytu i zapisu są używane przez kompilacje przyrostowe oraz przez sprawdzenie daty up-tow środowisku IDE. Pliki .tlog związane z wierszem polecenia są używane tylko w budowach 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. Używa się go w sprawdzaniu daty up-to.

Pliki .tlog zawierają informacje o wierszach poleceń używanych w kompilacji. Są one używane tylko do kompilacji przyrostowych, a nie do sprawdzania dat up-to, więc format wewnętrzny jest określany przez zadanie MSBuild, które je generuje.

Odczytaj format .tlog

Pliki .tlog do odczytu (*.read.*.tlog) zawierają informacje o plikach źródłowych i ich zależnościach.

Znacznik (^) na początku wiersza wskazuje jedno lub więcej źródeł. Ź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 zawierają pełne ścieżki.

Załóżmy na przykład, że źródła projektu znajdują się w 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 wymagane pisanie nazw plików wielkimi literami, ale jest to wygoda dla niektórych narzędzi.

Zapisz w formacie .tlog

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

Znak karetki (^) na początku wiersza wskazuje jedno lub więcej źródeł. 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łnymi ścieżkami.

Na przykład w przypadku prostego projektu ConsoleApplication z dodatkowym plikiem źródłowym Class1.cppplik link.write.1.tlog może zawierać plik:

^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++.

Cele CompileDesignTime 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 projektowych, 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)\Microsoft.Cpp.DesignTime.targets.

Obiekt docelowy GetClCommandLines zbiera opcje kompilatora dla funkcji IntelliSense:

<Target
  Name="GetClCommandLines"
  Returns="@(ClCommandLines)"
  DependsOnTargets="$(DesignTimeBuildInitTargets);$(ComputeCompileInputsTargets)">
  • DesignTimeBuildInitTargets — cele dostępne tylko w czasie projektowania, wymagane do inicjalizacji kompilacji w tym trybie. 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.

Obiekt docelowy wywołuje zadanie CLCommandLine, 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 przez właściwość ClangMode.

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

Jeśli dodajesz zadanie uruchamiane przed kompilacją, niezależnie od tego, czy jest to zwykła kompilacja, czy kompilacja w czasie projektowania, upewnij się, że nie przerywa ono budowania w czasie projektowania ani nie wpływa na wydajność. Najprostszym sposobem przetestowania celu jest otwarcie wiersza polecenia Dewelopera i wykonanie tej komendy.

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, pliki $(VSInstallDir)\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>

Aby użyć Task.HostObject w celu pobrania niezapisanej zawartości plików źródłowych, obiekty docelowe i zadanie powinny zostać 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 VS Project Systemi używa jego punktów rozszerzeń. 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

Aby uzyskać ogólne informacje o projekcie, zobacz Framework Multi-Targeting for VC++ Projects.

Mówiąc prosto, strony właściwości widoczne w oknie dialogowym właściwości projektu projektu dla projektu języka C++ są definiowane przez pliki reguły. 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 Microsoft.Build.Framework.XamlTypes. Aby uzyskać więcej informacji na temat używania plików reguł w projektach, zobacz pliki reguł XML na stronie właściwości .

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

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

Context limity metadanych ograniczają widoczność reguł, co jest również kontrolowane 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 definiuje sposób wyświetlania reguły w oknie dialogowym stron 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 kontekstów Project 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 z ItemType zdefiniowanymi w Rule.DataSource, chyba że nazwa reguły jest uwzględniona w grupie elementów ProjectTools.

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 ExportDebugger obiektu Debug Launcher MEF.

Przykład: $(VCTargetsPath)\1033\debugger_local_windows.xml
niestandardowy Szablon niestandardowy. Nazwa szablonu powinna być zgodna z atrybutem ExportPropertyPageUIFactoryProvider obiektu MEF PropertyPageUIFactoryProvider. 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:

  • edytory wartości pól

  • Dostawca dynamicznych wartości wyliczeniowych

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ąp regułę

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 grupy elementów PropertyPageSchema po zaimportowaniu domyślnych obiektów docelowych cpp. W projekcie jest używana tylko jedna reguła o podanej nazwie, a ostatnia zawarta w grupie elementów PropertyPageSchema wygrywa.

Elementy projektu

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

Domyślny plik ProjectItemsSchema znajduje się w $(VCTargetsPath)\1033\ProjectItemsSchema.xml. Aby go rozszerzyć, należy utworzyć plik schematu z nową nazwą, taką jak 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

Debuggery

Usługa debugowania w programie Visual Studio obsługuje rozszerzalność silnika 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 Debug Launcher MEF i dodać regułę debugger. Przykład można znaleźć w pliku $(VCTargetsPath)\1033\debugger_local_windows.xml.

Wdrożyć

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

wersja up-To— kontrola daty

Domyślnie, sprawdzanie daty kompilacji up-towymaga, aby podczas kompilacji w folderze $(TlogLocation) zostały utworzone pliki .tlog do odczytu i zapisu wszystkich danych wejściowych i wyjściowych kompilacji.

Aby użyć niestandardowego up-to-date check:

  1. Wyłącz domyślne sprawdzenie daty up-to, dodając funkcję NoVCDefaultBuildUpToDateCheckProvider w pliku Toolset.targets.

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

Uaktualnianie projektu

Domyślny uaktualniacz projektu .vcxproj

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

Uaktualniacz używa tych kryteriów, aby zdecydować, czy projekt można zaktualizować, czy nie.

  1. W przypadku projektów definiujących ApplicationType 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, w której wszystkie znaki inne niż alfanumeryczne zostały zastąpione znakiem podkreślenia (_).

Gdy projekt można zaktualizować, uczestniczy on w Solution Retargeting. Aby uzyskać więcej informacji, zobacz IVsTrackProjectRetargeting2.

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

Przykłady definicji właściwości _UpgradePlatformToolsetFor_<safe_toolset_name> i _PlatformToolsetShortNameFor_<safe_toolset_name> można znaleźć w pliku Microsoft.Cpp.Default.props. Przykłady użycia można znaleźć w pliku $(VCTargetPath)\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 definiowana w Microsoft.VisualStudio.ProjectSystem.VS.dll i jest podobna do IVsRetargetProjectAsync.

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

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

Wyłączanie uaktualniania projektu

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

<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, nie można utworzyć składników MEF rozszerzenia, które importują UnconfiguredProject lub ConfiguredProject. 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 projektu, czyli definiują właściwość VCProjectUpgraderObjectName

  • Projekty, które nie są przeznaczone dla systemu Windows dla komputerów stacjonarnych, to znaczy, definiują właściwość ApplicationType

  • 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 niezbędne do odpowiadania na zapytania get w kontekście interfejsów VCProjectEngine. Oznacza to, że wszystkie modyfikacje na poziomie plików MSBuild props i targets wykonane przez rozszerzenie powinny działać poprawnie 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 $(VCTargetsPath), zobacz Instalowanie poza folderem rozszerzeń.

Dodatkowe zasoby

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

Zarządzana struktura rozszerzalności (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 użycia mef przez cpS, zobacz CPS i MEF w VSProjectSystem omówienie mef.

Możesz dostosować istniejący system kompilacji, aby dodać kroki kompilacji lub nowe typy plików. Aby uzyskać więcej informacji, zobacz Przegląd MSBuild (Visual C++) oraz Praca z właściwościami projektu.