Makefile: нет правила для создания цели

Я искал решение на этом сайте, а также попробовал Google уже некоторое время, но почему-то я не могу заставить его работать.

Мой источник должен находиться в каталоге src, а объектные файлы будут находиться в каталоге obj. Теперь я пытаюсь создать простую makefie, но я либо получаю сообщение об ошибке, что нет правила, либо я не могу заставить его работать с каталогами.

CC = /usr/bin/gcc CXXFLAGS = -O2 -g -Wall -fmessage-length=0 SRC:= nohupshd.cpp \ task.cpp OBJ:= nohupshd.o \ task.o OBJDIR:= obj SRCDIR:= src DEP:= src/task.h LIBS:= TARGET:= nohupshd all: $(TARGET) $(TARGET): $(OBJ) $(CC) -o $(TARGET) $(OBJ) $(LIBS) clean: rm -f $(OBJ) $(TARGET) 

Вариант 1:

 $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$@ $(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$@ 

Вариант 1a:

 %.o: %.cpp $(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$@ $(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$@ 

Когда я использую этот шаблон, я всегда получаю сообщение об ошибке, что для nohupshd.o не существует правила.

Вариант 2:

 $(OBJ) : $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$@ $(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$@ 

Когда я использую этот вариант, я вижу, что он пытается построить, но я получаю ошибки, говоря, что «файл» .o не соответствует целевому шаблону.

Другая проблема заключается в том, что «$ <» не дает мне имя источника. По нескольким сайтам это должно быть, но я могу видеть на выходе, что ничего нет, так как я могу это исправить?

Обновить:

Тем временем моя новейшая версия выглядит так:

 $(OBJDIR)/$(OBJ) : $(OBJDIR)/%.o : $(SRCDIR)/%.cpp $(CC) -S $< -o $(OBJDIR)/`basename $@ .o`.asm $(CC) -c $< -o $@ 

Теперь это удается скомпилировать первый объектный файл (nohupshd.o), но когда make пытается сделать второй файл, он снова сработает, говоря: target ‘task.o’ не соответствует шаблону.

У вас на самом деле есть пара, если неправильно указано выше.

Сначала вы пишете Моя ошибка была, что я предполагал, что шаблон% .o соответствует любому шаблону, заканчивающемуся на .o, которого нет ; это не правда. Шаблон соответствует любой строке, заканчивающейся на .o . Однако символ шаблона % который сопоставляется с целевой стороной, заменяется на стороне предпосылки идентичной строкой. Поэтому, если у вас есть целевой obj/task.o и он соответствует шаблону %.o то стебель (то, что его называет ручное) будет obj/task , а когда предварительным условием является %.c это означает, что make будет искать Предпосылка obj/task.c Поскольку его нет, а make не знает, как его построить, это правило отбрасывается как не применяемое. При написании правил шаблонов вы должны писать их так, ТОЛЬКО идентичные части имен соответствуют символу шаблона ( % ). Все не идентичные части, включая каталоги, должны быть указаны явно.

Во-вторых, правило $(OBJ) : $(SRC) действительно неверно. В этой строке говорится, что каждый объектный файл зависит от всех исходных файлов, поэтому всякий раз, когда какой-либо один исходный файл изменяется, all объектные файлы будут перекомпилированы. Это действительно не то, что вы хотите (если это то, что вы хотите, вам не нужно делать: вы можете просто написать простой скрипт оболочки). Я не знаю, что вы подразумеваете, поскольку правила пустые, он вызывает правило шаблона ; вам не нужно это, чтобы вызвать правило шаблона. objective зависит от $(OBJ) , и каждый объектный файл зависит от его исходного файла (из-за шаблона). Вам не нужна эта линия вообще.

В-третьих, я не знаю, почему вы пытаетесь сконструировать файлы .asm, а не просто компилировать непосредственно из источника в объект, но если вы действительно хотите их, было бы более чисто и более «make-like», чтобы создать отдельное правило шаблона для построить их: создать правило шаблона $(OBJDIR)/%.o : $(OBJDIR)/%.asm и правило $(OBJDIR)/%.asm : $(SRCDIR)/%.c . Если вы хотите, чтобы файлы ASM были продуктами сборки, вы должны объявить их как обязательное условие для all или подобных, иначе они будут удалены как промежуточные файлы.

В-четвертых, использование таких вещей, как basename не требуется. Существует множество автоматических переменных, которые можно использовать вместо них. Например, $* расширяется до стебля, поэтому вы можете написать $(OBJDIR)/$*.asm . Конечно, если вы создадите отдельное правило шаблонов для файлов ASM, вы можете просто использовать $@ или $< напрямую. Существуют также различные функции выполнения, которые также могут использоваться; см. руководство.

В-пятых, вы определяете переменную, содержащую файл заголовка, DEP , но никогда не используйте его. Поскольку он не используется, если вы измените этот файл, ничего не будет перестроено. Если вы знаете, что все исходные файлы include каждый заголовок, вы можете использовать $(OBJ) : $(DEP) чтобы определить это; но это означает (как во втором пункте выше), что любое изменение любого заголовка заставляет все объекты перекомпилировать. Вам было бы лучше автоматизировать создание предпосылок; поскольку вы используете GCC, это довольно просто.

В-шестых, вы используете файлы C ++ (xxx.cpp), но вы используете компилятор C. Это не сработает (линия ссылок не удастся: хотя компилятор может видеть, что вы компилируете файл C ++ и делаете все правильно, даже если вы вызываете gcc, когда вы связываете кучу объектов вместе, это не имеет понятия, C объекты или объекты C ++ (или FORTRAN или что-то еще), поэтому вы ДОЛЖНЫ использовать интерфейс C ++ для связи, иначе он не потянет в нужные библиотеки C ++). Вы должны использовать переменную make CXX для создания кода C ++, а не CC , и установить ее в g++ не gcc .

В-седьмых, вам не нужны .SUFFIXES: .c .o использовать правила шаблонов. Они нужны только для правил суффикса, которых у вас здесь нет. Вы можете сохранить простой .SUFFIXES: хотя для отключения встроенного соответствия шаблонов это небольшое улучшение производительности.

Наконец, вы заметите, что вам действительно не нужна переменная $(SRC) потому что make может вывести ее из правил шаблона. Однако, если вы хотите, чтобы ваш makefile был менее обременительным для изменения, вы могли бы построить содержимое переменной OBJ из переменной SRC, например SRC = nohupshd.cpp task.cpp тогда OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(SRC)) .

Итак, олл-ин, вот как я бы рекомендовал вам написать свой make-файл (здесь я не включаю в него автоматически сгенерированные зависимости):

 .SUFFIXES: CXX := g++ CXXFLAGS := -O2 -g -Wall -fmessage-length=0 OBJDIR := obj SRCDIR := src TARGET := nohupshd SRC := nohupshd.cpp task.cpp DEP := src/task.h LIBS := # ---- OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o,$(SRC)) ASM := $(patsubst %.cpp,$(OBJDIR)/%.asm,$(SRC)) .PHONY: all clean all: $(TARGET) $(ASM) $(TARGET): $(OBJ) $(CXX) -o $@ $^ $(LIBS) clean: rm -f $(OBJDIR)/* $(TARGET) $(OBJDIR)/%.o : $(SRCDIR)/%.asm $(CXX) $(CXXFLAGS) -c -x assembler-with-cpp $< -o $@ $(OBJDIR)/%.asm : $(SRCDIR)/%.cpp $(CXX) $(CPPFLAGS) -S $< -o $@ 

Не повторяйте имена каталогов в строке компилятора. $< и $@ уже имеют имена каталогов.

 $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(CC) -S $< -o $@ $(CC) -c $< -o $@ 

Итак, наконец, я нашел ответ о том, как писать этот make-файл, потому что exaplanation моих ошибок смотрит на публикацию, которую я обозначил как правильный ответ:

Полученный make-файл выглядит так, и для полноты я размещаю его здесь, включая зависимости для файлов заголовков (удалите части ASM, если они вам не нужны):

 .SUFFIXES: .SUFFIXES: .o .cpp .SUFFIXES: .o .d CC := g++ LNK:= ar CXXFLAGS = -O2 -g -Wall -fmessage-length=0 OBJDIR:= obj SRCDIR:= src HDIR:= include INCLUDE_PATHS:= -Iinclude -Iinclude/interfaces -Iinclude/support CPP_FILES := propertyfile/propertyfile.cpp \ propertyfile/propertyitem.cpp \ propertyfile/propertyfactory.cpp OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o, $(CPP_FILES)) SRC := $(patsubst %.cpp,$(SRCDIR)/%.o, $(CPP_FILES)) ASM := $(patsubst %.cpp, $(OBJDIR)/$*.asm, $(CPP_FILES)) LIBS:= TARGET:= libsupport.a all: $(TARGET) $(TARGET): $(OBJ) @echo "Linking..." @$(LNK) rvs $(TARGET) $(OBJ) @cp $(TARGET) ../lib @cp -r include .. clean: rm -f $(OBJ) $(ASM) $(TARGET) -include $(patsubst %.cpp,$(OBJDIR)/%.d, $(CPP_FILES)) $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(OBJDIR)/%.d @mkdir -p `dirname $@` $(CC) $(CXXFLAGS) -S $< -o $(OBJDIR)/$*.asm $(INCLUDE_PATHS) $(CC) $(CXXFLAGS) -c $< -o $@ $(INCLUDE_PATHS) $(OBJDIR)/%.d: $(SRCDIR)/%.cpp $(CC) $(CXXFLAGS) -MM -MT $@ -MF $(OBJDIR)/$*.d -c $< $(INCLUDE_PATHS) 

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