我一直在寻找这个网站上的解决方案,现在也尝试谷歌一段时间,但不知怎的,我无法让它工作。
我的源代码应该在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)/$@
当我使用这个变种时,我可以看到它试图构建,但我得到错误,说“文件”.o不适合目标模式。
另一个问题是“$&lt;”不给我源名称。根据几个网站应该,但我可以在输出中看到没有任何内容,所以我该如何解决这个问题呢?
更新
与此同时,我的最新版本如下:
$(OBJDIR)/$(OBJ) : $(OBJDIR)/%.o : $(SRCDIR)/%.cpp
$(CC) -S $< -o $(OBJDIR)/`basename $@ .o`.asm
$(CC) -c $< -o $@
现在设法编译第一个目标文件(nohupshd.o)但是当make尝试执行第二个文件时,它再次失败说:target'task.o'与模式不匹配。
答案 0 :(得分:7)
如果上面的内容不正确,你实际上有一对。
首先你写我的错误是,我假设模式%.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))
。
所以,全押,这就是我建议您编写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 $@
答案 1 :(得分:1)
不要在编译器行中重复目录名称。 $<
和$@
已经拥有目录名称。
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
$(CC) -S $< -o $@
$(CC) -c $< -o $@
答案 2 :(得分:0)
所以最后我找到了关于如何编写这个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)
我希望这有助于其他用户。我发现的所有示例都非常简单,并且单独列出了多个文件而不是规则的一部分,但没有真正解释它是如何工作的,或者是如此复杂以至于我无法找到它如何帮助我。