Perché l'unità si costruisce più velocemente dato i moderni compilatori?

0

Considerare (usando Visual C ++ come esempio):

cl /EHsc a.cpp b.cpp c.cpp

vs

cat a.cpp b.cpp c.cpp > unity.cpp
cl /EHsc unity.cpp

Perché la prima variante è più lenta di un moderno compilatore? Ho visto persone dire che le build di unità evitano che le intestazioni vengano analizzate più volte. Ma allora perché un moderno compilatore non memorizza nella cache i suoi risultati di analisi dell'header e li riutilizza tra le unità di compilazione? Bene, lo fanno già. Ecco quali sono le intestazioni precompilate. Ma allora perché non farlo automaticamente per tutto il tempo? Potresti dire che l'ordine di include, undefs e altre strane merde può essere importante, ma questo è il caso patologico / eccezionale. È ancora possibile rilevare un file di intestazione ben gestito e memorizzarlo nella cache, non è possibile?

    
posta Ansis Māliņš 29.05.2017 - 10:57
fonte

1 risposta

4

La maggior parte dei file di intestazione C e C ++ (in particolare le intestazioni di sistema o quelle di grandi librerie C ++ come Qt ) hanno #include guards o non standard #pragma once . In pratica, le intestazioni standard di C ++ come <set> o <map> vengono spesso espanse ad almeno diecimila righe ciascuna.

Quindi, quando alcune unità di traduzione (come unity.cpp ) includono alcuni dati di un file di intestazione foo.h più volte, viene incluso solo una volta (la prima occorrenza del suo #include ).

Quindi, la forma pre-elaborata di unity.cpp è più breve (in token pre-elaborati) della somma della forma preelaborata di ciascuno di a.cpp , b.cpp , c.cpp .

E potreste verificarlo ottenendo il loro modulo pre-elaborato. Con GCC che useresti (magari aggiungendo altri opzioni del preprocessore come -I ... per aggiungere una directory include, -D ... per definire un simbolo del preprocessore, -H per ottenere il percorso dei file inclusi, ...)

g++ -C -E a.cpp > a.ii
g++ -C -E b.cpp > b.ii
g++ -C -E c.cpp > c.ii
g++ -C -E unity.cpp > unity.ii

e potresti confrontare il conteggio delle parole cumulato ottenuto da wc a.ii b.ii c.ii con quello di wc unity.ii

(Ti lascio adattare questi comandi Linux al tuo cl compilatore e Windows)

Tuttavia, la presenza di più unità di traduzione abilita le build parallele (in diversi processi eseguiti simultaneamente), ad es. con make -j .

(Quindi, in termini pratici, potresti volere un po 'di compromesso, ho l'abitudine di avere *.cc di file di qualche migliaio di righe)

You might say that the order of includes, undefs, and other weird shit can matter, but that's the pathological/exceptional case.

Non sono sicuro che sia patologico. Su Linux, presumo che potrebbe essere abbastanza comune. Vedi feature_test_macros (7)

You could still detect a well behaved header file and cache it

In pratica, questo non funziona bene. All'interno di GCC, alcune persone intelligenti hanno lavorato su intestazioni prepagate senza successo . I futuri standard C ++ potrebbero definire moduli (vedi anche Clang documentation su di essi )

NB: Sto rispondendo con un Linux & Vista centrica GCC, ma è possibile adattare la risposta al proprio Visual C ++ e amp; Windows (che non conosco) perché è molto più un problema linguistico (e pratico) di un sistema operativo e amp; compilatore uno.

    
risposta data 29.05.2017 - 11:08
fonte

Leggi altre domande sui tag