更改头文件时,如何使Makefile重新编译? [英] How to make Makefile recompile when a header file is changed?

查看:1717
本文介绍了更改头文件时,如何使Makefile重新编译?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经编写了一个Makefile来在OSX(Unix系统中更通用)上编译一个openCV程序.

I have written a Makefile to compile an openCV program on OSX (more general in Unix systems).

代码有一个名为constants.hpp的标头,其中定义了一些常量.

The code has a header named constants.hpp where some constants are defined.

当此头文件更改时,我想使Makefile重新编译程序,因为其中的常量值更改了程序行为.

I would like to make the Makefile recompile the program when this header file changes because the values of the constants in it change the program behavior.

以下是我的Makefile

My Makefile is the following

CPP = g++
CPPFLAGS = -std=c++11

all: main.o

main.o: main.cpp
    $(CPP) $^ $(CPPFLAGS) -o $@

搜索后,我尝试在CPPFLAGS之后定义值:

Searching around I tried to define after CPPFLAGS the value:

DEPS = constants.hpp 

,然后由于main.o依赖它 添加依赖项,如下所示:

and then since main.o depends on it adding the dependency as follows:

main.o: main.cpp $(DEPS)
        $(CPP) $^ $(CPPFLAGS) -o $@

但是我得到的错误是clang: error: cannot specify -o when generating multiple output files.

我也尝试了此答案,并尝试使用M MM标志,但是我想念一些东西.

I tried also this answer and tried to use th e M MM flags but I am missing something.

更改头文件时如何使Makefile重新编译?

How to make Makefile recompile when a header file is changed?

在对DevSolar的评论之后,我不得不完全修改该问题,他还询问了源代码.由于我发现这里无用地复制所有源代码,因此我用一个简单的hello world程序对其进行了简化.

Following the comments to DevSolar I had to modify completely the question and he asked also the source code. Since I found useless to copy all the source code here I simplified it with a simple hello world program.

以下是main.cpp:

#include<iostream>
#include"constants.hpp"

int main()
{

  std::cout<<"Hello world, the value is: " <<  myValue <<"\n";
  return 0;
}

和以下constants.hpp:

static const int myValue = 10;

推荐答案

前言

您正在使用$(CPP)$(CPPFLAGS) ...,用于预处理器.对于C ++编译器,您要使用的是$(CXX)$(CXXFLAGS).

You are using $(CPP) and $(CPPFLAGS)... that's for the preprocessor. What you want to use is $(CXX) and $(CXXFLAGS), for the C++ compiler.

以下内容假定使用GNU make和兼容GCC的编译器(使用clang即可).

The following assumes GNU make and a GCC-compatible compiler (clang will do).

第一步

使用通用规则,而不是每个源文件使用一个通用规则-后者很快就会变得毫无用处,并且容易出错.

Use generic rules, not one per source file -- the latter will very quickly become unwieldly, and is very error-prone.

手动列出您的源文件...

Either list your source files manually...

SOURCES := parking.cpp utils.cpp InputStateContext.cpp InputState.cpp InputStateA.cpp

...或自动列出所有源文件:

...or have all source files listed automatically:

SOURCES := $(wildcard *.cpp)

您还需要一个目标文件列表(每个.cpp一个.o):

You also need a list of the object files (one .o per .cpp):

OBJECTS := $(patsubst %.cpp,%.o,$(SOURCES))

现在,根据所有目标文件,为可执行文件提供规则,并使用命令将所有这些目标文件($^)链接到同一可执行文件($@)...

Now provide a rule for the executable, depending on all the object files, with a command that links all those object files ($^) into that same executable ($@)...

parking: $(OBJECTS)
        $(CXX) $(CXXFLAGS) $^ -o $@

...以及有关如何从相应的源文件(%.cpp)生成单个目标文件(%.o)的通用规则:

...and a generic rule on how to generate individual object files (%.o) from the corresponding source file (%.cpp):

%.o: %.cpp Makefile
        $(CXX) $(CXXFLAGS) &< -o $@

使目标文件也取决于Makefile可以确保Makefile中的更改,例如$(CXXFLAGS),也触发重新编译. $<解析为 first 依赖项(源文件).

Making the object file depend on the Makefile as well ensures that changes in the Makefile, e.g. $(CXXFLAGS), trigger a recompile as well. $< resolves to the first dependency (the source file).

我们稍后将扩展此规则.

We will extend this rule later.

第二步

每个源文件都有一个依赖文件 . (请在这里忍受.)我们可以像生成目标文件一样生成这些文件的列表...

We will have a dependency file for each source file. (Bear with me here.) We can generate a list of those files the same as we did for object files...

DEPENDS := $(patsubst %.cpp,%.d,$(SOURCES))

...并将它们包含在Makefile中:

...and include them into the Makefile:

-include $(DEPENDS)

那里的-意味着make不会抱怨那些文件不存在-因为它们现在不存在.

The - there means that make will not complain if those files do not exist -- because they do not, at this point.

第三步(问题答案的核心)

编译器为我们生成这些依赖文件 -因为它最了解.为此,我们扩展了目标文件的构建规则:

Have the compiler generate those dependency files for us -- because it knows best. For that, we extend our object file build rule:

%.o: %.cpp Makefile
        $(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@

-MMD标志生成依赖项文件(%.d),该文件将保存(以Makefile语法表示)规则,以使生成的文件(在这种情况下为%.o)取决于源文件和任何非-系统标头.这意味着只要触摸相关源,就会自动重新创建目标文件.如果您还希望依赖系统头文件(即在每次编译时检查它们的更新),请改用-MD.

The -MMD flag generates the dependency file (%.d), which will hold (in Makefile syntax) rules making the generated file (%.o in this case) depend on the source file and any non-system headers it includes. That means the object file gets recreated automatically whenever relevant sources are touched. If you want to also depend on system headers (i.e., checking them for updates on each compile), use -MD instead.

-MP选项添加了空的虚拟规则,可以避免在从文件系统中删除头文件时出错.

The -MP option adds empty dummy rules, which avoid errors should header files be removed from the filesystem.

在第一次编译运行时,没有依赖项信息-但是由于目标文件也不存在,因此无论如何编译器都必须运行.对于以后的每次运行,make都将包括自动生成的依赖文件,并做正确的事".

At the first compile run, there is no dependency information -- but since the object files don't exist either, the compiler must run anyway. For every subsequent run, make will include the auto-generated dependency files, and "do the right thing".

多合一(添加了更多语法糖):

All-In-One (with some more syntactic sugar added):

SOURCES := $(wildcard *.cpp)
OBJECTS := $(patsubst %.cpp,%.o,$(SOURCES))
DEPENDS := $(patsubst %.cpp,%.d,$(SOURCES))

# ADD MORE WARNINGS!
WARNING := -Wall -Wextra

# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean

# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: parking

clean:
        $(RM) $(OBJECTS) $(DEPENDS) parking

# Linking the executable from the object files
parking: $(OBJECTS)
        $(CXX) $(WARNING) $(CXXFLAGS) $^ -o $@

-include $(DEPENDS)

%.o: %.cpp Makefile
        $(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $@

这篇关于更改头文件时,如何使Makefile重新编译?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆