Clang vs GCC pour mon projet de développement Linux

175

Je suis à l'université et pour un projet que nous utilisons C. Nous avons exploré GCC et Clang, et Clang semble être beaucoup plus convivial que GCC. En conséquence, je me demande quels sont les avantages ou les inconvénients d'utiliser clang, par opposition à GCC, pour développer en C et C ++ sous Linux?

Dans mon cas, cela serait utilisé pour les programmes de niveau étudiant, pas pour la production.

Si j'utilise Clang, dois-je déboguer avec GDB et utiliser GNU Make, ou utiliser un autre débogueur et faire un utilitaire?

Haziz
la source
7
Pour autant que je sache, Clang est encore loin d'être "mature", notamment en ce qui concerne le support standard des bibliothèques. Néanmoins, il contient des messages d'erreur fantastiques, vous pouvez donc toujours aborder une erreur mystérieuse du compilateur en essayant le code sur Clang. Clang peut également compiler du C ++ en C, je crois.
Kerrek SB
3
@KerrekSB: quel élément de "support de bibliothèque standard" manque à clang?
Stephen Canon
2
@StephenCanon: La dernière fois que je l'ai essayé, j'ai dû utiliser libstdc ++ (qui ne fait pas partie de Clang pour autant que je sache). Et juste l'autre jour, nous avons eu ce problème . Quoi qu'il en soit, je ne suis pas à la fine pointe, donc mon point de vue est peut-être entièrement obsolète.
Kerrek SB
4
@KerrekSB: Concernant votre lien, Clang ne fonctionne pas sous Windows pur. Cela fonctionne cependant dans MinGW. En ce qui concerne la bibliothèque standard, il n'y a pas de véritable partie bibliothèque standard de Clang pour le moment. Clang est fourni avec libc ++ sur OSX, cependant libc ++ n'est pas entièrement porté dans d'autres environnements, donc sur ceux-ci, Clang a besoin d'une autre implémentation de bibliothèque standard pour être installé. Sous Linux, libstdc ++ fonctionne.
Matthieu M.
1
@KerrekSB: C ++ 98 est pris en charge à 100%. C ++ 11 est principalement pris en charge (la dernière fois que j'ai vérifié, <atomic>n'est pas pris en charge, peut-être que d'autres petites choses manquent ... Je ne peux pas l'utiliser, donc je ne suis pas tout à fait au courant).
James McNellis

Réponses:

122

ÉDITER:

Les gars de gcc ont vraiment amélioré l'expérience de diagnostic en gcc (ah compétition). Ils ont créé une page wiki pour le présenter ici . gcc 4.8 a maintenant également de bons diagnostics (gcc 4.9x a ajouté la prise en charge des couleurs). Clang est toujours en tête, mais l'écart se resserre.


Original:

Pour les étudiants, je recommanderais sans réserve Clang.

Les performances en termes de code généré entre gcc et Clang ne sont plus claires (même si je pense que gcc 4.7 a toujours la tête, je n'ai pas encore vu de benchmarks concluants), mais pour les étudiants, l'apprendre n'a pas vraiment d'importance de toute façon.

D'un autre côté, les diagnostics extrêmement clairs de Clang sont certainement plus faciles à interpréter pour les débutants.

Considérez ce simple extrait de code:

#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";
}

Vous remarquerez tout de suite que le point-virgule est manquant après la définition de la Studentclasse, non :)?

Eh bien, gcc le remarque aussi , d'une certaine manière:

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

Et Clang ne joue pas exactement ici non plus, mais quand même:

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

Je choisis délibérément un exemple qui déclenche un message d'erreur peu clair (provenant d'une ambiguïté dans la grammaire) plutôt que les exemples typiques «Oh mon dieu Clang lis mon esprit». Pourtant, nous remarquons que Clang évite le flot d'erreurs. Pas besoin d'effrayer les étudiants.

Matthieu M.
la source
2
Euh ... la dernière fois que j'ai vérifié, j'ai lu un article qui publiait divers benchmarks où le bruit a fait exploser gcc hors de l'eau dans tous les tests. Source: clang.llvm.org/features.html#performance
31
@AscensionSystems: attention, ces tests montrent les performances du binaire Clang lui-même (et c'était il y a quelque temps), pas les performances du binaire que vous compiliez.
Matthieu M.
C'est un bon point que je serais intéressé de voir une comparaison debout entre les exécutables compilés. J'ai l'impression que clang fait un bien meilleur travail en optimisation, mais je n'ai pas vu de benchmarks. Je vérifierai.
4
@AscensionSystems: voici le dernier banc que je connaisse pour comparer gcc 4.6 à llvm 3.0 qui montre un net avantage de gcc en moyenne. Le banc DragonEgg peut également être intéressant , DragonEgg est un plugin qui permet d'utiliser le front-end gcc (et éventuellement l'optimiseur) puis le backend LLVM pour générer le code.
Matthieu M.
1
La dernière fois que j'ai vérifié, les benchmarks phoronix n'étaient pas dignes de confiance: les indicateurs du compilateur n'étaient pas correctement documentés, mais les résultats suggéraient que les choses n'étaient pas correctement définies.
Eamon Nerbonne
35

À l'heure actuelle, GCC offre une prise en charge bien meilleure et plus complète des fonctionnalités C ++ 11 que Clang. De plus, le générateur de code pour GCC effectue une meilleure optimisation que celui de Clang (d'après mon expérience, je n'ai vu aucun test exhaustif).

D'un autre côté, Clang compile souvent le code plus rapidement que GCC, et produit de meilleurs messages d'erreur lorsqu'il y a quelque chose qui ne va pas avec votre code.

Le choix de celui à utiliser dépend vraiment de ce qui est important pour vous. J'apprécie plus le support C ++ 11 et la qualité de la génération de code que la commodité de la compilation. Pour cette raison, j'utilise GCC. Pour vous, les compromis pourraient être différents.

Mankarse
la source
3
Voici le dernier article de Phoronix comparant GCC 4.6 vs Clang 3.0 ainsi qu'un article précédent spécifique à la plateforme bulldozer. En fonction des benchmarks, le gagnant est l'un ou l'autre (dans l'article précédent, gcc 4.7 apparaît également), donc je trouve personnellement que je ne sais pas qui fonctionne le mieux.
Matthieu M.
Pourquoi ne pas utiliser les deux? Clang pour le développement et GCC pour la production.
segfault
5
@segfault: C'est ce que je fais actuellement. Cette réponse est assez ancienne et n'est plus entièrement vraie. Clang et GCC se sont considérablement améliorés depuis que je l'ai écrit (en particulier, Clang correspond maintenant au support global de GCC C ++ 11, et GCC a amélioré ses messages d'erreur et sa vitesse de compilation). Maintenant, je suggérerais d'utiliser les deux, avec une légère préférence pour Clang car le code source de Clang est beaucoup plus facile à comprendre que la source GCC.
Mankarse
23

J'utilise les deux car ils donnent parfois des messages d'erreur différents et utiles.

Le projet Python a pu trouver et corriger un certain nombre de petits bugs lorsque l'un des principaux développeurs a essayé de compiler pour la première fois avec clang.

Raymond Hettinger
la source
1
Que pensez-vous de l'utilisation de clang pour les versions de débogage mais de gcc pour les versions optimisées?
Olical
5
Il est raisonnable de développer avec Clang et de publier avec GCC, mais assurez-vous que votre version de GCC réussit votre suite de tests (avec et sans NDEBUG).
Raymond Hettinger
2
Merci pour la réponse. Je l'ai essayé pendant un moment et cela fonctionne très bien. Je reçois également différents ensembles d'avertissements, ce qui est génial.
Olical
11

Je l' utilise aussi bien Clang et GCC, je trouve Clang a quelques avertissements utiles, mais pour mes propres repères ray-tracing - sa constante 5-15% plus lent que GCC (prendre ce avec un grain de sel bien sûr, mais a tenté d'utiliser des drapeaux d'optimisation similaires pour les deux).

Donc pour l'instant j'utilise l'analyse statique de Clang et ses avertissements avec des macros complexes: (bien que maintenant les avertissements de GCC soient à peu près aussi bons - gcc4.8 - 4.9).

Quelques considérations:

  • Clang n'a pas de support OpenMP, cela n'a d'importance que si vous en profitez, mais puisque je le fais, c'est une limitation pour moi. (*****)
  • La compilation croisée peut ne pas être aussi bien supportée (FreeBSD 10 par exemple utilise toujours GCC4.x pour ARM), gcc-mingw par exemple est disponible sur Linux ... (YMMV).
  • Certains IDE ne prennent pas encore en charge l'analyse de la sortie de Clangs ( QtCreator par exemple *****). EDIT: QtCreator prend désormais en charge la sortie de Clang
  • Certains aspects de GCC sont mieux documentés et comme GCC existe depuis plus longtemps et est largement utilisé, vous trouverez peut-être plus facile d'obtenir de l'aide avec les avertissements / messages d'erreur.

***** - ces domaines sont en développement actif et pourraient bientôt être soutenus

ideasman42
la source
J'utilise également OpenMP mais je pense passer à TBB qui, je suppose, fonctionnerait avec Clang.
1
TBB peut être une alternative viable pour OpenMP dans certains cas (mais uniquement pour C ++ pour autant que je sache), pour C ce n'est pas pris en charge - également pour les grands projets, le passage d'OpenMP à autre chose pourrait ne pas valoir la peine, surtout si Clang finira par prend en charge OpenMP de toute façon.
ideasman42
7

Pour les programmes de niveau étudiant, Clang a l'avantage d'être, par défaut, plus strict. la norme C. Par exemple, la version K&R suivante de Hello World est acceptée sans avertissement par GCC, mais rejetée par Clang avec quelques messages d'erreur assez descriptifs:

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

Avec GCC, vous devez le donner -Werrorpour qu'il fasse vraiment remarquer que ce n'est pas un programme C89 valide. En outre, vous devez toujours utiliser c99ou gcc -std=c99obtenir le langage C99.

Fred Foo
la source
8
gccdevrait généralement être invoqué avec au moins -Wall, ce qui avertit pour ce programme. clangproduit de bons avertissements / erreurs, cependant.
caf
2
@caf: c'est exactement ce que j'essaie de faire, avec GCC, vous devez lui passer des options. Hors de la boîte, il peut être trop tolérant à des fins d'enseignement.
Fred Foo
C'est peut-être vrai, mais c'est un point assez mineur. Ce qui est plus important, c'est la qualité des messages d'erreur. GCC 4.6 est plutôt bon, même si je comprends que clang y fait de la vraie magie.
Kerrek SB
2
@dreamlax: Vrai; il y a aussi gnu99, et gnu++98et gnu++0x. Je pense que ce sont de véritables extensions , c'est-à-dire qu'elles compileront sans accroc du code conforme aux normes ISO. Voici les détails: pour C , pour C ++ .
Kerrek SB
1
Ce programme ne devrait pas produire d'erreurs ou d'avertissements. Il est conforme à la norme.
Miles Rout
3

Je pense que clang pourrait être une alternative.

GCC et clang ont des différences sur des expressions telles que a+++++a, et j'ai de nombreuses réponses différentes avec mes pairs qui utilisent clang sur Mac pendant que j'utilise gcc.

GCC est devenu la norme, et clang pourrait être une alternative. Parce que GCC est très stable et que le bruit est encore en développement.

songziming
la source
5
Clang se prépare rapidement à remplacer complètement GCC dans le monde Linux, et l'a largement fait dans le monde BSD. Il a remplacé GCC sur Mac il y a des années. Clang est une bonne chose. Je pense que GCC pourrait devenir une alternative, personnellement, et j'en serais ravi.
coder543
5
L'expression a +++++ a n'est pas définie, alors attendez-vous à obtenir une réponse différente sur chaque compilateur, ou même sur différentes versions du même compilateur. Vous pouvez même obtenir des résultats différents pour cette expression sur le même compilateur lors de la compilation à des moments différents. C'est ce que signifie «indéfini».
Lelanthran
1
a+++++adevrait échouer, car il est analysé comme a ++ ++ + aune erreur de syntaxe.
Miles Rout
@Lelanthran ce n'est pas ce que signifie indéfini. Il a un comportement indéfini, de sorte que le compilateur peut échouer à compiler cela, ou il peut lancer au moment de l'exécution ou verrouiller le processeur afin que vous deviez effectuer une réinitialisation matérielle ou quelque chose d'encore plus sinistre.
Antti Haapala