Команда make

Команда make позволяет задействовать одноименную утилиту, предназначенную для компиляции программного обеспечения из исходных кодов. Данная команда востребована главным образом программистами и системными администраторами, но может оказаться полезной и для обычных пользователей, желающих собрать то или иное программное обеспечение из исходных кодов вместо установки бинарных пакетов. Рассматриваемая утилита использует файлы описания целей сборки под названием Makefile и автоматически создает список файлов исходного кода, которые должны быть скомпилированы, экономя тем самым время программистов, постоянно модифицирующих исходный код своих продуктов. Поддерживаются любые компиляторы, которые могут запускаться с помощью терминала, причем в рамках файлов описания целей сборки могут описываться цели, предназначенные для установки ПО (обычно называются «install») и очистки окружения сборки (обычно называются «clean»). Нередко файлы Makefile генерируются автоматически, причем в таких случаях перед компиляцией ПО необходимо исполнять сценарий командной оболочки configure.sh, осуществляющий их генерацию и настройку сборочного окружения.

Базовый синтаксис команды выглядит следующим образом:

$ make [параметры] [цель] ...

Команда принимает названия целей в качестве аргументов, причем в случае отсутствия названия цели считается, что нужно использовать цель «all», обычно включающую все остальные цели. Для описания целей используются специальные файлы с именами Makefile, причем данные файлы имеют достаточно строгий синтаксис (к примеру, в них запрещается смешивать символы табуляции и пробела). Что касается параметров, то наиболее важными являются параметр -f для указания нестандартного имени файла описания целей, параметр -C для смены директории перед сборкой ПО, параметр -d для вывода отладочных сообщений, параметр -e для изменения переменных окружения, а также параметр -B для безусловной сборки всех целей.

Примеры использования

В качестве примера будет использоваться примитивная программа на языке C, выводящая сообщение «It works!». Она будет состоять из трех файлов исходного кода и файла с описанием целей сборки. Файл с описанием целей сборки создан вручную и не требует предварительной конфигурации.

Содержимое файла main.c:

#include <stdio.h>
#include <stdlib.h>

#include "core.h"

int main(int argc, char **argv)
{
    core();
    return 0;
}

Содержимое файла core.h:

#ifndef _CORE_H_
#define _CORE_H_

void core(void);

#endif

Содержимое файла core.c:

#include <stdio.h>
#include <stdlib.h>

void core(void)
{
    printf("It works!n");
}

Содержимое файла Makefile:

GCC = gcc -g -Wall
OBJ = core.o main.o

all: test

test: $(OBJ)
    $(GCC) $(LDFLAGS) $(OBJ) -o test

.c.o:
    $(GCC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@

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

Сборка программы из исходных кодов

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

$ make
gcc -g -Wall -c core.c -o core.o
gcc -g -Wall -c main.c -o main.o
gcc -g -Wall core.o main.o -o test
$ ./test
It works!

Очевидно, что программа была собрана и корректно функционирует.

Сборка программы с отладкой системы сборки

Если вы желаете отладить систему сборки, вы можете использовать параметр -d команды make:

$ make -d
GNU Make 4.3
Эта программа собрана для x86_64-pc-linux-gnu
Copyright (C) 1988-2020 Free Software Foundation, Inc.
Лицензия GPLv3+: GNU GPL версии 3 или новее <http://gnu.org/licenses/gpl.html>
Это свободное программное обеспечение: вы можете свободно изменять его и
распространять. НЕТ НИКАКИХ ГАРАНТИЙ вне пределов, допустимых законом.
Чтение make-файлов...
Чтение make-файла «Makefile»...
Обновление make-файлов....
Обработка целевого файла «Makefile».
Поиск неявного правила для «Makefile».
Попытка применения правила с образцом «Makefile».
Попытка применения неявной зависимости «Makefile.o».
Попытка применения правила с образцом «Makefile».
Попытка применения неявной зависимости «Makefile.c».
...
Целевой файл «test» успешно пересоздан.
Обновление целей, от которых зависит целевой файл «all», завершено.
Необходимо пересобрать цель «all».
Целевой файл «all» успешно пересоздан.
$ ./test
It works!

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

Сборка отдельных целей

Для сборки отдельной цели следует передать названием этой цели команде make. В нашем случае подходящей целью является цель с названием «test»:

$ make test
gcc -g -Wall -c core.c -o core.o
gcc -g -Wall -c main.c -o main.o
gcc -g -Wall core.o main.o -o test
$ ./test
It works!

И снова программа успешно собрана, причем в нашем случае цель «all» автоматически подразумевает сборку цели «test», поэтому никаких отличий с использованием команды make без параметров не будет наблюдаться.

Для очистки рабочего окружения следует инициировать сборку цели «clean»:

$ make clean
rm -f *.o
rm -f test

В результате будут удалены объектные файлы и результирующий исполняемый файл программы.

Сборка программы в заданной директории

Для сборки программы в заданной директории следует использовать параметр -C и путь к этой директории. Для демонстрации перейдем в директорию на уровень выше и попробуем пересобрать программу.

$ cd ..
$ make -C ./test/
make: вход в каталог «/home/alex/code/test»
gcc -g -Wall -c core.c -o core.o
gcc -g -Wall -c main.c -o main.o
gcc -g -Wall core.o main.o -o test
make: выход из каталога «/home/alex/code/test»
$ ./test/test
It works!

Разумеется, и в этом случае программа была успешно собрана.

Сборка программы с нестандартным именем файла описания целей сборки

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

$ mv Makefile Makefile.gcc
$ make
make: *** Не заданы цели и не найден make-файл. Останов.

И в этом случае сборка не будет представлять каких-либо сложностей:

$ make -f Makefile.gcc
gcc -g -Wall -c core.c -o core.o
gcc -g -Wall -c main.c -o main.o
gcc -g -Wall core.o main.o -o test
$ ./test
It works!

Таким образом вы можете использовать несколько файлов описания целей сборки в рамках одного проекта.