# Говорим make пересобрать hello тогда, когда изменяется hello.cpp
$(OUTPUTFILE): hello.cpp
# Цели Install и clean как в примере 1.16
Откуда make знает, как собирать исполняемый файл hello из исходного файла hello.cpp , без явного указания? Ответ состоит в том, что make содержит внутреннюю базу данных неявных правил, представляющих операции, часто выполняемые при сборке приложений, написанных на С и С++. Например, неявное правило для генерации исполняемого файла из файла .cpp выглядит так, как в примере 1.19.
Пример 1.19. Шаблон правила из внутренней базы данных make
%: %.cpp
# исполняемые команды (встроенные):
$(LINK.cpp) $(LOADLIBS) $(LDLIBS) -о $@
Правила, первые строки которых имеют вид % xxx :% yyy , известны как шаблонные правила (pattern rules) , а символ %действует как подстановочный знак (wildcard) . Когда устаревшему пререквизиту не соответствует ни одно из обычных правил, make ищет доступные шаблонные правила. Для каждого шаблонного правила make пытается найти строку, которая при подстановке подстановочного знака в целевую часть правила даст искомый устаревший пререквизит. Если make находит такую строку, make заменяет подстановочные знаки для цели и пререквизитов шаблонного правила и создает новое правило. Затем make пытается собрать устаревший пререквизит с помощью этого нового правила.
Чтобы напечатать базу данных неявных правил GNU make , используйте make -p .
Например, при первом выполнении make-файла из примера 1.18 пререквизит helloцели по умолчанию allявляется устаревшим. Хотя helloфигурирует как цель правила $(OUTPUTFILE): hello.cpp, это правило не содержит командного сценария, и, таким образом, оно бесполезно для сборки файла hello. Следовательно, make выполняет поиск в своей внутренней базе данных и находит правило, показанное в примере 1.19. Подставляя в правило из примера 1.19 вместо подстановочного знака строку hello, make генерирует следующее правило с helloв качестве цели.
hello: hello.cpp
$(LINK.cpp) $(LOADLIBS) $(LDLIBS) -o $@
Пока все хорошо, но есть еще кое-что. Повторный взгляд на внутреннюю базу данных make показывает, что переменная LINK.cppпо умолчанию раскрывается как $(LINK.cc). В свою очередь LINK.ccпо умолчанию раскрывается как
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
Наконец, переменная CXXпо умолчанию раскрывается как g++, а четыре другие переменные — $(CXXFLAGS), $(CPPFLAGS), $(LDFLAGS)и $(TARGET_ARCH)— раскрываются как пустые строки. После выполнения всех этих подстановок получается следующее правило, которое теперь выглядит более знакомо.
hello: hello.cpp
g++ $^ -o $@
Запутались? Это не страшно. Если вы изучите приведенное объяснение и потратите некоторое время на изучение внутренней базы данных make , неявные правила приобретут смысл.
Возможности для настройки
Теперь, когда вы увидели, как шаблонное правило из примера 1.19 приводит к тому, что make собирает исполняемый файл hello из исходного файла hello.cpp , вы можете спросить, почему было необходимо использовать столько промежуточных шагов. Почему вместо сложного правила из примера 1.19 во внутреннюю базу данных make просто не добавить правило
%: %.cpp
g++ $^ -о $@
Ответ состоит в том, что промежуточные переменные, такие как $(CXX), $(CXXFLAGS), $(CPPFLAGS)и $(LDFLAGS), служат как точки настройки (customization points). Например, указав значение LDFLAGSв командной строке, в make-файле или установив значение переменной среды, можно указать дополнительные флаги, передаваемые компоновщику. Переменные CPPFLAGSи CXXFLAGSиграют схожую роль для опций препроцессора и компилятора C++ соответственно. А установив значение переменной CXX, можно указать компилятор, отличный от GCC. Например, чтобы собрать hello с помощью Intel для Linux и используя make-файл из примера 1.18, вы должны в командной строке ввести make CXX=icpc , предполагая, что переменные среды, необходимые для компилятора Intel, уже установлены.
VPATH и директива vpath
В примере 1.18 make может применить правильное шаблонное правило, потому что файл .cpp находится в той же директории, в которой создается выходной файл. Если исходные файлы находятся в другой директории, то для указания make , где искать цели или пререквизиты, используется переменная VPATH.
Читать дальше