Udostępnij za pomocą


Debugowanie dynamiczne języka C++ (wersja zapoznawcza)

Ważne

Debugowanie dynamiczne języka C++ jest obecnie dostępne w wersji zapoznawczej . Te informacje odnoszą się do funkcji wersji wstępnej, która może zostać znacząco zmodyfikowana przed wydaniem. Firma Microsoft nie udziela żadnych gwarancji, wyrażonych ani domniemanych, w odniesieniu do podanych tutaj informacji.

Ta funkcja w wersji zapoznawczej, dostępna od programu Visual Studio 2022 w wersji 17.14 (wersja zapoznawcza 2), dotyczy tylko projektów x64.

Za pomocą debugowania dynamicznego języka C++ można debugować zoptymalizowany kod tak, jakby był niezoptymalizowany. Ta funkcja jest przydatna dla deweloperów, którzy wymagają korzyści z wydajności zoptymalizowanego kodu, takich jak deweloperzy gier, którzy potrzebują wysokich szybkości klatek. Dzięki debugowaniu dynamicznego języka C++ możesz cieszyć się środowiskiem debugowania niezoptymalizowanego kodu bez poświęcania korzyści z wydajności zoptymalizowanych kompilacji.

Debugowanie zoptymalizowanego kodu stanowi wyzwanie. Kompilator zmienia położenie i reorganizuje instrukcje w celu optymalizacji kodu. Wynik jest bardziej wydajnym kodem, ale oznacza to:

  • Optymalizator może usunąć zmienne lokalne lub przenieść je do lokalizacji nieznanych debugerowi.
  • Kod wewnątrz funkcji może nie być już zgodny z kodem źródłowym, gdy optymalizator scala bloki kodu.
  • Nazwy funkcji na stosie wywołań mogą być błędne, jeśli optymalizator scala dwie funkcje.

W przeszłości deweloperzy zajmowali się tymi i innymi problemami podczas debugowania zoptymalizowanego kodu. Teraz te wyzwania zostały wyeliminowane, ponieważ w przypadku debugowania dynamicznego języka C++ można przejść do zoptymalizowanego kodu tak, jakby nie był niezoptymalizowany.

Oprócz generowania zoptymalizowanych plików binarnych kompilowanie przy użyciu /dynamicdeopt generuje niezoptymalizowane pliki binarne używane podczas debugowania. Podczas dodawania punktu przerwania lub przechodzenia do funkcji (w tym funkcji __forceinline) debuger ładuje niezoptymalizowany plik binarny. Następnie można debugować niezoptymalizowany kod funkcji zamiast zoptymalizowanego kodu. Możesz debugować tak, jakby debugować niezoptymalizowany kod, podczas gdy nadal uzyskujesz zalety wydajności zoptymalizowanego kodu w pozostałej części programu.

Wypróbuj debugowanie dynamiczne języka C++

Najpierw sprawdźmy, jak wygląda debugowanie zoptymalizowanego kodu. Następnie możesz zobaczyć, jak debugowanie dynamiczne języka C++ upraszcza proces.

  1. Utwórz nowy projekt aplikacji konsolowej języka C++ w programie Visual Studio. Zastąp zawartość pliku ConsoleApplication.cpp następującym kodem:

    // Code generated by GitHub Copilot
    #include <iostream>
    #include <chrono>
    #include <thread>
    
    using namespace std;
    
    int step = 0;
    const int rows = 20;
    const int cols = 40;
    
    void printGrid(int grid[rows][cols])
    {
        cout << "Step: " << step << endl;
        for (int i = 0; i < rows; ++i)
        {
            for (int j = 0; j < cols; ++j)
            {
                cout << (grid[i][j] ? '*' : ' ');
            }
            cout << endl;
        }
    }
    
    int countNeighbors(int grid[rows][cols], int x, int y)
    {
        int count = 0;
        for (int i = -1; i <= 1; ++i)
        {
            for (int j = -1; j <= 1; ++j)
            {
                if (i == 0 && j == 0)
                {
                    continue;
                }
    
                int ni = x + i;
                int nj = y + j;
                if (ni >= 0 && ni < rows && nj >= 0 && nj < cols)
                {
                    count += grid[ni][nj];
                }
            }
        }
        return count;
    }
    
    void updateGrid(int grid[rows][cols])
    {
        int newGrid[rows][cols] = { 0 };
        for (int i = 0; i < rows; ++i)
        {
            for (int j = 0; j < cols; ++j)
            {
                int neighbors = countNeighbors(grid, i, j);
                if (grid[i][j] == 1)
                {
                    newGrid[i][j] = (neighbors < 2 || neighbors > 3) ? 0 : 1;
                }
                else
                {
                    newGrid[i][j] = (neighbors == 3) ? 1 : 0;
                }
            }
        }
        // Copy newGrid back to grid
        for (int i = 0; i < rows; ++i)
        {
            for (int j = 0; j < cols; ++j)
            {
                grid[i][j] = newGrid[i][j];
            }
        }
    }
    
    int main()
    {
        int grid[rows][cols] = { 0 };
    
        // Initial configuration (a simple glider)
        grid[1][2] = 1;
        grid[2][3] = 1;
        grid[3][1] = 1;
        grid[3][2] = 1;
        grid[3][3] = 1;
    
        while (true)
        {
            printGrid(grid);
            updateGrid(grid);
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            cout << "\033[H\033[J"; // Clear the screen
            step++;
        }
    
        return 0;
    }
    
  2. Zmień listę rozwijaną konfiguracji rozwiązania na Release. Upewnij się, że lista rozwijana platformy rozwiązań jest ustawiona na x64.

  3. Skompiluj ponownie, wybierając pozycję Kompilacja>Skompiluj rozwiązanie.

  4. Ustaw punkt przerwania na linii 55, int neighbors = countNeighbors(grid, i, j); w updateGrid(). Uruchom program.

  5. Po osiągnięciu punktu przerwania wyświetl okno Lokalnie. W menu głównym wybierz pozycję Debuguj>>Localssystemu Windows. Zwróć uwagę, że wartość i lub j nie jest widoczna w oknie Locals. Kompilator całkowicie zoptymalizował je.

  6. Spróbuj ustawić punkt przerwania w wierszu 19, cout << (grid[i][j] ? '*' : ' '); w printGrid(). Nie można. To zachowanie jest oczekiwane, ponieważ kompilator zoptymalizował kod.

Zatrzymaj program i włącz debugowanie dynamiczne języka C++ i spróbuj ponownie

  1. W eksploratorze rozwiązań kliknij prawym przyciskiem myszy projekt i wybierz Właściwości, aby otworzyć strony właściwości projektu.

  2. Wybierz pozycję Advanced>Use C++ Dynamic Debugging(Użyj dynamicznego debugowania języka C++), a następnie zmień ustawienie na Tak.

    Zrzut ekranu przedstawiający zaawansowane właściwości projektu.

    Zostanie otwarta strona właściwości konfiguracji > Zaawansowane > Użyj debugowania dynamicznego języka C++. Właściwość jest ustawiona na Tak.

    Ten krok dodaje przełącznik /dynamicdeopt do kompilatora i linkera. W tle wyłącza również przełączniki optymalizacji języka C++ /GL i /OPT:ICF. To ustawienie nie zastępuje przełączników dodanych ręcznie do wiersza polecenia lub innych ustawionych przełączników optymalizacji, takich jak /O1.

  3. Skompiluj ponownie, wybierając pozycję Kompilacja>Skompiluj rozwiązanie. Pojawia się kod diagnostyczny MSB8088, który wskazuje, że debugowanie dynamiczne i optymalizacja całego programu są niekompatybilne. Ten błąd oznacza, że cała optymalizacja programu (/GL) została automatycznie wyłączona podczas kompilacji.

    Możesz ręcznie wyłączyć optymalizację całego programu we właściwościach projektu. Wybierz Właściwości konfiguracji>Zaawansowane>Optymalizacja całego programui zmień ustawienie na Wyłącz. Teraz MSB8088 jest traktowana jako ostrzeżenie, ale może być traktowana jako błąd w przyszłej wersji programu Visual Studio.

  4. Uruchom ponownie aplikację.

    Teraz po osiągnięciu punktu przerwania w wierszu 55 zobaczysz wartości i i j w oknie Locals. Okno stosu wywołań pokazuje, że updateGrid() jest zdezoptymalizowany, a nazwa pliku jest life.alt.exe. Ten alternatywny plik binarny służy do debugowania zoptymalizowanego kodu.

    Zrzut ekranu przedstawiający debugowanie funkcji updateGrid.

    Punkt przerwania jest wyświetlany w funkcji updateGrid. Stos wywołań pokazuje, że funkcja jest zdezoptymalizowana, a nazwa pliku jest life.alt.exe. W oknie Lokalne wyświetlane są wartości zmiennych i oraz j, a także inne zmienne lokalne w funkcji.

    Funkcja updateGrid() jest dezoptymalizowana na żądanie, ponieważ ustawiono w niej punkt przerwania. Jeśli przechodzisz przez zoptymalizowaną funkcję podczas debugowania, nie traci ona optymalizacji. Jeśli wejdziesz do funkcji, zostanie ona zdezoptymalizowana. Głównym sposobem zdezoptymalizowania funkcji jest ustawienie w niej punktu przerwania lub wejście do niej.

    Można również deoptymalizować funkcję w oknie stosu wywołań . Kliknij prawym przyciskiem myszy funkcję lub wybraną grupę funkcji, a następnie wybierz pozycję Deoptimize na następnym wpisie. Ta funkcja jest przydatna, gdy chcesz wyświetlić zmienne lokalne w zoptymalizowanej funkcji, dla której nie ustawiono punktu przerwania w innym miejscu na stosie wywołań. Funkcje, które są zdezoptymalizowane w ten sposób, są grupowane razem w punkty przerwania w oknie jako grupa punktów przerwania o nazwie Funkcje Zdezoptymalizowane. Jeśli usuniesz grupę punktów przerwania, skojarzone funkcje zostaną przywrócone do ich zoptymalizowanego stanu.

Używanie warunkowych i zależnych punktów przerwania

  1. Spróbuj ponownie ustawić punkt przerwania w wierszu 19, cout << (grid[i][j] ? '*' : ' '); w printGrid(). Teraz to działa. Ustawienie punktu przerwania w funkcji deoptymalizuje go tak, aby można było je debugować normalnie.

  2. Kliknij prawym przyciskiem myszy punkt przerwania w wierszu 19, wybierz pozycję Warunkii ustaw warunek na i == 10 && j== 10. Następnie zaznacz pole wyboru Włącz tylko wtedy, gdy zostanie osiągnięty następujący punkt przerwania:. Wybierz punkt przerwania w wierszu 55 z listy rozwijanej. Teraz punkt przerwania w wierszu 19 nie zostanie aktywowany, dopóki punkt przerwania w wierszu 50 nie zostanie aktywowany jako pierwszy, a następnie gdy grid[10][10] ma zostać wyprowadzony do konsoli.

    Chodzi o to, że można ustawić warunkowe i zależne punkty przerwania w zoptymalizowanej funkcji i korzystać ze zmiennych lokalnych i wierszy kodu, które w zoptymalizowanej kompilacji mogą być niedostępne dla debugera.

    Zrzut ekranu przedstawiający ustawienia warunkowego punktu przerwania dla wiersza 19.

    Warunkowy punkt przerwania jest wyświetlany w wierszu 19, < < cout (grid[i][j] ? '*' : ' ');. Warunek jest ustawiony na i == 10 && j== 10. Pole wyboru "Włącz tylko, gdy zostanie osiągnięty następujący punkt przerwania" jest zaznaczone. Lista rozwijana punktu przerwania jest ustawiona na life.cpp wiersz 55.

  3. Kontynuuj uruchamianie aplikacji. Gdy punkt przerwania w wierszu 19 zostanie osiągnięty, możesz kliknąć prawym przyciskiem myszy wiersz 15 i wybrać Ustaw Następne Wykonanie, aby uruchomić pętlę ponownie.

    Zrzut ekranu przedstawiający debugowanie funkcji printGrid.

    Warunkowy i zależny punkt przerwania jest osiągany w wierszu 19, < < cout (grid[i][j] ? '*' : ' ');. W oknie Lokalne wyświetlane są wartości zmiennych i oraz j, a także inne zmienne lokalne w funkcji. Okno Stos wywołań pokazuje, że funkcja jest zdezoptymalizowana, a nazwa pliku jest life.alt.exe.

  4. Usuń wszystkie punkty przerwania, aby przywrócić funkcje zdezoptymalizowane do ich zoptymalizowanego stanu. W menu głównym programu Visual Studio wybierz pozycję Debuguj>Usuń wszystkie punkty przerwania. Wszystkie funkcje następnie powrócą do ich zoptymalizowanego stanu.

    Jeśli dodasz punkty przerwania za pośrednictwem okna stosu wywołańdeoptymalizuj przy następnym wpisie opcji, której nie zrobiliśmy w tym przewodniku, możesz kliknąć prawym przyciskiem myszy deoptymalizowane funkcje grupy i wybrać Usuń, aby przywrócić tylko funkcje w tej grupie z powrotem do ich zoptymalizowanego stanu.

    Zrzut ekranu przedstawiający okno Punkty przerwania.

    Okno "Punkty przerwania" pokazuje grupę Funkcje zdeoptymalizowane. Grupa jest zaznaczona, a menu kontekstowe jest otwarte z wybraną pozycją Usuń grupę punktów przerwania.

Wyłączanie debugowania dynamicznego języka C++

Może być konieczne debugowanie zoptymalizowanego kodu bez jego dezoptymalizacji lub umieszczenie punktu przerwania w zoptymalizowanym kodzie i utrzymanie jego optymalizacji po osiągnięciu punktu przerwania. Istnieje kilka sposobów wyłączania debugowania dynamicznego lub uniemożliwiania deoptymalizacji kodu po osiągnięciu punktu przerwania:

  • W menu głównym programu Visual Studio wybierz pozycję Narzędzia>Opcje. W okienku Opcje rozwiń sekcję Wszystkie ustawienia>Debugowanie>ogólne . Wyczyść pole wyboru Automatycznie deoptymalizuj debugowane funkcje, jeśli to możliwe (.NET 8+, Debugowanie Dynamiczne C++). Przy następnym uruchomieniu debugera kod pozostaje zoptymalizowany.
  • W menu głównym programu Visual Studio wybierz pozycję Narzędzia>Opcje. W oknie dialogowym Opcje rozwiń sekcję Debugowanie>ogólne . Wyczyść pole wyboru Automatycznie deoptymalizuj debugowane funkcje, jeśli to możliwe (.NET 8+, Debugowanie Dynamiczne C++). Przy następnym uruchomieniu debugera kod pozostaje zoptymalizowany.
  • Wiele dynamicznych punktów przerwania debugowania to dwa punkty przerwania: jeden w zoptymalizowanym pliku binarnym i jeden w niezoptymalizowanym pliku binarnym. W oknie punktów przerwania wybierz pozycję Pokaż kolumny>funkcji. Wyczyść punkt przerwania skojarzony z binarnym plikiem alt. Drugi punkt przerwania w parze przerywa działanie zoptymalizowanego kodu.
  • Podczas debugowania w menu głównym programu Visual Studio wybierz pozycję Debugowanie>>Dezasemblacja systemu Windows. Upewnij się, że ma fokus. Po wejściu do funkcji za pośrednictwem okna Dezasemblacja funkcja nie zostanie zdezoptymalizowana.
  • Wyłącz debugowanie dynamiczne całkowicie, nie przekazując /dynamicdeopt do cl.exe, lib.exei link.exe. Jeśli używasz bibliotek innych firm i nie możesz ich ponownie skompilować, nie przekazuj /dynamicdeopt podczas ostatniej link.exe, aby wyłączyć debugowanie dynamiczne dla tego pliku binarnego.
  • Aby szybko wyłączyć debugowanie dynamiczne dla pojedynczego pliku binarnego (na przykład test.dll), zmień nazwę lub usuń plik binarny alt (na przykład test.alt.dll).
  • Aby wyłączyć debugowanie dynamiczne dla co najmniej jednego pliku .cpp, nie przekazuj /dynamicdeopt podczas ich tworzenia. Pozostała część projektu została skompilowana przy użyciu debugowania dynamicznego.

Włącz dynamiczne debugowanie C++ dla Unreal Engine 5.6 lub nowszej

Program Unreal Engine 5.6 obsługuje dynamiczne debugowanie języka C++ dla narzędzia Unreal Build Tool i Unreal Build Accelerator. Istnieją dwa sposoby jej włączenia. Zmodyfikuj plik BuildConfiguration.xml lub plik Targets.cs.

Modyfikowanie BuildConfiguration.xml pliku

W programie Visual Studio wybierz konfigurację Edytora programowania i zmodyfikuj, BuildConfiguration.xml aby uwzględnić element <bDynamicDebugging>true</bDynamicDebugging>. Aby uzyskać więcej informacji na temat BuildConfiguration.xml i jego lokalizacji, zobacz Build Configuration (Konfiguracja kompilacji).

  1. Jednym ze sposobów zlokalizowania BuildConfiguration.xml pliku jest uruchomienie kompilacji i sprawdzenie danych wyjściowych dziennika kompilacji. Na przykład podczas tworzenia gry startowej Lyra są wyświetlane dane wyjściowe w następujący sposób:

    - Running UnrealBuildTool: dotnet "..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" LyraEditor Win64 Development -Project="C:\LyraStarterGame\LyraStarterGame.uproject" ...
     14% -   Log file: C:\Users\<user>\AppData\Local\UnrealBuildTool\Log.txt
    
  2. Wyszukaj to Log.txt dla BuildConfiguration.xml. Powinien zawierać wiersz podobny do Reading configuration file from: C:\LyraStarterGame\Saved\UnrealBuildTool\BuildConfiguration.xml

  3. Zmodyfikuj ten BuildConfiguration.xml plik tak, aby zawierał <bDynamicDebugging>true</bDynamicDebugging>:

    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
        <WindowsPlatform>
            <bDynamicDebugging>true</bDynamicDebugging> <!-- add this line -->
        </WindowsPlatform>
    </Configuration>
    

Modyfikowanie Targets.cs pliku

Aby włączyć dynamiczne debugowanie C++ dla narzędzi Unreal Build Tool i Unreal Build Accelerator, należy zmodyfikować plik Target.cs, aby zawierał WindowsPlatform.bDynamicDebugging = true.

Projekty Unreal Engine mają pliki Target.cs skojarzone z różnymi typami docelowymi, w tym:

{ProjectName}.Target.cs for the game executable.
{ProjectName}Editor.Target.cs for the editor build.

W przypadku kompilacji edytora {ProjectName}Editor.Target.cs w pliku dodaj WindowsPlatform.bDynamicDebugging = true; do konstruktora:

public class LyraEditorTarget : TargetRules
{
    public LyraEditorTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Editor;

        WindowsPlatform.bDynamicDebugging = true; // add this line
        // Other settings...
    }
}

Lub w przypadku kompilacji gry w pliku {ProjectName}.Target.cs dodaj WindowsPlatform.bDynamicDebugging = true; do ApplyShared{Project name}TargetSettings() polecenia :

internal static void ApplySharedLyraTargetSettings(TargetRules Target)
{
    ILogger Logger = Target.Logger;
    
    WindowsPlatform.bDynamicDebugging = true; // add this line
    // Other settings...
}

Aby uzyskać więcej informacji na temat plików docelowych Unreal Engine, zobacz Cele.

Włącz debugowanie dynamiczne C++ dla silnika Unreal Engine 5.5 lub starszego

Dla Unreal Engine 5.5 lub starszego, przenieś zmiany w Unreal Build Tool z GitHub do swojego repozytorium.

Uwaga / Notatka

Aby uzyskać dostęp do repozytoriów Epic w usłudze GitHub, potrzebujesz konta Epic i zarejestrowanego konta usługi GitHub.

Po wybraniu zmian, które mają zostać zastosowane w repozytorium, włącz bDynamicDebugging zgodnie z wcześniejszym opisem. Musisz również użyć Unreal Build Accelerator z Unreal Engine 5.6. Użyj najnowszych bitów z ue5-main lub wyłącz UBA, dodając następujące polecenie do BuildConfiguration.xml:

<BuildConfiguration>
    <bAllowUBAExecutor>false</bAllowUBAExecutor>
    <bAllowUBALocalExecutor>false</bAllowUBALocalExecutor>
</BuildConfiguration>

Aby uzyskać więcej informacji na temat konfigurowania budowy silnika Unreal Engine, zobacz Build Configuration.

Rozwiązywanie problemów

Jeśli punkty przerwania nie trafią w funkcje zdezoptymalizowane:

  • Jeśli wyjdziesz z [Deoptimized] ramki, być może będziesz w zoptymalizowanym kodzie, chyba że obiekt wywołujący został zdezoptymalizowany z powodu punktu przerwania w nim lub wszedł do obiektu wywołującego w drodze do bieżącej funkcji.

  • Upewnij się, że pliki alt.exe i alt.pdb zostały zbudowane. W przypadku test.exe i test.pdbtest.alt.exe i test.alt.pdb muszą istnieć w tym samym katalogu. Upewnij się, że odpowiednie przełączniki kompilacji są ustawione zgodnie z tym artykułem.

  • W debug directory istnieje wpis test.exe używany przez debuger do znalezienia pliku binarnego alt do użycia na potrzeby debugowania dezoptymalizowanego. Otwórz wiersz polecenia programu Visual Studio x64 i uruchom link /dump /headers <your executable.exe>, aby sprawdzić, czy istnieje wpis deopt. Wpis deopt pojawia się w kolumnie Type, jak pokazano w ostatnim wierszu tego przykładu:

      Debug Directories
    
            Time Type        Size      RVA  Pointer
        -------- ------- -------- -------- --------
        67CF0DA2 cv            30 00076330    75330    Format: RSDS, {7290497A-E223-4DF6-9D61-2D7F2C9F54A0}, 58, D:\work\shadow\test.pdb
        67CF0DA2 feat          14 00076360    75360    Counts: Pre-VC++ 11.00=0, C/C++=205, /GS=205, /sdl=0, guardN=204
        67CF0DA2 coffgrp      36C 00076374    75374
        67CF0DA2 deopt         22 00076708    75708    Timestamp: 0x67cf0da2, size: 532480, name: test.alt.exe
    

    Jeśli wpis katalogu debugowania deopt nie istnieje, upewnij się, że przekazujesz /dynamicdeopt do cl.exe, lib.exeoraz link.exe.

  • Deoptymizacja dynamiczna nie będzie działać spójnie, jeśli /dynamicdeopt nie zostanie przekazana do cl.exe, lib.exei link.exe dla wszystkich plików .cpp, .libi binarnych. Upewnij się, że podczas kompilowanie projektu ustawiono odpowiednie przełączniki.

Aby uzyskać więcej informacji na temat znanych problemów, zobacz dynamiczne debugowanie C++: pełne możliwości debugowania dla zoptymalizowanych kompilacji.

Jeśli coś nie działa zgodnie z oczekiwaniami, otwórz zgłoszenie w Developer Community. Uwzględnij jak najwięcej informacji o problemie.

Uwagi ogólne

Program IncrediBuild 10.24 obsługuje kompilacje debugowania dynamicznego języka C++.
Program FastBuild w wersji 1.15 obsługuje kompilacje debugowania dynamicznego języka C++.

Funkcje, które są inline'owane, są dezoptymalizowane na żądanie. Jeśli ustawisz punkt przerwania w funkcji wbudowanej, debuger deoptymizuje funkcję i jej obiekt wywołujący. Punkt przerwania osiąga oczekiwaną wartość, tak jakby program został skompilowany bez optymalizacji kompilatora.

Funkcja pozostaje zdezoptymalizowana, nawet jeśli wyłączysz w niej punkty przerwania. Aby przywrócić jego zoptymalizowany stan, należy usunąć punkt przerwania funkcji.

Wiele dynamicznych punktów przerwania debugowania to dwa punkty przerwania: jeden w zoptymalizowanym pliku binarnym i jeden w niezoptymalizowanym pliku binarnym. Z tego powodu widzisz w oknie punktów przerwania więcej niż jeden punkt przerwania.

Flagi kompilatora, które są używane dla wersji zdezoptymalizowanej, są takie same jak flagi używane dla zoptymalizowanej wersji, z wyjątkiem flag optymalizacji i /dynamicdeopt. To zachowanie oznacza, że wszystkie flagi ustawione na definiowanie makr itd. są również ustawione w zdezoptymalizowanej wersji.

Zdezoptymalizowany kod nie jest taki sam jak kod debugowania. Zdezoptymalizowany kod jest kompilowany z tymi samymi flagami optymalizacji co zoptymalizowana wersja, więc asercje i inne fragmenty kodu, które polegają na ustawieniach specyficznych dla debugowania, nie są uwzględniane.

Budowanie integracji systemu

Debugowanie dynamiczne języka C++ wymaga, aby flagi kompilatora i konsolidatora musiały być ustawione w określony sposób. W poniższych sekcjach opisano sposób konfigurowania dedykowanej konfiguracji debugowania dynamicznego, która nie ma przełączników powodujących konflikt.

Jeśli projekt został skompilowany przy użyciu systemu kompilacji programu Visual Studio, dobrym sposobem na skonfigurowanie debugowania dynamicznego jest użycie programu Configuration Manager do sklonowania konfiguracji wydania lub debugowania i wprowadzenia zmian w celu dostosowania się do debugowania dynamicznego. W poniższych dwóch sekcjach opisano procedury.

Tworzenie nowej konfiguracji wydania

  1. W menu głównym programu Visual Studio wybierz pozycję Build>Configuration Manager, aby otworzyć program Configuration Manager.

  2. Wybierz listę rozwijaną Konfiguracja , a następnie wybierz pozycję Nowy... <>.

    Zrzut ekranu przedstawiający program Configuration Manager.

    W programie Configuration Manager, w obszarze Konteksty projektu, lista rozwijana Konfiguracja jest otwarta, a "" jest wyróżnione.

  3. Otwiera się okno dialogowe Konfiguracja Nowego Rozwiązania. W polu Nazwa wprowadź nazwę nowej konfiguracji, na przykład ReleaseDD. Upewnij się, że ustawienia kopiowania z: są ustawione na wartość Wersja. Następnie wybierz pozycję OK, aby utworzyć nową konfigurację.

    Zrzut ekranu przedstawiający okno dialogowe Nowa konfiguracja projektu dla wersji produkcyjnej.

    Pole nazwy zostało ustawione na ReleaseDD. Lista rozwijana "Kopiuj ustawienia z" jest ustawiona na Wersja.

  4. Nowa konfiguracja zostanie wyświetlona na liście rozwijanej Aktywne rozwiązanie. Wybierz Zamknij.

  5. Po ustawieniu listy rozwijanej konfiguracji na ReleaseDDkliknij prawym przyciskiem myszy projekt w eksploratorze rozwiązań i wybierz pozycję Właściwości .

  6. W właściwościach konfiguracji>zaawansowaneustaw Użyj dynamicznego debugowania C++ na tak.

  7. Upewnij się, że optymalizacja całego programu jest ustawiona na Nie.

    Zrzut ekranu przedstawiający zaawansowane właściwości projektu.

    Strona właściwości jest otwarta w obszarze Właściwości konfiguracji > Zaawansowane. Użyj debugowania dynamicznego języka C++. Właściwość jest ustawiona na Tak. Optymalizacja całego programu ma wartość Nie.

  8. W Właściwości konfiguracji>Linker>Optymalizacjaupewnij się, że Włącz składanie COMDAT jest ustawione na Nie (/OPT:NOICF).

    Zrzut ekranu przedstawiający właściwości projektu optymalizacji Linkera.

    Strona właściwości otwiera się na Właściwości konfiguracji > Linker > Optymalizacja > Włączanie składania CMDAT. Właściwość jest ustawiona na Nie (/OPT:NOICF).

To ustawienie dodaje przełącznik /dynamicdeopt do kompilatora i linkera. Po wyłączeniu przełączników optymalizacji języka C++ /GL i /OPT:ICF można teraz skompilować i uruchomić projekt w nowej konfiguracji, gdy chcesz użyć zoptymalizowanej kompilacji wydania, której można używać z debugowaniem dynamicznym języka C++.

Do tej konfiguracji można dodać inne przełączniki używane z kompilacjami detalicznymi, aby zawsze mieć dokładnie te przełączniki włączone lub wyłączone, których oczekujesz podczas korzystania z Debugowania dynamicznego. Aby uzyskać więcej informacji na temat przełączników, których nie należy używać z debugowaniem dynamicznym, zobacz Opcje niezgodne.

Aby uzyskać więcej informacji na temat konfiguracji w programie Visual Studio, zobacz Tworzenie i edytowanie konfiguracji.

Tworzenie nowej konfiguracji debugowania

Jeśli chcesz używać plików binarnych debugowania, ale chcesz, aby działały szybciej, możesz zmodyfikować konfigurację debugowania.

  1. W menu głównym programu Visual Studio wybierz pozycję Build>Configuration Manager, aby otworzyć program Configuration Manager.

  2. Wybierz listę rozwijaną Konfiguracja , a następnie wybierz pozycję Nowy... <>.

    Zrzut ekranu przedstawiający program Configuration Manager.

    W programie Configuration Manager w części Konteksty projektu w oknie lista rozwijana Konfiguracja jest otwarta i wyróżniona .

  3. Otwarte zostanie okno dialogowe Nowa konfiguracja projektu. W polu Nazwa wprowadź nazwę nowej konfiguracji, na przykład DebugDD. Upewnij się, że ustawienia kopiowania z są ustawione na Debug. Następnie wybierz pozycję OK, aby utworzyć nową konfigurację.

    Zrzut ekranu przedstawiający okno dialogowe

    Pole nazwy jest ustawione na DebugDD. Opcja Kopiuj ustawienia z: na liście rozwijanej jest ustawiona na Debug.

  4. Nowa konfiguracja zostanie wyświetlona na liście rozwijanej Aktywne rozwiązanie. Wybierz Zamknij.

  5. Ustaw listę rozwijaną konfiguracji na DebugDD, kliknij prawym przyciskiem myszy projekt w Eksploratorze rozwiązań i wybierz właściwości .

  6. W właściwości konfiguracji>C/C++>Optymalizacja, włącz optymalizacje, które chcesz. Można na przykład ustawić optymalizacja na Maksymalizacja prędkości (/O2).

  7. W opcji generowania kodu C/C++>ustaw podstawowe testy w czasie wykonania na tryb domyślny.

  8. W >C/C++ Ogólnewyłącz Obsługa tylko mojego kodu debugowania.

  9. Ustaw format informacji debugowania na Program Database (/Zi).

Możesz dodać inne przełączniki używane z kompilacjami debugowania do tej konfiguracji, aby zawsze mieć włączone lub wyłączone przełączniki, których oczekujesz podczas korzystania z debugowania dynamicznego. Aby uzyskać więcej informacji na temat przełączników, których nie należy używać z debugowaniem dynamicznym, zobacz Opcje niezgodne.

Aby uzyskać więcej informacji na temat konfiguracji w programie Visual Studio, zobacz Tworzenie i edytowanie konfiguracji.

Zagadnienia dotyczące niestandardowego systemu kompilacji

Jeśli masz niestandardowy system kompilacji, upewnij się, że:

  • Przekaż /dynamicdeopt do cl.exe, lib.exei link.exe.
  • Nie używaj /ZI, żadnych flag /RTC ani /JMC.

Dla dystrybutorów kompilacji:

  • W przypadku projektu o nazwie testkompilator tworzy test.alt.obj, test.alt.exp, test.obji test.exp. Konsolidator tworzy test.alt.exe, test.alt.pdb, test.exei test.pdb.
  • Należy wdrożyć nowy binarny zestaw narzędzi c2dd.dll obok c2.dll.

Niezgodne opcje

Niektóre opcje kompilatora i konsolidatora są niezgodne z debugowaniem dynamicznym języka C++. Jeśli włączysz debugowanie dynamiczne języka C++ przy użyciu ustawień projektu programu Visual Studio, niezgodne opcje zostaną automatycznie wyłączone, chyba że zostały one specjalnie ustawione w dodatkowym ustawieniu opcji wiersza polecenia.

Następujące opcje kompilatora są niezgodne z debugowaniem dynamicznym języka C++:

/GH
/GL
/Gh
/RTC1 
/RTCc 
/RTCs 
/RTCu 
/ZI (/Zi is OK)
/ZW 
/clr 
/clr:initialAppDomain
/clr:netcore
/clr:newSyntax
/clr:noAssembly
/clr:pure
/clr:safe
/fastcap
/fsanitize=address
/fsanitize=kernel-address

Następujące opcje konsolidatora są niezgodne z debugowaniem dynamicznym języka C++:

/DEBUG:FASTLINK
/INCREMENTAL
/OPT:ICF  You can specify /OPT:ICF but the debugging experience may be poor

Zobacz też

/dynamicdeopt parametr kompilatora (wersja zapoznawcza)
/DYNAMICDEOPT "flaga łącznika" (wersja zapoznawcza)
debugowanie dynamiczne w języku C++: pełna możliwość debugowania dla zoptymalizowanych kompilacji
Debugowanie zoptymalizowanego kodu