linux C++ gmake“没有规则来制作目标”

Posted

技术标签:

【中文标题】linux C++ gmake“没有规则来制作目标”【英文标题】:linux C++ gmake "No rule to make target" 【发布时间】:2018-05-28 16:35:18 【问题描述】:

自从我不得不管理 makefile 以来已经有几十年了。我在这里检查了现有的答案,并在其他地方进行了谷歌搜索。当我使用目标时:$(BIN)/$(EXECUTABLE): $(OBJECTS) 我很困惑为什么我的 makefile 失败了:

$ 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 网站的自动依赖生成也不起作用。

【问题讨论】:

您的依赖处理可以修复,这将解决您在此过程中发现规则的问题。现在您将目标文件 (SRecord.o) 放入 src/;你想让他们在那里,还是bin/,或者obj/,或者别的什么地方? 感谢 Beta 版的评论。我现在对 src 中的对象很好。我想我对 gmake 为您做了多少以及必须明确说明多少感到困惑。我已经在下面发布了我修改后的 Makefile - 它有效。如果项目增长很多,我肯定会重新安排一些东西。现在了解了游戏,我将能够处理额外的复杂性。 【参考方案1】:

想想% 扩展成什么

%.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) 的行,去掉它们。

【讨论】:

您对目标文件的解决方案是正确的。然而,为了构建依赖,“覆盖”目标是绝对必要的。【参考方案2】:

为了让以后寻找答案的人更清楚,我发布了我修改后的 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 

【讨论】:

以上是关于linux C++ gmake“没有规则来制作目标”的主要内容,如果未能解决你的问题,请参考以下文章

gcc makefile错误:“没有规则来制作目标......”

没有规则来制作目标.o,为啥?

*** 没有规则来制作目标 `src/main/jni/Build.config'。停止

Makefile:没有规则来制作目标。停止

驱动程序未编译“没有规则来制作目标”

Makefiles 链是一团糟:没有规则来制作目标