Кланг проти GCC для мого проекту Linux Development


175

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

У моєму випадку це використовуватиметься для програм рівня студентів, а не для виробництва.

Якщо я використовую Clang, я повинен налагоджувати GDB і використовувати GNU Make, або використовувати інший налагоджувач і робити утиліту?


7
Наскільки я можу сказати, Кланг ще далеко не "зрілий", особливо що стосується стандартної бібліотечної підтримки. Тим не менш, у ньому є фантастичні повідомлення про помилки, тому ви завжди можете підійти до таємничої помилки компілятора, спробувавши код на Clang. Кланг також може компілювати C ++ до C, я вважаю.
Керрек СБ

3
@KerrekSB: який елемент "стандартної підтримки бібліотеки" відсутній у кланге?
Стівен Канон

2
@StephenCanon: Востаннє, коли я спробував це, мені довелося використовувати libstdc ++ (який, наскільки я розумію, не є частиною Clang). І лише днями у нас виникло це питання . У всякому разі, я не стежу за кровотоком, тому мій погляд може бути повністю застарілим.
Керрек СБ

4
@KerrekSB: Що стосується вашого посилання, Кланг не працює в чистому 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). Кланг все ще веде, але розрив скорочується.


Оригінал:

Студентам я б беззастережно рекомендував Кланг.

Продуктивність з точки зору генерованого коду між 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.

Я цілеспрямовано вибираю приклад, який викликає незрозуміле повідомлення про помилку (випливає з неоднозначності в граматиці), а не типові приклади "О, мій Боже, Кланг читав мені розум". І все-таки ми помічаємо, що Кланг уникає потоку помилок. Не потрібно лякати студентів.


2
Гм ... востаннє, коли я перевірив, я прочитав статтю, яка опублікувала різні орієнтири, де Кланг майже ніколи не випробовував GCC з води. Джерело: clang.llvm.org/features.html#performance

31
@AscensionSystems: будьте обережні, ці тести показують продуктивність самого бінарного Clang (і це було деякий час тому), а не продуктивність бінарного файлу, який ви збирали.
Матьє М.

Це хороший момент, я б зацікавився порівнянням порівняння між складеними виконуваними файлами. Мені здається, що Кланг робить набагато кращу роботу в оптимізації, але насправді я не бачив жодних орієнтирів. Я перевірю це.

4
@AscensionSystems: ось останній стенд, який я знаю, порівнюючи gcc 4.6 з llvm 3.0, який показує чисту перевагу gcc в середньому. Також цікавою може бути лавка DragonEgg , DragonEgg - плагін, який дозволяє використовувати передній частині gcc (і, можливо, оптимізатор), а потім і сервер LLVM для генерування коду.
Матьє М.

1
Минулого разу, коли я перевіряв, орієнтири phoronix були дуже недостовірними: прапори компілятора не були задокументовані належним чином, але результати підказували, що речі не були встановлені належним чином.
Еймон Нербонна

35

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

З іншого боку, Кланг часто компілює код швидше, ніж GCC, і видає кращі повідомлення про помилки, коли з вашим кодом щось не так.

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


3
Ось остання стаття Phoronix, яка порівнює GCC 4.6 проти Clang 3.0 , а також попередня стаття, характерна для платформи бульдозера. Залежно від еталонів, переможець стає або тим, або іншим (у попередній статті відображається також gcc 4.7), тому мені особисто незрозуміло, що краще.
Матьє М.

Чому б не використовувати обидва? Кланг для розвитку, а GCC для виробництва.
segfault

5
@segfault: Саме цим я зараз займаюся. Ця відповідь досить стара, і вже не зовсім правдива. І Clang, і GCC значно покращилися, оскільки я написав це (зокрема, зараз Clang відповідає загальній підтримці C ++ 11 для GCC, а GCC покращив повідомлення про помилки та швидкість компіляції). Тепер я б запропонував використовувати обидва, з невеликою перевагою до Кланг, тому що вихідний код Clang набагато простіше зрозуміти, ніж джерело GCC.
Манкарсе

23

Я використовую обидва, тому що іноді вони дають різні, корисні повідомлення про помилки.

Проект Python зміг знайти та виправити ряд невеликих помилок, коли один із основних розробників спробував компілювати кланг.


1
Які ваші думки щодо використання clang для налагодження версій, але gcc для оптимізованих версій?
Оликал

5
Розумно розробляти з Clang та випускати разом із GCC, але будьте впевнені, що ваш GCC-реліз пройде ваш тестовий набір (як з NDEBUG, так і без нього).
Реймонд Хеттінгер

2
Дякуємо за відповідь. Я спробував це трохи, і він працює дуже добре. Я також отримую різні набори попереджень, що чудово.
Оличний

11

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

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

Деякі міркування:

  • Кланг не має підтримки OpenMP, має значення лише якщо ви цим скористаєтеся, але оскільки я це роблю, це для мене обмеження. (*****)
  • Перехресна компіляція може бути не так добре підтримується (FreeBSD 10, наприклад, все ще використовує GCC4.x для ARM), gcc-mingw, наприклад, доступний в Linux ... (YMMV).
  • Деякі IDE ще не підтримують розбір виходу Clangs ( QtCreator, наприклад *****). EDIT: QtCreator тепер підтримує вихід Кланг
  • Деякі аспекти GCC краще задокументовані, і оскільки GCC існує довше і широко використовується, вам може бути легше отримати допомогу з попередженнями / повідомленнями про помилки.

***** - ці сфери перебувають в активному розвитку і незабаром можуть бути підтримані


Я також використовую OpenMP, але я думаю про перехід на TBB, який, напевно, буде працювати з Clang.

1
TBB може бути життєздатною альтернативою для OpenMP в деяких випадках (але, наскільки я можу сказати, лише для C ++), для C це не підтримується - також для великих проектів перехід з OpenMP на щось інше може бути не вартим, особливо якщо в кінцевому підсумку Clang підтримка OpenMP в будь-якому випадку.
ideaman42

7

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

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

З GCC ви повинні дати йому, -Werrorщоб він дійсно міг зробити висновок про те, що це не є дійсною програмою C89. Крім того, вам все одно потрібно використовувати c99або gcc -std=c99отримати мову C99.


8
gccяк правило, слід посилатися на щонайменше -Wall, що попереджає цю програму. clangвсе ж таки створює хороші попередження / помилки.
caf

2
@caf: що саме я намагаюся зробити, з GCC ви повинні передати його варіанти. Це може бути занадто толерантним до навчальних цілей.
Фред Фоо

Це може бути правдою, але це досить незначний момент. Що важливіше - це якість повідомлень про помилки. GCC 4.6 вийшов досить непоганим, хоча я розумію, що Кланг робить там справжню магію.
Керрек СБ

2
@dreamlax: Правда; є також gnu99, і gnu++98і gnu++0x. Я думаю, що це справжні розширення , тобто вони збиратимуть відповідний ISO-стандарт без кодов. Ось деталі: для C , для C ++ .
Керрек СБ

1
Ця програма не повинна створювати помилки або попередження. Він відповідає стандарту.
Майлз Рут

3

Я думаю, що Кланг може бути альтернативою.

У GCC і clang є деякі відмінності щодо виразів на зразок a+++++a, і я отримав багато різних відповідей зі своїм однолітком, який використовує clang на Mac, коли я використовую gcc.

GCC став стандартом, і кланг міг стати альтернативою. Оскільки GCC дуже стабільний і кланг все ще розвивається.


5
Кланг швидко готується повністю замінити GCC у світі Linux, і значною мірою це зробив у світі BSD. Він замінив GCC на Mac років тому. Кланг - хороший матеріал. Я думаю, що GCC може стати альтернативою особисто, і я би радий цьому.
coder543

5
Вираз a +++++ a не визначено, тому очікуйте отримати різну відповідь на кожен компілятор або навіть на різні версії одного компілятора. Ви навіть можете отримати різні результати для цього виразу на одному компіляторі, коли їх компілювали в різний час. Ось що означає "невизначений".
Лелантран

1
a+++++aповинен провалити, оскільки він розбирається, оскільки a ++ ++ + aце синтаксична помилка.
Майлз Рут

@Lelanthran - це не те, що не визначено. Він має невизначену поведінку, тому компілятор може не вдатися до компіляції цього, або він може кинути під час виконання роботи або заблокувати процесор, так що вам потрібно зробити жорсткий скидання або щось ще більш зловісне.
Антті Хаапала
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.