Freigeben über


Erweiterbarkeit des Visual Studio C++-Projektsystems und Toolsetintegration

Das Visual C++-Projektsystem wird für .vcxproj-Dateien genutzt. Es basiert auf dem Visual Studio Common Project System (CPS) und liefert zusätzliche, C++-spezifische Erweiterungspunkte für die einfache Integration neuer Toolsets, Buildarchitekturen und Zielplattformen.

Struktur von C++-MSBuild-Zielen

Alle .vcxproj-Dateien importieren die folgenden Dateien:

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

Diese Dateien definieren selbst nur wenig. Sie importieren vielmehr andere Dateien basierend auf diesen Eigenschaftswerten:

  • $(ApplicationType)

    Beispiele: Windows Store, Android, Linux

  • $(ApplicationTypeRevision)

    Das muss eine gültige Versionszeichenfolge der Form major.minor[.build[.revision]] sein.

    Beispiele: 1.0, 10.0.0.0

  • $(Platform)

    Die Buildarchitektur, die aus historischen Gründen als „Plattform“ bezeichnet wird.

    Beispiele: Win32, x86, x64, ARM

  • $(PlatformToolset)

    Beispiele: v140, v141, v141_xp, llvm

Diese Eigenschaftswerte geben Ordnernamen unter dem Stammordner $(VCTargetsPath) an:

$(VCTargetsPath)\
    Anwendungstyp\
        $(ApplicationType)\
            $(ApplicationTypeRevision)\
                Plattformen\
                    $(Platform)\
                        PlatformToolsets\
                            $(PlatformToolset)
    Plattformen\
        $(Platform)\
            PlatformToolsets\
                $(PlatformToolset)

Der Ordner $(VCTargetsPath)\Platforms\ wird für Windows-Desktopprojekte verwendet, wenn $(ApplicationType) leer ist.

Hinzufügen eines neuen Plattformtoolsets

Zum Hinzufügen eines neuen Toolsets, z. B. „MyToolset“ für die vorhandene Win32-Plattform müssen Sie einen Ordner MyToolset unter $(VCTargetsPath)\Platforms\Win32\PlatformToolsets\ und dann darin die Dateien Toolset.props und Toolset.targets erstellen.

Jeder Ordnername unter PlatformToolsets wird im Dialog Projekteigenschaften als verfügbares Plattformtoolset für die angegebene Plattform angezeigt, wie hier dargestellt:

Die Eigenschaft „Plattformtoolset“ im Dialog „Eigenschaftenseiten“ des Projekts

Erstellen Sie entsprechende Ordner MyToolset und Dateien Toolset.props Toolset.targets in jedem vorhandenen Plattformordner, den dieses Toolset unterstützt.

Hinzufügen einer neuen Plattform

Zum Hinzufügen einer neuen Plattform, z. B. „MyPlatform“ müssen Sie einen Ordner MyPlatform unter $(VCTargetsPath)\Platforms\ und dann darin die Dateien Platform.default.props, Platform.props und Platform.targets erstellen. Erstellen Sie außerdem einen Ordner $(VCTargetsPath)\Platforms\MyPlatform\PlatformToolsets\ und darin mindestens ein Toolset.

Alle Ordnernamen unter dem Ordner Platforms für jeden $(ApplicationType) und $(ApplicationTypeRevision) werden in der IDE als verfügbare Auswahlmöglichkeiten für die Plattform für ein Projekt angezeigt.

Die Auswahlmöglichkeit „Neue Plattform“ im Dialog „Neue Projektplattform“

Hinzufügen eines neuen Anwendungstyps

Zum Hinzufügen eines neuen Anwendungstyp müssen Sie unter einen Ordner MyApplicationType unter $(VCTargetsPath)\Application Type\ und darin eine Datei Defaults.props erstellen. Für einen Anwendungstyp ist mindestens eine Revision erforderlich. Erstellen Sie daher auch einen Ordner $(VCTargetsPath)\Application Type\MyApplicationType\1.0 und darin eine Datei Defaults.props. Sie sollten auch einen Ordner $(VCTargetsPath)\ApplicationType\MyApplicationType\1.0\Platforms und darin mindestens eine Plattform erstellen.

Die Eigenschaften $(ApplicationType) und $(ApplicationTypeRevision) sind auf der Benutzeroberfläche nicht sichtbar. Sie werden in den Projektvorlagen definiert und können nach dem Erstellen des Projekts nicht mehr geändert werden.

Die .vcxproj-Importstruktur

Eine vereinfachte Struktur der Importe für Microsoft C++-Eigenschaften- und Zieldateien sieht folgendermaßen aus:

$(VCTargetsPath)\Microsoft.Cpp.Default.props
    $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props
    $(VCTargetsPath)\ImportBefore\Default\*.props
    $(VCTargetsPath)\Application Type\$(ApplicationType)\Default.props
    $(VCTargetsPath)\Application Type\$(ApplicationType)\$(ApplicationTypeRevision)\Default.props
    $(VCTargetsPath)\Application Type\$(ApplicationType)\$(ApplicationTypeRevision)\Platforms\$(Platform)\Platform.default.props
    $(VCTargetsPath)\ImportAfter\Default\*.props

Windows-Desktopprojekte definieren $(ApplicationType) nicht und importieren deshalb nur

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

Die Eigenschaft $(_PlatformFolder) dient zum Speichern der $(Platform)-Plattformordner. Die Eigenschaft ist

$(VCTargetsPath)\Plattformen\$(Platform)

für Windows-Desktop-Apps und

$(VCTargetsPath)\Application Type\$(ApplicationType)\$(ApplicationTypeRevision)\Platforms\$(Platform)

für alles andere.

Die Eigenschaftendateien werden in diesen Ordner importiert:

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

Die Zieldateien werden in diesen Ordner importiert:

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

Wenn Sie gewisse Standardeigenschaften für Ihr Toolset definieren müssen, können Sie Dateien zu den entsprechenden Ordnern „ImportBefore“ und „ImportAfter“ hinzufügen.

Schreiben von Toolset.props- and Toolset.targets-Dateien

Toolset.props- und Toolset.targets-Dateien steuern vollständig die Vorgänge während eines Builds bei Verwendung dieses Toolsets. Sie können auch die verfügbaren Debugger, einen Teil der IDE-Benutzeroberfläche, wie z. B. den Inhalt im Dialog Eigenschaftenseiten und gewisse andere Aspekte des Projektverhaltens steuern.

Auch wenn ein Toolset den gesamten Buildprozess außer Kraft setzen kann, werden Sie normalerweise nur wollen, dass das Toolset einige Buildschritte ändert oder hinzufügt oder im Rahmen eines vorhandenen Buildprozesses verschiedene Buildtools verwendet. Zu diesem Zweck gibt es eine Reihe gängiger Eigenschaften- und Zieldateien, die Ihr Toolset importieren kann. Je nach der gewünschten Aufgabe Ihres Toolsets kann es sinnvoll sein, diese Dateien für Importe oder als Beispiele zu verwenden:

  • $(VCTargetsPath)\Microsoft.CppCommon.targets

    Diese Datei definiert die wichtigsten Teile des nativen Buildprozesses und importiert außerdem:

    • $(VCTargetsPath)\Microsoft.CppBuild.targets

    • $(VCTargetsPath)\Microsoft.BuildSteps.targets

    • $(MSBuildToolsPath)\Microsoft.Common.Targets

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

    Legt Standardwerte für Toolsets fest, die die Microsoft-Compiler und Windows als Ziel verwenden.

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

    Diese Datei bestimmt den Speicherort des Windows SDK und definiert einige wichtige Eigenschaften von Apps für Windows.

Integrieren toolsetspezifischer Ziele in den standardmäßigen C++-Buildprozess

Der standardmäßige C++-Buildprozess wird in Microsoft.CppCommon.targets definiert. Die Ziele dort rufen keine spezifischen Buildtools auf, sondern geben die wichtigsten Buildschritte, ihre Reihenfolge und ihre Abhängigkeiten an.

Für den C++-Build gibt es drei Hauptschritte, die durch die folgenden Ziele repräsentiert werden:

  • BuildGenerateSources

  • BuildCompile

  • BuildLink

Da jeder Buildschritt eigenständig ausgeführt werden kann, können die in einem Schritt ausgeführten Ziele nicht die Elementgruppen und Eigenschaften heranziehen, die in den als Teil eines anderen Schritts ausgeführten Zielen definiert werden. Diese Aufteilung ermöglicht gewisse Optimierungen der Buildleistung. Diese Trennung wird zwar nicht standardmäßig eingesetzt, sollte aber dennoch genutzt werden.

Die innerhalb jedes Schritts ausgeführten Ziele werden durch die folgenden Eigenschaften gesteuert:

  • $(BuildGenerateSourcesTargets)

  • $(BuildCompileTargets)

  • $(BeforeBuildLinkTargets)

Jeder Schritt hat auch Before- und After-Eigenschaften.

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

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

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

In der Datei Microsoft.CppBuild.targets finden Sie Beispiele für die in jedem Schritt enthaltenen Ziele:

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

Wenn Sie die Ziele wie z. B. _ClCompile betrachten, sehen Sie, dass sie nichts direkt selbst ausführen, sondern von anderen Zielen wie ClCompile abhängig sind:

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

ClCompile und andere buildtoolspezifische Ziele werden in Microsoft.CppBuild.targets als leere Ziele definiert:

<Target Name="ClCompile"/>

Da das Ziel ClCompile leer ist, wenn es nicht von einem Toolset überschrieben wird, wird keine wirkliche Buildaktion ausgeführt. Die Toolsetziele können das Ziel ClCompile überschreiben, d. h., sie können eine andere ClCompile-Definition enthalten, nachdem Microsoft.CppBuild.targets importiert wurde:

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

Trotz seines Namens, der vor der Implementierung der plattformübergreifenden Unterstützung von Visual Studio festgelegt wurde, muss das Ziel ClCompile nicht CL.exe aufrufen. Es kann auch über die entsprechenden MSBuild-Aufgaben Clang, gcc oder andere Compiler aufrufen.

Das Ziel ClCompile sollte keine Abhängigkeiten haben. Davon ausgenommen ist das Ziel SelectClCompile, das erforderlich ist, damit der Befehl zum Kompilieren einzelner Dateien in der IDE funktioniert.

In Toolsetzielen zu verwendende MSBuild-Aufgaben

Zum Aufrufen eines tatsächliches Buildtools muss das Ziel eine MSBuild-Aufgabe aufrufen. Es gibt eine grundlegende Exec-Aufgabe, mit der Sie eine auszuführende Befehlszeile angeben können. Buildtools haben jedoch in der Regel viele Optionen, Eingaben und Ausgaben zum Verfolgen inkrementelle Builds, weshalb spezielle Aufgaben dafür sinnvoller sind. Beispielsweise übersetzt die Aufgabe CL MSBuild-Eigenschaften in CL.exe-Schalter, schreibt sie in eine Antwortdatei und ruft CL.exe auf. Sie verfolgt außerdem alle Eingabe- und Ausgabedateien für spätere inkrementelle Builds. Weitere Informationen finden Sie unter Inkrementelle Builds und Prüfung des neuesten Stands.

Microsoft.Cpp.Common.Tasks.dll implementiert diese Aufgaben:

  • BSCMake

  • CL

  • ClangCompile (clang-gcc-Schalter)

  • LIB

  • LINK

  • MIDL

  • Mt

  • RC

  • XDCMake

  • CustomBuild (wie Exec, aber mit Verfolgung der Eingabe und Ausgabe)

  • SetEnv

  • GetOutOfDateItems

Wenn Sie ein Tool haben, das die gleiche Aktion wie ein vorhandenes Tool ausführt und ähnliche Befehlszeilenschalter hat (wie clang-cl und CL), können Sie für beides die gleiche Aufgabe verwenden.

Wenn Sie eine neue Aufgabe für ein Buildtool erstellen müssen, stehen die folgenden Optionen zur Auswahl:

  1. Wenn Sie diese Aufgabe selten verwenden oder ein paar Sekunden für Ihren Build keine Rolle spielen, können Sie MSBuild-„Inline“-aufgaben verwenden:

    • Xaml-Aufgabe (eine benutzerdefinierte Buildregel)

      Ein Beispiel für eine Xaml-Aufgabendeklaration finden Sie unter $(VCTargetsPath)\BuildCustomizations\masm.xml und Informationen zur Verwendung unter $(VCTargetsPath)\BuildCustomizations\masm.targets.

    • Code-Aufgabe

  2. Wenn Sie eine bessere Aufgabenleistung wünschen oder einfach komplexere Funktionen benötigen, sollten Sie den regulären MSBuild-Prozess zum Schreiben von Aufgaben verwenden.

    Wenn nicht alle Eingaben und Ausgaben des Tools in der Befehlszeile aufgeführt sind, wie in den Fällen CL, MIDL und RC, und wenn Sie die automatische Nachverfolgung von Eingabe- und Ausgabedateien und Erstellung der .tlog-Datei wünschen, sollten Sie Ihre Aufgabe aus der Klasse Microsoft.Build.CPPTasks.TrackedVCToolTask ableiten. Derzeit gibt es zwar eine Dokumentation zur Basisklasse ToolTask, aber keine Beispiele und keine Dokumentationen zu den Details der Klasse TrackedVCToolTask. Wenn das von besonderem Interesse wäre, sollten Sie dies in einer Anfrage in der Entwicklercommunity äußern.

Inkrementelle Builds und Prüfung des neuesten Stands

Die standardmäßigen inkrementellen MSBuild-Buildziele verwenden die Attribute Inputs und Outputs. Wenn Sie sie angeben, ruft MSBuild das Ziel nur dann auf, wenn eine der Eingaben einen neueren Zeitstempel als alle Ausgaben hat. Da Quelldateien häufig andere Dateien enthalten oder importieren und Buildtools je nach Tooloptionen unterschiedliche Ausgaben erzeugen, ist es schwierig, alle möglichen Eingaben und Ausgaben in MSBuild-Zielen anzugeben.

Um dieses Problem zu bewältigen, setzt der C++-Build eine andere Technik zum Unterstützen inkrementeller Builds ein. Die meisten Ziele geben keine Eingaben und Ausgaben an und werden daher während des Builds immer ausgeführt. Die von den Zielen aufgerufenen Aufgaben schreiben Informationen zu allen Eingaben und Ausgaben in tlog-Dateien, die die Erweiterung .tlog haben. Anhand der .tlog-Dateien können spätere Builds prüfen, was sich geändert hat und neu erstellt werden muss und was auf dem neuesten Stand ist. Die .tlog-Dateien sind auch die einzige Quelle für die standardmäßige Prüfung des neuesten Stands des Builds in der IDE.

Zum Ermitteln aller Eingaben und Ausgaben verwenden native Toolaufgaben tracker.exe und die von MSBuild bereitgestellte FileTracker-Klasse.

Microsoft.Build.CPPTasks.Common.dll definiert die öffentliche abstrakte Basisklasse TrackedVCToolTask. Die meisten nativen Toolaufgaben sind aus dieser Klasse abgeleitet.

Ab Visual Studio 2017 Update 15.8 können Sie mithilfe der in Microsoft.Cpp.Common.Tasks.dll implementierten Aufgabe GetOutOfDateItems .tlog-Dateien für benutzerdefinierte Ziele mit bekannten Eingaben und Ausgaben erstellen. Alternativ können Sie sie auch mithilfe der Aufgabe WriteLinesToFile erstellen. Ein Beispiel für das Ziel _WriteMasmTlogs finden Sie in $(VCTargetsPath)\BuildCustomizations\masm.targets.

.tlog-Dateien

Es gibt drei Typen von .tlog-Dateien: Lesen, Schreiben und Befehlszeile. .tlog-Dateien für das Lesen und Schreiben werden von inkrementellen Builds und von der Prüfung des neuesten Stands in der IDE verwendet. .tlog-Dateien für die Befehlszeile werden nur inkrementellen Builds verwendet.

MSBuild verfügt über die folgenden Hilfsklassen für .tlog-Dateien für das Lesen und Schreiben:

Die Klasse FlatTrackingData kann für den Zugriff auf .tlog-Dateien für das Lesen wie auch für das Schreiben verwendet werden und zum Ermitteln von Eingaben, die neuer sind als Ausgaben, sowie zum Prüfen, ob eine Ausgabe fehlt. Sie wird in der Prüfung des neuesten Stands verwendet.

.tlog-Dateien für die Befehlszeile enthalten Informationen zu den im Build verwendeten Befehlszeilen. Sie werden nur für inkrementelle Builds und nicht für die Prüfung des neuesten Stands verwendet, weshalb das interne Format von der MSBuild-Aufgabe bestimmt wird, die sie erzeugt.

.tlog-Format für das Lesen

.tlog-Dateien für das Lesen (*.read.*.tlog) enthalten Informationen zu Quelldateien und deren Abhängigkeiten.

Ein Caret-Zeichen (^) am Anfang einer Zeile verweist auf eine oder mehrere Quellen. Quellen mit den gleichen Abhängigkeiten werden durch einen senkrechten Strich (|) voneinander getrennt.

Abhängigkeitsdateien werden im Anschluss an die Quellen jeweils in einer eigenen Zeile aufgeführt. Alle Dateinamen sind vollständige Pfade.

Angenommen, Ihre Projektquellen befinden sich in F:\test\ConsoleApplication1\ConsoleApplication1. Wenn es in Ihrer Quelldatei, Class1.cpp, die folgenden Include-Anweisungen gibt,

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

enthält die Datei CL.read.1.tlog die Quelldatei, gefolgt von ihren zwei Abhängigkeiten:

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

Es ist nicht erforderlich, Dateinamen in Großbuchstaben zu schreiben, ist aber für einige Tools zweckmäßig.

.tlog-Format für das Schreiben

.tlog-Dateien für das Schreiben (*.write.*.tlog) verbinden Quellen und Ausgaben.

Ein Caret-Zeichen (^) am Anfang einer Zeile verweist auf eine oder mehrere Quellen. Mehrere Quellen werden durch einen senkrechten Strich (|) voneinander getrennt.

Die aus den Quellen erstellten Ausgabedateien sollten im Anschluss an die Quellen jeweils in einer eigenen Zeile aufgeführt werden. Alle Dateinamen müssen vollständige Pfade sein.

Bei einem einfachen ConsoleApplication-Projekt mit einer zusätzlichen Quelldatei Class1.cpp kann die Datei link.write.1.tlog zum Beispiel Folgendes enthalten:

^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

Entwurfszeit-Build

In der IDE verwenden .vcxproj-Projekte eine Reihe von MSBuild-Zielen, um zusätzliche Informationen aus dem Projekt abzurufen und Ausgabedateien neu zu generieren. Einige dieser Ziele werden nur in Entwurfszeit-Builds verwendet, viele davon aber sowohl in regulären Builds als auch in Entwurfszeit-Builds.

Allgemeine Informationen zu Entwurfszeit-Builds finden Sie in der CPS-Dokumentation zu Entwurfszeit-Builds. Diese Dokumentation gilt nur teilweise für Visual C++-Projekte.

Die in der Dokumentation zu Entwurfszeit-Builds erwähnten Ziele CompileDesignTime und Compile werden für .vcxproj-Projekte niemals ausgeführt. .vcxproj-Projekte in Visual C++ verwenden unterschiedliche Entwurfszeitziele zum Abrufen von IntelliSense-Informationen.

Entwurfszeitziele für IntelliSense-Informationen

Die in .vcxproj-Projekten verwendeten Entwurfszeitziele werden in $(VCTargetsPath)\Microsoft.Cpp.DesignTime.targets definiert.

Das Ziel GetClCommandLines erfasst Compileroptionen für IntelliSense:

<Target
  Name="GetClCommandLines"
  Returns="@(ClCommandLines)"
  DependsOnTargets="$(DesignTimeBuildInitTargets);$(ComputeCompileInputsTargets)">
  • DesignTimeBuildInitTargets – Reine Entwurfszeitziele, die für die Initialisierung des Entwurfszeit-Builds benötigt werden. Diese Ziele deaktivieren unter anderem einige der regulären Buildfunktionen, um die Leistung zu verbessern.

  • ComputeCompileInputsTargets – eine Gruppe von Zielen, die Compileroptionen und -elemente ändert. Diese Ziele werden sowohl in Entwurfszeit-Builds als auch in regulären Builds ausgeführt.

Das Ziel ruft die Aufgabe CLCommandLine auf, um die für IntelliSense zu verwendende Befehlszeile zu erstellen. Trotz ihres Namens kann sie nicht nur CL-Optionen, sondern auch Clang- und gcc-Optionen verarbeiten. Der Typ der Compilerschalter wird von der Eigenschaft ClangMode gesteuert.

Derzeit verwendet die von der Aufgabe CLCommandLine erstellte Befehlszeile immer CL-Schalter (auch im Clang-Modus), da sie für die IntelliSense-Engine einfacher zu parsen sind.

Wenn Sie ein Ziel hinzufügen, das regulär oder zur Entwurfszeit vor der Kompilierung ausgeführt wird, müssen Sie sicherstellen, dass es nicht die Entwurfszeit-Builds unterbricht oder die Leistung beeinträchtigt. Die einfachste Möglichkeit zum Testen Ihres Ziels besteht darin, eine Developer-Eingabeaufforderung zu öffnen und diesen Befehl auszuführen:

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

Dieser Befehl erstellt ein detailliertes Buildprotokoll, msbuild.log, mit einer Leistungsübersicht für die Ziele und Aufgaben am Ende.

Verwenden Sie unbedingt Condition ="'$(DesignTimeBuild)' != 'true'" bei allen Vorgängen, die nur für reguläre Builds und nicht für Entwurfszeit-Builds sinnvoll sind.

Entwurfszeitziele, die Quellen generieren

Dieses Feature ist für native Desktopprojekte standardmäßig deaktiviert und wird für zwischengespeicherte Projekte derzeit nicht unterstützt.

Wenn GeneratorTarget-Metadaten für ein Projektelement definiert sind, wird das Ziel sowohl beim Laden des Projekts und als auch beim Ändern der Quelldatei automatisch ausgeführt.

Zum automatischen Generieren von .cpp- oder .h-Dateien aus .xaml-Dateien definieren die Dateien $(VSInstallDir)\MSBuild\Microsoft\WindowsXaml\v16.0\*\Microsoft.Windows.UI.Xaml.CPP.Targets diese Entitäten:

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

Damit Task.HostObject zum Abrufen des nicht gespeicherten Inhalts von Quelldateien verwendet wird, sollten die Ziele und die Aufgabe als MsbuildHostObjects für die angegebenen Projekte in einer pkgdef registriert werden:

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

Erweiterbarkeit von Visual C++-Projekten in der Visual Studio-IDE

Das Visual C++-Projektsystem basiert auf dem VS-Projektsystem und nutzt dessen Erweiterbarkeitspunkte. Die Implementierung der Projekthierarchie ist jedoch spezifisch für Visual C++ und basiert nicht auf CPS, weshalb die Erweiterbarkeit der Hierarchie auf Projektelemente beschränkt ist.

Seiten mit Projekteigenschaften

Allgemeine Entwurfsinformationen finden Sie unter Framework Multi-Targeting für VC++-Projekte.

Einfach ausgedrückt werden die im Dialog Projekteigenschaften für ein C++-Projekt angezeigten Eigenschaftenseiten durch Regel-Dateien definiert. Eine Regeldatei gibt vor, welcher Satz von Eigenschaften auf einer Eigenschaftenseite angezeigt werden soll und wie und wo sie in der Projektdatei gespeichert werden sollen. Regeldateien sind .xml-Dateien im XAML-Format. Die zum Serialisieren verwendeten Typen werden unter Microsoft.Build.Framework.XamlTypes beschrieben. Weitere Informationen zum Einsatz von Regeldateien in Projekten finden Sie unter XML-Regeldateien für Eigenschaftenseiten.

Die Regeldateien müssen zur Elementgruppe PropertyPageSchema hinzugefügt werden:

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

Context-Metadaten beschränken die Sichtbarkeit der Regel, was ebenfalls vom Regeltyp gesteuert wird, und können einen der folgenden Werte haben:

Project | File | PropertySheet

CPS unterstützt weitere Werte für den Kontexttyp, die in Visual C++-Projekten aber nicht verwendet werden.

Wenn die Regel in mehr als einem Kontext sichtbar sein sollte, müssen die Kontextwerte durch Semikolon (;) voneinander getrennt werden, wie hier dargestellt:

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

Regelformat und wichtigste Typen

Da das Regelformat unkompliziert ist, werden in diesem Abschnitt nur die Attribute beschrieben, die sich auf das Aussehen der Regel auf der Benutzeroberfläche auswirken.

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

Das Attribut PageTemplate definiert, wie die Regel im Dialog Eigenschaftenseiten angezeigt wird. Das Attribut kann einen dieser Werte haben:

Attribute Beschreibung
generic Alle Eigenschaften werden auf einer Seite unter den Kategorieüberschriften angezeigt.
Die Regel kann für die Kontexte Project und PropertySheet sichtbar sein, nicht aber für File.

Beispiel: $(VCTargetsPath)\1033\general.xml
tool Kategorien werden als Unterseiten angezeigt.
Die Regel kann in allen Kontexten sichtbar sein: Project, PropertySheet und File.
Die Regel ist in den Projekteigenschaften nur dann sichtbar, wenn das Projekt Elemente hat, bei denen ItemType in Rule.DataSource definiert ist, es sei denn, der Regelname ist in der Elementgruppe ProjectTools enthalten.

Beispiel: $(VCTargetsPath)\1033\clang.xml
debugger Die Seite wird als Teil der Debugging-Seite angezeigt.
Kategorien werden derzeit ignoriert.
Der Name der Regel sollte dem Attribut ExportDebugger des MEF-Objekts des Debug-Launchers entsprechen.

Beispiel: $(VCTargetsPath)\1033\debugger_local_windows.xml
custom Benutzerdefinierte Vorlage. Der Name der Vorlage sollte dem Attribut ExportPropertyPageUIFactoryProvider des MEF-Objekts PropertyPageUIFactoryProvider entsprechen. Siehe Microsoft.VisualStudio.ProjectSystem.Designers.Properties.IPropertyPageUIFactoryProvider.

Beispiel: $(VCTargetsPath)\1033\userMacros.xml

Wenn die Regel eine der auf dem Eigenschaftsraster basierenden Vorlagen verwendet, kann sie diese Erweiterbarkeitspunkte für ihre Eigenschaften verwenden:

Erweitern einer Regel

Wenn Sie eine vorhandene Regel verwenden möchten, aber nur ein paar Eigenschaften hinzufügen oder entfernen (d. h. ausblenden) müssen, können Sie eine Erweiterungsregel erstellen.

Überschreiben einer Regel

Sie möchten vielleicht in ihrem Toolset die meisten Standardregeln des Projekts verwenden und nur eine oder ein paar davon ersetzen. Angenommen, Sie möchten nur die C/C++-Regel dahingehend ändern, dass andere Compilerschalter angezeigt werden. Sie können eine neue Regel mit demselben Namen und Anzeigenamen wie die vorhandene Regel bereitstellen und sie nach dem Import der standardmäßigen ccp-Ziele in die Elementgruppe PropertyPageSchema aufnehmen. Im Projekt wird nur eine Regel mit einem bestimmten Namen verwendet, und die letzte in die Elementgruppe PropertyPageSchema aufgenommene Regel trägt den Sieg davon.

Projektelemente

Die Datei ProjectItemsSchema.xml definiert die ContentType- und ItemType-Werte für Elemente, die als Projektelemente behandelt werden, und definiert FileExtension-Elemente, um zu bestimmen, zu welcher Elementgruppe eine neue Datei hinzugefügt wird.

Die standardmäßige Datei ProjectItemsSchema ist unter $(VCTargetsPath)\1033\ProjectItemsSchema.xml zu finden. Um sie zu erweitern, müssen Sie eine Schemadatei mit einem neuen Namen erstellen, wie z. B. 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>

Fügen Sie dann in der Zieldatei Folgendes hinzu:

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

Beispiel: $(VCTargetsPath)\BuildCustomizations\masm.xml

Debugger

Der Debugdienst in Visual Studio unterstützt die Erweiterbarkeit für die Debug-Engine. Weitere Informationen finden Sie in diesen Beispielen:

Zum Angeben der Debug-Engine und anderer Eigenschaften für die Debugsitzung müssen Sie eine Debug Launcher-MEF-Komponente implementieren und eine debugger-Regel hinzufügen. Ein Beispiel finden Sie in der Datei $(VCTargetsPath)\1033\debugger_local_windows.xml.

Bereitstellen

.vcxproj-Projekte nutzen die Erweiterbarkeit des Visual Studio-Projektsystems für Deploy-Anbieter.

Prüfung des neuesten Stands des Builds

Standardmäßig müssen für die Prüfung des neuesten Stands des Builds während des Builds für alle Buildeingaben und -ausgaben im Ordner $(TlogLocation) .tlog-Dateien für das Lesen und Schreiben erstellt werden.

Gehen Sie für eine benutzerdefinierte Prüfung des neuesten Stands folgendermaßen vor:

  1. Deaktivieren Sie die standardmäßige Prüfung des neuesten Stands, indem Sie die Funktion NoVCDefaultBuildUpToDateCheckProvider in der Datei Toolset.targets hinzufügen:

    <ItemGroup>
      <ProjectCapability Include="NoVCDefaultBuildUpToDateCheckProvider" />
    </ItemGroup>
    
  2. Implementieren Sie Ihren eigenen IBuildUpToDateCheckProvider.

Projektupgrade

Standardupgrader für .vcxproj-Projekte

Der Standardupgrader für .vcxproj-Projekte ändert PlatformToolset, ApplicationTypeRevision, die MSBuild-Toolset-Version und das .NET Framework. Die letzten beiden werden immer in die Standardeinstellungen der Visual Studio-Version geändert, PlatformToolset und ApplicationTypeRevision können aber durch spezielle MSBuild-Eigenschaften gesteuert werden.

Der Upgrader entscheidet anhand dieser Kriterien, ob ein Upgrade für ein Projekt möglich ist oder nicht:

  1. Bei Projekten, die ApplicationType und ApplicationTypeRevision definieren, gibt es einen Ordner mit einer höheren als der aktuellen Revisionsnummer.

  2. Die Eigenschaft _UpgradePlatformToolsetFor_<safe_toolset_name> wird für das aktuelle Toolset definiert, und der Wert ist nicht gleich dem aktuellen Toolset.

    In diesen Eigenschaftennamen stellt <safe_toolset_name> den Namen des Toolsets dar, wobei alle nicht alphanumerischen Zeichen durch einen Unterstrich (_) ersetzt sind.

Wenn für ein Projekt ein Upgrade möglich ist, nimmt es an der Neuzuweisung der Lösung teil. Weitere Informationen finden Sie unter IVsTrackProjectRetargeting2.

Wenn Sie Projektnamen im Projektmappen-Explorer ausschmücken möchten, wenn Projekte ein bestimmtes Toolset verwenden, müssen Sie eine Eigenschaft _PlatformToolsetShortNameFor_<safe_toolset_name> definieren.

Beispiele für Definitionen der Eigenschaften _UpgradePlatformToolsetFor_<safe_toolset_name> und _PlatformToolsetShortNameFor_<safe_toolset_name> finden Sie in der Datei Microsoft.Cpp.Default.props. Beispiele für die Verwendung finden Sie in der Datei $(VCTargetPath)\Microsoft.Cpp.Platform.targets.

Benutzerdefinierter Projektupgrader

Für den Einsatz eines benutzerdefinierten Projektupgraderobjekts müssen Sie eine MEF-Komponente implementieren, wie hier dargestellt:

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

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

Ihr Code kann das standardmäßige .vcxproj-Upgraderobjekt importieren und aufrufen:

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

IProjectRetargetHandler ist in Microsoft.VisualStudio.ProjectSystem.VS.dll definiert und ist vergleichbar mit IVsRetargetProjectAsync.

Definieren Sie die Eigenschaft VCProjectUpgraderObjectName, um das Projektsystem anzuweisen, Ihr benutzerdefiniertes Upgraderobjekt zu verwenden:

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

Deaktivieren des Projektupgrades

Verwenden Sie zum Deaktivieren des Projektupgrades einen NoUpgrade-Wert:

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

Projekt-Cache und Erweiterbarkeit

Um beim Arbeiten mit umfangreichen C++-Lösungen in Visual Studio 2017 die Leistung zu verbessern, wurde der Projekt-Cache eingeführt. Er wird als eine mit Projektdaten aufgefüllte SQLite-Datenbank implementiert und dann zum Laden von Projekten eingesetzt, ohne dass MSBuild- oder CPS-Projekte in den Arbeitsspeicher geladen werden.

Da für aus dem Cache geladene VCXPROJ-Projekte keine CPS-Objekte vorhanden sind, können die MEF-Komponenten der Erweiterung, die UnconfiguredProject oder ConfiguredProject importieren, nicht erstellt werden. Zur Unterstützung der Erweiterbarkeit wird der Projekt-Cache nicht genutzt, wenn Visual Studio erkennt, dass ein Projekt MEF-Erweiterungen verwendet (oder voraussichtlich verwenden wird).

Diese Projekttypen werden immer vollständig geladen und verfügen über CPS-Objekte im Arbeitsspeicher, sodass alle MEF-Erweiterungen dafür erstellt werden:

  • Startup-Projekte

  • Projekte mit einem benutzerdefinierten Projektupgrader, d. h. mit definierter Eigenschaft VCProjectUpgraderObjectName

  • Projekte, die nicht Desktop-Windows zum Ziel haben, d. h. mit definierter Eigenschaft ApplicationType

  • Projekte mit freigegebenen Elementen (.vcxitems) und Projekte, die durch den Import von .vcxitems-Projekten auf diese verweisen.

Wenn keine dieser Bedingungen erkannt wird, wird ein Projekt-Cache erstellt. Der Cache enthält alle Daten aus dem MSBuild-Projekt, die zum Beantworten von get-Abfragen auf VCProjectEngine-Schnittstellen erforderlich sind. Dies bedeutet, dass alle Änderungen, die von einer Erweiterung auf der Ebene der MSBuild-Eigenschaften- und Zieldateien vorgenommen werden, in den aus dem Cache geladenen Projekten funktionieren sollten.

Bereitstellen Ihrer Erweiterung

Informationen zum Erstellen von VSIX-Dateien finden Sie unter Bereitstellen von Visual Studio-Erweiterungen. Informationen zum Hinzufügen von Dateien zu speziellen Installationsspeicherorten, z. B. zum Hinzufügen von Dateien unter $(VCTargetsPath), finden Sie unter Installieren außerhalb des Ordners für Erweiterungen.

Zusätzliche Ressourcen

Das Microsoft Build System (MSBuild) stellt die Build-Engine und das erweiterbare XML-basierte Format für Projektdateien bereit. Sie sollten mit den grundlegenden MSBuild-Konzepten und der Funktionsweise von MSBuild für Visual C++ vertraut sein, um das Visual C++-Projektsystem zu erweitern.

Das Managed Extensibility Framework (MEF) stellt die Erweiterungs-APIs bereit, die von CPS und vom Visual C++-Projektsystem verwendet werden. Eine Übersicht über den Einsatz des MEF durch CPS finden Sie unter CPS und MEF in der VSProjectSystem-Übersicht für MEF.

Sie können das vorhandene Buildsystem anpassen und Buildschritte oder neue Dateitypen hinzuzufügen. Weitere Informationen finden Sie unter Übersicht über MSBuild (Visual C++) und Arbeiten mit Projekteigenschaften.