Поскольку это для Unix, исполняемые файлы не имеют никаких расширений.
Стоит отметить, что root-config
это утилита, которая обеспечивает правильные флаги компиляции и компоновки; и правильные библиотеки для создания приложений против root. Это просто деталь, связанная с первоначальной аудиторией этого документа.
Сделай меня, детка
или ты никогда не забудешь первый раз, когда тебя сделали
Вводное обсуждение make и как написать простой make-файл
Что такое марка? И почему я должен заботиться?
Инструмент под названием Make является менеджером зависимостей сборки. То есть он должен знать, какие команды нужно выполнить и в каком порядке взять ваш программный проект из коллекции исходных файлов, объектных файлов, библиотек, заголовков и т. Д. И т. Д. - некоторые из которых могли измениться недавно --- и превращение их в правильную актуальную версию программы.
На самом деле, вы можете использовать Make и для других вещей, но я не буду об этом говорить.
Тривиальный Makefile
Предположим, что у вас есть каталог, содержащий:, tool
tool.cc
tool.o
support.cc
support.hh
и support.o
который зависит root
и должен быть скомпилирован в вызываемую программу tool
, и предположим, что вы взламывали исходные файлы (что означает, что существующий tool
сейчас устарел) и хотите скомпилируйте программу.
Чтобы сделать это самостоятельно, вы могли бы
Проверьте, является ли один из них support.cc
или support.hh
новее support.o
, и, если это так, выполните команду вроде
g++ -g -c -pthread -I/sw/include/root support.cc
Проверьте, является ли один из них support.hh
или tool.cc
новее tool.o
, и если да, выполните команду
g++ -g -c -pthread -I/sw/include/root tool.cc
Проверьте, tool.o
является ли новее, чем tool
, и если так, выполните команду как
g++ -g tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
Уф! Что за хлопоты! Здесь есть что вспомнить и несколько шансов ошибиться. (Кстати, особенности представленных здесь командных строк зависят от нашей программной среды. Эти работают на моем компьютере.)
Конечно, вы можете просто запустить все три команды каждый раз. Это бы сработало, но оно плохо масштабируется для существенного программного обеспечения (например, DOGS, которое компилируется с нуля на моем MacBook более 15 минут).
Вместо этого вы можете написать файл под названием makefile
так:
tool: tool.o support.o
g++ -g -o tool tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
tool.o: tool.cc support.hh
g++ -g -c -pthread -I/sw/include/root tool.cc
support.o: support.hh support.cc
g++ -g -c -pthread -I/sw/include/root support.cc
и просто введите make
в командной строке. Который выполнит три шага, показанных выше, автоматически.
Здесь строки с отступом имеют форму «target: dependencies» и сообщают Make, что соответствующие команды (строки с отступом) должны выполняться, если какая-либо из зависимостей новее, чем target. То есть строки зависимости описывают логику того, что необходимо перестроить, чтобы учесть изменения в различных файлах. Если support.cc
изменения, это означает, что support.o
должны быть восстановлены, но tool.o
могут быть оставлены в покое. Когда support.o
изменения tool
должны быть перестроены.
Команды, связанные с каждой линией зависимостей, обозначаются вкладкой (см. Ниже), которая должна изменить цель (или, по крайней мере, коснуться ее, чтобы обновить время модификации).
Переменные, встроенные правила и другие полезности
На этом этапе наш make-файл просто запоминает работу, которая должна быть выполнена, но нам все еще приходилось разбираться и вводить все необходимые команды в полном объеме. Так не должно быть: Make - это мощный язык с переменными, функциями манипулирования текстом и целым рядом встроенных правил, которые могут упростить нам задачу.
Сделать переменные
Синтаксис для доступа к переменному гриму является $(VAR)
.
Синтаксис для назначения переменной Make: VAR = A text value of some kind
(или VAR := A different text value but ignore this for the moment
).
Вы можете использовать переменные в правилах, таких как эта улучшенная версия нашего make-файла:
CPPFLAGS=-g -pthread -I/sw/include/root
LDFLAGS=-g
LDLIBS=-L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz \
-Wl,-framework,CoreServices -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root \
-lm -ldl
tool: tool.o support.o
g++ $(LDFLAGS) -o tool tool.o support.o $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
который немного более читабелен, но все же требует много печатать
Сделать функции
GNU make поддерживает множество функций для доступа к информации из файловой системы или других команд в системе. В этом случае мы заинтересованы в том, $(shell ...)
что расширяет к выходу аргумента (ов), и $(subst opat,npat,text)
который заменяет все экземпляры opat
с npat
в тексте.
Воспользовавшись этим, мы получаем:
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
tool: $(OBJS)
g++ $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
который легче набирать и гораздо более читаемый.
Заметь
- Мы по-прежнему явно указываем зависимости для каждого объектного файла и конечного исполняемого файла.
- Нам пришлось явно ввести правило компиляции для обоих исходных файлов
Неявные и шаблонные правила
Как правило, мы ожидаем, что все исходные файлы C ++ должны обрабатываться одинаково, и Make предоставляет три способа заявить это:
- правила суффиксов (считаются устаревшими в GNU make, но сохраняются для обратной совместимости)
- неявные правила
- шаблонные правила
Неявные правила встроены, и некоторые из них будут обсуждаться ниже. Шаблонные правила указываются в виде
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
Это означает, что объектные файлы генерируются из исходных файлов C с помощью показанной команды, где «автоматическая» переменная $<
расширяется до имени первой зависимости.
Встроенные правила
Make имеет целый набор встроенных правил, которые означают, что очень часто проект может быть скомпилирован очень простым make-файлом.
В GNU make встроено правило для исходных файлов на Си, которое показано выше. Точно так же мы создаем объектные файлы из исходных файлов C ++ с правилом вроде $(CXX) -c $(CPPFLAGS) $(CFLAGS)
.
Одиночные объектные файлы связаны с использованием $(LD) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
, но это не будет работать в нашем случае, потому что мы хотим связать несколько объектных файлов.
Переменные, используемые встроенными правилами
Встроенные правила используют набор стандартных переменных, которые позволяют вам указывать информацию о локальной среде (например, где искать включаемые файлы ROOT) без переписывания всех правил. Наиболее вероятными для нас являются:
CC
- использовать компилятор C
CXX
- использовать компилятор C ++
LD
- компоновщик для использования
CFLAGS
- флаг компиляции для исходных файлов C
CXXFLAGS
- флаги компиляции для исходных файлов C ++
CPPFLAGS
- флаги для c-препроцессора (обычно включают пути к файлам и символы, определенные в командной строке), используемые C и C ++
LDFLAGS
- флаги компоновщика
LDLIBS
- библиотеки для ссылки
Основной Makefile
Используя преимущества встроенных правил, мы можем упростить наш make-файл для:
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
tool.o: tool.cc support.hh
support.o: support.hh support.cc
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) tool
Мы также добавили несколько стандартных целей, которые выполняют специальные действия (например, очистка исходного каталога).
Обратите внимание, что когда make вызывается без аргумента, он использует первую цель, найденную в файле (в данном случае все), но вы также можете назвать цель, которую хотите получить, что и делает make clean
удаление объектных файлов в этом случае.
У нас все еще есть жестко запрограммированные зависимости.
Некоторые Таинственные Улучшения
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
depend: .depend
.depend: $(SRCS)
$(RM) ./.depend
$(CXX) $(CPPFLAGS) -MM $^>>./.depend;
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) *~ .depend
include .depend
Заметь
- Для исходных файлов больше нет строк зависимости!?!
- Существует некоторая странная магия, связанная с .depend и зависимость
- Если вы это сделаете,
make
то ls -A
увидите файл с именем, .depend
который содержит вещи, которые выглядят как строки зависимости
Другое Чтение
Знайте ошибки и исторические заметки
Язык ввода для Make чувствителен к пробелам. В частности, строки действий, следующие за зависимостями, должны начинаться с вкладки . Но ряд пробелов может выглядеть одинаково (и действительно есть редакторы, которые будут молча преобразовывать вкладки в пробелы или наоборот), что приводит к тому, что файл Make выглядит правильно и все еще не работает. Это было определено как ошибка на ранней стадии, но ( история продолжается ) это не было исправлено, потому что уже было 10 пользователей.
(Это было скопировано с поста вики, который я написал для аспирантов по физике.)