Clang vs GCC per il mio progetto di sviluppo Linux


175

Sono al college e per un progetto che stiamo usando C. Abbiamo esplorato GCC e Clang e Clang sembra essere molto più user friendly di GCC. Di conseguenza, mi chiedo quali siano i vantaggi o gli svantaggi dell'utilizzo di clang, al contrario di GCC, per lo sviluppo in C e C ++ su Linux?

Nel mio caso questo sarebbe usato per programmi a livello di studente, non per produzione.

Se uso Clang, dovrei eseguire il debug con GDB e utilizzare GNU Make oppure utilizzare un altro debugger e creare utility?


7
Per quanto ne so, Clang è ancora lungi dall'essere "maturo", soprattutto per quanto riguarda il supporto di librerie standard. Tuttavia, ha fantastici messaggi di errore, quindi puoi sempre affrontare un misterioso errore del compilatore provando il codice su Clang. Clang può anche compilare C ++ in C, credo.
Kerrek SB,

3
@KerrekSB: quale elemento del "supporto libreria standard" manca dal clang?
Stephen Canon,

2
@StephenCanon: L'ultima volta che l'ho provato, ho dovuto usare libstdc ++ (che per quanto ho capito non fa parte di Clang). E proprio l'altro giorno abbiamo avuto questo problema . Ad ogni modo, non sto seguendo il limite, quindi la mia visione potrebbe essere del tutto obsoleta.
Kerrek SB,

4
@KerrekSB: per quanto riguarda il tuo collegamento, Clang non funziona su Windows puro. Funziona in MinGW però. Per quanto riguarda la libreria standard, al momento non esiste una vera libreria standard di Clang. Clang è in bundle con libc ++ su OSX, tuttavia libc ++ non è completamente portato in altri ambienti, quindi su quelli Clang è necessaria un'altra implementazione di libreria standard da installare. Su Linux, libstdc ++ funziona.
Matthieu M.,

1
@KerrekSB: C ++ 98 è supportato al 100%. Il C ++ 11 è per lo più supportato (l'ultimo che ho controllato, <atomic>non è supportato, forse mancano alcune altre piccole cose ... Non posso usarlo, quindi non sono completamente al passo con esso).
James McNellis,

Risposte:


122

MODIFICARE:

I ragazzi di gcc hanno davvero migliorato l'esperienza di diagnosi in gcc (ah competizione). Hanno creato una pagina wiki per mostrarla qui . gcc 4.8 ora ha anche una buona diagnostica (gcc 4.9x ha aggiunto il supporto colore). Clang è ancora in testa, ma il gap si sta chiudendo.


Originale:

Per gli studenti, consiglierei incondizionatamente Clang.

Le prestazioni in termini di codice generato tra gcc e Clang non sono ora chiare (anche se penso che gcc 4.7 abbia ancora il vantaggio, non ho ancora visto parametri di riferimento conclusivi), ma per gli studenti apprendere che non ha comunque importanza.

D'altra parte, la diagnostica estremamente chiara di Clang è sicuramente più facile da interpretare per i principianti.

Considera questo semplice frammento:

#include <string>
#include <iostream>

struct Student {
std::string surname;
std::string givenname;
}

std::ostream& operator<<(std::ostream& out, Student const& s) {
  return out << "{" << s.surname << ", " << s.givenname << "}";
}

int main() {
  Student me = { "Doe", "John" };
  std::cout << me << "\n";
}

Noterai subito che manca il punto e virgola dopo la definizione della Studentclasse, giusto :)?

Bene, anche gcc se ne accorge , dopo una moda:

prog.cpp:9: error: expected initializer before ‘&’ token
prog.cpp: In function int main()’:
prog.cpp:15: error: no match for operator<<’ in std::cout << me
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:112: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>& (*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:121: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:131: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:169: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:173: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:177: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/ostream.tcc:97: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:184: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/ostream.tcc:111: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:195: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:204: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:208: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:213: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:217: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:225: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:229: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/ostream.tcc:125: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_streambuf<_CharT, _Traits>*) [with _CharT = char, _Traits = std::char_traits<char>]

E Clang non è nemmeno esattamente protagonista qui, ma comunque:

/tmp/webcompile/_25327_1.cc:9:6: error: redefinition of 'ostream' as different kind of symbol
std::ostream& operator<<(std::ostream& out, Student const& s) {
     ^
In file included from /tmp/webcompile/_25327_1.cc:1:
In file included from /usr/include/c++/4.3/string:49:
In file included from /usr/include/c++/4.3/bits/localefwd.h:47:
/usr/include/c++/4.3/iosfwd:134:33: note: previous definition is here
  typedef basic_ostream<char>           ostream;        ///< @isiosfwd
                                        ^
/tmp/webcompile/_25327_1.cc:9:13: error: expected ';' after top level declarator
std::ostream& operator<<(std::ostream& out, Student const& s) {
            ^
            ;
2 errors generated.

Ho scelto di proposito un esempio che innesca un messaggio di errore poco chiaro (proveniente da un'ambiguità nella grammatica) piuttosto che i tipici esempi "Oh mio dio Clang leggimi nella mente". Tuttavia, notiamo che Clang evita il diluvio di errori. Non c'è bisogno di spaventare gli studenti.


2
Ehm ... l'ultima volta che ho controllato ho letto un articolo che ha pubblicato vari parametri di riferimento in cui clang ha praticamente fatto esplodere gcc dall'acqua in ogni test. Fonte: clang.llvm.org/features.html#performance

31
@AscensionSystems: attenzione, quei test mostrano le prestazioni del binario stesso di Clang (e quello era un po 'di tempo fa), non le prestazioni del binario che stavi compilando.
Matthieu M.

Questo è un buon punto, sarei interessato a vedere un confronto tra i file eseguibili compilati. Ho l'impressione che Clang svolga un lavoro molto migliore nell'ottimizzazione, ma in realtà non ho visto alcun benchmark. Lo guarderò.

4
@AscensionSystems: ecco l'ultimo banco che conosco confrontando gcc 4.6 con llvm 3.0 che mostra in media un vantaggio netto di gcc. Interessante anche la panchina di DragonEgg , DragonEgg è un plugin che consente di utilizzare il front-end gcc (e possibilmente l'ottimizzatore) e quindi il backend LLVM per generare il codice.
Matthieu M.,

1
L'ultima volta che ho controllato, i benchmark phoronix erano molto inaffidabili: i flag del compilatore non erano adeguatamente documentati, ma i risultati suggerivano che le cose non erano state impostate correttamente.
Eamon Nerbonne,

35

A partire da ora, GCC ha un supporto molto migliore e più completo per le funzionalità di C ++ 11 rispetto a Clang. Inoltre, il generatore di codice per GCC esegue un'ottimizzazione migliore rispetto a quello di Clang (nella mia esperienza, non ho visto alcun test esaustivo).

D'altra parte, Clang spesso compila il codice più rapidamente di GCC e produce messaggi di errore migliori quando c'è qualcosa di sbagliato nel tuo codice.

La scelta di quale usare dipende davvero da quali cose sono importanti per te. Apprezzo il supporto C ++ 11 e la qualità della generazione del codice più di quanto apprezzo la convenienza della compilazione. Per questo motivo, utilizzo GCC. Per te, i compromessi potrebbero essere diversi.


3
Ecco l'ultimo articolo di Phoronix che confronta GCC 4.6 con Clang 3.0 e un articolo precedente specifico per la piattaforma bulldozer. A seconda dei benchmark, il vincitore è l'uno o l'altro (nell'articolo precedente appare anche gcc 4.7), quindi personalmente trovo poco chiaro quale sia il rendimento migliore.
Matthieu M.,

Perché non usare entrambi? Clang per lo sviluppo e GCC per la produzione.
segfault

5
@segfault: è quello che sto facendo attualmente. Questa risposta è piuttosto vecchia e non è più del tutto vera. Sia Clang che GCC sono migliorati significativamente da quando l'ho scritto (in particolare, Clang ora corrisponde al supporto C ++ 11 complessivo di GCC e GCC ha migliorato i suoi messaggi di errore e la velocità di compilazione). Ora suggerirei di usare entrambi, con una leggera preferenza per Clang perché il codice sorgente di Clang è molto più facile da capire rispetto alla fonte GCC.
Mankarse,

23

Uso entrambi perché a volte forniscono messaggi di errore diversi e utili.

Il progetto Python è stato in grado di trovare e correggere numerosi piccoli buglet quando uno degli sviluppatori principali ha provato a compilare con clang.


1
Cosa ne pensi dell'utilizzo di clang per build di debug ma gcc per versioni ottimizzate?
Olical,

5
È ragionevole sviluppare con Clang e rilasciarlo con GCC, ma assicurati che la tua versione GCC superi la tua suite di test (sia con che senza NDEBUG).
Raymond Hettinger,

2
Grazie per la risposta. L'ho provato per un po 'e funziona davvero bene. Ricevo anche diversi avvertimenti, il che è fantastico.
Olical,

11

Uso sia Clang che GCC, trovo che Clang abbia alcuni avvertimenti utili, ma per i miei benchmark di ray-tracing - è costantemente più lento del 5-15% rispetto a GCC (prendilo ovviamente con granello di sale , ma ho provato a usare flag di ottimizzazione simili per entrambi).

Quindi per ora uso l'analisi statica di Clang e i suoi avvisi con macro complesse: (anche se ora gli avvisi di GCC sono abbastanza buoni - gcc4.8 - 4.9).

Alcune considerazioni:

  • Clang non ha supporto OpenMP, conta solo se ne approfitti, ma da quando lo faccio, è una limitazione per me. (*****)
  • La compilazione incrociata potrebbe non essere altrettanto supportata (FreeBSD 10 ad esempio usa ancora GCC4.x per ARM), ad esempio gcc-mingw è disponibile su Linux ... (YMMV).
  • Alcuni IDE non supportano ancora l'analisi dell'output di Clangs ( ad esempio QtCreator *****). EDIT: QtCreator ora supporta l'output di Clang
  • Alcuni aspetti di GCC sono meglio documentati e poiché GCC è in circolazione da più tempo ed è ampiamente utilizzato, potresti trovare più facile ottenere aiuto con avvisi / messaggi di errore.

*****: queste aree sono in fase di sviluppo attivo e potrebbero presto essere supportate


Uso anche OpenMP ma sto pensando di passare a TBB che suppongo funzionerebbe con Clang.

1
TBB può essere un'alternativa praticabile per OpenMP in alcuni casi (ma solo per C ++ per quanto ne so), per C non è supportato - anche per progetti di grandi dimensioni, il passaggio da OpenMP a qualcos'altro potrebbe non essere utile soprattutto se Clang alla fine supportare comunque OpenMP.
ideasman42

7

Per i programmi a livello di studente, Clang ha il vantaggio di essere, per impostazione predefinita, più rigorosa. lo standard C. Ad esempio, la seguente versione K&R di Hello World è accettata senza preavviso da GCC, ma rifiutata da Clang con alcuni messaggi di errore piuttosto descrittivi:

main()
{
    puts("Hello, world!");
}

Con GCC, devi darlo -Werrorper farlo davvero capire che questo non è un programma C89 valido. Inoltre, è ancora necessario utilizzare c99o gcc -std=c99per ottenere il linguaggio C99.


8
gccdovrebbe essere generalmente invocato con almeno -Wall, il che avverte per questo programma. clangproduce comunque buoni avvisi / errori.
Caf

2
@caf: che è esattamente il punto che sto cercando di chiarire, con GCC devi passare le opzioni. All'improvviso, potrebbe essere troppo tollerante ai fini dell'insegnamento.
Fred Foo,

Questo può essere vero, ma è un punto abbastanza secondario. La cosa più importante è la qualità dei messaggi di errore. GCC 4.6 è diventato abbastanza buono, anche se capisco che clang sta facendo della vera magia lì.
Kerrek SB,

2
@dreamlax: True; c'è anche gnu99, e gnu++98e gnu++0x. Penso che quelle siano autentiche estensioni , tuttavia, cioè compileranno il codice ISO conforme senza intoppi. Ecco i dettagli: per C , per C ++ .
Kerrek SB,

1
Questo programma non dovrebbe produrre errori o avvisi. È conforme allo standard.
Miles Rout l'

3

Penso che il clang potrebbe essere un'alternativa.

GCC e clang hanno alcune differenze su espressioni come a+++++a, e ho molte risposte diverse con il mio peer che usa clang su Mac mentre uso gcc.

GCC è diventato lo standard e il clang potrebbe essere un'alternativa. Perché GCC è molto stabile e il clang è ancora in fase di sviluppo.


5
Clang si sta rapidamente preparando a sostituire completamente GCC nel mondo Linux, e lo ha fatto in gran parte nel mondo BSD. Ha sostituito GCC su Mac anni fa. Clang è roba buona. Penso che GCC potrebbe diventare un'alternativa, personalmente, e ne sarei felice.
coder543,

5
L'espressione a +++++ a non è definita, quindi aspettati di ottenere una risposta diversa su ciascun compilatore o anche su versioni diverse dello stesso compilatore. Potresti anche ottenere risultati diversi per quell'espressione sullo stesso compilatore quando compilato in momenti diversi. Questo è ciò che significa "indefinito".
Lelanthran,

1
a+++++adovrebbe fallire, poiché viene analizzato come a ++ ++ + aerrore di sintassi.
Miles Rout

@Lelanthran non è ciò che significa indefinito. Ha un comportamento indefinito, quindi il compilatore potrebbe non riuscire a compilarlo, oppure può lanciarsi in fase di esecuzione o bloccare la CPU in modo da dover eseguire un hard reset o qualcosa di ancora più sinistro.
Antti Haapala,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.