Я часто использовал Make для небольших проектов, но для более крупных это было слишком утомительно. До недавнего времени я хотел, чтобы моя система сборки выполняла за меня четыре вещи, которые я не знал, как сделать в Make:

  • Сборки вне исходного кода (объектные файлы выгружаются в отдельный каталог от источника)
  • Автоматические (и точные!) Зависимости заголовков
  • Автоматическое определение списка объектных / исходных файлов
  • Автоматическая генерация флагов включаемых каталогов

Вот простой Makefile, который будет делать все это и работать с C, C ++ и сборкой:

See the code in the full post.

Неплохо!
Кроме того, если вас не интересуют сборки вне исходного кода, вы можете использовать еще более простой Makefile, который использует преимущества встроенных неявных правил:

See the code in the full post.

Вот краткий обзор того, как это работает:

Сборки вне исходного кода

Я хочу, чтобы все артефакты из сборки попали в какой-то каталог (я обычно называю его «./build»), отдельный от источника. Это позволяет легко выполнить чистку (просто rm -rf ./build), даже если там останутся другие артефакты, помимо тех, которые сгенерированы с помощью Make. Это также делает многое другое, например поиск источника с помощью grep'а, намного приятнее.

Чтобы сделать это в Make, вам в основном нужно просто добавить выходной каталог в начало правил шаблона. Например, вместо шаблона типа:% .o:% .c, который будет отображать ваши файлы .c для файлов .o в том же каталоге, вы можете использовать $ (BUILD_DIR)%. O:% .c.

Автоматические зависимости заголовков

Обработка зависимостей заголовков, пожалуй, самая самая утомительная вещь в использовании классической техники Make. Тем более, что если вы его испортите, вы не получите явных ошибок - вещи просто не будут повторно компилироваться, когда они должны быть. Это может привести к тому, что файлы .o будут иметь разные представления о том, как выглядят типы или прототипы.

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

Если вы создаете файлы зависимостей как часть этапа компиляции, все становится намного проще. Чтобы сгенерировать файлы зависимостей, все, что вам нужно сделать, это добавить несколько флагов к команде компиляции (поддерживается как Clang, так и GCC):

  • -MMD -MP
    , который создаст файл .d рядом с файлом .o. Затем, чтобы использовать файлы .d, вам просто нужно найти их все:
  • DEPS: = $ (OBJS: .o = .d)
    , а затем -включите их:
  • -включить $ (DEPS)

Автоматическое определение списка объектных / исходных файлов

Сначала найдите все исходные файлы в указанных исходных каталогах. Самый простой и быстрый способ, который я нашел, - это просто выпустить оболочку и использовать find.

  • SRCS: = $ (shell find $ (SRC_DIRS) -name * .cpp -or -name * .c -or -name * .s)
    Но поскольку Make работает в обратном направлении от объектных файлов к источнику, нам нужно для вычисления всех объектных файлов, которые нам нужны, из наших исходных файлов. Я просто добавляю $ (BUILD_DIR) / и добавляю .o к каждому пути исходного файла:
  • OBJS: = $ (SRCS:% = $ (BUILD_DIR) /%. O)
    И затем вы можете сделать вашу цель зависимой от файлов объектов:
See the code in the full post.

Автоматическое создание флагов включаемых каталогов

Я использовал похожую технику для генерации флагов включаемых каталогов. Найдите все каталоги в указанных исходных каталогах:

  • INC_DIRS: = $ (shell find $ (SRC_DIRS) -type d)
    А затем добавьте к ним префикс -I:
  • INC_FLAGS: = $ (addprefix -I, $ (INC_DIRS))

Надеюсь, эти методы будут вам полезны.

Первоначально опубликовано на сайте spin.atomicobject.com 26 августа 2016 г.