2015-10-18 56 views
1

这是我目前的makefile:制作和C++文件, “包括” 在CPP

# Compiler # 
CXX  = g++ 
DEBUG = -g 
LFLAGS = 
CXXFLAGS = -Wall 

# Directories # 
SRCDIR = src/ 
INCDIR = include/ 
BUILDDIR = build/ 
BINDIR = bin/ 

# Objects # 
OBJ_NAMES = main.o dfa.o dfaException.o state.o 
OBJS  = $(addprefix $(BUILDDIR), $(OBJ_NAMES)) 

# Output # 
NAME = pract3 
TARGET = $(BINDIR)pract3 

# Clean # 
ifeq ($(OS),Windows_NT) 
    RM = del /q /s $(BUILDDIR:/=\)*.o $(BINDIR:/=\)$(NAME)* 
else 
    RM = rm -rf $(BUILDDIR)*.o $(TARGET)* 
endif 

# Files # 
$(TARGET): $(OBJS) 
    $(CXX) $(CXXFLAGS) $(LFLAGS) $(OBJS) -o $(TARGET) 

$(BUILDDIR)%.o: $(SRCDIR)%.cpp 
    $(CXX) $(CXXFLAGS) $(LFLAGS) -c $< -o [email protected] 

clean: 
    $(RM) 

这是我的项目树:

Porject/ 

    bin/ 

    build/ 

    doc/ 
     ... 

    include/ 
     connection.hpp 
     dfa.hpp 
     dfaException.hpp 
     state.hpp 

    src/ 
     dfa.cpp 
     dfaException.cpp 
     main.cpp 
     state.cpp 

    Makefile 
    Readme 

现在,我有三个“问题”。

首先,我希望我的makefile创建bin并创建目录,以防万一它们不存在。我想我只需要使用:

mkdir $(BUILDDIR) 
mkdir $(BINDIR) 

但是我应该把它们放在哪里?另外,我怎样才能防止mkdir和rm(或删除窗口中)消息,如“无法找到...”或“x目录已存在...”

二,我猜我可以读取对象来自src /的名称(将.cpp转换为.o),但是如何从目录中读取文件名?

最后,我有一个模板类:connection.hpp(所有功能都在标题中)。该文件包含在state.hpp中,使用:#include "../include/connection.hpp"。我跑了make一次全部正确,然后我故意在connection.hpp中发生语法错误。然后我再次运行make,但它只编译了目标文件,使用build中的.o文件没有任何错误。每当我想编辑connection.hpp我必须使用make clean然后make。有没有更好的方法来做到这一点?

回答

1
  1. 如果你需要一个目录存在,您可以继续之前,简单地说

    mkdir -p ${DIRECTORY} 
    

    你需要在你的规则之前。如果该目录已经存在,mkdir -p将会愉快地无所作为。

    同样,如果您使用rm -f FILE,它不应该抱怨,如果FILE首先不存在。

  2. 没有可移植的方式来创建一个变量来保存目录中所有文件的名称。但是,你已经在使用GNU做出特色,所以你可以只使用

    SOURCES = $(wildcard ${SRCDIR}/*.cpp) 
    

    然后

    OBJECTS = $(SOURCES:.cpp=.o) 
    

    把它们转化成目标文件名。我想你可能也想替换主要的目录名称。

  3. 您没有在make文件中列出任何*.hpp文件作为先决条件。您可以手动添加它们,如

    foo.o: foo.cpp bar.hpp baz.hpp 
    

    但这会变得很快令人不快。另一个窍门是使用编译器通过文件告诉你头文件(可传递地)#include d。如果您使用的是GCC,则可以运行

    gcc -MM foo.cpp 
    

    将其输出到上面的生成文件片段。你可以把一个模式规则类似下面

    %.deps: %.cpp 
        ${CXX} -MM ${CPPFLAGS} $< > [email protected] 
    

    到你的化妆文件,然后include生成的*.deps文件。

    include $(SOURCES:.cpp=.deps) 
    

    GNU都会得到足够的智慧首先是解析补充文件,认识到*.deps文件不存在,因此不能include d,但弄清楚,有生成它们的规则。所以它会执行该规则,然后继续解析make-file。

    我已经从彼得米勒的伟大文章Recursive Make Considered Harmful那里学到了这个技巧,如果你想学习如何编写好的make-files,那么这是一个很好的阅读。

+0

这个信息对我来说非常有用,谢谢,但我无法设法让最后一部分工作。包括哪里去?我使用它像:DEPS = $(OBJS:.o = .deps)',然后,在所有食谱我做'包括$(DEPS)'之前。如果没有包含,'.deps'文件就会生成,然后被删除,但是随之而来的是它们停留在那里。而且,使用include没有区别,如果我编译并编辑'connecion.hpp',直到我再次清理并编译完成,仍然没有错误。 – Ediolot

+0

@Ediolot可以不删除'* .deps'文件。如果你想清理它们,在'clean'目标中执行'rm -f $ {DEPS}'。我无法推测为什么你的文件没有像你期望的那样被编译。如果你无法正常工作,可以用最小的'Makefile'和一些“hello world”程序来提出另一个问题,这个程序包含一个可以重现问题的头文件。也许有一个小小的错误。我可以向你保证,我正在使用这种技术很多,它的工作非常好。 – 5gon12eder