Разница между использованием Makefile и CMake для компиляции кода

Я кодирую на C/C++ и использую (GNU) Makefile для компиляции кода. Я могу сделать то же самое с CMake и получить MakeFile. Однако в чем разница между использованием Makefile и CMake для компиляции кода?

Ответ 1

Make (или, скорее, Makefile) - это система сборки - она управляет компилятором и другими инструментами сборки для сборки вашего кода.

CMake - это генератор сборочных систем. Он может создавать файлы Makefile, он может создавать файлы сборки Ninja, он может создавать проекты KDEvelop или Xcode, он может создавать решения Visual Studio. С той же начальной точки, тот же файл CMakeLists.txt. Так что, если у вас есть независимый от платформы проект, CMake - это способ сделать его также независимым от системы.

Если у вас есть разработчики Windows, привыкшие к разработчикам Visual Studio и Unix, которые клянутся GNU Make, CMake - это один из способов.

Я всегда рекомендовал бы использовать CMake (или другой генератор системы сборки, но CMake - это мое личное предпочтение), если вы хотите, чтобы ваш проект был мультиплатформенным или широко используемым. Сам CMake также предоставляет некоторые полезные функции, такие как обнаружение зависимостей, управление интерфейсом библиотеки или интеграция с CTest, CDash и CPack.

Использование генератора системы сборки делает ваш проект более перспективным. Даже если вы сейчас используете GNU-Make-only, что если вы позже решите перейти на другие платформы (будь то Windows или что-то встроенное) или просто захотите использовать IDE?

Ответ 2

Утверждение о том, что CMake является "генератором сборки", является распространенным заблуждением.

Это не технически неправильно; это просто описывает КАК это работает, но не ЧТО это делает.

В контексте вопроса они делают одно и то же: возьмите кучу файлов C/C++ и превратите их в двоичный файл.

Так в чем же разница?

  • CMake гораздо более высокого уровня. Он предназначен для компиляции C++, для которой вы пишете гораздо меньше кода сборки, но также может использоваться для сборки общего назначения. make также имеет некоторые встроенные правила C/C++, но они в основном бесполезны.

  • CMake выполняет двухэтапную сборку: он генерирует низкоуровневый скрипт сборки в ninja или make или во многих других генераторах, а затем вы запускаете его. Все части сценария оболочки, которые обычно складываются в Makefile, выполняются только на этапе генерации. Таким образом, сборка CMake может быть на несколько порядков быстрее.

  • Грамматику CMake гораздо проще поддерживать для внешних инструментов , чем для.

  • Как только make создает артефакт, он забывает, как он был построен. Из каких источников он был собран, какие флаги компилятора? CMake отслеживает это, make оставляет это на ваше усмотрение. Если один из источников библиотеки был удален со времени предыдущей версии Makefile, make не будет перестраивать его.

  • Modern CMake (начиная с версии 3.something) работает с точки зрения зависимостей между "целями". Цель - все еще единственный файл otput (к сожалению), но может иметь переходные ("public"/"interface" в терминах CMake) зависимости. Эти транзитивные зависимости могут быть открыты или скрыты от зависимых пакетов. CMake будет управлять каталогами и для вас. С make вы застряли на уровне файлов и управления каталогами вручную.

Вы могли бы что-то кодировать в make, используя файлы флагов, чтобы покрыть последние два пробела, но вы по своему усмотрению. make содержит полный язык Тьюринга (даже два, иногда три, считая Guile), и все они ужасны.

Честно говоря, это то, что объединяет CMake и make - их языки довольно ужасные:

  • У них нет типов;
  • нет массивов, только строки, разделенные пробелом, таким образом, выходящий из ада;
  • вы обычно передаете аргументы в функции, устанавливая глобальные переменные; (это решается в современном CMake - переменные теперь могут иметь пространства имен; цель - это пространство имен для своих свойств)
  • ссылка на неопределенную переменную по умолчанию игнорируется;

начать с.

Но в CMake вы пишете гораздо меньше строк кода.