Переключение между GCC и Clang/LLVM с использованием CMake

У меня есть несколько проектов, созданных с использованием 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? Какая разница?

12 ответов

Решение

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

Суффикс _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 с упомянутыми переопределениями переменных.

Общесистемные изменения 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++.

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

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

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

Вы можете использовать команду option:

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

и затем оберните настройки компилятора clang в if()s:

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

Таким образом, он отображается как опция cmake в инструментах настройки GUI.

Чтобы сделать его общесистемным, вы, конечно, можете использовать переменную окружения в качестве значения по умолчанию или остаться с ответом Ферруччо.

Изменение всей системы 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:

Если компилятор по умолчанию выбрал cmake является gcc и вы установили clang, вы можете использовать простой способ компилировать ваш проект с clang:

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

Вам определенно не нужно использовать различные программы 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 в вашей программе, который вам может не понадобиться (это значительно увеличит время компиляции), и по умолчанию clang перейдет в режим c99, так что флаг также не обязательно нужен.

Согласно помощи 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

Clang:

cmake -C clang_compiler.txt XXXXXXXX

Просто добавьте это в конец вашего ~ / .bashrc

      export CC=/usr/bin/clang
export CXX=/usr/bin/clang++

Перезапустите терминал, и с этого момента cmake будет использовать clang для сборки всех проектов. Отредактируйте ~ / .bashrc, чтобы вернуться к gcc.

Лучше не указывать компилятор в CMakelists.txt.

Просто добавьте следующую команду

-D CMAKE_CXX_COMPILER="xx" -D CMAKE_C_COMPILER="xx"

Пример:

      cmake -D CMAKE_CXX_COMPILER="/bin/clang++-xx" -D CMAKE_C_COMPILER="/bin/clang-xx"

В CMakeList.txt:

      set(CMAKE_C_COMPILER "clang-10")
set(CMAKE_CXX_COMPILER "/usr/bin/clang++-10")

Или версия clang, которая у вас есть.

Вы можете использовать синтаксис: $ENV{environment-variable} в вашем CMakeLists.txt для доступа к переменным среды. Вы можете создавать сценарии, которые соответствующим образом инициализируют набор переменных среды и просто имеют ссылки на эти переменные в вашем CMakeLists.txt файлы.

Другие вопросы по тегам