Dlaczego kompilacja C++ trwa tak długo?

Kompilacja pliku C++ zajmuje bardzo dużo czasu w porównaniu do C# i Javy. Skompilowanie pliku C++ zajmuje znacznie więcej czasu niż uruchomienie skryptu Pythona o normalnym rozmiarze. Obecnie używam VC++, ale tak samo jest z każdym kompilatorem. Dlaczego?

Dwa powody, dla których przyszło mi do głowy, to ładowanie plików nagłówkowych i uruchamianie preprocesora, ale to chyba nie powinno wyjaśniać, dlaczego trwa to tak długo.

Author: Martin Broadhurst, 2008-11-25

14 answers

Kilka powodów

Pliki nagłówkowe

Każda pojedyncza jednostka kompilacji wymaga setek lub nawet tysięcy nagłówków do załadowania (1) i skompilowania (2). Każdy z nich zazwyczaj musi być rekompilowany dla każdej jednostki kompilacji, ponieważ preprocesor zapewnia, że Wynik kompilacji nagłówka Może różnić się między każdą jednostką kompilacji. (Makro może być zdefiniowane w jednej jednostce kompilacji, która zmienia zawartość nagłówka).

To prawdopodobnie główny powód, ponieważ wymaga ogromnych ilości kodu do skompilowania dla każdej jednostki kompilacji, dodatkowo każdy nagłówek musi być kompilowany wielokrotnie (raz dla każdej jednostki kompilacji, która ją zawiera).

Linkowanie

Po skompilowaniu wszystkie pliki obiektowe muszą być ze sobą połączone. Jest to w zasadzie monolityczny proces, który nie może być bardzo dobrze równoległy i musi przetworzyć cały projekt.

Parsowanie

Składnia jest niezwykle skomplikowany w analizie, w dużej mierze zależy od kontekstu i jest bardzo trudny do rozróżnienia. To zajmuje dużo czasu.

Szablony

W C#, List<T> jest jedynym typem, który jest kompilowany, bez względu na to, ile instancji listy masz w swoim programie. W C++, vector<int> jest całkowicie oddzielnym typem od vector<float>, a każdy z nich będzie musiał być skompilowany osobno.

Dodaj do tego, że szablony tworzą pełny "pod-język Turinga", który kompilator musi zinterpretować, a to może stań się śmiesznie skomplikowany. Nawet stosunkowo prosty kod metaprogramowania szablonów może definiować rekurencyjne szablony, które tworzą dziesiątki i dziesiątki instancji szablonów. Szablony mogą również powodować bardzo złożone typy, z śmiesznie długimi nazwami, dodając wiele dodatkowej pracy do linkera. (Musi porównywać wiele nazw symboli, a jeśli te nazwy mogą urosnąć do wielu tysięcy znaków, może to stać się dość kosztowne).

I oczywiście zaostrzają problemy z pliki nagłówkowe, ponieważ szablony na ogół muszą być zdefiniowane w nagłówkach, co oznacza, że o wiele więcej kodu musi być parsowanych i kompilowanych dla każdej jednostki kompilacji. W prostym kodzie C nagłówek zazwyczaj zawiera tylko deklaracje forward, ale bardzo mało rzeczywistego kodu. W C++ nie jest rzadkością, że prawie cały kod znajduje się w plikach nagłówkowych.

Optymalizacja

C++ pozwala na bardzo dramatyczne optymalizacje. C # czy Java nie pozwalają na całkowite wyeliminowanie klas (muszą być tam w celach refleksji), ale nawet prosty metaprogram szablonów C++ może łatwo wygenerować dziesiątki lub setki klas, wszystkie z nich są inline i wyeliminowane ponownie w fazie optymalizacji.

Ponadto program C++ musi być w pełni zoptymalizowany przez kompilator. Program C# może polegać na kompilatorze JIT do wykonywania dodatkowych optymalizacji w czasie ładowania, C++ nie ma takiej "drugiej szansy". To, co generuje kompilator, jest tak zoptymalizowane, jak będzie get.

Maszyna

C++ jest kompilowany do kodu maszynowego, który może być nieco bardziej skomplikowany niż bajtowe Java lub. NET (szczególnie w przypadku x86). (Jest to wymienione w kompletności tylko dlatego, że zostało wspomniane w komentarzach i tym podobnych. W praktyce jest mało prawdopodobne, aby ten krok zajął więcej niż niewielki ułamek całkowitego czasu kompilacji).

Podsumowanie

Większość z tych czynników jest współdzielona przez kod C, który w rzeczywistości kompiluje się dość wydajnie. Parsowanie step jest dużo bardziej skomplikowany w C++ i może zająć znacznie więcej czasu, ale głównym sprawcą są prawdopodobnie szablony. Są użyteczne i sprawiają, że C++ jest o wiele potężniejszym językiem, ale także zbiera swoje żniwo pod względem szybkości kompilacji.

 728
Author: jalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-10 14:39:24

Spowolnienie niekoniecznie jest takie samo w przypadku każdego kompilatora.

Nie używałem Delphi lub Kylix, ale w czasach MS-DOS program Turbo Pascal kompilowałby się niemal natychmiast, podczas gdy odpowiedni program Turbo C++ po prostu się czołgał.

Dwie główne różnice to bardzo silny system modułów i składnia pozwalająca na kompilację jednoprzebiegową.

Jest z pewnością możliwe, że szybkość kompilacji nie była priorytetem dla programistów C++, ale istnieją również pewne nieodłączne komplikacje w składni C/C++, które utrudniają jej przetwarzanie. (Nie jestem ekspertem w C, ale Walter Bright jest, a po zbudowaniu różnych komercyjnych kompilatorów C / C++ stworzył język D. Jedną z jego zmian było wprowadzenie gramatyki bezkontekstowej, aby język był łatwiejszy do analizy.)

Zauważysz również, że ogólnie pliki Makefile są tak skonfigurowane, że każdy plik jest kompilowany osobno w C, więc jeśli 10 plików źródłowych używa tego samego plik include, który plik include jest przetwarzany 10 razy.

 36
Author: tangentstorm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-25 18:55:04

Parsowanie i generowanie kodu są dość szybkie. Prawdziwym problemem jest otwieranie i zamykanie plików. Pamiętaj, że nawet z zabezpieczeniami include, kompilator wciąż ma open the .Plik H i odczytać każdą linię (a następnie zignorować).

Pewnego razu znajomy (znudzony w pracy) wziął aplikację swojej firmy i włożył wszystko-wszystkie pliki źródłowe i nagłówkowe-do jednego dużego pliku. Czas kompilacji spadł z 3 godzin do 7 minut.

 32
Author: James Curran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-03 10:38:19

C++ jest kompilowany do kodu maszynowego. Więc masz pre-procesor, kompilator, optymalizator i wreszcie assembler, wszystkie z nich muszą działać.

[[0]} Java i C# są kompilowane do kodu bajtowego / IL, a Java virtual machine/. NET Framework execute (lub JIT kompilowane do kodu maszynowego) przed wykonaniem.

Python jest językiem interpretowanym, który jest również kompilowany do kodu bajtowego.

Jestem pewien, że są ku temu inne powody, ale ogólnie rzecz biorąc, nie trzeba skompilowanie do natywnego języka maszynowego oszczędza czas.

 16
Author: Alan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-02 16:06:51

Innym powodem jest użycie pre-procesora C do lokalizowania deklaracji. Nawet z osłonami,.h nadal musi być analizowane w kółko, za każdym razem, gdy są włączone. Niektóre Kompilatory obsługują wstępnie skompilowane nagłówki, które mogą w tym pomóc, ale nie zawsze są używane.

Zobacz także: C++ Często zadawane pytania odpowiedzi

 15
Author: Dave Ray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-25 18:32:37

Największe problemy to:

1) nieskończona reparacja nagłówka. Już wspomniałem. Ograniczenia (jak #pragma raz) zwykle działają tylko na jednostkę kompilacji, a nie na kompilację.

2) fakt, że toolchain jest często podzielony na wiele binariów (make, preprocesor, kompilator, asembler, archiver, impdef, linker i dlltool w skrajnych przypadkach), że wszystkie muszą ponownie inicjalizować i przeładowywać wszystkie stany cały czas dla każdego wywołania (kompilator, asembler) lub co kilka plików (archiver, linker i dlltool).

Zobacz także tę dyskusję na temat comp.Kompilatory: http://compilers.iecc.com/comparch/article/03-11-078 szczególnie ten:

Http://compilers.iecc.com/comparch/article/02-07-128

Zauważ, że John, moderator comp.wydaje się, że Kompilatory się zgadzają, a to oznacza, że powinno być możliwe osiągnięcie podobnych prędkości również dla C, jeśli integruje się w pełni toolchain i implementuje wstępnie skompilowane nagłówki. Wiele komercyjnych C Kompilatory robią to do pewnego stopnia.

Zauważ, że uniksowy model faktoringu wszystkiego do osobnego pliku binarnego jest rodzajem najgorszego modelu Dla Windows (z jego powolnym tworzeniem procesu). Jest to bardzo zauważalne przy porównywaniu czasów kompilacji GCC pomiędzy Windows i * nix, szczególnie jeśli system make/configure wywołuje również niektóre programy tylko w celu uzyskania informacji.

 11
Author: Marco van de Voort,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-03 17:28:25

budowanie C / C++: co tak naprawdę się dzieje i dlaczego trwa to tak długo

Stosunkowo duża część czasu tworzenia oprogramowania nie jest poświęcana na pisanie, uruchamianie, debugowanie czy nawet projektowanie kodu, ale na oczekiwanie na zakończenie kompilacji. Aby wszystko było szybkie, musimy najpierw zrozumieć, co się dzieje, gdy oprogramowanie C/C++ jest kompilowane. Kroki są mniej więcej następujące:

  • Konfiguracja
  • Build tool startup
  • zależność sprawdzanie
  • kompilacja
  • linkowanie

Przyjrzymy się teraz każdemu etapowi bardziej szczegółowo, koncentrując się na tym, w jaki sposób można je przyspieszyć.

Konfiguracja

Jest to pierwszy krok podczas tworzenia. Zwykle oznacza uruchomienie skryptu configure lub CMake, Gyp, SCons lub innego narzędzia. Może to zająć od jednej sekundy do kilku minut w przypadku bardzo dużych skryptów konfiguracyjnych opartych na Autotools.

Ten krok zdarza się stosunkowo rzadko. It only musi być uruchomiony podczas zmiany konfiguracji lub zmiany konfiguracji kompilacji. Oprócz zmieniających się Systemów budowania, nie ma wiele do zrobienia, aby ten krok był szybszy.

Build tool startup

Tak się dzieje, gdy uruchamiasz make lub klikasz ikonę build na IDE (który jest zwykle aliasem dla make). Narzędzie build Binary uruchamia i odczytuje swoje pliki konfiguracyjne, jak również konfigurację build, które zazwyczaj są tym samym.

W zależności od budowy złożoność i rozmiar, może to trwać od ułamka sekundy do kilku sekund. Samo w sobie nie byłoby tak źle. Niestety większość systemów budowania opartych na make powoduje, że make jest invocowany dziesiątki do setek razy dla każdej pojedynczej kompilacji. Zwykle jest to spowodowane rekurencyjnym użyciem make (co jest złe).

Należy zauważyć, że powodem, dla którego Make jest tak powolny, nie jest błąd implementacji. Składnia Makefiles ma kilka dziwactw, które sprawiają, że naprawdę szybka implementacja, ale niemożliwe. Ten problem jest jeszcze bardziej zauważalny w połączeniu z następnym krokiem.

Sprawdzanie zależności

Gdy narzędzie kompilacji odczytuje swoją konfigurację, musi określić, które pliki zostały zmienione i które należy przekompilować. Pliki konfiguracyjne zawierają ukierunkowany Graf acykliczny opisujący zależności budowania. Wykres ten jest zwykle budowany podczas etapu konfiguracji. Czas uruchamiania narzędzia Build i skaner zależności są uruchamiane na każdej kompilacji. Ich łączny czas pracy określa dolną granicę w cyklu edycji-kompilacji-debugowania. W przypadku małych projektów czas ten wynosi zwykle kilka sekund. To jest znośne. Istnieją alternatywy do zrobienia. Najszybszym z nich jest Ninja, który został zbudowany przez inżynierów Google dla Chromium. Jeśli używasz CMake lub Gyp do budowania, po prostu przełącz się na ich backend Ninja. Nie musisz niczego zmieniać w samych plikach kompilacji, po prostu ciesz się zwiększeniem prędkości. Ninja nie jest pakowany w większości dystrybucji, choć, więc może będziesz musiał sam go zainstalować.

Kompilacja

W tym momencie w końcu wywołujemy kompilator. Wycinając niektóre rogi, oto przybliżone kroki podjęte.

  • Scalanie obejmuje
  • parsowanie kodu
  • generowanie/Optymalizacja kodu

Wbrew powszechnemu przekonaniu, kompilowanie C++ nie jest tak powolne. STL jest powolny, a większość narzędzi kompilacji używanych do kompilacji C++ jest powolna. Istnieją jednak szybsze narzędzia i sposoby na / align = "left" /

Używanie ich wymaga odrobiny smaru łokciowego, ale korzyści są niezaprzeczalne. Krótsze czasy tworzenia prowadzą do szczęśliwszych programistów, większej zwinności i ostatecznie lepszego kodu.

 9
Author: Ravindra Acharya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-15 10:48:35

Język skompilowany zawsze będzie wymagał większego obciążenia początkowego niż język interpretowany. Ponadto, być może nie dobrze skonstruowałeś swój kod C++. Na przykład:

#include "BigClass.h"

class SmallClass
{
   BigClass m_bigClass;
}

Kompiluje się dużo wolniej niż:

class BigClass;

class SmallClass
{
   BigClass* m_bigClass;
}
 7
Author: Andy Brice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-25 18:33:53

Łatwym sposobem na skrócenie czasu kompilacji w większych projektach C++ jest utworzenie *.plik dołączony cpp, który zawiera wszystkie pliki cpp w Twoim projekcie i kompiluje je. Zmniejsza to problem wybuchu nagłówka do jednego. Zaletą tego jest to, że błędy kompilacji nadal będą odwoływać się do właściwego pliku.

Na przykład, załóżmy, że masz a.cpp, b.cpp oraz c.cpp.. Utwórz plik: wszystko.cpp:

#include "a.cpp"
#include "b.cpp"
#include "c.cpp"

Następnie skompilować projekt, po prostu tworząc wszystko.cpp

 5
Author: rileyberton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-03 22:35:22

Niektóre powody to:

1) Gramatyka C++ jest bardziej złożona niż C# czy Java i zajmuje więcej czasu.

2) (ważniejsze) kompilator C++ wytwarza kod maszynowy i wykonuje wszystkie optymalizacje podczas kompilacji. C# i Java przejść tylko w połowie drogi i pozostawić te kroki do JIT.

 4
Author: Nemanja Trifunovic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-25 18:27:36

Kompromis, jaki dostajesz, polega na tym, że program działa trochę szybciej. Może to być zimny komfort dla Ciebie podczas rozwoju, ale może to mieć duże znaczenie, gdy rozwój zostanie zakończony, a program jest po prostu prowadzony przez użytkowników.

 4
Author: T.E.D.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-31 15:08:32

Większość odpowiedzi jest nieco niejasna, wspominając, że C# zawsze będzie działać wolniej ze względu na koszt wykonywania działań, które w C++ są wykonywane tylko raz w czasie kompilacji, ten koszt wydajności ma również wpływ ze względu na zależności uruchomieniowe(więcej rzeczy do załadowania, aby móc uruchomić), nie wspominając o tym, że programy C# zawsze będą miały większy ślad pamięci, co powoduje, że wydajność jest bliżej związana z możliwościami dostępnego sprzętu. To samo dotyczy innych języków, które są interpretowane lub zależą od maszyny wirtualnej.

 2
Author: Panic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-20 05:10:56

Są dwa problemy, które mogą mieć wpływ na szybkość kompilacji Twoich programów w C++.

Możliwy problem #1-kompilowanie nagłówka: (Może to być już rozwiązane inną odpowiedzią lub komentarzem.) Microsoft Visual C++ (Aka VC++) obsługuje wstępnie skompilowane nagłówki, które Gorąco polecam. Po utworzeniu nowego projektu i wybraniu typu tworzonego programu na ekranie powinno pojawić się okno kreatora konfiguracji. Jeśli trafisz przycisk "Dalej >" na dole okna przeniesie Cię do strony, która ma kilka list funkcji; upewnij się, że pole obok opcji "Precompiled header" jest zaznaczone. (UWAGA: To było moje doświadczenie z aplikacjami konsolowymi Win32 w C++, ale może nie być tak w przypadku wszystkich rodzajów programów w C++.)

Możliwy problem # 2 - Lokalizacja kompilowana do: tego lata brałem udział w kursie programowania i musieliśmy przechowywać wszystkie nasze projekty we flashu 8GB dyski, ponieważ komputery w laboratorium, z których korzystaliśmy, były wymazywane każdej nocy o północy, co wymazałoby całą naszą pracę. Jeśli kompilujesz do zewnętrznego urządzenia pamięci masowej ze względu na przenośność/bezpieczeństwo/itp., skompilowanie programu może potrwać bardzo długo (nawet z wstępnie skompilowanymi nagłówkami, o których wspomniałem powyżej), zwłaszcza jeśli jest to dość duży program. Moja rada dla Ciebie w tym przypadku byłoby tworzenie i kompilowanie programów na dysku twardym komputera używasz i kiedy chcesz/musisz przestać pracować nad projektem z dowolnego powodu, przenieś je do zewnętrznego urządzenia pamięci masowej, a następnie kliknij ikonę "Bezpiecznie usuń sprzęt i wysuń nośnik", która powinna pojawić się jako mały dysk flash za małym zielonym kółkiem z białym znacznikiem wyboru, aby go odłączyć.

Mam nadzieję, że to ci pomoże; daj mi znać,jeśli tak! :)

 1
Author: cjor530,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-18 02:11:17

Jak już skomentowano, kompilator spędza dużo czasu na tworzeniu i tworzeniu instancji na nowo szablonów. Do tego stopnia, że istnieją projekty, które koncentrują się na tym konkretnym elemencie i twierdzą, że obserwowalne przyspieszenie 30x w niektórych naprawdę korzystnych przypadkach. Zobacz http://www.zapcc.com .

 0
Author: akim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-26 10:36:07