Linux C ++ gmake "Нет правил, чтобы сделать цель" - PullRequest
0 голосов
/ 28 мая 2018

Прошло пару десятилетий с тех пор, как мне пришлось управлять 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 ]

0 голосов
/ 28 мая 2018

Для ясности любому, кто ищет ответ в будущем, я публикую свой исправленный 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 
0 голосов
/ 28 мая 2018

Подумайте о том, что расширяет % в

%.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), избавьтесь от них.

...