สลับระหว่าง GCC และ Clang / LLVM โดยใช้ CMake


269

ฉันมีโครงการหลายโครงการที่สร้างโดยใช้ CMake และฉันต้องการที่จะสามารถสลับระหว่างการใช้ GCC หรือ Clang / LLVM เพื่อรวบรวมได้อย่างง่ายดาย ฉันเชื่อ (โปรดแก้ไขให้ฉันถ้าฉันเข้าใจผิด!) ที่จะใช้เสียงดังกราวฉันต้องตั้งค่าต่อไปนี้:

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

มีวิธีที่ง่ายในการสลับระหว่างตัวแปร GCC เหล่านี้และค่าเริ่มต้นโดยเฉพาะอย่างยิ่งการเปลี่ยนแปลงทั้งระบบมากกว่าเฉพาะโครงการ (เช่นไม่เพียงเพิ่มเข้าไปใน CMakeLists.txt ของโครงการ)

นอกจากนี้จำเป็นต้องใช้llvm-*โปรแกรมแทนที่จะเป็นค่าเริ่มต้นของระบบเมื่อทำการคอมไพล์โดยใช้ clang แทน gcc หรือไม่? ความแตกต่างคืออะไร?

คำตอบ:


342

CMake ให้เกียรติตัวแปรสภาพแวดล้อมCCและCXXเมื่อตรวจจับคอมไพเลอร์ C และ C ++ ที่จะใช้:

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

แฟล็กเฉพาะคอมไพเลอร์สามารถถูกเขียนทับได้โดยวางลงในไฟล์ CMake ทั้งระบบและชี้ไปที่CMAKE_USER_MAKE_RULES_OVERRIDEตัวแปร สร้างไฟล์ที่~/ClangOverrides.txtมีเนื้อหาดังต่อไปนี้:

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

คำต่อท้าย_INITจะทำให้ CMake เริ่มต้น*_FLAGSตัวแปรที่สอดคล้องกับค่าที่กำหนด จากนั้นเรียกใช้cmakeด้วยวิธีต่อไปนี้:

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

สุดท้ายที่จะบังคับใช้ binutils LLVM _CMAKE_TOOLCHAIN_PREFIXที่ตั้งค่าตัวแปรภายใน ตัวแปรนี้ได้รับการยกย่องจากCMakeFindBinUtilsโมดูล:

$ cmake -D_CMAKE_TOOLCHAIN_PREFIX=llvm- ..

วางนี้ทั้งหมดเข้าด้วยกันคุณสามารถเขียนกระดาษห่อเปลือกซึ่งตั้งค่าตัวแปรสภาพแวดล้อมCCและCXXจากนั้นจะเรียกcmakeกับการแทนที่ตัวแปรที่กล่าวถึง


1
ฉันได้ติดตามคำตอบของคุณและทุกอย่างยกเว้นCMAKE_USER_MAKE_RULES_OVERRIDEงาน ดูเหมือนว่าไฟล์จะถูกละเว้น (เช่นแม้จะCMAKE_C_FLAGS_RELEASEถูกตั้งค่าเป็น-O4ในไฟล์แทนที่ก็แสดงค่าเริ่มต้นเป็น-O3 -DNDEBUGcmake)
Rezzie

18
โปรดทราบว่าข้อมูลนี้ส่วนใหญ่จะถูกเก็บไว้ในไฟล์ CMakeCache.txt ในระดับสูงสุดของโครงสร้างการสร้างของคุณ ในการสลับไปมาระหว่าง gcc และ clang คุณควรมีโครงสร้างการสร้างสองต้นแยกกันโดยสมบูรณ์และเพียง cd ไปมาเพื่อคอมไพเลอร์ "สลับ" เมื่อสร้างบิลด์ด้วยคอมไพเลอร์ที่กำหนดคุณจะไม่สามารถสลับคอมไพเลอร์สำหรับบิลด์นั้น
DLRdave

@DLRdave การใช้ต้นไม้สร้างสองแยกเป็นแนวคิดที่เหมาะสม หนึ่งฉันไม่ได้พิจารณา อ๊ะ :) อย่างไรก็ตามแม้จะทำในsrc/build-clangไดเรกทอรีใหม่การแทนที่จะถูกละเว้น
Rezzie

1
@Rezzie ค่าสถานะใน ClangOverrides.txt ต้องถูกกำหนดด้วยคำต่อท้าย _INIT ดูคำตอบที่อัปเดต
sakra

8
หมายเหตุถึงผู้อ่าน หากคุณกำลังมีปัญหากับ CMake ไม่เคารพCCและCXXตัวแปรอาจเป็นเพราะคุณต้องลบไฟล์ทั้งหมดออกจากไดเรกทอรีการสร้างก่อน rm CMakeCache.txtอาจไม่ฝืดเคือง
John Dibling

128

การเปลี่ยนแปลงทั้งระบบ C ++ บน Ubuntu:

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

จะพิมพ์แบบนี้:

  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

จากนั้นเพียงแค่เลือก clang ++


3
ขอบคุณฉันไม่รู้เกี่ยวกับสิ่งนี้! แม้ว่าฉันเดาว่ามันขึ้นอยู่กับที่ cmake กำลังมองหาคอมไพเลอร์ใช่มั้ย
อิบราฮิม

1
@Ibrahim การกำหนดค่านี้ตั้งค่า symlink "c ++" ให้กับคอมไพเลอร์ที่คุณเลือกและ cmake จะตรวจสอบ "c ++" ตามค่าเริ่มต้นไม่ใช่ "g ++" ดังนั้นหากการกำหนดค่า cmake มีความเฉพาะเจาะจงมากสิ่งนี้ควรใช้งานได้ดี (และทำได้สำหรับฉัน)
Zoomulator

2
ฉันได้รับคำตอบว่า "มีทางเลือกเดียวในกลุ่มลิงก์ c ++" โปรดขยายคำตอบของคุณเพื่อรวมวิธีเพิ่มเสียงดังกราวในรายการนี้
vedant

3
ระมัดระวังตัวเลือกนี้เนื่องจากอาจทำให้เกิดผลข้างเคียงกับระบบของคุณ มีปัญหากับแพคเกจเช่นไดรเวอร์ nvidia ที่คอมไพล์โมดูลเคอร์เนลบางตัวระหว่างการติดตั้งและไม่สามารถใช้งานร่วมกับเสียงดังกราว
Falco

2
หากคุณต้องการติดตั้ง clang-3.5, clang-3.6 เป็นต้นใช้สิ่งนี้เพื่อตั้งค่าstackoverflow.com/a/30742451/1427533เริ่มต้นเป็นอย่างอื่นคุณจะได้รับThere is only one alternative in link group cc (providing /usr/bin/cc): /usr/bin/gcc
miguel.martin

23

คุณสามารถใช้คำสั่ง option:

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

และตัดการตั้งค่า clang-compiler ใน if () s:

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

วิธีนี้แสดงเป็นตัวเลือก cmake ในเครื่องมือ gui-configuration

เพื่อให้เป็นระบบทั้งระบบคุณสามารถใช้ตัวแปรสภาพแวดล้อมเป็นค่าเริ่มต้นหรืออยู่กับคำตอบของ Ferruccio


นั่นคือวิธีที่ฉันตั้งไว้ในขณะนี้ แต่เห็นได้ชัดว่ามันต้องทำในแต่ละโครงการ ฉันหวังว่าจะมีคำสั่งเช่นcmake -DCMAKE_COMPILER_DEFINITIONS=MyLlvmDefinitions.cmakeนี้
Rezzie

1
ตอนนี้ฉันเข้าใจสิ่งที่คุณพยายามทำให้สำเร็จ ฉันไม่ทราบว่าพฤติกรรมนั้นมีให้โดย cmake แต่คุณสามารถลองใช้ตัวเลือก -C ที่ดูเหมือนว่าจะโหลดสคริปต์ก่อนที่จะเริ่มเรียกใช้ CMakeLists.txt ยังไม่ได้ลองเลย
Tobias Schlegel

18

การเปลี่ยนแปลงทั้งระบบ C บน Ubuntu:

sudo update-alternatives --config cc

การเปลี่ยนแปลงทั้งระบบ C ++ บน Ubuntu:

sudo update-alternatives --config c++

สำหรับแต่ละข้างต้นกดหมายเลขการเลือก (1) และ Enter เพื่อเลือก 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:

7
หากคุณติดตั้งเสียงดังกราวของคุณด้วยตนเองและวางไว้ในตำแหน่งที่ไม่ได้มาตรฐานอาจไม่แสดงพร้อม --config ตัวอย่างเช่นถ้าใน/opt/clang-llvm-3.5/นั้นก่อนอื่นให้ติดตั้งทางเลือกใหม่: sudo update-alternatives --install /usr/bin/c++ c++ /opt/clang-llvm-3.5/bin/clang++ 30
CodeKid

16

คุณสามารถใช้กลไกของไฟล์ toolchain CMake เพื่อวัตถุประสงค์นี้เห็นเช่นที่นี่ คุณเขียนไฟล์ toolchain สำหรับคอมไพเลอร์แต่ละตัวที่มีคำจำกัดความที่เกี่ยวข้อง เมื่อถึงเวลากำหนดค่าให้คุณรันเช่น

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

และข้อมูลคอมไพเลอร์ทั้งหมดจะถูกตั้งค่าในระหว่างการเรียก project () จากไฟล์ toolchain แม้ว่าในเอกสารจะกล่าวถึงเฉพาะในบริบทของการคอมไพล์ข้ามมันทำงานได้ดีสำหรับคอมไพเลอร์ต่าง ๆ ในระบบเดียวกัน


4
ฉันยังคงประหลาดใจที่พบคำตอบที่ถูกต้องที่ด้านล่างของเธรดที่ SO เท่านั้น
Slava

10

แน่นอนคุณไม่จำเป็นต้องใช้โปรแกรม llvm-ar ที่แตกต่างกัน:

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

สิ่งเหล่านี้ใช้เพื่อทำงานกับรูปแบบภายในของ lvm และดังนั้นจึงไม่มีประโยชน์ในการสร้างแอปพลิเคชันของคุณ

ในฐานะโน้ต -O4 จะเรียกใช้ LTO ในโปรแกรมของคุณซึ่งคุณอาจไม่ต้องการ (มันจะเพิ่มเวลาในการคอมไพล์อย่างมาก) และค่าเริ่มต้นของเสียงดังกราวไปยังโหมด c99 เพื่อไม่ให้จำเป็นต้องตั้งค่าสถานะ


7

หากคอมไพเลอร์เริ่มต้นที่เลือกโดยcmakeเป็นgccและคุณได้ติดตั้งclangแล้วคุณสามารถใช้วิธีง่าย ๆ ในการรวบรวมโครงการของคุณด้วยclang:

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

5

ตามความช่วยเหลือของ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.

คุณสามารถสร้างไฟล์เช่นgcc_compiler.txtและclang_compiler.txtรวมการกำหนดค่าที่เกี่ยวข้องทั้งหมดในไวยากรณ์ CMake

ตัวอย่างเสียงดังกราว (clang_compiler.txt):

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

จากนั้นเรียกใช้เป็น

GCC:

cmake -C gcc_compiler.txt XXXXXXXX

เสียงดังกราว:

cmake -C clang_compiler.txt XXXXXXXX

3

คุณสามารถใช้ไวยากรณ์: $ENV{environment-variable}ในCMakeLists.txtการเข้าถึงตัวแปรสภาพแวดล้อม คุณสามารถสร้างสคริปต์ที่เริ่มต้นชุดตัวแปรสภาพแวดล้อมอย่างเหมาะสมและเพียงแค่มีการอ้างอิงถึงตัวแปรเหล่านั้นในCMakeLists.txtไฟล์ของคุณ


กรุณาช่วยอธิบายเพิ่มเติมอีกหน่อยได้ไหม? คุณหมายถึงเชลล์สคริปต์เพื่อส่งออกตัวแปรสภาพแวดล้อมก่อนเปิดตัว cmake หรือไม่ ตัวแปรใดที่จำเป็นต้องตั้งค่า หรือคุณหมายถึงสคริปต์ / นามแฝงที่เพิ่งเรียก cmake กับ-DCMAKE_C_COMPILER ...ฯลฯ ?
Rezzie

ฉันหมายถึงสคริปต์ที่เพิ่งส่งออกตัวแปรสภาพแวดล้อมที่เหมาะสม คุณจะสร้างตัวแปรสภาพแวดล้อมของคุณเองและอ้างอิงพวกเขาในไฟล์ CMakeLists.txt
Ferruccio

อ่า; ฉันเห็นสิ่งที่คุณหมายถึง สิ่งเดียวคือต้องผ่านCMakeLists.txtทุกโครงการและให้มีการสอบถามตัวแปรใหม่ ฉันหวังว่าจะมีวิธีที่สะดวกในการทำทั้งระบบโดยไม่ต้องแก้ไขไฟล์โครงการใด ๆ CMAKE_TOOLCHAIN_FILEคล้ายกับการส่งผ่าน
Rezzie
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.