Перемикання між GCC та Clang / LLVM за допомогою CMake


269

У мене є ряд проектів, побудованих за допомогою CMake, і я хотів би мати можливість легко переключатися між використанням GCC або Clang / LLVM для їх компіляції. Я вважаю (будь ласка, виправте мене, якщо я помиляюся!), Що для використання Clang мені потрібно встановити наступне:

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

Нарешті, щоб змусити використовувати бінулети 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 -DNDEBUGу cmake).
Rezzie

18
Зауважте, що значна частина цієї інформації зберігається у файлі CMakeCache.txt у верхньому рівні дерева вашої збірки. Щоб переключитися між gcc та clang, у вас повинно бути два повністю відокремлених дерева побудови та просто cd назад і вперед, щоб "переключити" компілятори. Як тільки дерево збірки генерується із заданим компілятором, ви не можете переключити компілятор для цього дерева збірки.
DLRdave

@DLRdave Використання двох окремих дерев збірки - розумна ідея; одного я не розглядав. На жаль :) Але навіть роблячи це в новому src/build-clangкаталозі, скасування ігноруються.
Реззі

1
@Rezzie Прапори в ClangOverrides.txt мають бути визначені суфіксом _INIT. Дивіться оновлену відповідь.
сакра

8
Примітка читачам. Якщо у вас виникають проблеми з нешануванням CCі CXXзмінними CMake , це може бути тому, що вам потрібно спочатку видалити всі файли з каталогу збирання. rm CMakeCache.txtможе бути неефективним.
Джон Даблінг

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 Ця конфігурація встановлює символьне посилання "c ++" до обраного вами компілятора, а cmake за замовчуванням перевіряє "c ++", а не "g ++". Тому, якщо конфігурація cmake не є дуже специфічною, це повинно працювати добре (і для мене).
Zoomulator

2
Я отримую відповідь, що "Є лише одна альтернатива в групі посилань c ++". Розгорніть свою відповідь, щоб включити, як додати кланг до цього списку
vedant

3
Будьте обережні з цією альтернативою, оскільки це може призвести до побічних ефектів у вашій системі. Уже виникли проблеми з такими пакетами, як драйвер nvidia, який перекомпілює деякі модулі ядра під час встановлення та не був сумісний з clang.
Фалько

2
Якщо ви хочете встановити брязкіт-3,5, брязкіт-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(USE_CLANG "build application with clang" OFF) # OFF is the default

а потім оберніть налаштування компілятора clang у if () s:

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

Таким чином він відображається як параметр cmake в інструментах gui-конфігурації.

Щоб зробити це загальносистемним, ви, звичайно, можете використовувати змінну середовища як значення за замовчуванням або залишитись відповіддю Ферруччо.


Саме тому я зараз його налаштував, але очевидно, що це потрібно робити на основі проекту. Я сподівався, що буде така команда cmake -DCMAKE_COMPILER_DEFINITIONS=MyLlvmDefinitions.cmake.
Реззі

1
Тепер я розумію, що ви намагаєтеся досягти. Я не знаю, чи забезпечується така поведінка cmake, але ви можете спробувати варіант -C, який, здається, завантажує сценарій, перш ніж почати запускати CMakeLists.txt. Не намагався, хоча.
Тобіас Шлегель

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

Для цього ви можете використовувати механізм файлів інструментального ланцюга cmake, див., Наприклад, тут . Ви пишете файл ланцюжка інструментів для кожного компілятора, що містить відповідні визначення. У час конфігурації ви запускаєте, наприклад

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

і вся інформація компілятора буде встановлена ​​під час виклику project () з файлу ланцюжка інструментів. Хоча в документації згадується лише в контексті перехресного складання, вона працює також для різних компіляторів в одній системі.


4
Я все ще дивуюсь, як правильні відповіді можна знайти лише в нижній частині теми тут.
Слава

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

Вони створені для роботи у внутрішньому форматі llvm і як такі не корисні для складання вашої програми.

Як зауваження, -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 (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перегляду кожного проекту та надання йому запиту на нові змінні. Я сподівався, що це буде зручний спосіб зробити це в усьому світі, не змінюючи файлів проекту. Схожий на проходження a CMAKE_TOOLCHAIN_FILE.
Rezzie
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.