Clang vs GCC para o meu projeto de desenvolvimento Linux

175

Estou na faculdade e, para um projeto que estamos usando C. Exploramos o GCC e o Clang, e o Clang parece ser muito mais amigável que o GCC. Como resultado, estou me perguntando quais são as vantagens ou desvantagens de usar o clang, em oposição ao GCC, para desenvolver em C e C ++ no Linux?

No meu caso, isso seria usado para programas em nível de aluno, não para produção.

Se eu usar o Clang, devo depurar com o GDB e usar o GNU Make, ou usar outro depurador e criar utilitário?

haziz
fonte
7
Até onde eu sei, Clang ainda está longe de ser "maduro", principalmente no que diz respeito ao suporte padrão da biblioteca. No entanto, ele possui mensagens de erro fantásticas, para que você possa sempre abordar um erro misterioso do compilador tentando o código no Clang. Clang também pode compilar C ++ para C, acredito.
Kerrek SB
3
@KerrekSB: que elemento do "suporte padrão à biblioteca" está faltando no clang?
Stephen Canon
2
@StephenCanon: A última vez que tentei, tive que usar o libstdc ++ (que não faz parte do Clang até onde sei). E outro dia tivemos esse problema . De qualquer forma, não estou seguindo o limite, então minha visão pode ser totalmente obsoleta.
Kerrek SB
4
@KerrekSB: Em relação ao seu link, o Clang não funciona no Windows puro. Porém, ele funciona em MinGW. Em relação à biblioteca padrão, não há nenhuma parte da biblioteca padrão real do Clang no momento. O Clang é fornecido com o libc ++ no OSX; no entanto, o libc ++ não é totalmente portado em outros ambientes; portanto, o Clang precisa de outra implementação da Biblioteca Padrão para ser instalada. No Linux, libstdc ++ funciona.
precisa
1
@KerrekSB: C ++ 98 é 100% suportado. O C ++ 11 é principalmente suportado (da última vez que verifiquei, <atomic>não é suportado, talvez algumas outras pequenas coisas estejam faltando ... Eu não posso usá-lo, por isso não estou totalmente atualizado com ele).
precisa saber é o seguinte

Respostas:

122

EDITAR:

O pessoal do gcc realmente melhorou a experiência de diagnóstico no gcc (ah concorrência). Eles criaram uma página wiki para mostrá-la aqui . O gcc 4.8 agora também possui diagnósticos muito bons (suporte a cores adicionado ao gcc 4.9x). Clang ainda está na liderança, mas a diferença está diminuindo.


Original:

Para os alunos, eu recomendaria incondicionalmente o Clang.

O desempenho em termos de código gerado entre o gcc e o Clang agora não está claro (embora eu ache que o gcc 4.7 ainda lidera, ainda não vi benchmarks conclusivos), mas para os alunos aprenderem, isso realmente não importa.

Por outro lado, os diagnósticos extremamente claros de Clang são definitivamente mais fáceis para os iniciantes interpretarem.

Considere este trecho simples:

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

Você notará imediatamente que o ponto-e-vírgula está ausente após a definição do Student classe, certo :)?

Bem, o GCC também nota , de certa forma:

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 não está exatamente estrelando aqui também, mas ainda assim:

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

Eu escolhi propositadamente um exemplo que aciona uma mensagem de erro pouco clara (proveniente de uma ambiguidade na gramática), em vez dos exemplos típicos "Oh meu Deus, Clang, leia minha mente". Ainda assim, percebemos que o Clang evita o fluxo de erros. Não há necessidade de assustar os alunos.

Matthieu M.
fonte
2
Hum ... da última vez que verifiquei, li um artigo que publicou vários benchmarks em que o chiclete quase explodiu a água em todos os testes. Fonte: clang.llvm.org/features.html#performance
31
@AscensionSystems: cuidado, esses testes mostram o desempenho do próprio binário Clang (e isso foi há um tempo atrás), não o desempenho do binário que você estava compilando.
Matthieu M.
Esse é um bom ponto. Eu estaria interessado em ver uma comparação entre os executáveis ​​compilados. Tenho a impressão de que o clang faz um trabalho muito melhor na otimização, mas na verdade não vi nenhum parâmetro de referência. Vou dar uma olhada.
4
@AscensionSystems: aqui está o último banco que eu conheço ao comparar o gcc 4.6 ao llvm 3.0, que mostra uma vantagem líquida do gcc em média. Também interessante pode ser o banco DragonEgg , o DragonEgg é um plug-in que permite usar o front-end do gcc (e possivelmente o otimizador) e, em seguida, o back-end do LLVM para gerar o código.
Matthieu M.
1
Na última vez que verifiquei, os benchmarks do phoronix eram muito confiáveis: os sinalizadores do compilador não foram documentados adequadamente, mas os resultados sugeriram que as coisas não estavam sendo definidas corretamente.
Eamon Nerbonne
35

No momento, o GCC tem um suporte muito melhor e mais completo para os recursos do C ++ 11 do que o Clang. Além disso, o gerador de código para o GCC executa uma otimização melhor do que o de Clang (na minha experiência, eu não vi nenhum teste exaustivo).

Por outro lado, o Clang geralmente compila o código mais rapidamente que o GCC e produz melhores mensagens de erro quando há algo errado com o seu código.

A escolha de qual usar realmente depende do que é importante para você. Eu valorizo ​​mais o suporte ao C ++ 11 e a qualidade de geração de código do que a conveniência da compilação. Por causa disso, eu uso o GCC. Para você, os trade-offs podem ser diferentes.

Mankarse
fonte
3
Aqui está o artigo mais recente da Phoronix comparando o GCC 4.6 vs Clang 3.0 , bem como um artigo anterior específico da plataforma de escavadeiras. Dependendo dos benchmarks, o vencedor é um ou outro (no artigo anterior, o gcc 4.7 também aparece), então, pessoalmente, não está claro qual é o melhor desempenho.
precisa
Por que não usar os dois? Clang para desenvolvimento e GCC para produção.
seg13
5
@segfault: É ​​o que estou fazendo atualmente. Essa resposta é bastante antiga e não é mais totalmente verdadeira. O Clang e o GCC melhoraram significativamente desde que eu o escrevi (em particular, o Clang agora corresponde ao suporte geral ao C ++ 11 do GCC e o GCC aprimorou suas mensagens de erro e velocidade de compilação). Agora, eu sugeriria o uso de ambos, com uma leve preferência pelo Clang, porque o código-fonte do Clang é muito mais fácil de entender do que o código-fonte do GCC.
precisa saber é o seguinte
23

Eu uso os dois porque às vezes eles dão mensagens de erro diferentes e úteis.

O projeto Python conseguiu encontrar e corrigir vários pequenos bugs quando um dos principais desenvolvedores tentou compilar com o clang.

Raymond Hettinger
fonte
1
O que você pensa sobre o uso do clang para compilações de depuração, além do gcc para versões otimizadas?
Olical
5
É razoável desenvolver com o Clang e lançar com o GCC, mas certifique-se de que sua versão do GCC seja aprovada no seu conjunto de testes (com e sem NDEBUG).
Raymond Hettinger
2
Obrigado pela resposta. Eu tenho experimentado isso um pouco e funciona muito bem. Também recebo diferentes conjuntos de avisos, o que é ótimo.
Olical
11

Eu uso o Clang e o GCC, acho que o Clang tem alguns avisos úteis, mas para meus próprios benchmarks de rastreamento de raios - é consistentemente 5-15% mais lento que o GCC (leve isso com grão de sal, é claro, mas tentei usar sinalizadores de otimização semelhantes) para ambos).

Então, por enquanto, uso a análise estática de Clang e seus avisos com macros complexas: (embora agora os avisos do GCC sejam igualmente bons - gcc4.8 - 4.9).

Algumas considerações:

  • Clang não tem suporte ao OpenMP, só importa se você tirar proveito disso, mas desde que eu faço isso, é uma limitação para mim. (*****)
  • A compilação cruzada pode não ser tão bem suportada (o FreeBSD 10, por exemplo, ainda usa o GCC4.x para ARM), o gcc-mingw, por exemplo, está disponível no Linux ... (YMMV).
  • Alguns IDE ainda não suportam a análise da saída de Clangs ( Clangs QtCreator, por exemplo, *****). EDIT: QtCreator agora suporta a saída de Clang
  • Alguns aspectos do GCC são mais bem documentados e, como o GCC existe há mais tempo e é amplamente usado, talvez seja mais fácil obter ajuda com avisos / mensagens de erro.

***** - essas áreas estão em desenvolvimento ativo e em breve poderão ser apoiadas

ideasman42
fonte
Também uso o OpenMP, mas estou pensando em mudar para o TBB, que acho que funcionaria com o Clang.
1
TBB pode ser uma alternativa viável para o OpenMP em alguns casos (mas apenas para C ++, tanto quanto eu posso dizer), pois C não é suportado - também para grandes projetos, a mudança do OpenMP para outra coisa pode não valer a pena, especialmente se Clang eventualmente suporte OpenMP de qualquer maneira.
ideasman42
7

Para programas em nível de aluno, o Clang tem o benefício de, por padrão, ser mais rígido. o padrão C. Por exemplo, a seguinte versão K&R do Hello World é aceita sem aviso prévio pelo GCC, mas rejeitada pelo Clang com algumas mensagens de erro bastante descritivas:

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

Com o GCC, você deve dar o seu consentimento -Werrorpara que ele realmente faça questão de não ser um programa C89 válido. Além disso, você ainda precisa usar c99ou gcc -std=c99obter o idioma C99.

Fred Foo
fonte
8
gccgeralmente deve ser chamado com pelo menos -Wall, o que adverte para este programa. clangproduz bons avisos / erros, no entanto.
Caf
2
@caf: que é exatamente o ponto que estou tentando destacar, com o GCC você precisa passar as opções. Fora da caixa, pode ser muito tolerante para fins de ensino.
Fred Foo
Isso pode ser verdade, mas é um ponto bem menor. O mais importante é a qualidade das mensagens de erro. O GCC 4.6 ficou muito bom, embora eu entenda que o clang está fazendo alguma mágica real lá.
precisa saber é o seguinte
2
@dreamlax: True; há também gnu99, e gnu++98e gnu++0x. Eu acho que essas são extensões genuínas , no entanto, ou seja, elas compilarão o código padrão ISO sem problemas. Aqui estão os detalhes: para C , para C ++ .
21411 Kerrek SB
1
Este programa não deve produzir erros ou avisos. Está em conformidade com o padrão.
Route de milhas
3

Eu acho que o clang poderia ser uma alternativa.

GCC e clang têm algumas diferenças em expressões como a+++++a , e eu tenho muitas respostas diferentes com meus colegas que usam clang no Mac enquanto eu uso o gcc.

O CCG se tornou o padrão e o clang pode ser uma alternativa. Porque o GCC é muito estável e o clang ainda está em desenvolvimento.

songziming
fonte
5
Clang está se preparando rapidamente para substituir completamente o GCC no mundo Linux, e o fez em grande parte no mundo BSD. Ele substituiu o GCC no Mac anos atrás. Clang é uma coisa boa. Eu acho que o GCC poderia se tornar uma alternativa, pessoalmente, e eu ficaria feliz com isso.
coder543
5
A expressão a +++++ a é indefinida, portanto, espere obter uma resposta diferente em cada compilador, ou mesmo em versões diferentes do mesmo compilador. Você pode obter resultados diferentes para essa expressão no mesmo compilador quando compilado em momentos diferentes. Isso é o que "indefinido" significa.
Lelanthran
1
a+++++adeve falhar, pois é analisado como a ++ ++ + aum erro de sintaxe.
Miles Rout
@Lelanthran, não é isso que significa indefinido. Ele tem um comportamento indefinido, de modo que o compilador pode falhar ao compilar isso, ou pode ser executado em tempo de execução ou bloquear a CPU para que você precise fazer uma reinicialização completa ou algo ainda mais sinistro.
Antti Haapala