Оскільки це для Unix, виконувані файли не мають розширень.
Варто зазначити, що root-config
це утиліта, яка забезпечує правильну компіляцію та зв'язування прапорів; і потрібні бібліотеки для побудови програм проти root. Це лише деталь, пов’язана з оригінальною аудиторією цього документа.
Зроби мене дитиною
або ти ніколи не забув перший раз, коли ти зробив
Вступне обговорення make і як написати простий makefile
Що таке 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
Фу! Що за клопоти! Є багато що запам'ятати і кілька шансів помилитися. (BTW - деталі викладених тут командних рядків залежать від нашого програмного середовища. Вони працюють на моєму комп'ютері.)
Звичайно, ви могли просто виконувати всі три команди кожен раз. Це спрацювало б, але воно не підходить до значної частини програмного забезпечення (наприклад, DOGS, на який потрібно збирати більше 15 хвилин з мого MacBook).
Замість цього ви можете написати файл, який називається 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
у командному рядку. Який виконає три етапи, показані вище автоматично.
Тут нерозрізнені рядки мають вигляд "ціль: залежності" і повідомляють Зробити, що пов'язані команди (відступні рядки) повинні бути запущені, якщо будь-яка із залежностей новіша від цілі. Тобто рядки залежностей описують логіку того, що потрібно перебудувати для розміщення змін у різних файлах. Якщо support.cc
зміни, це означає, що їх support.o
треба перебудувати, але tool.o
їх можна залишити в спокої. Коли support.o
зміни tool
повинні бути відновлені.
Команди, пов'язані з кожним рядком залежності, зміщені вкладкою (див. Нижче), повинні змінювати ціль (або принаймні торкатися її, щоб оновити час модифікації).
Змінні, вбудовані правила та інші смаколики
На даний момент наш makefile просто запам'ятовує роботу, яку потрібно виконати, але нам все-таки потрібно було розібратися і набрати кожну необхідну команду в цілому. Це не повинно бути таким чином: Make - це потужна мова зі змінними, функціями маніпулювання текстом та цілим рядом вбудованих правил, які можуть зробити це нам набагато простіше.
Складіть змінні
Синтаксис доступу до змінної make є $(VAR)
.
Синтаксис для призначення змінної Make є: VAR = A text value of some kind
(або VAR := A different text value but ignore this for the moment
).
Ви можете використовувати змінні в таких правилах, як вдосконалена версія нашого файлу:
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 є ціла низка вбудованих правил, які означають, що дуже часто проект може бути складений дуже простим makefile.
Вбудоване правило GNU для вихідних файлів C - це те, що було показано вище. Аналогічно ми створюємо об’єктні файли з вихідних файлів 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
Користуючись вбудованими правилами, ми можемо спростити наш makefile до:
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 користувачів.
(Це було скопійовано з публікації у вікі, яку я написав для аспірантів з фізики.)