Учебники

Makefile — Краткое руководство

Почему Makefile?

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

Makefiles — это файлы специального формата, которые помогают автоматически создавать проекты и управлять ими.

Например, предположим, у нас есть следующие исходные файлы.

  • main.cpp
  • hello.cpp
  • factorial.cpp
  • functions.h

main.cpp

Ниже приведен код для исходного файла main.cpp —

#include <iostream>

using namespace std;

#include "functions.h"

int main(){
   print_hello();
   cout << endl;
   cout << "The factorial of 5 is " << factorial(5) << endl;
   return 0;
}

hello.cpp

Код, приведенный ниже, предназначен для исходного файла hello.cpp —

#include <iostream>

using namespace std;

#include "functions.h"

void print_hello(){
   cout << "Hello World!";
}

factorial.cpp

Код для factorial.cpp приведен ниже —

#include "functions.h"

int factorial(int n){
   
   if(n!=1){
      return(n * factorial(n-1));
   } else return 1;
}

functions.h

Ниже приведен код для fnctions.h —

void print_hello();
int factorial(int n);

Тривиальный способ компилировать файлы и получить исполняемый файл, выполнив команду —

gcc  main.cpp hello.cpp factorial.cpp -o hello

Эта команда генерирует привет двоичный файл. В этом примере у нас всего четыре файла, и мы знаем последовательность вызовов функций. Следовательно, можно ввести указанную выше команду и подготовить окончательный двоичный файл.

Однако для большого проекта, в котором у нас есть тысячи файлов исходного кода, становится сложно поддерживать двоичные сборки.

Команда make позволяет вам управлять большими программами или группами программ. Когда вы начинаете писать большие программы, вы замечаете, что перекомпиляция больших программ занимает больше времени, чем перекомпиляция коротких программ. Более того, вы замечаете, что обычно работаете только над небольшим разделом программы (например, над одной функцией), и большая часть оставшейся программы остается неизменной.

В следующем разделе мы увидим, как подготовить make-файл для нашего проекта.

Makefile — Макросы

Программа make позволяет вам использовать макросы, которые похожи на переменные. Макросы определены в Makefile как пары =. Пример был показан ниже —

MACROS  = -me
PSROFF  = groff -Tps
DITROFF = groff -Tdvi
CFLAGS  = -O -systype bsd43
LIBS    = "-lncurses -lm -lsdl"
MYFACE  = ":*)"

Специальные макросы

Перед выполнением любой команды в целевом наборе правил предопределены определенные специальные макросы —

  • $ @ — это имя файла, который нужно создать.

  • $? это имена измененных иждивенцев.

$ @ — это имя файла, который нужно создать.

$? это имена измененных иждивенцев.

Например, мы можем использовать правило следующим образом:

hello: main.cpp hello.cpp factorial.cpp
   $(CC) $(CFLAGS) $? $(LDFLAGS) -o $@

Alternatively:

hello: main.cpp hello.cpp factorial.cpp
   $(CC) $(CFLAGS) $@.cpp $(LDFLAGS) -o $@

В этом примере $ @ представляет привет и $? или $ @. cpp забирает все измененные исходные файлы.

В неявных правилах используются еще два специальных макроса. Они —

  • $ <имя связанного файла, вызвавшего действие.

  • $ * префикс, общий для целевых и зависимых файлов.

$ <имя связанного файла, вызвавшего действие.

$ * префикс, общий для целевых и зависимых файлов.

Общее неявное правило — для создания .o (объектных) файлов из .cpp (исходных файлов).

.cpp.o:
   $(CC) $(CFLAGS) -c $<

Alternatively:

.cpp.o:
   $(CC) $(CFLAGS) -c $*.c

Обычные макросы

Существуют различные макросы по умолчанию. Вы можете увидеть их, набрав «make -p» для распечатки значений по умолчанию. Большинство из них довольно очевидно из правил, в которых они используются.

Эти предопределенные переменные, то есть макросы, используемые в неявных правилах, делятся на два класса. Они заключаются в следующем —

  • Макросы, которые являются названиями программ (например, CC)

  • Макросы, которые содержат аргументы программ (например, CFLAGS).

Макросы, которые являются названиями программ (например, CC)

Макросы, которые содержат аргументы программ (например, CFLAGS).

Ниже приведена таблица некоторых распространенных переменных, используемых в качестве имен программ во встроенных правилах make-файлов.

Sr.No Переменные и описание
1

Арканзас

Архивно-поддерживающая программа; по умолчанию это `ar ‘.

2

КАК

Программа для компиляции сборочных файлов; по умолчанию `as ‘.

3

CC

Программа для составления программ на С; по умолчанию это `cc ‘.

4

Колорадо

Программа для проверки файлов из RCS; по умолчанию это `co ‘.

5

CXX

Программа для компиляции программ на C ++; по умолчанию это `g ++ ‘.

6

CPP

Программа для запуска препроцессора C, с результатами на стандартный вывод; по умолчанию это `$ (CC) -E ‘.

7

FC

Программа для компиляции или предварительной обработки программ на Fortran и Ratfor; по умолчанию `f77 ‘.

8

ПОЛУЧИТЬ

Программа для извлечения файла из SCCS; по умолчанию `get ‘.

9

LEX

Программа для превращения грамматик Lex в исходный код; по умолчанию это `lex ‘.

10

YACC

Программа для преобразования грамматики Yacc в исходный код; по умолчанию это `yacc ‘.

11

LINT

Программа для запуска lint в исходном коде; по умолчанию это `lint ‘.

12

M2C

Программа, используемая для компиляции исходного кода Modula-2; по умолчанию `m2c ‘.

13

ПК

Программа для компиляции программ на Паскале; по умолчанию это `pc ‘.

14

MAKEINFO

Программа для преобразования исходного файла Texinfo в Info-файл; по умолчанию это `makeinfo ‘.

15

TEX

Программа для создания файлов TeX DVI из источника TeX; по умолчанию это `tex ‘.

16

texi2dvi

Программа для создания файлов TeX dvi из источника Texinfo; по умолчанию используется texi2dvi.

17

WEAVE

Программа для перевода Web в TeX; по умолчанию это «переплетение».

18

CWEAVE

Программа для перевода C Web в TeX; по умолчанию это `cweave ‘.

19

TANGLE

Программа для перевода веб на Паскаль; по умолчанию это «клубок».

20

CTANGLE

Программа для перевода C Web в C; по умолчанию это `ctangle ‘.

21

RM

Команда на удаление файла; по умолчанию это `rm -f ‘.

Арканзас

Архивно-поддерживающая программа; по умолчанию это `ar ‘.

КАК

Программа для компиляции сборочных файлов; по умолчанию `as ‘.

CC

Программа для составления программ на С; по умолчанию это `cc ‘.

Колорадо

Программа для проверки файлов из RCS; по умолчанию это `co ‘.

CXX

Программа для компиляции программ на C ++; по умолчанию это `g ++ ‘.

CPP

Программа для запуска препроцессора C, с результатами на стандартный вывод; по умолчанию это `$ (CC) -E ‘.

FC

Программа для компиляции или предварительной обработки программ на Fortran и Ratfor; по умолчанию `f77 ‘.

ПОЛУЧИТЬ

Программа для извлечения файла из SCCS; по умолчанию `get ‘.

LEX

Программа для превращения грамматик Lex в исходный код; по умолчанию это `lex ‘.

YACC

Программа для преобразования грамматики Yacc в исходный код; по умолчанию это `yacc ‘.

LINT

Программа для запуска lint в исходном коде; по умолчанию это `lint ‘.

M2C

Программа, используемая для компиляции исходного кода Modula-2; по умолчанию `m2c ‘.

ПК

Программа для компиляции программ на Паскале; по умолчанию это `pc ‘.

MAKEINFO

Программа для преобразования исходного файла Texinfo в Info-файл; по умолчанию это `makeinfo ‘.

TEX

Программа для создания файлов TeX DVI из источника TeX; по умолчанию это `tex ‘.

texi2dvi

Программа для создания файлов TeX dvi из источника Texinfo; по умолчанию используется texi2dvi.

WEAVE

Программа для перевода Web в TeX; по умолчанию это «переплетение».

CWEAVE

Программа для перевода C Web в TeX; по умолчанию это `cweave ‘.

TANGLE

Программа для перевода веб на Паскаль; по умолчанию это «клубок».

CTANGLE

Программа для перевода C Web в C; по умолчанию это `ctangle ‘.

RM

Команда на удаление файла; по умолчанию это `rm -f ‘.

Вот таблица переменных, значения которых являются дополнительными аргументами для программ выше. Значениями по умолчанию для всех них является пустая строка, если не указано иное.

Sr.No. Переменные и описание
1

ARFLAGS

Флаги для выдачи архива, поддерживающего программу; по умолчанию это `rv ‘.

2

ASFLAGS

Дополнительные флаги для ассемблера при явном вызове в файл `.s ‘или` .S.

3

CFLAGS

Дополнительные флаги для компилятора Си.

4

CXXFLAGS

Дополнительные флаги для компилятора Си.

5

COFLAGS

Дополнительные флаги для передачи в программу RCS.

6

CPPFLAGS

Дополнительные флаги для препроцессора C и программ, которые его используют (таких как компиляторы C и Fortran).

7

FFLAGS

Дополнительные флаги для компилятора Фортрана.

8

GFLAGS

Дополнительные флаги для программы SCCS get.

9

LDFLAGS

Дополнительные флаги для компиляторов, когда они должны вызывать компоновщик, `ld ‘.

10

LFLAGS

Дополнительные флаги для Лекса.

11

YFLAGS

Дополнительные флаги для Yacc.

12

PFLAGS

Дополнительные флаги для передачи компилятору Pascal.

13

RFLAGS

Дополнительные флаги для компилятора Фортрана для программ Ratfor.

14

LINTFLAGS

Дополнительные флаги для ворса.

ARFLAGS

Флаги для выдачи архива, поддерживающего программу; по умолчанию это `rv ‘.

ASFLAGS

Дополнительные флаги для ассемблера при явном вызове в файл `.s ‘или` .S.

CFLAGS

Дополнительные флаги для компилятора Си.

CXXFLAGS

Дополнительные флаги для компилятора Си.

COFLAGS

Дополнительные флаги для передачи в программу RCS.

CPPFLAGS

Дополнительные флаги для препроцессора C и программ, которые его используют (таких как компиляторы C и Fortran).

FFLAGS

Дополнительные флаги для компилятора Фортрана.

GFLAGS

Дополнительные флаги для программы SCCS get.

LDFLAGS

Дополнительные флаги для компиляторов, когда они должны вызывать компоновщик, `ld ‘.

LFLAGS

Дополнительные флаги для Лекса.

YFLAGS

Дополнительные флаги для Yacc.

PFLAGS

Дополнительные флаги для передачи компилятору Pascal.

RFLAGS

Дополнительные флаги для компилятора Фортрана для программ Ratfor.

LINTFLAGS

Дополнительные флаги для ворса.

ПРИМЕЧАНИЕ. — Вы можете отменить все переменные, используемые неявными правилами, с помощью опции ‘-R’ или ‘—no-builtin-variable’.

Вы также можете определить макросы в командной строке, как показано ниже —

make CPP = /home/courses/cop4530/spring02

Определение зависимостей в Makefile

Очень часто конечный двоичный файл будет зависеть от различных исходных кодов и исходных файлов заголовков. Зависимости важны, потому что они позволяют узнать об источнике для любой цели. Рассмотрим следующий пример —

hello: main.o factorial.o hello.o
   $(CC) main.o factorial.o hello.o -o hello

Здесь мы говорим make, что hello зависит от файлов main.o, factorial.o и hello.o. Следовательно, всякий раз, когда происходит изменение в любом из этих объектных файлов, make будет действовать.

В то же время нам нужно указать make как подготовить файлы .o. Следовательно, мы должны определить эти зависимости также следующим образом:

main.o: main.cpp functions.h
   $(CC) -c main.cpp

factorial.o: factorial.cpp functions.h
   $(CC) -c factorial.cpp

hello.o: hello.cpp functions.h
   $(CC) -c hello.cpp

Определение правил в Makefile

Теперь мы изучим правила для Makefile.

Общий синтаксис целевого правила Makefile —

target [target...] : [dependent ....]
[ command ...]

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

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

hello: main.o factorial.o hello.o
   $(CC) main.o factorial.o hello.o -o hello

ПРИМЕЧАНИЕ. — В этом примере вам нужно будет задать правила для создания всех объектных файлов из исходных файлов.

Семантика очень проста. Когда вы говорите «make target», make находит целевое правило, которое применяется; и, если какой-либо из зависимостей новее, чем цель, make выполняет команды по одной (после подстановки макросов). Если необходимо создать каких-либо иждивенцев, это происходит в первую очередь (поэтому у вас есть рекурсия).

Make завершается, если какая-либо команда возвращает статус ошибки. В таком случае будет показано следующее правило:

clean:
   -rm *.o *~ core paper

Make игнорирует возвращенный статус в командной строке, начинающейся с тире. Например, кого это волнует, если нет файла ядра?

Make повторяет команды после замены макроса, чтобы показать вам, что происходит. Иногда вы можете захотеть отключить это. Например —

install:
   @echo You must be root to install

Люди ожидают определенных целей в Makefiles. Вы должны всегда просматривать в первую очередь. Тем не менее, разумно ожидать, что цели все (или просто сделать), установить и очистить найдены.

  • make all — компилирует все, чтобы вы могли выполнять локальное тестирование перед установкой приложений.

  • make install — устанавливает приложения в нужных местах

  • make clean — очищает приложения, избавляется от исполняемых файлов, любых временных файлов, объектных файлов и т. д.

make all — компилирует все, чтобы вы могли выполнять локальное тестирование перед установкой приложений.

make install — устанавливает приложения в нужных местах

make clean — очищает приложения, избавляется от исполняемых файлов, любых временных файлов, объектных файлов и т. д.

Makefile Неявные правила

Эта команда должна работать во всех случаях, когда мы создаем исполняемый файл x из исходного кода x.cpp. Это можно сформулировать как неявное правило —

.cpp:
   $(CC) $(CFLAGS) $@.cpp $(LDFLAGS) -o $@

Это неявное правило говорит о том, как сделать x из xc — запустить cc на xc и вызвать вывод x. Правило неявное, потому что не указана конкретная цель. Может использоваться во всех случаях.

Другое распространенное неявное правило — для создания .o (объектных) файлов из .cpp (исходных файлов).

.cpp.o:
   $(CC) $(CFLAGS) -c $<

alternatively

.cpp.o:
   $(CC) $(CFLAGS) -c $*.cpp

Определение пользовательских суффиксных правил в Makefile

Make может автоматически создать файл, используя cc -c для соответствующего файла .c. Эти правила встроены в make , и вы можете воспользоваться этим преимуществом, чтобы сократить ваш Makefile. Если вы укажете только файлы .h в строке зависимостей файла Makefile, от которого зависит текущая цель, make узнает, что соответствующий файл .cfile уже требуется. Вам не нужно включать команду для компилятора.

Это еще больше уменьшает Makefile, как показано ниже —

OBJECTS = main.o hello.o factorial.o
hello: $(OBJECTS)
   cc $(OBJECTS) -o hello
hellp.o: functions.h

main.o: functions.h 
factorial.o: functions.h 

Make использует специальную цель с именем .SUFFIXES, которая позволяет вам определять свои собственные суффиксы. Например, обратитесь к строке зависимости, приведенной ниже —

.SUFFIXES: .foo .bar

Он сообщает make, что вы будете использовать эти специальные суффиксы для создания своих собственных правил.

Подобно тому, как make уже знает, как сделать файл .o из файла .c , вы можете определить правила следующим образом:

.foo.bar:
   tr '[A-Z][a-z]' '[N-Z][A-M][n-z][a-m]' < $< > $@
.c.o:
   $(CC) $(CFLAGS) -c $<

Первое правило позволяет вам создать файл .bar из файла .foo . Это в основном шифрует файл. Второе правило — это правило по умолчанию, используемое make для создания файла .o из файла .c .

Makefile — Директивы

Существуют многочисленные директивы, доступные в различных формах. Программа make в вашей системе может не поддерживать все директивы. Поэтому, пожалуйста, проверьте, поддерживает ли ваша марка директивы, которые мы здесь объясняем. GNU make поддерживает эти директивы.

Условные Директивы

Условные директивы —

  • Директива ifeq начинает условное выражение и определяет условие. Он содержит два аргумента, разделенных запятой и заключенных в скобки. Подстановка переменных выполняется для обоих аргументов, а затем они сравниваются. Строки make-файла, следующие за ifeq, выполняются, если два аргумента совпадают; в противном случае они игнорируются.

  • Директива ifneq начинает условное выражение и определяет условие. Он содержит два аргумента, разделенных запятой и заключенных в скобки. Подстановка переменных выполняется для обоих аргументов, а затем они сравниваются. Строки make-файла, следующие за ifneq, выполняются, если два аргумента не совпадают; в противном случае они игнорируются.

  • Директива ifdef начинает условное выражение и определяет условие. Он содержит один аргумент. Если данный аргумент является истинным, тогда условие становится истинным.

  • Директива ifndef начинает условное выражение и определяет условие. Он содержит один аргумент. Если данный аргумент является ложным, то условие становится истинным.

  • Директива else заставляет подчиняться следующие строки, если предыдущее условие не выполнено. В приведенном выше примере это означает, что вторая альтернативная команда связывания используется всякий раз, когда первая альтернатива не используется. Необязательно иметь другое в условном выражении.

  • Директива endif завершает условие. Каждое условие должно заканчиваться endif.

Директива ifeq начинает условное выражение и определяет условие. Он содержит два аргумента, разделенных запятой и заключенных в скобки. Подстановка переменных выполняется для обоих аргументов, а затем они сравниваются. Строки make-файла, следующие за ifeq, выполняются, если два аргумента совпадают; в противном случае они игнорируются.

Директива ifneq начинает условное выражение и определяет условие. Он содержит два аргумента, разделенных запятой и заключенных в скобки. Подстановка переменных выполняется для обоих аргументов, а затем они сравниваются. Строки make-файла, следующие за ifneq, выполняются, если два аргумента не совпадают; в противном случае они игнорируются.

Директива ifdef начинает условное выражение и определяет условие. Он содержит один аргумент. Если данный аргумент является истинным, тогда условие становится истинным.

Директива ifndef начинает условное выражение и определяет условие. Он содержит один аргумент. Если данный аргумент является ложным, то условие становится истинным.

Директива else заставляет подчиняться следующие строки, если предыдущее условие не выполнено. В приведенном выше примере это означает, что вторая альтернативная команда связывания используется всякий раз, когда первая альтернатива не используется. Необязательно иметь другое в условном выражении.

Директива endif завершает условие. Каждое условие должно заканчиваться endif.

Синтаксис условных директив

Синтаксис простого условного выражения без указания следующего:

conditional-directive
   text-if-true
endif

Text-if-true может быть любыми строками текста, которые будут считаться частью make-файла, если условие истинно. Если условие ложно, текст не используется.

Синтаксис сложного условия следующий:

conditional-directive
   text-if-true
else
   text-if-false
endif

Если условие истинно, используется text-if-true; в противном случае используется text-if-false. Text-if-false может быть любым количеством строк текста.

Синтаксис условной директивы один и тот же, простой или сложный условный. Существует четыре разных директивы, которые проверяют различные условия. Они как дано —

ifeq (arg1, arg2)
ifeq 'arg1' 'arg2'
ifeq "arg1" "arg2"
ifeq "arg1" 'arg2'
ifeq 'arg1' "arg2" 

Противоположными указаниями вышеуказанных условий являются:

ifneq (arg1, arg2)
ifneq 'arg1' 'arg2'
ifneq "arg1" "arg2"
ifneq "arg1" 'arg2'
ifneq 'arg1' "arg2" 

Пример условных директив

libs_for_gcc = -lgnu
normal_libs =

foo: $(objects)
ifeq ($(CC),gcc)
   $(CC) -o foo $(objects) $(libs_for_gcc)
else
   $(CC) -o foo $(objects) $(normal_libs)
endif

Директива включения

Директива include позволяет make приостанавливать чтение текущего make-файла и читать один или несколько других make-файлов перед продолжением. Директива — это строка в make-файле, которая выглядит следующим образом:

include filenames...

Имена файлов могут содержать шаблоны имен файлов оболочки. Дополнительные пробелы разрешены и игнорируются в начале строки, но вкладка не допускается. Например, если у вас есть три файла `.mk ‘, а именно,` a.mk’, `b.mk ‘и` c.mk’ и $ (bar), то он расширяется до bish bash, а затем выражение.

include foo *.mk $(bar)

is equivalent to:

include foo a.mk b.mk c.mk bish bash

Когда make обрабатывает директиву include, он приостанавливает чтение make-файла и читает по очереди из каждого указанного файла. Когда это закончится, make возобновляет чтение make-файла, в котором появляется директива.

Директива переопределения

Если переменная была установлена ​​с аргументом команды, то обычные присваивания в make-файле игнорируются. Если вы хотите установить переменную в make-файле, даже если она была установлена ​​с помощью аргумента команды, вы можете использовать директиву override, которая выглядит следующим образом:

override variable = value

or

override variable := value

Makefile — Перекомпиляция

Программа make — это интеллектуальная утилита, которая работает на основе изменений, которые вы делаете в своих исходных файлах. Если у вас есть четыре файла main.cpp, hello.cpp, factorial.cpp и functions.h, то все остальные файлы зависят от functions.h, а main.cpp зависит как от hello.cpp, так и factorial.cpp. Следовательно, если вы сделаете какие-либо изменения в functions.h, то make перекомпилирует все исходные файлы для генерации новых объектных файлов. Однако, если вы сделаете какие-либо изменения в main.cpp, так как это не зависит ни от какого другого файла, то перекомпилируется только файл main.cpp, а help.cpp и factorial.cpp — нет.

При компиляции файла make проверяет свой объектный файл и сравнивает отметки времени. Если исходный файл имеет более новую временную отметку, чем объектный файл, то он создает новый объектный файл, предполагая, что исходный файл был изменен.

Избегать перекомпиляции

Может быть проект, состоящий из тысяч файлов. Иногда вы можете изменить исходный файл, но вы можете не захотеть перекомпилировать все файлы, которые зависят от него. Например, предположим, что вы добавляете макрос или объявление в заголовочный файл, от которого зависят другие файлы. Будучи консервативным, make предполагает, что любое изменение в заголовочном файле требует перекомпиляции всех зависимых файлов, но вы знаете, что они не нуждаются в перекомпиляции, и вы бы предпочли не тратить свое время на ожидание их компиляции.

Если вы предвидите проблему до изменения заголовочного файла, вы можете использовать флаг `-t ‘. Этот флаг указывает make не запускать команды в правилах, а помечать цель как актуальную, изменяя дату ее последнего изменения. Вы должны следовать этой процедуре —

  • Используйте команду `make ‘для перекомпиляции исходных файлов, которые действительно нуждаются в перекомпиляции.

  • Внесите изменения в заголовочные файлы.

  • Используйте команду `make -t ‘, чтобы пометить все объектные файлы как актуальные. В следующий раз, когда вы запустите make, изменения в заголовочных файлах не вызовут никакой перекомпиляции.

Используйте команду `make ‘для перекомпиляции исходных файлов, которые действительно нуждаются в перекомпиляции.

Внесите изменения в заголовочные файлы.

Используйте команду `make -t ‘, чтобы пометить все объектные файлы как актуальные. В следующий раз, когда вы запустите make, изменения в заголовочных файлах не вызовут никакой перекомпиляции.

Если вы уже изменили заголовочный файл в то время, когда некоторые файлы нуждаются в перекомпиляции, сделать это слишком поздно. Вместо этого вы можете использовать флаг `-o file ‘, который помечает указанный файл как« старый ». Это означает, что сам файл не будет переделан, и больше ничего не будет переделано на его счет. вам нужно следовать этой процедуре —

  • Перекомпилируйте исходные файлы, которые нужно компилировать по причинам, независимым от конкретного заголовочного файла, с помощью `make -o header file ‘. Если задействовано несколько файлов заголовков, используйте отдельный параметр `-o ‘для каждого файла заголовков.

  • Обновите все объектные файлы с помощью `make -t ‘.

Перекомпилируйте исходные файлы, которые нужно компилировать по причинам, независимым от конкретного заголовочного файла, с помощью `make -o header file ‘. Если задействовано несколько файлов заголовков, используйте отдельный параметр `-o ‘для каждого файла заголовков.

Обновите все объектные файлы с помощью `make -t ‘.

Makefile — другие функции

В этой главе мы рассмотрим различные другие особенности Makefile.

Рекурсивное использование Make

Рекурсивное использование make означает использование make в качестве команды в make-файле. Этот метод полезен, когда вам нужны отдельные make-файлы для различных подсистем, составляющих большую систему. Например, предположим, что у вас есть подкаталог с именем `subdir ‘, который имеет свой собственный make-файл, и вы хотели бы, чтобы make-файл содержащего каталога запускал make в этом подкаталоге. Вы можете сделать это, написав следующий код —

subsystem:
   cd subdir && $(MAKE)

or, equivalently:
 	
subsystem:
   $(MAKE) -C subdir

Вы можете написать рекурсивные команды make, просто скопировав этот пример. Тем не менее, вам необходимо знать, как они работают и почему, и как подзадача связана с маркой верхнего уровня.

Передача переменных в суб-марку

Значения переменных make верхнего уровня могут быть переданы подкоманде через окружение по явному запросу. Эти переменные определены в дополнительном производстве как значения по умолчанию. Вы не можете переопределить то, что указано в make-файле, используемом подфайл-make-файлом, если вы не используете ключ `-e ‘.

Чтобы передать или экспортировать переменную, make добавляет переменную и ее значение в среду для выполнения каждой команды. Подзадача, в свою очередь, использует среду для инициализации своей таблицы значений переменных.

Специальные переменные SHELL и MAKEFLAGS всегда экспортируются (если вы не экспортируете их). MAKEFILES экспортируется, если вы установите его на что-либо.

Если вы хотите экспортировать определенные переменные в подкомпонент, используйте директиву экспорта, как показано ниже —

export variable ...

Если вы хотите предотвратить экспорт переменной, воспользуйтесь директивой unsport, как показано ниже:

unexport variable ...

Переменная MAKEFILES

Если переменная окружения MAKEFILES определена, make рассматривает ее значение как список имен (разделенных пробелом) дополнительных make-файлов, которые должны быть прочитаны перед остальными. Это работает так же, как директива include: для поиска этих файлов используются разные каталоги.

Основное использование MAKEFILES — это связь между рекурсивными вызовами make .

Включая заголовочный файл из разных каталогов

Если вы поместили файлы заголовков в разные каталоги и запускаете make в другом каталоге, то необходимо указать путь к файлам заголовков. Это можно сделать с помощью опции -I в make-файле. Если предположить, что файл functions.h находится в папке / home / tutorialspoint / header, а остальные файлы находятся в папке / home / tutorialspoint / src /, то файл makefile будет записан следующим образом:

INCLUDES = -I "/home/tutorialspoint/header"
CC = gcc
LIBS =  -lm
CFLAGS = -g -Wall
OBJ =  main.o factorial.o hello.o

hello: ${OBJ}
   ${CC} ${CFLAGS} ${INCLUDES} -o $@ ${OBJS} ${LIBS}
.cpp.o:
   ${CC} ${CFLAGS} ${INCLUDES} -c $<

Добавление дополнительного текста к переменным

Часто полезно добавить больше текста к значению уже определенной переменной. Вы делаете это со строкой, содержащей `+ = ‘, как показано —

objects += another.o

Он берет значение переменных объектов и добавляет к нему текст «another.o», которому предшествует один пробел, как показано ниже.

objects = main.o hello.o factorial.o
objects += another.o

Приведенный выше код устанавливает объекты в main.o hello.o factorial.o another.o.

Использование `+ = ‘похоже на:

objects = main.o hello.o factorial.o
objects := $(objects) another.o

Строка продолжения в Makefile

Если вам не нравятся слишком большие строки в вашем файле Makefile, вы можете разбить вашу строку, используя обратную косую черту «\», как показано ниже —

OBJ =  main.o factorial.o \
   hello.o

is equivalent to

OBJ =  main.o factorial.o hello.o

Запуск Makefile из командной строки

Если вы подготовили Makefile с именем «Makefile», просто напишите make в командной строке, и он запустит файл Makefile. Но если вы дали другое имя Makefile, используйте следующую команду:

make -f your-makefile-name

Makefile — Пример

Это пример Makefile для компиляции программы hello. Эта программа состоит из трех файлов main.cpp , factorial.cpp и hello.cpp .

# Define required macros here
SHELL = /bin/sh

OBJS =  main.o factorial.o hello.o
CFLAG = -Wall -g
CC = gcc
INCLUDE =
LIBS = -lm

hello:${OBJ}
   ${CC} ${CFLAGS} ${INCLUDES} -o $@ ${OBJS} ${LIBS}

clean:
   -rm -f *.o core *.core

.cpp.o:
   ${CC} ${CFLAGS} ${INCLUDES} -c $<

Теперь вы можете собрать свою программу привет, используя make . Если вы выполните команду make clean, она удалит все объектные файлы и файлы ядра, доступные в текущем каталоге.