Як зробити простий C ++ Makefile


302

Нам потрібно використовувати Makefile, щоб зібрати все разом для нашого проекту, але наш професор так і не показав нам, як це робити.

У мене є тільки один файл, a3driver.cpp. Водій імпортує клас з місця, "/user/cse232/Examples/example32.sequence.cpp".

Це воно. Все інше міститься в .cpp.

Як би я міг створити простий Makefile, який створює виконуваний файл під назвою a3a.exe?


9
.EXE так, безумовно, Windows. По другій думці ... шлях у стилі Unix. Можливо, використовуючи Mingw-32.
Натан Осман

2
Зітхнути. Я припускаю, що ви повинні вивчити основи кожної торгівлі, навіть якщо ви ніколи не будете ними користуватися. Просто треба зрозуміти, як працює матеріал. Хоча ймовірно, що ви завжди будете розвиватися в IDE, як Eclipse. Тут ви отримаєте відповідь на ваш простий однолінійний випадок, і є багато навчальних посібників в Інтернеті, але якщо ви хочете отримати глибокі знання, ви не можете перемогти книгу O'reilly (те саме для більшості с / ш тем). amazon.com/Managing-Projects-Make-Nutshell-Handbooks/dp/… Виберіть копію 2-ї руки з amazon, half.com, bestworldbooks eBay
Mawg каже відновити Моніку

2
Посилання, розміщене @Dennis, тепер мертве, але той самий матеріал можна знайти на цій сторінці archive.org .
Гільгерме Саломе

Я віддаю перевагу ідеям цієї людини. ( hiltmon.com/blog/2013/07/03/… ) Структуру проекту можна легко змінити відповідно до потреб . І я також погоджуюся, що час розробника повинен витрачатися на інші речі, ніж автоматизація / autoconf. Ці інструменти мають своє місце, але, можливо, не для внутрішніх проектів. Я будую сценарій, який створить таку структуру проекту.
Дайсуке Арамакі

@ GuilhermeSalomé Спасибі, я вважаю, що це найкращий простий і повний підручник.
Hareen Laks

Відповіді:


559

Оскільки це для Unix, виконувані файли не мають розширень.

Варто зазначити, що root-configце утиліта, яка забезпечує правильну компіляцію та зв'язування прапорів; і потрібні бібліотеки для побудови програм проти root. Це лише деталь, пов’язана з оригінальною аудиторією цього документа.

Зроби мене дитиною

або ти ніколи не забув перший раз, коли ти зробив

Вступне обговорення make і як написати простий makefile

Що таке Make? І чому я повинен дбати?

Інструмент під назвою Make - це менеджер залежності побудови. Тобто потрібно піклуватися про те, які команди потрібно виконати, в якому порядку брати ваш програмний проект із колекції вихідних файлів, об’єктних файлів, бібліотек, заголовків тощо тощо - - деякі з яких можуть бути змінені останнім часом --- і перетворення їх у правильну оновлену версію програми.

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

Тривіальний Makefile

Припустимо, у вас є каталог, що містить: tool tool.cc tool.o support.cc support.hhі support.oякий залежить від rootі повинен бути скомпільований у програму під назвою tool, і припустимо, що ви зламали вихідні файли (це означає, що існуючі toolзараз застаріли) і хочете скласти програму.

Зробити це самостійно ти міг

  1. Перевірте, support.ccчи support.hhє, чи новіше support.o, і якщо так, виконайте команду типу

    g++ -g -c -pthread -I/sw/include/root support.cc
  2. Перевірте, support.hhчи tool.ccє, чи новіші tool.o, і якщо так, виконайте команду типу

    g++ -g  -c -pthread -I/sw/include/root tool.cc
  3. Перевірте, чи 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

який легше набирати та набагато легше читати.

Зауважте це

  1. Ми все ще прямо заявляємо залежності для кожного об'єктного файлу та остаточного виконуваного файлу
  2. Нам потрібно було чітко ввести правило компіляції для обох вихідних файлів

Неявні та шаблонні правила

Як правило, ми очікуємо, що всі файли вихідних файлів C ++ повинні трактуватися однаково, і Make надає три способи констатувати це:

  1. правила суфікса (вважаються застарілими в GNU make, але зберігаються для зворотної сумісності)
  2. неявні правила
  3. правила шаблону

Неявні правила вбудовані, і деякі з них будуть розглянуті нижче. Правила візерунка задаються у формі

%.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

Зауважте це

  1. Більше не існує рядків залежності для вихідних файлів!?!
  2. Існує якась дивна магія, пов’язана з .depend і залежить
  3. Якщо ви робите , makeто ls -Aви побачите файл з ім'ям , .dependякий містить речі , які виглядають як лінії залежностей замикаючих

Інше читання

Знайте помилок та історичні записки

Мова введення для Make є чутливою до пробілу. Зокрема, рядки дій, які відповідають залежностям, повинні починатися з вкладки . Але ряд пробілів може виглядати однаково (і справді є редактори, які мовчки перетворять вкладки в пробіли або навпаки), в результаті чого файл Make виглядає правильно і все ще не працює. Це було визначено як помилка на початку, але ( розповідь іде ), це не було виправлено, оскільки вже було 10 користувачів.

(Це було скопійовано з публікації у вікі, яку я написав для аспірантів з фізики.)


9
Цей метод породження залежностей застарілий і фактично шкідливий. Див. Розширене покоління автоматичної залежності .
Максим Єгорушкін

5
-pthreadпрапор викликає gccвизначення необхідних макросів, -D_REENTRANTзайвий.
Максим Єгорушкін

8
@jcoe Це зайвий додатковий перепроцесорний прохід для генерування залежностей. Виконуючи непотрібну роботу, вона просто розсіює тепло, тане льодові полюси, і в більшому масштабі наближається до теплової смерті нашого Всесвіту.
Максим Єгорушкін

2
Напевно, "шкідливим" є занадто багато, але враховуючи, що явні фази або цілі породження залежностей застаріли, оскільки, як мінімум, GCC 3, я дійсно думаю, що всі ми повинні пройти повз них. bruno.defraine.net/techtips/makefile-auto-dependitions-with-gcc/…
hmijail сумує у відставці

2
Дійсно, прийнята відповідь не повинна залежати від дуже конкретного програмного забезпечення ( root-config). Більш загальну альтернативу з такою ж можливістю слід запропонувати, якщо така є, або вона повинна бути просто опущена. Я не відмовився від переліку та пояснення найбільш часто використовуваних макросів.
зелений діод

56

Я завжди думав, що це було легше дізнатися на детальному прикладі, тож ось, як я думаю про makefiles. Для кожного розділу ви маєте один рядок, який не є відступним, і він показує назву розділу, за яким слід залежність. Залежності можуть бути або іншими розділами (які будуть запущені до поточного розділу), або файлами (які, якщо оновлено, спричинить повторний запуск поточного розділу під час наступного запускуmake ).

Ось короткий приклад (майте на увазі, що я використовую 4 пробіли, де я повинен використовувати вкладку. Переповнення стека не дозволяє мені використовувати вкладки):

a3driver: a3driver.o
    g++ -o a3driver a3driver.o

a3driver.o: a3driver.cpp
    g++ -c a3driver.cpp

Коли ви вводите текст make , він вибере перший розділ (a3driver). a3driver залежить від a3driver.o, тому він перейде до цього розділу. a3driver.o залежить від a3driver.cpp, тому він запускатиметься лише в тому випадку, якщо a3driver.cpp змінився з моменту останнього запуску. Якщо припустити, що він (або ніколи не був запущений), він скомпілює a3driver.cpp у файл .o, потім повернеться до a3driver і складе остаточний виконуваний файл.

Оскільки є лише один файл, його можна навіть зменшити до:

a3driver: a3driver.cpp
    g++ -o a3driver a3driver.cpp

Причиною, що я показав перший приклад, є те, що він показує силу гри. Якщо вам потрібно зібрати інший файл, ви можете просто додати ще один розділ. Ось приклад із secondFile.cpp (який завантажується у заголовку під назвою secondFile.h):

a3driver: a3driver.o secondFile.o
    g++ -o a3driver a3driver.o secondFile.o

a3driver.o: a3driver.cpp
    g++ -c a3driver.cpp

secondFile.o: secondFile.cpp secondFile.h
    g++ -c secondFile.cpp

Таким чином, якщо ви щось зміните в secondFile.cpp або secondFile.h та перекомпілюйте, він лише перекомпілює secondFile.cpp (не a3driver.cpp). Або по черзі, якщо ви щось зміните в a3driver.cpp, воно не перекомпілює secondFile.cpp.

Повідомте мене, якщо у вас є якісь питання.

Також традиційно включати розділ під назвою "все" та розділ з назвою "чисто". "all", як правило, збирає всі виконувані файли, а "clean" видаляє "збирає артефакти", такі як .o файли та виконувані файли:

all: a3driver ;

clean:
    # -f so this will succeed even if the files don't exist
    rm -f a3driver a3driver.o

EDIT: Я не помітив, що ви в Windows. Я думаю, що єдиною різницею є зміна -o a3driverна -o a3driver.exe.


Абсолютний код, який я намагаюся використовувати, це: p4a.exe: p4driver.cpp g ++ -o p4a p4driver.cpp АЛЕ, він каже мені "пропущений роздільник". Я використовую TAB, але він все ще говорить про це. Будь-яка ідея?
Припадає

2
Наскільки я можу сказати, це повідомлення про помилку з’являється лише в тому випадку, якщо у вас є пробіли. Переконайтеся, що у вас немає жодних рядків, починаючи з пробілів (пробіл + вкладка видасть цю помилку). Це єдине, про що я можу придумати ..
Брендан Довгий

Примітка майбутнім редакторам: StackOverflow не може відображати вкладки, навіть якщо ви редагуєте їх у відповідь, тому, будь ласка, не намагайтеся "виправити" мою замітку про це.
Брендан Лонг

35

Чому всі люблять перелічувати вихідні файли? Проста команда знаходження може легко перейнятися цим.

Ось приклад брудового простого C ++ Makefile. Просто опустіть його в каталог, що містить .Cфайли, а потім введіть make...

appname := myapp

CXX := clang++
CXXFLAGS := -std=c++11

srcfiles := $(shell find . -name "*.C")
objects  := $(patsubst %.C, %.o, $(srcfiles))

all: $(appname)

$(appname): $(objects)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)

depend: .depend

.depend: $(srcfiles)
    rm -f ./.depend
    $(CXX) $(CXXFLAGS) -MM $^>>./.depend;

clean:
    rm -f $(objects)

dist-clean: clean
    rm -f *~ .depend

include .depend

2
Причиною не автоматично знаходити вихідні файли є те, що у кожного можуть бути різні цілі побудови, які потребують різних файлів.
hmijail сумує у відставці

Погоджено @hmijail, а також підмодулі, які містять безліч джерел / заголовків, які ви не хочете складати / пов’язувати ... та, безсумнівно, багато інших обставин, коли вичерпний пошук / використання не підходить.
Інженер

Навіщо використовувати "shell find", а не "wildcard"?
Нолан

1
@Nolan знайти вихідні файли у дереві каталогів джерел
AlejandroVD

13

У вас було два варіанти.

Варіант 1: найпростіший makefile = NO MAKEFILE.

Перейменуйте "a3driver.cpp" на "a3a.cpp", а потім у командному рядку напишіть:

nmake a3a.exe

І це все. Якщо ви використовуєте GNU Make, використовуйте "make" або "gmake" або інше.

Варіант 2: дворядковий файловий файл.

a3a.exe: a3driver.obj
    link /out:a3a.exe a3driver.obj

3
Це було б чудовою відповіддю, якби вона не передбачала так багато речей щодо деталей оточення ОП. Так, вони є в Windows, але це не означає, що вони використовуються nmake. linkКомандний рядок також виглядає дуже специфічною для конкретного компілятора, і повинна в самому крайньому випадку документа , в якому один.
трійчатка

6

Ваш файл Make матиме одне або два правила залежності, залежно від того, компілюєте ви та зв'язуєтесь з однією командою, або з однією командою для компіляції та однією для посилання.

Залежність - це дерево правил, яке виглядає приблизно так (зауважте, що в відступі має бути таблиця TAB):

main_target : source1 source2 etc
    command to build main_target from sources

source1 : dependents for source1
    command to build source1

Там повинна бути порожній рядок після того, як команди для мети, і повинен НЕ бути символом нового рядка перед командами. Перша мета в makefile є загальною метою, а інші цілі будуються лише в тому випадку, якщо перша ціль залежить від них.

Тож ваш makefile буде виглядати приблизно так.

a3a.exe : a3driver.obj 
    link /out:a3a.exe a3driver.obj

a3driver.obj : a3driver.cpp
    cc a3driver.cpp

6

Я пропоную (зауважте, що відступ - це таблиця TAB):

tool: tool.o file1.o file2.o
    $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@

або

LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
tool: tool.o file1.o file2.o

Остання пропозиція трохи краща, оскільки вона повторно використовує GNU Make неявні правила. Однак для роботи вихідний файл повинен мати те саме ім'я, що і остаточний виконуваний файл (тобто: tool.cі tool).

Зауважте, не потрібно декларувати джерела. Проміжні файли об'єктів генеруються за допомогою неявного правила. Отже, ця Makefileробота для C і C ++ (а також для Fortran тощо).

Також зауважте, що за замовчуванням Makefile використовується $(CC)як посилання. $(CC)не працює для посилання об'єктних файлів C ++. Ми змінюємо LINK.oлише через це. Якщо ви хочете скласти код C, вам не доведеться форсувати LINK.oзначення.

Звичайно, ви також можете додати ваші компіляційні прапори зі змінною CFLAGSта додати свої бібліотеки LDLIBS. Наприклад:

CFLAGS = -Wall
LDLIBS = -lm

Одна сторона: якщо вам доведеться використовувати зовнішні бібліотеки, я пропоную використовувати pkg-config , щоб правильно встановити CFLAGSта LDLIBS:

CFLAGS += $(shell pkg-config --cflags libssl)
LDLIBS += $(shell pkg-config --libs libssl)

Уважний читач помітить, що це Makefileне відбудується належним чином, якщо змінено один заголовок. Додайте ці рядки, щоб вирішити проблему:

override CPPFLAGS += -MMD
include $(wildcard *.d)

-MMDдозволяє будувати .d файли, що містять фрагменти Makefile про залежності заголовків. Другий рядок просто використовує їх.

Напевно, добре написаний Makefile також повинен містити cleanі distcleanправила:

clean:
    $(RM) *.o *.d

distclean: clean
    $(RM) tool

Зауважте, $(RM)це еквівалент rm -f, але не варто телефонуватиrm безпосередньо .

allПравило також цінується. Для роботи це має бути першим правилом вашого файлу:

all: tool

Ви також можете додати installправило:

PREFIX = /usr/local
install:
    install -m 755 tool $(DESTDIR)$(PREFIX)/bin

DESTDIRза замовчуванням порожній. Користувач може встановити його для встановлення вашої програми в альтернативній системі (обов’язково для перехресної компіляції). Обслуговувачі пакунків для багаторазового розповсюдження можуть також змінюватися PREFIXдля встановлення вашого пакета/usr .

Одне заключне слово: не розміщуйте вихідні файли у підкаталогах. Якщо ви дійсно хочете це зробити, збережіть це Makefileу кореневому каталозі та використовуйте повні шляхи для ідентифікації своїх файлів (тобтоsubdir/file.o ).

Отже, підсумовуючи, ваш повний Makefile повинен виглядати так:

LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
PREFIX = /usr/local
override CPPFLAGS += -MMD
include $(wildcard *.d)

all: tool
tool: tool.o file1.o file2.o
clean:
    $(RM) *.o *.d
distclean: clean
    $(RM) tool
install:
    install -m 755 tool $(DESTDIR)$(PREFIX)/bin

Під кінець: Чи не повинно бути порожніх рядків між правилами? Відповідь Джона Кноллера стверджувала це.
Пітер Мортенсен

Жодна реалізація того, makeщо я знаю (GNU Make і BSD Make), не потребує порожніх рядків між правилами. Однак існує багато makeреалізацій із власними помилками ^ Wspecificities.
Jérôme Pouiller

5

Я використав відповідь Фрідмуда . Я деякий час переглядав це, і, здається, це хороший спосіб почати. Це рішення також має чітко визначений метод додавання прапорів компілятора. Я відповів ще раз, бо вніс зміни, щоб він працював у моєму середовищі, Ubuntu та g ++. Інші робочі приклади - найкращий вчитель, іноді.

appname := myapp

CXX := g++
CXXFLAGS := -Wall -g

srcfiles := $(shell find . -maxdepth 1 -name "*.cpp")
objects  := $(patsubst %.cpp, %.o, $(srcfiles))

all: $(appname)

$(appname): $(objects)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)

depend: .depend

.depend: $(srcfiles)
    rm -f ./.depend
    $(CXX) $(CXXFLAGS) -MM $^>>./.depend;

clean:
    rm -f $(objects)

dist-clean: clean
    rm -f *~ .depend

include .depend

Макіяжі видаються дуже складними. Я використовував один, але він генерував помилку, пов’язану з тим, що не зв’язувати бібліотеки g ++. Ця конфігурація вирішила цю проблему.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.