Вперед: 2.9. Система управления заданиями на вычислительных кластерах
Назад: 2.8.3. Работа с библиотеками
К содержанию: Оглавление


2.8.4. Утилита make

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

Мощным средством для работы с большими программными комплексами в среде UNIX/Linux является утилита make [25]. Она существенно облегчает перекомпиляцию программы при внесении изменений в отдельные файлы, в тех случаях, когда программа состоит из большого числа файлов. Однако, эта утилита весьма полезна даже в тех случаях, когда программа состоит из одного небольшого файла.

Рассмотрим, как работает команда make на простейшем примере. Предположим, что мы хотим получить бинарную программу test. Если мы наберем команду:

make test ,

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

test <- test.o <- test.c | test.сс | test.f

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

make -p.

Аргументом команды make является цель, которая должна быть достигнута в результате выполнения команды. Если в каталоге имелся файл с программой на языке Фортран, то для достижения цели выполнится последовательность команд:

g77 -c -o test.o test.f
g77 -o test test.o

Трудно, конечно, рассчитывать на то, что команда make корректно сработает без специальных пояснений, если программа состоит из нескольких файлов или требуется подключение каких-либо библиотек. Такие пояснения команда make ищет в файлах makefile или Makefile, причем именно в такой последовательности.

Makefile представляет собой текстовый файл, в котором описаны макроопределения, имеющие вид:

и правила, имеющие вид:

Пример:

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

Синтаксис команды make:

make [-f make-файл] [-p] [-i] [-k] [-s] [-r] [-n] [-b] [-e] [-u] [-t[[целевой_файл ...]]

Команда make обновляет целевой_файл только в том случае, если файлы, от которых он зависит, оказываются новее по времени модификации. Опция -u диктует безусловное обновление.

Обычно Makefile пишется так, чтобы запуск make без аргументов приводил к компиляции проекта, однако, помимо компиляции, Makefile может использоваться и для выполнения других вспомогательных действий, напрямую не связанных с созданием каких-либо файлов. К таким действиям относится очистка проекта от всех результатов компиляции или вызов процедуры инсталляции проекта в системе. Для выполнения подобных действий в Makefile могут быть указаны дополнительные цели, обращение к которым будет осуществляться указанием их имени аргументом вызова make (например, "make clean"). Подобные вспомогательные цели носят название ложных, что связанно с отсутствием в проекте файлов, соответствующих их именам. Ложная цель может содержать список зависимостей и должна содержать список команд для исполнения.

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

Каманда make активно работает с суффиксами имен файлов. Правило создания файла с суффиксом .o из файла с суффиксом .c указывается как раздел с именем .c.o: и пустым списком зависимостей. Команды shell'а, связанные с этим именем, определяют способ получения файла с расширением .o из файла с расширением .c.

Пример:

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

В заключение в качестве примера рассмотрим Makefile, который использовался для компиляции пакета FDMNES.

----------- раздел макроопределений ------------
PROG = fdmnes - определяем имя выходного файла
OBJ = main.o general.o lecture.o clemf0.o dirac.o \
      coabs.o mat.o sphere.o convolution.o spgroup.o \
      metric.o tab_data.o minim.o fprime.o \
      not_mpi.o tensor.o

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

FC = ifort - определяем компилятор
FFLAGS = -O - определяем опции компилятора
LDFLAGS = -O - определяем опции линковщика
LIBS = -lmkl_lapack -lmkl -lguide

определяем переменную LIBS, содержащую список библиотек, которые должны подключаться при сборке программы

----------------- раздел целей ---------------------
all: exe - список главных целей
exe: $(OBJ) - определение цели из списка
    ${FС} ${LDFLAGS} -o $(PROG) ${OBJ} ${LIBS} - команда
clean : - ложная цель (удаление объектных файлов)
    rm -f *.o
.f.o : ; $(FС) -c ${FFLAGS} $*.f - правило получения объектных файлов


Вперед: 2.9. Система управления заданиями на вычислительных кластерах
Назад: 2.8.3. Работа с библиотеками
К содержанию: Оглавление