2011-08-11 34 views
205

Tôi có một số dự án được xây dựng bằng CMake và tôi muốn có thể dễ dàng chuyển đổi giữa sử dụng GCC hoặc Clang/LLVM để biên dịch chúng. Tôi tin rằng (hãy sửa lại cho tôi nếu tôi nhầm!) Rằng để sử dụng Clang Tôi cần phải thiết lập như sau:Chuyển đổi giữa GCC và Clang/LLVM bằng CMake

SET (CMAKE_C_COMPILER    "/usr/bin/clang") 
    SET (CMAKE_C_FLAGS    "-Wall -std=c99") 
    SET (CMAKE_C_FLAGS_DEBUG   "-g") 
    SET (CMAKE_C_FLAGS_MINSIZEREL  "-Os -DNDEBUG") 
    SET (CMAKE_C_FLAGS_RELEASE  "-O4 -DNDEBUG") 
    SET (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g") 

    SET (CMAKE_CXX_COMPILER    "/usr/bin/clang++") 
    SET (CMAKE_CXX_FLAGS    "-Wall") 
    SET (CMAKE_CXX_FLAGS_DEBUG   "-g") 
    SET (CMAKE_CXX_FLAGS_MINSIZEREL  "-Os -DNDEBUG") 
    SET (CMAKE_CXX_FLAGS_RELEASE  "-O4 -DNDEBUG") 
    SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") 

    SET (CMAKE_AR  "/usr/bin/llvm-ar") 
    SET (CMAKE_LINKER "/usr/bin/llvm-ld") 
    SET (CMAKE_NM  "/usr/bin/llvm-nm") 
    SET (CMAKE_OBJDUMP "/usr/bin/llvm-objdump") 
    SET (CMAKE_RANLIB "/usr/bin/llvm-ranlib") 

Có một cách dễ dàng chuyển đổi giữa những điều này và các biến GCC mặc định, tốt nhất là như một hệ thống thay đổi toàn diện hơn là dự án cụ thể (nghĩa là không chỉ thêm chúng vào CMakeLists.txt của dự án)?

Ngoài ra, có cần sử dụng các chương trình llvm-* thay vì mặc định của hệ thống khi biên dịch bằng cách sử dụng clang thay vì gcc không? Có gì khác biệt?

Trả lời

258

CMake vinh danh các biến môi trường CCCXX khi phát hiện C và C++ biên dịch sử dụng: cờ cụ thể

$ export CC=/usr/bin/clang 
$ export CXX=/usr/bin/clang++ 
$ cmake .. 
-- The C compiler identification is Clang 
-- The CXX compiler identification is Clang 

Trình biên dịch có thể được ghi đè bằng cách đưa vào một hệ thống tập tin CMake rộng và chỉ biến CMAKE_USER_MAKE_RULES_OVERRIDE cho nó. Tạo một file ~/ClangOverrides.txt với các nội dung sau:

SET (CMAKE_C_FLAGS_INIT    "-Wall -std=c99") 
SET (CMAKE_C_FLAGS_DEBUG_INIT   "-g") 
SET (CMAKE_C_FLAGS_MINSIZEREL_INIT  "-Os -DNDEBUG") 
SET (CMAKE_C_FLAGS_RELEASE_INIT  "-O4 -DNDEBUG") 
SET (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g") 

SET (CMAKE_CXX_FLAGS_INIT    "-Wall") 
SET (CMAKE_CXX_FLAGS_DEBUG_INIT   "-g") 
SET (CMAKE_CXX_FLAGS_MINSIZEREL_INIT  "-Os -DNDEBUG") 
SET (CMAKE_CXX_FLAGS_RELEASE_INIT  "-O4 -DNDEBUG") 
SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O2 -g") 

Các _INIT hậu tố sẽ làm cho CMake khởi tạo *_FLAGS biến tương ứng với giá trị nhất định. Sau đó gọi cmake theo cách sau:

$ cmake -DCMAKE_USER_MAKE_RULES_OVERRIDE=~/ClangOverrides.txt .. 

Cuối cùng để buộc việc sử dụng các binutils LLVM, thiết lập các nội biến _CMAKE_TOOLCHAIN_PREFIX. Biến này được vinh danh bởi module CMakeFindBinUtils:

$ cmake -D_CMAKE_TOOLCHAIN_PREFIX=llvm- .. 

Đưa này tất cả cùng nhau bạn có thể viết một wrapper shell trong đó thiết lập các biến môi trường CCCXX và sau đó gọi cmake với ghi đè biến đề cập.

+1

Tôi đã theo dõi câu trả lời của bạn và mọi thứ ngoại trừ 'CMAKE_USER_MAKE_RULES_OVERRIDE' hoạt động. Dường như tệp bị bỏ qua (tức là mặc dù 'CMAKE_C_FLAGS_RELEASE' được đặt thành' -O4' trong tệp ghi đè, tệp này hiển thị giá trị mặc định của '-O3 -DNDEBUG' trong cmake). – Rezzie

+11

Lưu ý rằng phần lớn thông tin này được lưu trữ trong tệp CMakeCache.txt ở cấp cao nhất của cây xây dựng của bạn. Để chuyển đổi giữa gcc và clang, bạn nên có hai cây xây dựng hoàn toàn riêng biệt, và chỉ đơn giản là cd qua lại để "chuyển đổi" trình biên dịch. Khi một cây xây dựng được tạo ra với một trình biên dịch đã cho, bạn không thể chuyển đổi trình biên dịch cho cây dựng đó. – DLRdave

+0

@DLRdave Sử dụng hai cây xây dựng riêng biệt là một ý tưởng hợp lý; một cái mà tôi đã không xem xét. Rất tiếc :) Tuy nhiên, ngay cả khi thực hiện nó trong thư mục 'src/build-clang' mới, các ghi đè sẽ bị bỏ qua. – Rezzie

3

Bạn có thể sử dụng cú pháp: $ENV{environment-variable} trong số CMakeLists.txt để truy cập các biến môi trường. Bạn có thể tạo tập lệnh khởi tạo một tập các biến môi trường một cách thích hợp và chỉ có tham chiếu đến các biến đó trong các tệp CMakeLists.txt của bạn.

+0

Xin bạn có thể xây dựng thêm một chút? Bạn có nghĩa là một kịch bản shell để xuất các biến môi trường trước khi khởi chạy cmake? Những biến nào cần phải được đặt? Hoặc bạn có nghĩa là một kịch bản/bí danh mà chỉ cần gọi cmake với '-DCMAKE_C_COMPILER ...' etc? – Rezzie

+0

Tôi có nghĩa là một tập lệnh chỉ xuất các biến môi trường thích hợp. Bạn sẽ tạo các biến môi trường của riêng bạn và tham chiếu chúng trong các CMakeLists.tệp txt. – Ferruccio

+0

Ahh; Tôi hiểu ý bạn là gì. Điều duy nhất là yêu cầu phải thông qua 'CMakeLists.txt' của mọi dự án và yêu cầu nó truy vấn các biến mới. Tôi đã hy vọng sẽ có một cách thuận tiện để làm cho nó toàn hệ thống, mà không cần phải sửa đổi bất kỳ tập tin dự án. Tương tự như truyền một 'CMAKE_TOOLCHAIN_FILE'. – Rezzie

20

Bạn có thể sử dụng lệnh tùy chọn:

option(USE_CLANG "build application with clang" OFF) # OFF is the default 

và sau đó quấn các thiết lập kêu vang-trình biên dịch trong if() s:

if(USE_CLANG) 
    SET (...) 
    .... 
endif(USE_CLANG) 

Bằng cách này nó sẽ được hiển thị như một tùy chọn cmake trong công cụ cấu hình gui.

Để làm cho toàn bộ hệ thống, bạn có thể sử dụng biến môi trường làm giá trị mặc định hoặc ở lại với câu trả lời của Ferruccio.

+0

Đó là cách tôi hiện đã thiết lập, nhưng rõ ràng nó cần làm trên cơ sở từng dự án. Tôi đã hy vọng sẽ có một lệnh như 'cmake -DCMAKE_COMPILER_DEFINITIONS = MyLlvmDefinitions.cmake'. – Rezzie

+0

Bây giờ tôi hiểu những gì bạn đang cố gắng hoàn thành. Tôi không biết nếu hành vi đó được cung cấp bởi cmake, nhưng bạn có thể thử tùy chọn -C mà dường như tải một kịch bản trước khi bắt đầu chạy CMakeLists.txt. Đã không thử nó mặc dù. –

8

Bạn chắc chắn không cần phải sử dụng llvm-ar vv chương trình khác nhau khác nhau:

SET (CMAKE_AR  "/usr/bin/llvm-ar") 
SET (CMAKE_LINKER "/usr/bin/llvm-ld") 
SET (CMAKE_NM  "/usr/bin/llvm-nm") 
SET (CMAKE_OBJDUMP "/usr/bin/llvm-objdump") 
SET (CMAKE_RANLIB "/usr/bin/llvm-ranlib") 

Những được thực hiện để làm việc trên các định dạng nội llvm và như vậy không phải là hữu ích để việc xây dựng ứng dụng của bạn.

Như một lưu ý -O4 sẽ gọi LTO trên chương trình mà bạn có thể không muốn (nó sẽ tăng thời gian biên dịch rất nhiều) và mặc định là chế độ c99 để cờ không cần thiết.

103

Hệ thống rộng C++ thay đổi trên Ubuntu:

sudo apt-get install clang 
sudo update-alternatives --config c++ 

sẽ in một cái gì đó như thế này:

Selection Path    Priority Status 
------------------------------------------------------------ 
* 0   /usr/bin/g++  20  auto mode 
    1   /usr/bin/clang++ 10  manual mode 
    2   /usr/bin/g++  20  manual mode 

Sau đó chỉ cần chọn vang ++. thay đổi

+3

Cảm ơn, tôi không biết về điều này! Mặc dù tôi đoán nó phụ thuộc vào nơi mà cmake đang tìm kiếm một trình biên dịch, phải không? – Ibrahim

+1

@Ibrahim Cấu hình này đặt liên kết tượng trưng "C++" thành trình biên dịch bạn chọn và kiểm tra cmake "C++" theo mặc định, không phải "g ++". Vì vậy, trừ khi cấu hình cmake là rất cụ thể, điều này sẽ làm việc tốt (và không cho tôi). – Zoomulator

+0

Ngay bây giờ, tôi không biết ý tôi là gì:/Vâng, tôi đoán một điều thay đổi mọi thứ một chút là nếu bạn định nghĩa các biến môi trường cho CC và CXX, thì nó có khả năng ở một nơi khác. – Ibrahim

13

Hệ thống rộng C trên Ubuntu:

sudo update-alternatives --config cc

Hệ thống rộng C++ thay đổi trên Ubuntu:

sudo update-alternatives --config c++

Đối với mỗi, số báo chí lựa chọn ở trên (1) và Enter để chọn Clang:

Selection Path   Priority Status 
------------------------------------------------------------ 
* 0   /usr/bin/gcc  20  auto mode 
    1   /usr/bin/clang 10  manual mode 
    2   /usr/bin/gcc  20  manual mode 
Press enter to keep the current choice[*], or type selection number: 
+4

Nếu bạn đã cài đặt clang theo cách thủ công và đặt nó ở một nơi không chuẩn, nó có thể không hiển thị với --config. Ví dụ: nếu nó nằm trong '/ opt/clang-llvm-3.5 /' thì trước tiên hãy cài đặt một giải pháp thay thế mới: 'sudo update-alternative - install/usr/bin/C++ C++ /opt/clang-llvm-3.5/ bin/clang ++ 30' – CodeKid

1

Theo sự giúp đỡ của cmake:

-C <initial-cache> 
    Pre-load a script to populate the cache. 

    When cmake is first run in an empty build tree, it creates a CMakeCache.txt file and populates it with customizable settings for the project. This option may be used to specify a file from 
    which to load cache entries before the first pass through the project's cmake listfiles. The loaded entries take priority over the project's default values. The given file should be a CMake 
    script containing SET commands that use the CACHE option, not a cache-format file. 

Bạn thực hiện có thể tạo ra các tập tin như gcc_compiler.txtclang_compiler.txt để bao gồm tất cả cấu hình tương đối trong cú pháp CMake.

Clang Ví dụ (clang_compiler.txt):

set(CMAKE_C_COMPILER "/usr/bin/clang" CACHE string "clang compiler" FORCE) 

Sau đó chạy nó như

GCC:

cmake -C gcc_compiler.txt XXXXXXXX 

Clang:

cmake -C clang_compiler.txt XXXXXXXX 
1

Bạn có thể sử dụng toolchain cơ chế tập tin của cma ke cho mục đích này, xem ví dụ here. Bạn viết một tệp chuỗi công cụ cho mỗi trình biên dịch chứa các định nghĩa tương ứng. Vào thời gian cấu hình, bạn chạy ví dụ:

cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/clang-toolchain.cmake .. 

và tất cả thông tin trình biên dịch sẽ được đặt trong khi gọi dự án() từ tệp chuỗi công cụ. Mặc dù trong tài liệu hướng dẫn chỉ đề cập đến trong bối cảnh biên dịch chéo, nó cũng hoạt động tốt cho các trình biên dịch khác nhau trên cùng một hệ thống.

1

Nếu trình biên dịch mặc định chọn bởi cmakegcc và bạn đã cài đặt clang, bạn có thể sử dụng một cách dễ dàng để biên dịch dự án của bạn với clang:

$ mkdir build && cd build 
$ CXX=clang++ CC=clang cmake .. 
$ make -j2 
Các vấn đề liên quan