Как сделать SIMPLE C ++ Makefile

303

Мы должны использовать Makefile, чтобы собрать все вместе для нашего проекта, но наш профессор никогда не показывал нам, как это сделать.

У меня есть только один файл a3driver.cpp. Драйвер импортирует класс из местоположения "/user/cse232/Examples/example32.sequence.cpp".

Вот и все. Все остальное содержится в .cpp.

Как бы я сделал простой Makefile для создания исполняемого файла с именем a3a.exe?

случаться
источник
9
.EXE, так что это определенно Windows. Если подумать ... путь в стиле Unix. Вероятно, с помощью Mingw-32.
Натан Осман
2
Вздох. Я полагаю, вы должны изучить основы каждой сделки, даже если вы никогда не будете их использовать. Просто нужно понять, как все работает. Впрочем, есть вероятность, что вы всегда будете развиваться в IDE, например, в Eclipse. Вы получите ответ здесь для своего простого однострочного случая, и есть множество веб-уроков, но если вы хотите углубиться в знания, вы не сможете превзойти книгу О'рейли (то же самое для большинства программ). amazon.com/Managing-Projects-Make-Nutshell-Handbooks/dp/… Возьмите вторую копию с сайта amazon, half.com, betterworldbooks eBay
Моуг говорит восстановить Монику
2
Ссылка, размещенная @Dennis, теперь мертва, но этот же материал можно найти на этой странице archive.org .
Гильерме Саломе
Я предпочитаю идеи этого человека. ( hiltmon.com/blog/2013/07/03/… ) Структура проекта может быть легко изменена в соответствии с требованиями. И я также согласен, что время разработчика должно быть потрачено на другие вещи, кроме automake / autoconf. Эти инструменты имеют свое место, но, возможно, не для внутренних проектов. Я строю сценарий, который будет производить такую ​​структуру проекта.
Дайсуке Арамаки
@ GuilhermeSalomé Спасибо, я считаю, что это лучший простой и полный учебник.
Харин Лакс

Ответы:

562

Поскольку это для Unix, исполняемые файлы не имеют никаких расширений.

Стоит отметить, что root-configэто утилита, которая обеспечивает правильные флаги компиляции и компоновки; и правильные библиотеки для создания приложений против root. Это просто деталь, связанная с первоначальной аудиторией этого документа.

Сделай меня, детка

или ты никогда не забудешь первый раз, когда тебя сделали

Вводное обсуждение make и как написать простой 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
    

Уф! Что за хлопоты! Здесь есть что вспомнить и несколько шансов ошибиться. (Кстати, особенности представленных здесь командных строк зависят от нашей программной среды. Эти работают на моем компьютере.)

Конечно, вы можете просто запустить все три команды каждый раз. Это бы сработало, но оно плохо масштабируется для существенного программного обеспечения (например, 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

который легче набирать и гораздо более читаемый.

Заметь

  1. Мы по-прежнему явно указываем зависимости для каждого объектного файла и конечного исполняемого файла.
  2. Нам пришлось явно ввести правило компиляции для обоих исходных файлов

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

Как правило, мы ожидаем, что все исходные файлы C ++ должны обрабатываться одинаково, и Make предоставляет три способа заявить это:

  1. правила суффиксов (считаются устаревшими в GNU make, но сохраняются для обратной совместимости)
  2. неявные правила
  3. шаблонные правила

Неявные правила встроены, и некоторые из них будут обсуждаться ниже. Шаблонные правила указываются в виде

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

Заметь

  1. Для исходных файлов больше нет строк зависимости!?!
  2. Существует некоторая странная магия, связанная с .depend и зависимость
  3. Если вы это сделаете, makeто ls -Aувидите файл с именем, .dependкоторый содержит вещи, которые выглядят как строки зависимости

Другое Чтение

Знайте ошибки и исторические заметки

Язык ввода для Make чувствителен к пробелам. В частности, строки действий, следующие за зависимостями, должны начинаться с вкладки . Но ряд пробелов может выглядеть одинаково (и действительно есть редакторы, которые будут молча преобразовывать вкладки в пробелы или наоборот), что приводит к тому, что файл Make выглядит правильно и все еще не работает. Это было определено как ошибка на ранней стадии, но ( история продолжается ) это не было исправлено, потому что уже было 10 пользователей.

(Это было скопировано с поста вики, который я написал для аспирантов по физике.)

dmckee --- котенок экс-модератора
источник
9
Этот метод генерации зависимостей устарел и действительно вреден. См. Advanced Auto-Dependency Generation .
Максим Егорушкин
5
-pthreadФлаг, заставляющий gccопределять необходимые макросы, -D_REENTRANTне нужен.
Максим Егорушкин
8
@jcoe Это делает ненужный дополнительный проход препроцессора для генерации зависимостей. Выполняя ненужную работу, он просто рассеивает тепло, таящее ледяные столбы, и в большем масштабе приближается к тепловой смерти нашей вселенной.
Максим Егорушкин
2
Возможно, «вредно» - это слишком много, но, учитывая, что явные фазы или цели генерации зависимостей устарели, так как, по крайней мере, GCC 3, я действительно думаю, что мы все должны пройти мимо них. bruno.defraine.net/techtips/makefile-auto-dependencies-with-gcc/…
hmijail скорбит в отставку
2
Действительно, принятый ответ не должен зависеть от очень специфического программного обеспечения ( root-config). Должна быть предложена более общая альтернатива с той же способностью, если таковая имеется, или ее следует просто исключить. Я не понизил голосование из-за перечисления и объяснения наиболее часто используемых макросов make.
зеленый диод
56

Я всегда думал, что это было легче изучить на подробном примере, так что вот как я думаю о make-файлах. Для каждого раздела у вас есть одна строка, которая не имеет отступа, и показывает название раздела, за которым следуют зависимости. Зависимости могут быть либо другими разделами (которые будут выполняться до текущего раздела), либо файлами (которые при обновлении приведут к повторному запуску текущего раздела при следующем запуске 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

Причина, по которой я показал первый пример, заключается в том, что он показывает силу make-файлов. Если вам нужно скомпилировать другой файл, вы можете просто добавить другой раздел. Вот пример с 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». «all» обычно собирает все исполняемые файлы, а «clean» удаляет «артефакты сборки», такие как файлы .o и исполняемые файлы:

all: a3driver ;

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

РЕДАКТИРОВАТЬ: я не заметил, что вы на Windows. Я думаю , что единственное различие изменяя -o a3driverк -o a3driver.exe.

Брендан Лонг
источник
Абсолютный код, который я пытаюсь использовать: p4a.exe: p4driver.cpp g ++ -o p4a p4driver.cpp, НО, он говорит мне об отсутствии разделителя. Я использую TAB, но он все еще говорит мне об этом. Любая идея?
Станьте
2
Насколько я могу судить, это сообщение об ошибке появляется только при наличии пробелов. Убедитесь, что у вас нет строк, начинающихся с пробелов (пробел + tab выдаст эту ошибку). Это единственное, о чем я могу думать ...
Брендан Лонг
Примечание для будущих редакторов: 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
friedmud
источник
2
Причина, по которой не нужно автоматически находить исходные файлы, заключается в том, что для разных целей могут потребоваться разные файлы.
hmijail скорбит по отставке
Согласованный @hmijail, а также подмодули, которые содержат массу источников / заголовков, которые вы не хотите компилировать / связывать ... и, несомненно, многие другие обстоятельства, когда исчерпывающий поиск / использование не подходит.
инженер
Почему вместо этого использовать «поиск оболочки», а не «подстановочный знак»?
Нолан
1
@Nolan, чтобы найти исходные файлы в дереве каталогов исходного кода
AlejandroVD
13

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

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

Переименуйте «a3driver.cpp» в «a3a.cpp», а затем в командной строке напишите:

nmake a3a.exe

И это все. Если вы используете GNU Make, используйте «make», «gmake» или что-то еще.

Вариант 2: 2-строчный make-файл.

a3a.exe: a3driver.obj
    link /out:a3a.exe a3driver.obj
Ни один. Никто
источник
3
Это был бы превосходный ответ, если бы он не предполагал так много вещей о деталях окружающей среды ОП. Да, они на Windows, но это не значит, что они используют nmake. linkКомандная строка также выглядит очень специфичной для конкретного компилятора, и должна в самом крайнем случае документа , в котором один.
tripleee
6

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

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

main_target : source1 source2 etc
    command to build main_target from sources

source1 : dependents for source1
    command to build source1

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

Так что ваш make-файл будет выглядеть примерно так.

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реализаций со своими собственными ошибками.
Жером Пуйлер
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

Makefiles кажутся очень сложными. Я использовал один, но он генерировал ошибку, связанную с отсутствием связи в библиотеках g ++. Эта конфигурация решила эту проблему.

VectorVortec
источник