Linux C++ gmake "Нет правил, чтобы сделать цель"
Прошло пару десятилетий с тех пор, как мне пришлось управлять make-файлами. Я проверил существующие ответы здесь, а также поиск в других местах. Когда я использую цель: $(BIN)/$(EXECUTABLE): $(OBJECTS)
Я озадачен тем, почему мой make-файл не работает с:
$ make
make: *** No rule to make target 'src/SRecord.o', needed by 'bin/main'. Stop.
Вот Makefile:
# execute `make D='-g'` to make with debug symbols
DEFS := $(D)
CC := gcc $(DEFS)
CFLAGS := -std=c99 -Wall -Wextra
CXX := g++ $(DEFS)
CXXFLAGS := -std=c++17 -Wall -Wextra
BIN := bin
SRC := src
INCLUDE := include
LIB := lib
#LIBSOURCES := $(wildcard $(LIB)/*.cpp)
#LIBOBJECTS := $(LIBSOURCES:%.cpp=%.o)
#OBJECTS := $(subst $(LIB)/,,$(LIBOBJECTS))
SOURCES := $(wildcard $(SRC)/*.cpp)
OBJECTS := $(SOURCES:%.cpp=%.o)
# SOURCES := \
# $(SRC)/main.cpp \
# $(SRC)/SerialPort.cpp \
# $(SRC)/ShadowUpdate.cpp \
# $(SRC)/SRecord.cpp
# OBJECTS := \
# $(SRC)/SerialPort.o \
# $(SRC)/ShadowUpdate.o \
# $(SRC)/SRecord.o
EXECUTABLE := main
#
# Targets
#
.PHONY: clean all
all: $(BIN)/$(EXECUTABLE)
clean:
$(RM) $(BIN)/$(EXECUTABLE)
$(RM) $(OBJECTS)
run: all
./$(BIN)/$(EXECUTABLE)
# $(BIN)/$(EXECUTABLE): $(SRC)/*
$(BIN)/$(EXECUTABLE): $(OBJECTS)
$(CXX) $(CXXFLAGS) -I$(INCLUDE) -L$(LIB) $^ -o $@
#
# Dependencies - must be at end of makefile
#
DEPDIR := .d
$(shell mkdir -p $(DEPDIR) >/dev/null)
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td
POSTCOMPILE = @mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $@
%.o: %.c
%.o: %.c $(DEPDIR)/%.d
$(CC) -c -o $*.o $(DEPFLAGS) $(CFLAGS) $<
$(POSTCOMPILE)
%.o: %.cpp
%.o: %.cpp $(DEPDIR)/%.d
$(CXX) -c -o $*.o $(DEPFLAGS) $(CXXFLAGS) $<
$(POSTCOMPILE)
$(DEPDIR)/%.d: ;
.PRECIOUS: $(DEPDIR)/%.d
include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SOURCES))))
Работает с закомментированной целью: # $(BIN)/$(EXECUTABLE): $(SRC)/*
Но я хочу, чтобы у меня был более сложный проект, чем просто перечисление всех исходных файлов в качестве зависимостей для исполняемого файла.
Вот мое дерево файлов:
src/
src/SerialPort.cpp
src/SRecord.cpp
src/ShadowUpdate.cpp
src/main.cpp
include
include/ShadowUpdate.h
include/SerialPort.h
include/SRecord.h
include/the_exo.h
bin/
bin/main
Makefile
lib/
.d/
Автоматическая генерация зависимостей тоже не работает, хотя она прямо с сайта GNU.
2 ответа
Подумай о том, что %
расширяется до в
%.o: %.cpp $(DEPDIR)/%.d
подключить src/SRecord.o
:
src/SRecord.o: src/SRecord.cpp .d/src/SRecord.d
Вы видите проблему? Попробуйте следующее
$(SRC)/%.o: $(SRC)/%.cpp $(SRC)/$(DEPDIR)/%.d
Вам не понадобятся строки, которые переопределяют встроенные рецепты (%.o: %.cpp
), Избавься от них.
Для ясности всем, кто ищет ответ в будущем, я публикую свой пересмотренный Makefile:
BIN := bin
SRC := src
INCLUDE := include
LIB := lib
# execute `make D='-g'` to make with debug symbols
DEFS := $(D)
CC := gcc $(DEFS)
CFLAGS := -I$(INCLUDE) -std=c99 -Wall -Wextra
CXX := g++ $(DEFS)
CXXFLAGS := -I$(INCLUDE) -std=c++17 -Wall -Wextra
#LIBSOURCES := $(wildcard $(LIB)/*.cpp)
#LIBOBJECTS := $(LIBSOURCES:%.cpp=%.o)
#OBJECTS := $(subst $(LIB)/,,$(LIBOBJECTS))
SOURCES := $(wildcard $(SRC)/*.cpp)
OBJECTS := $(SOURCES:%.cpp=%.o)
EXECUTABLE := main
#
# Targets
#
.PHONY: clean all
all: $(BIN)/$(EXECUTABLE)
clean:
$(RM) $(BIN)/$(EXECUTABLE)
$(RM) $(OBJECTS)
run: all
./$(BIN)/$(EXECUTABLE)
$(BIN)/$(EXECUTABLE): $(OBJECTS)
$(CXX) $(CXXFLAGS) -L$(LIB) $^ -o $@
#
# Dependencies - must be at end of makefile
#
DEPDIR := $(SRC)/.d
$(shell mkdir -p $(DEPDIR) >/dev/null)
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td
POSTCOMPILE = @mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $@
%.o: %.c
%.o: %.c $(DEPDIR)/%.d
$(CC) -c -o $@ $(DEPFLAGS) $(CFLAGS) $<
$(POSTCOMPILE)
%.o: %.cpp
$(SRC)/%.o: $(SRC)/%.cpp $(DEPDIR)/%.d
$(CXX) -c -o $@ $(DEPFLAGS) $(CXXFLAGS) $<
$(POSTCOMPILE)
$(DEPDIR)/%.d: ;
.PRECIOUS: $(DEPDIR)/%.d
include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SOURCES))))
Чтобы уточнить мой комментарий к ответу выше, если я закомментирую цель "переопределить" (%.o: %.cpp
), вот вывод:
$ make clean; make
rm -f bin/main
rm -f src/SRecord.o src/SerialPort.o src/ShadowUpdate.o src/main.o
g++ -Iinclude -std=c++17 -Wall -Wextra -c -o src/SRecord.o src/SRecord.cpp
g++ -Iinclude -std=c++17 -Wall -Wextra -c -o src/SerialPort.o src/SerialPort.cpp
g++ -Iinclude -std=c++17 -Wall -Wextra -c -o src/ShadowUpdate.o src/ShadowUpdate.cpp
g++ -Iinclude -std=c++17 -Wall -Wextra -c -o src/main.o src/main.cpp
g++ -Iinclude -std=c++17 -Wall -Wextra -Llib src/SRecord.o src/SerialPort.o src/ShadowUpdate.o src/main.o -o bin/main
Понятно, что зависимости не создаются. Мое правило не было выполнено.
Но с пустым %.o: %.cpp
цель на месте, make выполняет, как ожидалось:
$ make clean; make
rm -f bin/main
rm -f src/SRecord.o src/SerialPort.o src/ShadowUpdate.o src/main.o
g++ -c -o src/SRecord.o -MT src/SRecord.o -MMD -MP -MF src/.d/SRecord.Td -Iinclude -std=c++17 -Wall -Wextra src/SRecord.cpp
g++ -c -o src/SerialPort.o -MT src/SerialPort.o -MMD -MP -MF src/.d/SerialPort.Td -Iinclude -std=c++17 -Wall -Wextra src/SerialPort.cpp
g++ -c -o src/ShadowUpdate.o -MT src/ShadowUpdate.o -MMD -MP -MF src/.d/ShadowUpdate.Td -Iinclude -std=c++17 -Wall -Wextra src/ShadowUpdate.cpp
g++ -c -o src/main.o -MT src/main.o -MMD -MP -MF src/.d/main.Td -Iinclude -std=c++17 -Wall -Wextra src/main.cpp
g++ -Iinclude -std=c++17 -Wall -Wextra -Llib src/SRecord.o src/SerialPort.o src/ShadowUpdate.o src/main.o -o bin/main