Clang vs GCC cho dự án Phát triển Linux của tôi


175

Tôi đang học đại học và trong một dự án chúng tôi đang sử dụng C. Chúng tôi đã khám phá GCC và Clang, và Clang dường như thân thiện với người dùng hơn nhiều so với GCC. Kết quả là, tôi tự hỏi những lợi thế hoặc bất lợi của việc sử dụng clang, trái ngược với GCC, để phát triển trong C và C ++ trên Linux là gì?

Trong trường hợp của tôi, nó sẽ được sử dụng cho các chương trình cấp độ sinh viên, không phải sản xuất.

Nếu tôi sử dụng Clang, tôi có nên gỡ lỗi với GDB và sử dụng GNU Make hay sử dụng trình gỡ lỗi khác và tạo tiện ích không?


7
Theo như tôi có thể nói, Clang vẫn còn lâu mới "trưởng thành", đặc biệt là liên quan đến hỗ trợ thư viện tiêu chuẩn. Tuy nhiên, nó có các thông báo lỗi tuyệt vời, vì vậy bạn luôn có thể tiếp cận một lỗi trình biên dịch bí ẩn bằng cách thử mã trên Clang. Clang cũng có thể biên dịch C ++ thành C, tôi tin thế.
Kerrek SB

3
@KerrekSB: yếu tố nào của "hỗ trợ thư viện chuẩn" bị thiếu trong tiếng kêu?
Stephen Canon

2
@StephenCanon: Lần trước tôi đã thử nó, tôi đã phải sử dụng libstdc ++ (không phải là một phần của Clang theo như tôi hiểu). Và chỉ một ngày khác chúng tôi đã có vấn đề này . Dù sao, tôi không theo sát cạnh chảy máu, vì vậy quan điểm của tôi có thể hoàn toàn lỗi thời.
Kerrek SB

4
@KerrekSB: Về liên kết của bạn, Clang không hoạt động trên Windows thuần túy. Nó hoạt động trong MinGW mặc dù. Về thư viện tiêu chuẩn, hiện tại không có phần thư viện tiêu chuẩn thực sự của Clang. Clang được đóng gói với libc ++ trên OSX, tuy nhiên libc ++ không được chuyển hoàn toàn trong các môi trường khác, vì vậy trên Clang cần cài đặt Thư viện chuẩn khác để cài đặt. Trên Linux, libstdc ++ hoạt động.
Matthieu M.

1
@KerrekSB: C ++ 98 được hỗ trợ 100%. C ++ 11 hầu hết được hỗ trợ (tôi đã kiểm tra lần cuối, <atomic>không được hỗ trợ, có lẽ một số thứ nhỏ khác bị thiếu ... Tôi không thể sử dụng nó, vì vậy tôi không hoàn toàn theo kịp tốc độ của nó).
James McNellis

Câu trả lời:


122

BIÊN TẬP:

Các anh chàng gcc thực sự cải thiện trải nghiệm chẩn đoán trong gcc (cạnh tranh ah). Họ đã tạo một trang wiki để giới thiệu nó ở đây . gcc 4.8 bây giờ cũng có chẩn đoán khá tốt (gcc 4.9x thêm hỗ trợ màu). Clang vẫn đang dẫn đầu, nhưng khoảng cách đang đóng lại.


Nguyên:

Đối với sinh viên, tôi muốn giới thiệu Clang vô điều kiện.

Hiệu suất về mã được tạo giữa gcc và Clang hiện chưa rõ ràng (mặc dù tôi nghĩ rằng gcc 4.7 vẫn dẫn đầu, tôi chưa thấy điểm chuẩn kết luận nào), nhưng dù sao thì học sinh cũng không thực sự quan trọng.

Mặt khác, chẩn đoán cực kỳ rõ ràng của Clang chắc chắn dễ dàng hơn cho người mới bắt đầu để giải thích.

Hãy xem xét đoạn trích đơn giản này:

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

Bạn sẽ nhận thấy ngay rằng dấu chấm phẩy bị thiếu sau định nghĩa của Studentlớp, phải không :)?

Vâng, gcc cũng nhận thấy điều đó , sau một thời trang:

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

Và Clang cũng không chính xác đóng vai chính ở đây, nhưng vẫn:

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

Tôi cố tình chọn một ví dụ kích hoạt thông báo lỗi không rõ ràng (xuất phát từ sự mơ hồ trong ngữ pháp) chứ không phải là ví dụ điển hình "Ôi trời ơi Clang đọc suy nghĩ của tôi". Tuy nhiên, chúng tôi nhận thấy rằng Clang tránh được lũ lụt. Không cần phải sợ học sinh đi.


2
Ừm ... lần trước tôi đã kiểm tra tôi đã đọc một bài báo công bố các tiêu chuẩn khác nhau trong đó tiếng kêu khá nhiều gcc ra khỏi nước trong bao giờ thử nghiệm. Nguồn: clang.llvm.org/features.html#performance

31
@AscensionSystems: hãy cẩn thận, những thử nghiệm đó cho thấy hiệu suất của chính nhị phân Clang (và đó là một thời gian trước đây), chứ không phải hiệu suất của nhị phân bạn đang biên dịch.
Matthieu M.

Đó là một điểm tốt tôi muốn thấy sự so sánh đứng lên giữa các tệp thực thi được biên dịch. Tôi có ấn tượng rằng clang thực hiện công việc tối ưu hóa tốt hơn nhiều nhưng tôi thực sự không thấy bất kỳ điểm chuẩn nào. Tôi sẽ kiểm tra.

4
@AscensionSystems: đây là băng ghế mới nhất tôi biết so sánh gcc 4.6 với llvm 3.0 , cho thấy lợi thế ròng của gcc trung bình. Cũng thú vị có thể là băng ghế dự bị DragonEgg , DragonEgg là một plugin cho phép sử dụng gcc front-end (và có thể là trình tối ưu hóa) và sau đó là phụ trợ LLVM để tạo mã.
Matthieu M.

1
Lần trước tôi đã kiểm tra, điểm chuẩn phoronix rất không đáng tin: cờ trình biên dịch không được ghi lại đúng cách, nhưng kết quả cho thấy mọi thứ không được đặt đúng.
Eamon Nerbonne

35

Tính đến thời điểm hiện tại, GCC có hỗ trợ tốt hơn và đầy đủ hơn cho các tính năng của C ++ 11 so với Clang. Ngoài ra, trình tạo mã cho GCC thực hiện tối ưu hóa tốt hơn so với Clang (theo kinh nghiệm của tôi, tôi chưa thấy bất kỳ thử nghiệm toàn diện nào).

Mặt khác, Clang thường biên dịch mã nhanh hơn GCC và tạo ra các thông báo lỗi tốt hơn khi có lỗi với mã của bạn.

Sự lựa chọn sử dụng cái nào thực sự phụ thuộc vào những thứ quan trọng đối với bạn. Tôi đánh giá cao sự hỗ trợ của C ++ 11 và chất lượng tạo mã hơn là tôi đánh giá sự tiện lợi của việc biên dịch. Vì điều này, tôi sử dụng GCC. Đối với bạn, sự đánh đổi có thể khác.


3
Dưới đây là bài viết mới nhất của Phoronix so sánh GCC 4.6 vs Clang 3.0 cũng như một bài viết trước đó dành riêng cho nền tảng máy ủi. Tùy thuộc vào điểm chuẩn, người chiến thắng là người này hoặc người kia (trên bài viết trước, gcc 4.7 cũng xuất hiện), vì vậy cá nhân tôi thấy không rõ điều gì đang hoạt động tốt hơn.
Matthieu M.

Tại sao không sử dụng cả hai? Clang cho phát triển, và GCC cho sản xuất.
segfault

5
@segfault: Đó là những gì tôi đang làm hiện tại. Câu trả lời này khá cũ, và nó không còn hoàn toàn đúng nữa. Cả Clang và GCC đều đã được cải thiện đáng kể kể từ khi tôi viết nó (đặc biệt, Clang hiện phù hợp với hỗ trợ C ++ 11 chung của GCC và GCC đã cải thiện thông báo lỗi và tốc độ biên dịch của nó). Bây giờ tôi sẽ đề nghị sử dụng cả hai, với một ưu tiên nhỏ đối với Clang vì mã nguồn Clang dễ hiểu hơn nhiều so với nguồn GCC.
Mankude

23

Tôi sử dụng cả hai vì đôi khi chúng đưa ra các thông báo lỗi khác nhau, hữu ích.

Dự án Python đã có thể tìm và sửa một số lỗi nhỏ khi một trong những nhà phát triển cốt lõi lần đầu tiên thử biên dịch với tiếng kêu.


1
Suy nghĩ của bạn về việc sử dụng clang cho các bản dựng gỡ lỗi nhưng gcc cho các bản phát hành được tối ưu hóa là gì?
Olical

5
Việc phát triển với Clang và phát hành với GCC là hợp lý, nhưng hãy chắc chắn rằng bản phát hành GCC của bạn vượt qua bộ thử nghiệm của bạn (cả có và không có NDEBUG).
Raymond Hettinger

2
Cảm ơn vì sự trả lời. Tôi đã thử nó một chút và nó hoạt động rất tốt. Tôi cũng nhận được nhiều cảnh báo khác nhau, điều này thật tuyệt.
Olical

11

Tôi sử dụng cả Clang và GCC, tôi thấy Clang có một số cảnh báo hữu ích, nhưng đối với các điểm chuẩn dò tia của riêng tôi - GCC chậm hơn 5-15% (dĩ nhiên là dùng hạt muối, nhưng đã cố gắng sử dụng các cờ tối ưu hóa tương tự cho cả hai).

Vì vậy, hiện tại tôi sử dụng phân tích tĩnh Clang và các cảnh báo của nó với các macro phức tạp: (mặc dù hiện tại các cảnh báo của GCC khá tốt - gcc4.8 - 4.9).

Một số cân nhắc:

  • Clang không có hỗ trợ OpenMP, chỉ có vấn đề nếu bạn tận dụng điều đó nhưng vì tôi làm vậy, đó là một hạn chế đối với tôi. (*****)
  • Biên dịch chéo có thể không được hỗ trợ tốt (ví dụ FreeBSD 10 vẫn sử dụng GCC4.x cho ARM), ví dụ gcc-mingw có sẵn trên Linux ... (YMMV).
  • Một số IDE chưa hỗ trợ phân tích đầu ra Clangs ( ví dụ QtCreator *****). EDIT: QtCreator hiện hỗ trợ đầu ra của Clang
  • Một số khía cạnh của GCC được ghi lại tốt hơn và vì GCC đã tồn tại lâu hơn và được sử dụng rộng rãi, bạn có thể thấy dễ dàng hơn khi nhận trợ giúp với các thông báo lỗi / thông báo lỗi.

***** - những lĩnh vực này đang được phát triển tích cực và có thể sớm được hỗ trợ


Tôi cũng sử dụng OpenMP nhưng tôi nghĩ đến việc chuyển sang TBB mà tôi đoán sẽ hoạt động với Clang.

1
TBB có thể là sự thay thế khả thi cho OpenMP trong một số trường hợp (nhưng chỉ với C ++ theo như tôi có thể nói), đối với C nó không được hỗ trợ - đối với các dự án lớn, việc chuyển từ OpenMP sang một thứ khác có thể không đáng giá đặc biệt là nếu Clang cuối cùng sẽ hỗ trợ OpenMP nào.
ideaman42

7

Đối với các chương trình cấp độ sinh viên, Clang có lợi ích là, theo mặc định, wrt chặt chẽ hơn. tiêu chuẩn C. Ví dụ: phiên bản K & R sau đây của Hello World được chấp nhận mà không có cảnh báo của GCC, nhưng bị Clang từ chối với một số thông báo lỗi mô tả khá hay:

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

Với GCC, bạn phải cung cấp cho nó -Werrorđể thực sự đưa ra quan điểm về việc đây không phải là một chương trình C89 hợp lệ. Ngoài ra, bạn vẫn cần sử dụng c99hoặc gcc -std=c99để có được ngôn ngữ C99.


8
gccnói chung nên được gọi với ít nhất -Wall, điều này cảnh báo cho chương trình này. clangkhông tạo ra cảnh báo / lỗi tốt, mặc dù.
phê

2
@caf: đó chính xác là điểm tôi đang cố gắng thực hiện, với GCC, bạn phải vượt qua các tùy chọn. Ra khỏi hộp, nó có thể quá khoan dung cho mục đích giảng dạy.
Fred Foo

Điều đó có thể đúng, nhưng đó là một điểm khá nhỏ. Điều quan trọng hơn là chất lượng của các thông báo lỗi. GCC 4.6 đã hoạt động khá tốt, mặc dù tôi hiểu rằng clang đang thực hiện một số phép thuật thực sự ở đó.
Kerrek SB

2
@dreamlax: Đúng; cũng có gnu99, gnu++98gnu++0x. Tuy nhiên, tôi nghĩ đó là những tiện ích mở rộng chính hãng , tức là chúng sẽ biên dịch mã theo tiêu chuẩn ISO mà không gặp trở ngại nào. Dưới đây là chi tiết: cho C , cho C ++ .
Kerrek SB

1
Chương trình này không nên tạo ra lỗi hoặc cảnh báo. Nó phù hợp với tiêu chuẩn.
Miles Rout

3

Tôi nghĩ clang có thể là một sự thay thế.

GCC và clang có một số khác biệt về biểu thức như a+++++a, và tôi đã có nhiều câu trả lời khác nhau với bạn bè của tôi, những người sử dụng clang trên Mac trong khi tôi sử dụng gcc.

GCC đã trở thành tiêu chuẩn và tiếng kêu có thể là một sự thay thế. Bởi vì GCC rất ổn định và tiếng kêu vẫn đang được phát triển.


5
Clang đang nhanh chóng chuẩn bị để thay thế hoàn toàn GCC trong thế giới Linux và phần lớn đã làm như vậy trong thế giới BSD. Nó đã thay thế GCC trên Mac nhiều năm trước. Clang là thứ tốt. Tôi nghĩ rằng GCC có thể trở thành một sự thay thế, cá nhân, và tôi sẽ vui vì điều đó.
coder543

5
Biểu thức a +++++ a không được xác định vì vậy mong đợi nhận được câu trả lời khác nhau trên mỗi trình biên dịch hoặc thậm chí trên các phiên bản khác nhau của cùng một trình biên dịch. Bạn thậm chí có thể nhận được các kết quả khác nhau cho biểu thức đó trên cùng một trình biên dịch khi được biên dịch vào các thời điểm khác nhau. Đó là những gì "không xác định" có nghĩa là.
Lelanthran

1
a+++++anên thất bại, vì nó được phân tích cú pháp a ++ ++ + alà lỗi cú pháp.
Tuyến Miles

@Lelanthran đó không phải là ý nghĩa không xác định. Nó có hành vi không xác định để trình biên dịch có thể không biên dịch được, hoặc nó có thể ném vào thời gian chạy hoặc khóa CPU để bạn cần thực hiện thiết lập lại cứng hoặc một cái gì đó thậm chí còn độc ác hơn.
Antti Haapala
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.