Чтение онлайн

на главную - закладки

Жанры

C++. Сборник рецептов

Когсуэлл Джефф

Шрифт:
Обсуждение

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

clean
. Затем я объявляю цель по умолчанию
all
, как в примере 1.14.

Правило для сборки статической библиотеки выглядит так.

$(OUTPUTFILE): john.o paul.o johnpaul.о

ar ru $@ $^

ranlib $@

Это непосредственная адаптация записи для GCC из табл. 1.10. Здесь

$(OUTPUTFILE)
и
$@
раскрываются
как
libjohnpaul.a
, а
$^
раскрывается в виде списка пререквизитов
john.o paul.o johnpaul.о
.

Следующие два правила объявляют цели

install
и
clean
, как в рецепте 1.15. Единственное отличие состоит в том, что в примере 1.20 для удаления всех файлов, чьи расширения имеются в списке
о а
— т. е. все объектные файлы и файлы статической библиотеки, - я использую цикл оболочки.

for file in $(CLEANEXTS); do rm -f *.$$file; done

Двойной знак доллара я использовал для того, чтобы запретить make раскрывать переменную

$$file
при передаче ее оболочке.

Три последних правила указывают отношения зависимостей между файлами .cpp библиотеки и включаемыми в них заголовочными файлами. Здесь указано по одному правилу для каждого .cpp– файла. Целью такого правила является объектный файл, собираемый из .cpp– файла, а пререквизитами являются заголовочные файлы, явно или неявно включаемые .cpp– файлом.

john.o: john.hpp

paul.o: paul.hpp

johnpaul.o. john.hpp paul.hpp johnpaul.hpp

Это можно понять следующим образом. Если .cpp– файл явно или косвенно включает заголовочный файл, то он должен быть пересобран при каждом изменении этого заголовочного файла. Однако, так как .cpp– файл существует и не является целью какого-либо правила, он никогда не устаревает, как описано в рецепте 1.15. Следовательно, при изменении заголовочного файла перекомпиляции не происходит. Чтобы исправить эту ситуацию, требуется объявить правило, сделав эти зависимости явными; когда один из используемых заголовочных файлов изменяется, объектный файл, соответствующий .cpp– файлу, устаревает, что приводит к перекомпиляции .cpp– файла.

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

# Генерируем зависимости .cpp-файлов от .hpp-файлов

include john.o paul.o johnpaul.о

%.d: %.cpp

$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \

sed 's.\($*\)\.o[ :]*.\1.o $@ : ,g' < $@.$$$$ > $@, \

rm -f $@.$$$$

Этот фрагмент кода основан на опции компилятора – M, которая заставляет GCC вывести в make-файл информацию о зависимостях. За подробным описанием того, как это работает, и почему иногда не подходит, обратитесь к книге Managing Projects with GNU make, Third Edition, написанной Робертом Мекленбургом (Robert Mecklenburg) (O'Reilly).

Код
для генерации зависимостей помещайте в конец make-файла.

Так как большинство компиляторов имеет опцию, аналогичную опции – М GCC, этот метод может быть адаптирован для работы с большинством инструментов. На самом деле обычно эта опция называется – М или – m. Однако Visual C++ не имеет опции для генерации зависимостей в make-файле. При использовании Visual C++ есть две возможности. Можно использовать опцию – Gm совместно с опциями – Zi или – ZI, обсуждаемыми в рецепте 1.21. Опция – Gm говорит компилятору создать базу данных, сохраняемую в файле с расширением idb, содержащую информацию о зависимостях между исходными файлами. Файл .idb создается при первоначальной компиляции файла или набора файлов .cpp. При последующих компиляциях перекомпилируются только те исходные файлы, которые были изменены или зависят от изменившихся заголовочных файлов.

Кроме того, можно использовать опцию – showIncludes совместно с опцией – E. Опция – showIncludes приводит к тому, что компилятор при каждом обнаружении директивы include выводит в стандартный поток ошибок сообщение. Опция – E говорит компилятору запустить препроцессор и выйти, не создавая никаких двоичных файлов. С помощью небольшого сценария оболочки можно использовать вывод, сгенерированный – showIncludes; для создания зависимостей в make-файле.

include john.d paul.d johnpaul.d

%d: %.cpp

"$(MSVCDIR)/bin/cl" -E -showIncludes $< 2> $@.$$$$ > /dev/null; \

sed -n 's/^Note: including file: *\(.*\)/$*.obj•$*.d:\1/gp' \

< $@.$$$$ | sed "s:\\:/:g:s: :\\ :gp" > $@; \

rm -f $@.$$$$

В этом примере символ • обозначает Tab.

Давайте сделаем еще одно последнее усовершенствование примера 1.20. В настоящий момент последовательность

john paul johnpaul
содержится в двух местах — в пререквизитах правила для сборки статической библиотеки и в директиве
include
, используемой для генерации зависимостей. Если список исходных файлов изменится, вам придется вносить изменения в двух местах make-файла. Гораздо лучше определить переменную
SOURCES
и заменить оба использования последовательности
john paul johnpaul
на выражения, использующие
SOURCES
.

SOURCES = john.cpp paul.cpp johnpaul.cpp

...

# Собираем libjohnpaul.a из john.о, paul.o и johnpaul.о

$(OUTPUTFILE): $(subst .cpp, .o,$(SOURCES))

ar ru $@ $^

ranlib $@

...

# Генерируем зависимости .cpp-файлов от .hpp-файлов

include $(subst .cpp,.d,$(SOURCES))

%d: %.cpp

$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \

Поделиться:
Популярные книги

Весь цикл «Десантник на престоле». Шесть книг

Ланцов Михаил Алексеевич
Десантник на престоле
Фантастика:
альтернативная история
8.38
рейтинг книги
Весь цикл «Десантник на престоле». Шесть книг

Убивать чтобы жить 6

Бор Жорж
6. УЧЖ
Фантастика:
боевая фантастика
космическая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 6

Мужчина моей судьбы

Ардова Алиса
2. Мужчина не моей мечты
Любовные романы:
любовно-фантастические романы
8.03
рейтинг книги
Мужчина моей судьбы

Прорвемся, опера! Книга 3

Киров Никита
3. Опер
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Прорвемся, опера! Книга 3

Бастард Императора. Том 2

Орлов Андрей Юрьевич
2. Бастард Императора
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Бастард Императора. Том 2

Измена. Право на сына

Арская Арина
4. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Право на сына

Игра на чужом поле

Иванов Дмитрий
14. Девяностые
Фантастика:
попаданцы
альтернативная история
5.50
рейтинг книги
Игра на чужом поле

Жена со скидкой, или Случайный брак

Ардова Алиса
Любовные романы:
любовно-фантастические романы
8.15
рейтинг книги
Жена со скидкой, или Случайный брак

Ворон. Осколки нас

Грин Эмилия
2. Ворон
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Ворон. Осколки нас

Сумеречный стрелок

Карелин Сергей Витальевич
1. Сумеречный стрелок
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Сумеречный стрелок

Измена. Испорченная свадьба

Данич Дина
Любовные романы:
современные любовные романы
короткие любовные романы
5.00
рейтинг книги
Измена. Испорченная свадьба

Прометей: Неандерталец

Рави Ивар
4. Прометей
Фантастика:
героическая фантастика
альтернативная история
7.88
рейтинг книги
Прометей: Неандерталец

Генерал-адмирал. Тетралогия

Злотников Роман Валерьевич
Генерал-адмирал
Фантастика:
альтернативная история
8.71
рейтинг книги
Генерал-адмирал. Тетралогия

Четвертый год

Каменистый Артем
3. Пограничная река
Фантастика:
фэнтези
9.22
рейтинг книги
Четвертый год