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