Beralih antara GCC dan Dentang / LLVM menggunakan CMake

269

Saya memiliki sejumlah proyek yang dibangun menggunakan CMake dan saya ingin dapat dengan mudah beralih antara menggunakan GCC atau Dentang / LLVM untuk mengkompilasinya. Saya percaya (tolong perbaiki saya jika saya salah!) Bahwa untuk menggunakan Dentang saya perlu mengatur yang berikut:

    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")

Apakah ada cara mudah untuk beralih antara ini dan variabel GCC default, lebih disukai sebagai perubahan seluruh sistem daripada spesifik proyek (yaitu tidak hanya menambahkannya ke dalam CMakeLists.txt proyek)?

Juga, apakah perlu menggunakan llvm-*program daripada sistem default saat kompilasi menggunakan dentang bukan gcc? Apa bedanya?

Rezzie
sumber

Jawaban:

342

CMake menghargai variabel lingkungan CCdan CXXsetelah mendeteksi kompiler C dan C ++ untuk menggunakan:

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

Flag spesifik compiler dapat diganti dengan meletakkannya ke dalam file CMake sistem yang lebar dan mengarahkan CMAKE_USER_MAKE_RULES_OVERRIDEvariabel ke sana. Buat file ~/ClangOverrides.txtdengan konten berikut:

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        "-O3 -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        "-O3 -DNDEBUG")
SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O2 -g")

Suffix _INITakan membuat CMake menginisialisasi *_FLAGSvariabel yang sesuai dengan nilai yang diberikan. Kemudian panggil cmakedengan cara berikut:

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

Akhirnya untuk memaksa penggunaan binutils LLVM, atur variabel internal _CMAKE_TOOLCHAIN_PREFIX. Variabel ini dihormati oleh CMakeFindBinUtilsmodul:

$ cmake -D_CMAKE_TOOLCHAIN_PREFIX=llvm- ..

Menempatkan ini semua bersama-sama Anda dapat menulis bungkus shell yang menetapkan variabel lingkungan CCdan CXXkemudian memanggil cmakedengan menimpa variabel yang disebutkan.

sakra
sumber
1
Saya sudah mengikuti jawaban Anda dan semuanya kecuali CMAKE_USER_MAKE_RULES_OVERRIDEkarya. Tampaknya file tersebut diabaikan (yaitu meskipun CMAKE_C_FLAGS_RELEASEdiatur ke -O4dalam file yang diganti, itu menunjukkan nilai default -O3 -DNDEBUGdalam cmake).
Rezzie
18
Perhatikan bahwa banyak dari informasi ini di-cache dalam file CMakeCache.txt di tingkat atas pohon build Anda. Untuk beralih antara gcc dan dentang, Anda harus memiliki dua pohon bangunan yang benar-benar terpisah, dan cukup cd bolak-balik ke kompiler "switch". Setelah membangun pohon dibuat dengan kompiler yang diberikan, Anda tidak dapat beralih kompilator untuk membangun pohon itu.
DLRdave
@DLRdave Menggunakan dua pohon bangunan yang terpisah adalah ide yang masuk akal; yang belum saya pertimbangkan. Ups :) Namun, meskipun melakukannya di src/build-clangdirektori baru , pengabaiannya diabaikan.
Rezzie
1
@Rezzie Bendera di ClangOverrides.txt harus didefinisikan dengan akhiran _INIT. Lihat jawaban yang diperbarui.
sakra
8
Catatan untuk pembaca. Jika Anda mengalami masalah dengan CMake yang tidak menghormati variabel CCdan CXX, itu mungkin karena Anda harus menghapus semua file dari direktori build terlebih dahulu. rm CMakeCache.txtmungkin tidak cukup.
John Dibling
128

C ++ seluruh sistem berubah pada Ubuntu:

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

Akan mencetak sesuatu seperti ini:

  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

Kemudian cukup pilih dentang ++.

Coder
sumber
3
Terima kasih, saya tidak tahu tentang ini! Meskipun saya kira itu tergantung di mana cmake mencari kompiler, bukan?
Ibrahim
1
@Ibrahim Konfigurasi ini menetapkan symlink "c ++" ke compiler yang Anda pilih dan cmake memeriksa "c ++" secara default, bukan "g ++". Jadi kecuali konfigurasi cmake sangat spesifik, ini akan berfungsi dengan baik (dan tidak untuk saya).
Zoomulator
2
Saya mendapat balasan bahwa "Hanya ada satu alternatif di grup tautan c ++". Harap rentangkan jawaban Anda untuk memasukkan cara menambahkan dentang ke daftar ini
vedant
3
Hati-hati dengan alternatif ini karena dapat menyebabkan efek samping dengan sistem Anda. Sudah mengalami masalah dengan paket-paket seperti driver nvidia yang mengkompilasi ulang beberapa modul kernel saat instalasi dan tidak kompatibel dengan dentang.
Falco
2
Jika Anda ingin menginstal clang-3.5, clang-3.6, dll. Gunakan ini untuk mengatur stackoverflow.com/a/30742451/1427533 default seperti yang akan Anda dapatkanThere is only one alternative in link group cc (providing /usr/bin/cc): /usr/bin/gcc
miguel.martin
23

Anda dapat menggunakan perintah opsi:

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

dan kemudian bungkus pengaturan clang-compiler di if () s:

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

Dengan cara ini ditampilkan sebagai opsi cmake di alat konfigurasi gui.

Untuk membuatnya menjadi sistem Anda tentu saja dapat menggunakan variabel lingkungan sebagai nilai default atau tetap dengan jawaban Ferruccio.

Tobias Schlegel
sumber
Begitulah cara saya mengaturnya, tetapi jelas itu perlu dilakukan berdasarkan per proyek. Saya berharap akan ada perintah seperti cmake -DCMAKE_COMPILER_DEFINITIONS=MyLlvmDefinitions.cmake.
Rezzie
1
Sekarang saya mengerti apa yang ingin Anda capai. Saya tidak tahu apakah perilaku itu disediakan oleh cmake, tetapi Anda bisa mencoba opsi -C yang tampaknya memuat skrip sebelum mulai menjalankan CMakeLists.txt. Belum mencobanya.
Tobias Schlegel
18

Perubahan sistem C yang lebar di Ubuntu:

sudo update-alternatives --config cc

C ++ seluruh sistem berubah pada Ubuntu:

sudo update-alternatives --config c++

Untuk masing-masing di atas, tekan Nomor pilihan (1) dan Enter untuk memilih Dentang:

  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:
Victor Lyuboslavsky
sumber
7
Jika Anda telah menginstal dentang Anda secara manual dan meletakkannya di tempat yang tidak standar, itu mungkin tidak muncul dengan --config. Misalnya jika sudah di /opt/clang-llvm-3.5/maka instal dulu alternatif baru: sudo update-alternatives --install /usr/bin/c++ c++ /opt/clang-llvm-3.5/bin/clang++ 30
CodeKid
16

Anda dapat menggunakan mekanisme file toolchain cmake untuk tujuan ini, lihat misalnya di sini . Anda menulis file toolchain untuk setiap kompiler yang berisi definisi yang sesuai. Pada waktu konfigurasi, Anda menjalankan mis

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

dan semua informasi kompiler akan ditetapkan selama panggilan proyek () dari file toolchain. Meskipun dalam dokumentasi disebutkan hanya dalam konteks kompilasi silang, ia berfungsi juga untuk kompiler yang berbeda pada sistem yang sama.

j_fu
sumber
4
Saya masih heran bagaimana jawaban yang benar hanya dapat ditemukan di utas di sini di SO.
Slava
10

Anda pasti tidak perlu menggunakan berbagai program dll llvm-ar yang berbeda:

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")

Ini dibuat untuk bekerja pada format internal llvm dan karena itu tidak berguna untuk membangun aplikasi Anda.

Sebagai catatan -O4 akan menjalankan LTO pada program Anda yang mungkin tidak Anda inginkan (ini akan sangat meningkatkan waktu kompilasi) dan menempelkan default ke mode c99 sehingga flag juga tidak diperlukan.

echristo
sumber
7

Jika kompiler default dipilih oleh cmakeadalah gccdan Anda telah menginstal clang, Anda dapat menggunakan cara mudah untuk mengkompilasi proyek Anda dengan clang:

$ mkdir build && cd build
$ CXX=clang++ CC=clang cmake ..
$ make -j2
ya
sumber
5

Menurut bantuan dari 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.

Anda dapat membuat file seperti gcc_compiler.txtdan clang_compiler.txtmemasukkan semua konfigurasi relatif dalam sintaks CMake.

Contoh Dentang (clang_compiler.txt):

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

Kemudian jalankan sebagai

GCC:

cmake -C gcc_compiler.txt XXXXXXXX

Dentang:

cmake -C clang_compiler.txt XXXXXXXX
Enze Chi
sumber
3

Anda dapat menggunakan sintaks: $ENV{environment-variable}di Anda CMakeLists.txtuntuk mengakses variabel lingkungan. Anda bisa membuat skrip yang menginisialisasi seperangkat variabel lingkungan dengan tepat dan hanya memiliki referensi ke variabel-variabel tersebut di CMakeLists.txtfile Anda .

Ferruccio
sumber
Bisakah Anda menjelaskan sedikit lebih jauh? Apakah maksud Anda skrip shell untuk mengekspor variabel lingkungan sebelum meluncurkan cmake? Variabel mana yang perlu diatur? Atau maksud Anda skrip / alias yang hanya memanggil cmake dengan -DCMAKE_C_COMPILER ...dll?
Rezzie
Maksud saya skrip yang hanya mengekspor variabel lingkungan yang sesuai. Anda akan membuat variabel lingkungan Anda sendiri dan referensi mereka dalam file CMakeLists.txt.
Ferruccio
Ahh; Saya mengerti apa yang kamu maksud. Satu-satunya hal yang harus melalui CMakeLists.txtsetiap proyek dan meminta permintaan variabel baru. Saya berharap akan ada cara yang nyaman untuk melakukannya di seluruh sistem, tanpa harus memodifikasi file proyek apa pun. Mirip dengan melewati a CMAKE_TOOLCHAIN_FILE.
Rezzie