Clang против GCC для моего проекта по разработке Linux

175

Я учусь в колледже, и для проекта, в котором мы используем C. Мы изучили GCC и Clang, и Clang выглядит гораздо более удобным для пользователя, чем GCC. В результате мне интересно, каковы преимущества или недостатки использования clang, в отличие от GCC, для разработки на C и C ++ в Linux?

В моем случае это будет использоваться для программ уровня студента, а не производства.

Если я использую Clang, должен ли я отлаживать с помощью GDB и использовать GNU Make, или использовать другой отладчик и утилиту make?

haziz
источник
7
Насколько я могу судить, Clang все еще далек от "зрелости", особенно в отношении поддержки стандартной библиотеки. Тем не менее, он имеет фантастические сообщения об ошибках, поэтому вы всегда можете подойти к загадочной ошибке компилятора, попробовав код на Clang. Я полагаю, что Clang также может компилировать C ++ в C.
Kerrek SB
3
@KerrekSB: какой элемент «поддержки стандартной библиотеки» отсутствует в clang?
Стивен Кэнон
2
@StephenCanon: в прошлый раз, когда я попробовал это, мне пришлось использовать libstdc ++ (насколько я понимаю, это не является частью Clang). И только на днях у нас была эта проблема . Во всяком случае, я не слежу за передовой, так что мой взгляд может быть полностью устаревшим.
Kerrek SB
4
@KerrekSB: Что касается вашей ссылки, Clang не работает на чистой Windows. Это работает в MinGW, хотя. Что касается стандартной библиотеки, то в настоящий момент нет стандартной библиотечной части Clang. Clang поставляется с libc ++ для OSX, однако libc ++ не полностью перенесен в другие среды, поэтому для этих Clang требуется установить другую реализацию стандартной библиотеки. В Linux работает libstdc ++.
Матье М.
1
@KerrekSB: C ++ 98 поддерживается на 100%. C ++ 11 в основном поддерживается (последнее, что я проверял, <atomic>не поддерживается, возможно, отсутствуют некоторые другие мелочи ... Я не могу его использовать, поэтому я не совсем в курсе этого).
Джеймс МакНеллис

Ответы:

122

РЕДАКТИРОВАТЬ:

Ребята из gcc действительно улучшили опыт диагностики в gcc (ну соревнования). Они создали страницу вики, чтобы продемонстрировать это здесь . У gcc 4.8 теперь неплохая диагностика (в gcc 4.9x добавлена ​​поддержка цвета). Clang по-прежнему лидирует, но разрыв сокращается.


Оригинал:

Для студентов я безоговорочно рекомендую Clang.

Производительность с точки зрения сгенерированного кода между gcc и Clang теперь неясна (хотя я думаю, что gcc 4.7 все еще лидирует, я еще не видел убедительных тестов), но для студентов, изучающих его, в любом случае это не имеет значения.

С другой стороны, предельно ясная диагностика Кланга, безусловно, легче интерпретировать новичкам.

Рассмотрим этот простой фрагмент:

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

Вы сразу заметите, что точка с запятой отсутствует после определения Studentкласса, верно :)?

Что ж, gcc тоже это замечает по моде:

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

И Кленг тоже не играет здесь главную роль, но все же:

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

Я целенаправленно выбираю пример, который вызывает неясное сообщение об ошибке (возникающее из-за двусмысленности в грамматике), а не типичные примеры «Боже мой, Кланг, читай мои мысли». Тем не менее, мы замечаем, что Clang избегает потока ошибок. Не нужно пугать учеников.

Матье М.
источник
2
Гм ... в прошлый раз, когда я проверил, я прочитал статью, в которой публиковались различные тесты, в которых лязг в большинстве случаев вырывал gcc из воды. Источник: clang.llvm.org/features.html#performance
31
@AscensionSystems: будьте осторожны, эти тесты показывают производительность самого двоичного файла Clang (а это было некоторое время назад), а не производительность двоичного файла, который вы компилировали.
Матье М.
Это хороший момент, мне было бы интересно увидеть сравнение между скомпилированными исполняемыми файлами. У меня сложилось впечатление, что clang гораздо лучше справляется с оптимизацией, но на самом деле я не видел никаких тестов. Я проверю это.
4
@AscensionSystems: вот последняя версия, которую я знаю, сравнивая gcc 4.6 с llvm 3.0, который показывает чистое преимущество gcc в среднем. Также интересным может быть стенд DragonEgg , DragonEgg - плагин, который позволяет использовать внешний интерфейс gcc (и, возможно, оптимизатор), а затем внутренний интерфейс LLVM для генерации кода.
Матье М.
1
В прошлый раз, когда я проверял, тесты phoronix были очень ненадежными: флаги компилятора не были должным образом задокументированы, но результаты показали, что вещи не были установлены правильно.
Имон Нербонн
35

На данный момент GCC имеет гораздо лучшую и более полную поддержку функций C ++ 11, чем Clang. Кроме того, генератор кода для GCC выполняет лучшую оптимизацию, чем в Clang (по моему опыту, я не видел исчерпывающих тестов).

С другой стороны, Clang часто компилирует код быстрее, чем GCC, и выдает лучшие сообщения об ошибках, когда с вашим кодом что-то не так.

Выбор того, какой из них использовать, действительно зависит от того, что для вас важно. Я ценю поддержку C ++ 11 и качество генерации кода больше, чем удобство компиляции. Из-за этого я использую GCC. Для вас компромиссы могут быть разными.

Mankarse
источник
3
Вот последняя статья о Phoronix, сравнивающая GCC 4.6 и Clang 3.0, а также предыдущая статья, касающаяся платформы бульдозера. В зависимости от тестов, победителем становится один или другой (в предыдущей статье также появляется gcc 4.7), поэтому лично мне неясно, какие из них лучше.
Матье М.
Почему бы не использовать оба? Clang для разработки и GCC для производства.
Segfault
5
@segfault: это то, чем я сейчас занимаюсь. Этот ответ довольно старый, и он больше не является полностью верным. И Clang, и GCC значительно улучшились с момента его написания (в частности, Clang теперь соответствует общей поддержке C ++ 11 в GCC, а GCC улучшила свои сообщения об ошибках и скорость компиляции). Теперь я бы предложил использовать оба, с небольшим предпочтением Clang, потому что исходный код Clang намного легче понять, чем исходный код GCC.
Mankarse
23

Я использую оба, потому что иногда они дают разные, полезные сообщения об ошибках.

Проект Python смог найти и исправить несколько небольших ошибок, когда один из разработчиков ядра впервые попытался скомпилировать с помощью clang.

Раймонд Хеттингер
источник
1
Что вы думаете об использовании clang для отладочных сборок, но gcc для оптимизированных выпусков?
Olical
5
Разумно разрабатывать с Clang и выпускать с GCC, но убедитесь, что ваш выпуск GCC прошел тестовый набор (как с NDEBUG, так и без него).
Рэймонд Хеттингер
2
Спасибо за ответ. Я попробовал это немного, и это работает очень хорошо. Я тоже получаю разные наборы предупреждений, и это здорово.
Olical
11

Я использую и Clang, и GCC, и обнаружил, что у Clang есть несколько полезных предупреждений, но для моих собственных тестов трассировки лучей - он на 5-15% медленнее, чем GCC (конечно, с долей соли, но пытался использовать похожие флаги оптимизации для обоих).

Поэтому сейчас я использую статический анализ Clang и его предупреждения со сложными макросами: (хотя теперь предупреждения GCC в значительной степени хороши - gcc4.8 - 4.9).

Некоторые соображения:

  • Clang не поддерживает OpenMP, имеет значение только в том случае, если вы этим пользуетесь, но, поскольку я это делаю, для меня это ограничение. (*****)
  • Кросс-компиляция может поддерживаться не так хорошо (например, FreeBSD 10 по-прежнему использует GCC4.x для ARM), например, gcc-mingw доступен в Linux ... (YMMV).
  • Некоторые IDE еще не поддерживают синтаксический анализ вывода Clangs ( например, QtCreator *****). РЕДАКТИРОВАТЬ: QtCreator теперь поддерживает вывод Clang
  • Некоторые аспекты GCC лучше документированы, и, поскольку GCC существует дольше и широко используется, вам может оказаться проще получить помощь с предупреждениями / сообщениями об ошибках.

***** - эти направления активно развиваются и в ближайшее время могут быть поддержаны

ideasman42
источник
Я также использую OpenMP, но я думаю о переходе на TBB, который, я думаю, будет работать с Clang.
1
TBB может быть жизнеспособной альтернативой для OpenMP в некоторых случаях (но, насколько я могу судить, только для C ++, для C он не поддерживается - также для крупных проектов, переход с OpenMP на что-то еще может не стоить, особенно если Clang в конечном итоге Поддержка OpenMP в любом случае.
ideasman42
7

Для программ уровня студентов Clang имеет то преимущество, что по умолчанию он более строгий. стандарт С Например, следующая версия Hello & World от K & R принята без предупреждения GCC, но отклонена Clang с некоторыми довольно описательными сообщениями об ошибках:

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

С GCC вы должны дать ему -Werrorпонять, что он не является действительной программой C89. Кроме того, вам все еще нужно использовать c99или gcc -std=c99получить язык C99.

Фред Фу
источник
8
gccкак правило, должен вызываться, по крайней мере -Wall, который предупреждает для этой программы. clangдействительно производит хорошие предупреждения / ошибки, все же.
кафе
2
@caf: это именно то, что я пытаюсь сделать, с GCC вы должны передать его параметры. Из коробки это может быть слишком терпимым в учебных целях.
Фред Фу
Это может быть правдой, но это довольно незначительный момент. Что более важно, так это качество сообщений об ошибках. GCC 4.6 довольно хорош, хотя я понимаю, что clang действительно творит чудеса.
Kerrek SB
2
@dreamlax: правда; есть также gnu99, и gnu++98и gnu++0x. Я думаю, что это подлинные расширения , то есть они будут компилировать соответствующий код стандарта ISO без проблем. Вот подробности: для C , для C ++ .
Керрек С.Б.
1
Эта программа не должна выдавать ошибки или предупреждения. Это соответствует стандарту.
Майлз Рут
3

Я думаю, что лязг может быть альтернативой.

GCC и clang имеют некоторые различия в выражениях, например a+++++a, и у меня много разных ответов с моим коллегой, который использует clang на Mac, а я использую gcc.

GCC стал стандартом, и Clang может быть альтернативой. Потому что GCC очень стабилен, а лязг все еще развивается.

songziming
источник
5
Clang быстро готовится полностью заменить GCC в мире Linux, и в основном сделал это в мире BSD. Он заменил GCC на Mac лет назад. Clang это хороший материал. Я думаю, что GCC мог бы стать альтернативой лично, и я был бы рад этому.
coder543
5
Выражение a +++++ a не определено, поэтому ожидайте получить разные ответы для каждого компилятора или даже для разных версий одного и того же компилятора. Вы могли бы даже получить разные результаты для этого выражения на одном и том же компиляторе, если компилировали в разное время. Вот что значит «неопределенный».
Lelanthran
1
a+++++aдолжен произойти сбой, так как он анализируется как a ++ ++ + aсинтаксическая ошибка.
Майлз Рут
@Lelanthran это не то, что означает неопределенное. Он имеет неопределенное поведение, поэтому компилятор может не скомпилировать его, или он может выдать во время выполнения или заблокировать процессор, так что вам нужно сделать hard reset или что-то еще более зловещее.
Антти Хаапала