繁体   English   中英

Makefile:无规则可作为目标

[英]Makefile: no rule to make target

我一直在这个网站上寻找解决方案,并且也尝试了一段时间的google,但是不知为何我无法使用它。

我的源应该在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)/$@

变体1a:

%.o: %.cpp
    $(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$@
    $(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$@

当我使用此模式时,总是会收到错误,提示nohupshd.o没有构建规则。

变体2:

$(OBJ) : $(OBJDIR)/%.o: $(SRCDIR)/%.cpp
    $(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$@
    $(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$@

当我使用此变体时,可以看到它尝试构建,但是出现错误,提示“ file” .o不适合目标模式。

另一个问题是“ $ <”没有给我源名称。 根据几个站点,它应该可以,但是我可以在输出中看到什么都没有,那么如何解决这个问题?

更新:

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

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

现在,它可以编译第一个目标文件(nohupshd.o),但是当make尝试处理第二个目标文件时,它再次失败:目标'task.o'与模式不匹配。

如果上面的内容不正确,您实际上有一对。

首先,您写的错误是,我假设模式%.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东西。 有许多自动生成变量可以代替使用。 例如, $*扩展到词干,因此您可以编写$(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))

因此,总的来说,这就是我建议您编写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 $@

不要在编译器行中重复目录名称。 $<$@已经具有目录名称。

$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
    $(CC) -S $< -o $@
    $(CC) -c $< -o $@

因此,最后我找到了有关如何编写此makefile的答案,以解决我的错误,请看一下我标记为正确答案的帖子:

生成的makefile看起来像这样,为完整起见,我将其发布在此处,包括头文件的依赖项(如果不需要'em',请删除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)  

我希望这对其他用户有帮助。 我发现的所有示例都非常简单,并且单独列出了多个文件,而不是规则的一部分,但并没有真正解释它的工作原理,或者过于复杂,以至于我找不到它可以如何帮助我。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM