Я разработал нерекурсивную систему make для одного проекта C ++ среднего размера, который предназначен для использования в unix-подобных системах (включая Mac). Код в этом проекте находится в дереве каталогов с корнем в каталоге src /. Я хотел написать нерекурсивную систему, в которой можно было бы набрать "make all" из любого подкаталога верхнего уровня каталога src /, чтобы скомпилировать все исходные файлы в дереве каталогов с корнем в рабочем каталоге, как в рекурсивной системе make. Поскольку мое решение, кажется, немного отличается от других, которые я видел, я хотел бы описать его здесь и посмотреть, получу ли я какую-нибудь реакцию.
Основными элементами моего решения были следующие:
1) Каждый каталог в дереве src / имеет файл с именем sources.mk. Каждый такой файл определяет переменную makefile, в которой перечислены все исходные файлы в дереве с корнем в каталоге. Имя этой переменной имеет вид [каталог] _SRCS, в котором [каталог] представляет собой каноническую форму пути от каталога src / верхнего уровня к этому каталогу, с обратными косыми чертами, замененными знаками подчеркивания. Например, файл src / util / param / sources.mk определяет переменную с именем util_param_SRCS, которая содержит список всех исходных файлов в src / util / param и его подкаталоги, если таковые имеются. Каждый файл sources.mk также определяет переменную с именем [каталог] _OBJS, которая содержит список соответствующих целей объектного файла * .o. В каждом каталоге, содержащем подкаталоги, файл sources.mk включает файл sources.mk из каждого подкаталога и объединяет переменные [подкаталог] _SRCS для создания своей собственной переменной [каталог] _SRCS.
2) Все пути выражаются в файлах sources.mk как абсолютные пути, в которых каталог src / представлен переменной $ (SRC_DIR). Например, в файле src / util / param / sources.mk файл src / util / param / Componenent.cpp будет указан как $ (SRC_DIR) /util/param/Component.cpp. Значение $ (SRC_DIR) не установлено ни в одном файле sources.mk.
3) Каждый каталог также содержит Makefile. Каждый Makefile включает глобальный файл конфигурации, который устанавливает значение переменной $ (SRC_DIR) равным абсолютному пути к корневому каталогу src /. Я решил использовать символическую форму абсолютных путей, потому что это оказался самый простой способ создать несколько make-файлов в нескольких каталогах, которые будут одинаково интерпретировать пути для зависимостей и целей, при этом позволяя при желании перемещать все исходное дерево. , изменив значение $ (SRC_DIR) в одном файле. Это значение устанавливается автоматически простым скриптом, который пользователь получает указание запустить, когда пакет загружается или клонируется из репозитория git, или когда перемещается все исходное дерево.
4) Makefile в каждом каталоге включает файл sources.mk для этого каталога. Целевой объект "all" для каждого такого Makefile перечисляет файл [directory] _OBJS для этого каталога как зависимость, что требует компиляции всех исходных файлов в этом каталоге и его подкаталогах.
5) Правило для компиляции файлов * .cpp создает файл зависимостей для каждого исходного файла с суффиксом * .d в качестве побочного эффекта компиляции, как описано здесь: http://mad-science.net/make/autodep.html. Я решил использовать компилятор gcc для генерации зависимостей, используя параметр -M. Я использую gcc для генерации зависимостей даже при использовании другого компилятора для компиляции исходных файлов, потому что gcc почти всегда доступен в unix-подобных системах, и потому что это помогает стандартизировать эту часть системы сборки. Фактически для компиляции исходных файлов можно использовать другой компилятор.
6) Использование абсолютных путей для всех файлов в переменных _OBJS и _SRCS потребовало, чтобы я написал сценарий для редактирования файлов зависимостей, сгенерированных gcc, который создает файлы с относительными путями. Я написал для этой цели скрипт на Python, но другой человек мог использовать sed. Пути для зависимостей в результирующих файлах зависимостей являются буквальными абсолютными путями. В данном контексте это нормально, потому что файлы зависимостей (в отличие от файлов sources.mk) создаются локально, а не распространяются как часть пакета.
7) Makefile в каждом директоре включает файл sources.mk из того же каталога и содержит строку «-include $ ([directory] _OBJS: .o = .d)», которая пытается включить файлы зависимостей для каждого исходного файла. в каталоге и его подкаталогах, как описано в приведенном выше URL-адресе.
Основное различие между этой схемой и другими схемами, которые я видел, которые позволяют вызывать "make all" из любого каталога, заключается в использовании абсолютных путей, позволяющих согласованно интерпретировать одни и те же пути, когда Make вызывается из разных каталогов. Пока эти пути выражаются с использованием переменной, представляющей исходный каталог верхнего уровня, это не мешает перемещать исходное дерево и является более простым, чем некоторые альтернативные методы достижения той же цели.
В настоящее время моя система для этого проекта всегда выполняет сборку «на месте»: объектный файл, созданный путем компиляции каждого исходного файла, помещается в тот же каталог, что и исходный файл. Было бы просто включить неуместные сборки, изменив сценарий, который редактирует файлы зависимостей gcc, чтобы заменить абсолютный путь к каталогу src / на переменную $ (BUILD_DIR), которая представляет каталог сборки в выражении для цель объектного файла в правиле для каждого объектного файла.
На данный момент я считаю эту систему простой в использовании и обслуживании. Необходимые фрагменты make-файла короткие и сравнительно простые для понимания соавторами.
Проект, для которого я разработал эту систему, написан на полностью автономном ANSI C ++ без внешних зависимостей. Я думаю, что такая самодельная нерекурсивная система make-файлов - разумный вариант для автономного, очень переносимого кода. Однако я бы рассмотрел более мощную систему сборки, такую как CMake или gnu autotools, для любого проекта, который имеет нетривиальные зависимости от внешних программ или библиотек или от нестандартных функций операционной системы.
person
D Morse
schedule
10.12.2012