我已经编写了一个Makefile来在OSX(Unix系统中更常见)上编译一个openCV程序。
该代码具有一个名为constants.hpp
的标头,其中定义了一些常量。
当此头文件更改时,我想使Makefile重新编译程序,因为其中的常量值更改了程序行为。
以下是我的Makefile
CPP = g++
CPPFLAGS = -std=c++11
all: main.o
main.o: main.cpp
$(CPP) $^ $(CPPFLAGS) -o $@
搜索时,我尝试在CPPFLAGS
之后定义值:
DEPS = constants.hpp
,然后由于main.o
依赖它
添加依赖项,如下所示:
main.o: main.cpp $(DEPS)
$(CPP) $^ $(CPPFLAGS) -o $@
但是我得到的错误是clang: error: cannot specify -o when generating multiple output files
。
我也尝试了this answer,并尝试使用M
MM
标志,但是我丢失了一些东西。
更改头文件时如何使Makefile重新编译?
编辑:在对DevSolar的评论之后,我不得不完全修改问题,他还询问了源代码。由于我发现这里无用地复制所有源代码,因此我用一个简单的hello world程序对其进行了简化。
以下是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;
答案 0 :(得分:2)
如果您只有一个源代码文件,请输入目标文件所依赖的编译文件
main.o: main.cpp $(DEPS)
$(CPP) -c $< $(CPPFLAGS) -o $@
仅当您不使用多个.cpp
文件进入编辑时,此方法才起作用。
$^
是一个自动变量,它包含当前配方的所有先决条件,并用空格分隔,而$<
仅保留第一个先决条件。这就是为什么您不能对同一编译中的多个.cpp
文件使用此解决方案的原因。
答案 1 :(得分:1)
序言
您正在使用$(CPP)
和$(CPPFLAGS)
...用于预处理器。对于C ++编译器,您要使用$(CXX)
和$(CXXFLAGS)
。
以下内容假定使用GNU make和兼容GCC的编译器(使用clang即可)。
第一步
使用通用规则,而不是每个源文件一个规则-后者很快就会变得毫无用处,并且容易出错。
手动列出您的源文件...
SOURCES := parking.cpp utils.cpp InputStateContext.cpp InputState.cpp InputStateA.cpp
...或自动列出所有源文件:
SOURCES := $(wildcard *.cpp)
您还需要一个目标文件列表(每个.cpp一个.o):
OBJECTS := $(patsubst %.cpp,%.o,$(SOURCES))
现在根据所有目标文件为可执行文件提供规则...
parking: $(OBJECTS)
$(CXX) $(CXXFLAGS) $^ -o $@
...以及关于如何将单个源文件转换为目标文件的通用规则:
%.o: %.cpp Makefile
$(CXX) $(CXXFLAGS) &< -o $@
使此规则也取决于Makefile可以确保例如$(CXXFLAGS)
中的更改也会触发重新编译。 $<
解析为 first 依赖项(源文件)。
我们稍后将扩展此规则。
第二步
每个源文件都有一个依赖文件 。 (在这里与我在一起。)我们可以生成这些文件的列表...
DEPENDS := $(patsubst %.cpp,%.d,$(SOURCES))
...并将它们包含在Makefile中:
-include $(DEPENDS)
那里的-
意味着make
不会抱怨那些文件不存在-因为它们现在不存在。
第三步(问题答案的核心)
让编译器为我们生成这些依赖文件 -因为它最了解。为此,我们扩展了构建规则:
%.o: %.cpp Makefile
$(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@
-MMD
标志生成依赖项文件(%.d
),该文件将保存(使用Makefile语法)规则,使生成的文件(在这种情况下为%.o
)取决于源文件及其包含的所有非系统标头。这意味着只要触摸相关源,就会自动重新创建目标文件。如果您还希望依赖系统标头(即在每次编译时检查它们的更新),请改用-MD
。
-MP
选项添加了空的虚拟规则,可以避免在从文件系统中删除头文件时出错。
在第一次编译运行时,没有依赖项信息-但是由于目标文件也不存在,因此无论如何编译器都必须运行。对于以后的每次运行,make
都将包含自动生成的依赖文件,并“做正确的事”。
多合一(添加了一些语法糖):
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 $@