C++. Сборник рецептов
Шрифт:
Давайте подробно рассмотрим пример 1.20. Вначале я определяю переменные, представляющие выходной файл, директорию установки и расширения файлов, которые должны удаляться при сборке цели
Правило для сборки статической библиотеки выглядит так.
Это непосредственная адаптация записи для GCC из табл. 1.10. Здесь
Следующие два правила объявляют цели
Двойной знак доллара я использовал для того, чтобы запретить make раскрывать переменную
Три последних правила указывают отношения зависимостей между файлами .cpp библиотеки и включаемыми в них заголовочными файлами. Здесь указано по одному правилу для каждого .cpp– файла. Целью такого правила является объектный файл, собираемый из .cpp– файла, а пререквизитами являются заголовочные файлы, явно или неявно включаемые .cpp– файлом.
Это можно понять следующим образом. Если .cpp– файл явно или косвенно включает заголовочный файл, то он должен быть пересобран при каждом изменении этого заголовочного файла. Однако, так как .cpp– файл существует и не является целью какого-либо правила, он никогда не устаревает, как описано в рецепте 1.15. Следовательно, при изменении заголовочного файла перекомпиляции не происходит. Чтобы исправить эту ситуацию, требуется объявить правило, сделав эти зависимости явными; когда один из используемых заголовочных файлов изменяется, объектный файл, соответствующий .cpp– файлу, устаревает, что приводит к перекомпиляции .cpp– файла.
Это решение удобно только для очень небольших проектов, так как очень сложно постоянно отслеживать зависимости целей, представляющих собой исходные файлы, входящие в большую базу кода. К счастью, имеется несколько способов автоматической генерации этих зависимостей. Например, три последних правила примера 1.20 можно заменить на следующие.
Этот фрагмент кода основан на опции компилятора – M, которая заставляет GCC вывести в make-файл информацию о зависимостях. За подробным описанием того, как это работает, и почему иногда не подходит, обратитесь к книге Managing Projects with GNU make, Third Edition, написанной Робертом Мекленбургом (Robert Mecklenburg) (O'Reilly).
Так как большинство компиляторов имеет опцию, аналогичную опции – М GCC, этот метод может быть адаптирован для работы с большинством инструментов. На самом деле обычно эта опция называется – М или – m. Однако Visual C++ не имеет опции для генерации зависимостей в make-файле. При использовании Visual C++ есть две возможности. Можно использовать опцию – Gm совместно с опциями – Zi или – ZI, обсуждаемыми в рецепте 1.21. Опция – Gm говорит компилятору создать базу данных, сохраняемую в файле с расширением idb, содержащую информацию о зависимостях между исходными файлами. Файл .idb создается при первоначальной компиляции файла или набора файлов .cpp. При последующих компиляциях перекомпилируются только те исходные файлы, которые были изменены или зависят от изменившихся заголовочных файлов.
Кроме того, можно использовать опцию – showIncludes совместно с опцией – E. Опция – showIncludes приводит к тому, что компилятор при каждом обнаружении директивы include выводит в стандартный поток ошибок сообщение. Опция – E говорит компилятору запустить препроцессор и выйти, не создавая никаких двоичных файлов. С помощью небольшого сценария оболочки можно использовать вывод, сгенерированный – showIncludes; для создания зависимостей в make-файле.
В этом примере символ • обозначает Tab.
Давайте сделаем еще одно последнее усовершенствование примера 1.20. В настоящий момент последовательность