Makefile:没有规则来制作目标
Makefile: no rule to make target
我在这个网站上寻找解决方案,也尝试了谷歌一段时间了,但不知何故我不能让它工作。
我的源文件应该在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)/$@
1变种:
%.o: %.cpp
$(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$@
$(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$@
当我使用这个模式时,我总是得到一个错误,没有nohupshd规则。
变种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 $@
这现在设法编译第一个objectfile (nohupshd.o),但当make试图执行第二个文件时,它再次失败,说:target 'task。O '不符合模式
你实际上有几个不正确的东西。
首先写我的错误是,我假设模式%。o匹配任何以。o结尾但不的模式;这不是真的。模式不匹配任何以.o
结尾的字符串。但是,在目标端匹配的模式字符%
在前提端被替换为相同的字符串。因此,如果您有一个目标obj/task.o
并且它与模式%.o
相匹配,那么干(手册中这样称呼它)将是obj/task
,当先决条件是%.c
时,这意味着make将寻找先决条件obj/task.c
。由于不存在,make也不知道如何构建,因此该规则被视为不适用而被丢弃。在编写模式规则时,必须使只有名称的相同部分匹配模式字符(%
)。所有不相同的部分,包括目录,必须显式指定。
第二,规则$(OBJ) : $(SRC)
确实不正确。这一行表示,每个目标文件依赖于所有源文件,因此每当任何单个源文件更改all
时,目标文件将被重新编译。这真的不是你想要的(如果这是你想要的,你不需要make:你可以只写一个简单的shell脚本)。我不知道你说的是什么意思,因为规则是空的,它调用模式规则;您不需要这个来调用模式规则。目标依赖于$(OBJ)
,每个目标文件依赖于它的源文件(由于模式)。你根本不需要这一行。
第三,我不知道为什么你试图构造。asm文件,而不是直接从源编译到对象,但是如果你真的想要它们,创建一个单独的模式规则来构建它们会更干净,更像"make-like":创建一个模式规则$(OBJDIR)/%.o : $(OBJDIR)/%.asm
和一个规则$(OBJDIR)/%.asm : $(SRCDIR)/%.c
。如果您希望ASM文件成为构建的产物,您应该将它们声明为all
或类似的先决条件,否则它们将作为中间文件被删除。
第四,使用basename
之类的东西是不必要的。有很多自动make变量可以用来代替。例如,$*
展开为词干,因此可以写成$(OBJDIR)/$*.asm
。当然,如果您为ASM文件制定单独的模式规则,您可以直接使用$@
或$<
。有各种make功能也可以使用;
第五,您定义了一个包含头文件DEP
的变量,但此后从不使用它。因为没有使用它,所以如果更改该文件,将不会重新构建任何内容。如果你知道所有的源文件包括每个头文件,你可以使用$(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不那么麻烦的改变,你可以从SRC变量构造OBJ变量的内容,像SRC = nohupshd.cpp task.cpp
然后OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(SRC))
。
.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 $@
所以最后我找到了关于如何编写这个makefile的答案,对于我的错误的解释,请查看我标记为正确答案的帖子:
生成的makefile看起来像这样,为了完整性,我把它贴在这里,包括头文件的依赖项(如果你不需要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)
我希望这对其他用户有所帮助。我找到的所有示例要么非常简单,单独列出多个文件,而不是规则的一部分,但没有真正解释它是如何工作的,要么太复杂了,以至于我无法找到它如何帮助我。
- 制作文件:没有规则来制定目标:如何设置正确的规则?
- antlr 规则上下文是否可以独立于目标
- C++ 如何将两个 makefile 对象目标规则(位于另一个文件夹中)合并到一个目标/规则中?
- 朋友声明的复杂范围界定规则有什么意义?
- Cassandra C++ MacOS High Sierra上的驱动程序:make:没有规则来制作目标
- 可变参数模板在目标文件中有重复的符号?
- 没有规则来设定目标'/usr/lib/x86_64-linux-gnu/libboost_filesystem.so'
- 目标提升::<library>已经有导入的位置 + 链接错误
- 是否有可能编写新的叮当声现代化规则?
- 没有规则来制作目标.o,为什么?
- 在 decltype(auto) 的情况下,lambda 是否有特殊规则?
- 在VC++中从DLLMAIN内部调用D3D的CREATEDEVICE时,它会创建一个死锁(loaderlock?)。有没有办法克服这个问题?最终目标内
- 制作:没有实现目标的规则 - 找不到源文件
- 没有要成为目标的规则:代码块
- 链接器命令 - 没有为第三方库设定目标的规则
- EclipseCDT:没有使目标全部成为目标的规则
- 没有制定目标的规则.所以
- C++生成文件错误:没有要设为目标的规则
- Qt创建者中的通用c++项目-没有使目标成为目标的规则
- OpenCv没有制定目标的规则