Makefile:没有规则来制作目标

Dev*_*lus 1 c c++ makefile build

我一直在寻找这个网站的解决方案,现在也尝试谷歌一段时间了,但不知怎的,我无法让它工作.

我的源应该在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)
Run Code Online (Sandbox Code Playgroud)

变式1:

$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
    $(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$@
    $(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$@
Run Code Online (Sandbox Code Playgroud)

变式1a:

%.o: %.cpp
    $(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$@
    $(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$@
Run Code Online (Sandbox Code Playgroud)

当我使用这个模式时,我总是会遇到一个错误,即nohupshd.o没有构建规则.

变式2:

$(OBJ) : $(OBJDIR)/%.o: $(SRCDIR)/%.cpp
    $(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$@
    $(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$@
Run Code Online (Sandbox Code Playgroud)

当我使用这个变体时,我可以看到它试图构建,但我得到错误,说"文件".o不适合目标模式.

另一个问题是"$ <"没有给我源名称.根据几个网站应该,但我可以在输出中看到什么都没有,所以我该如何解决这个问题呢?

更新:

与此同时,我的最新版本如下所示:

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

这现在设法编译第一个目标文件(nohupshd.o),但是当make尝试执行第二个文件时,它再次失败说:target'task.o'与模式不匹配.

Mad*_*ist 7

如果不正确的话,你实际上有几个.

首先你写的我的错误是,我假设模式%.o匹配以.o结尾的任何模式,而不是 ; 这不是真的.该模式匹配任何字符串结尾.o.但是,在%目标端匹配的模式字符在先决条件侧被替换为相同的字符串.因此,如果你有一个目标obj/task.o并且它与模式匹配,%.o那么词干(手动调用它)将是obj/task,并且当先决条件是%.c这意味着make将寻找先决条件obj/task.c.由于没有一个,并且make不知道如何构建一个,该规则被丢弃为不应用.在编写模式规则你必须写他们,所以只有名称的相同部分匹配的模式字符(%).必须明确指定所有不相同的部分,包括目录.

其次,这条规则$(OBJ) : $(SRC)真的不对.该行表示每个目标文件都依赖于所有源文件,因此每当任何单个源文件发生更改时all,都将重新编译目标文件.这真的不是你想要的(如果那是你想要的,你不需要make:你可以写一个简单的shell脚本).我不知道你的意思,因为规则是空的,它调用模式规则 ; 你不需要这个来调用模式规则.目标取决于$(OBJ),每个目标文件取决于其源文件(由于模式).你根本不需要这条线.

第三,我不知道你为什么要尝试构建.asm文件,而不是直接从源代码编译到对象,但如果你真的想要它们,那么创建一个单独的模式规则会更清晰,更"仿制"构建它们:创建模式规则$(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++不构建C++代码gcc.

第七,您不需要.SUFFIXES: .c .o使用模式规则.它们仅用于后缀规则,这是您没有的.您可以保持简单,.SUFFIXES:但禁用内置模式匹配,这是一个轻微的性能改进.

最后,您会注意到您实际上并不需要$(SRC)变量,因为make可以从模式规则中推断出它.但是,如果你想让你的makefile不那么繁重,你就可以从SRC变量构造OBJ变量的内容,就像SRC = nohupshd.cpp task.cpp那样OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(SRC)).

所以,all-in,这就是我建议你编写你的makefile的方法(虽然这里我不包括自动生成的依赖项):

.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 $@
Run Code Online (Sandbox Code Playgroud)