We are required to use a Makefile to pull everything together for our project but our professor never showed us how to.
我们被要求使用Makefile来为我们的项目整合所有的东西,但是我们的教授从来没有教过我们怎么做。
I only have ONE file, a3driver.cpp
. The driver imports a class from a location "/user/cse232/Examples/example32.sequence.cpp"
.
我只有一个文件,a3driver.cpp。驱动程序从一个位置导入一个类“/user/cse232/ example /example32.sequence.cpp”。
That's it, everything else is contained with the .cpp
.
就是这样,其他的都包含在。cpp中。
How would I go about making a simple Makefile that creates an executable called a3a.exe
?
我该如何制作一个简单的Makefile来创建一个名为a3a.exe的可执行文件呢?
7 个解决方案
#1
424
Copied from a wiki post I wrote for physics grad students.
抄袭了我为物理研究生写的维基文章。
Since this is for unix the executables have no extensions.
因为这是针对unix的,所以可执行文件没有扩展。
One thing to note is that root-config
is a utility which provides the right compilation and linking flags; and the right libraries for building applications against root. That's just a detail related to the original audience for this document.
需要注意的一点是,root-config是一种实用工具,它提供正确的编译和链接标志;以及针对root用户构建应用程序的正确库。这只是与本文档的原始读者相关的细节。
Make Me Baby
or You Never Forget The First Time You Got Made
或者你永远不会忘记你第一次被创造
A introductory discussion of make, and how to write a simple makefile
介绍了make,以及如何编写一个简单的makefile
What is Make? And Why Should I Care?
是做什么呢?为什么我要在乎?
The tool called make is a build dependency manager. That is, it takes care of knowing what commands need to be executed in what order to take your software project from a collection of source files, object files, libraries, headers, etc. etc.---some of which may have changed recently---and turning them into a correct up-to-date version of the program.
称为make的工具是一个构建依赖管理器。也就是说,它负责了解需要执行哪些命令,以便从源文件、对象文件、库、头文件等集合中获取软件项目所需的命令——其中一些命令最近可能已经更改了——并将它们转换为正确的程序最新版本。
Actually you can use make for other things too, but I'm not going to talk about that.
实际上你也可以用make来做其他的事情,但我不打算讲这个。
A Trivial Makefile
一个微不足道的Makefile
Suppose that you have a directory containing: tool
tool.cc
tool.o
support.cc
support.hh
, and support.o
which depend on root
and are supposed to be compiled into a program called tool
, and suppose that you've been hacking on the source files (which means the existing tool
is now out of date) and want to compile the program.
假设您有一个包含:tool工具的目录。cc的工具。o的支持。cc的支持。hh,和支持。o依赖于根,应该被编译成一个叫做tool的程序,假设您一直在对源文件进行黑客攻击(这意味着现有的工具已经过时),并希望编译这个程序。
To do this yourself you could
你可以自己做这件事
1) check if either support.cc
or support.hh
is newer than support.o
, and if so run a command like
1)检查是否有支持。cc或支持。hh比支持新。o,如果是,运行类似的命令
g++ -g -c -pthread -I/sw/include/root support.cc
2) check if either support.hh
or tool.cc
are newer than tool.o
, and if so run a command like
2)检查是否有支持。hh或工具。cc比工具更新。o,如果是,运行类似的命令
g++ -g -c -pthread -I/sw/include/root tool.cc
3) check if tool.o
is newer than tool
, and if so run a command like
3)检查工具。o比工具更新,如果是,运行类似的命令
g++ -g tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
Phew! What a hassle! There is a lot to remember and several chances to make mistakes. (BTW-- The particulars of the command lines exhibited here depend on our software environment. These ones work on my computer.)
唷!真麻烦!要记住的东西很多,犯错的机会也很多。(顺便说一句,这里展示的命令行细节取决于我们的软件环境。这些在我的电脑上工作。
Of course, you could just run all three commands every time. That would work, but doesn't scale well to a substantial piece of software (like DOGS which takes more than 15 minutes to compile from the ground up on my MacBook).
当然,您可以每次都运行这三个命令。这是可行的,但不能很好地扩展到一个重要的软件(比如狗狗,从我的MacBook上开始编译需要超过15分钟)。
Instead you could write a file called makefile
like this:
相反,您可以编写一个名为makefile的文件,如下所示:
tool: tool.o support.o
g++ -g -o tool tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
tool.o: tool.cc support.hh
g++ -g -c -pthread -I/sw/include/root tool.cc
support.o: support.hh support.cc
g++ -g -c -pthread -I/sw/include/root support.cc
and just type make
at the command line. which will perform the three steps shown above automatically.
在命令行输入make。它将自动执行上述三个步骤。
The un-indented lines here have the form "target: dependencies" and tell make that the associated commands (indented lines) should be run if any of the dependencies are newer than the target. That is the dependency lines describe the logic of what needs to be rebuilt to accommodate changes in various files. If support.cc
changes that means that support.o
must be rebuilt, but tool.o
can be left alone. When support.o
changes tool
must be rebuilt.
这里未缩进的行具有“目标:依赖项”的形式,如果任何依赖项比目标新,则告诉make应该运行相关的命令(缩进行)。这就是依赖线描述了需要重新构建的逻辑,以适应不同文件中的更改。如果支持。cc更改了这意味着支持。o必须重建,但要有工具。o可以被单独放置。当支持。o变更工具必须重建。
The commands associated with each dependency line are set off with a tab (see below) should modify the target (or at least touch it to update the modification time).
与每个依赖项行相关联的命令都设置了一个选项卡(请参见下面),该选项卡应该修改目标(或者至少触摸它以更新修改时间)。
Variables, Built In Rules, and Other Goodies
At this point, our makefile is simply remembering the work that needs doing, but we still had to figure out and type each and every needed command in its entirety. It does not have to be that way: make is a powerful language with variables, text manipulation functions, and a whole slew of built-in rules which can make this much easier for us.
此时,我们的makefile只是简单地记住需要做的工作,但是我们仍然需要找出并输入所有需要的命令。它不需要这样:make是一种功能强大的语言,带有变量、文本操作功能,以及一系列内置的规则,这些规则可以让我们变得更容易。
Make Variables
使变量
The syntax for accessing a make variable is $(VAR)
.
访问make变量的语法是$(VAR)。
The syntax for assigning to a make variable is: VAR = A text value of some kind
(or VAR := A different text value but ignore this for the moment
).
为make变量赋值的语法是:VAR =某种文本值(或VAR:=另一个文本值,但暂时忽略它)。
You can use variables in rules like this improved version of our makefile:
您可以在规则中使用变量,比如我们的makefile的这个改进版本:
CPPFLAGS=-g -pthread -I/sw/include/root
LDFLAGS=-g
LDLIBS=-L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz \
-Wl,-framework,CoreServices -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root \
-lm -ldl
tool: tool.o support.o
g++ $(LDFLAGS) -o tool tool.o support.o $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
which is a little more readable, but still requires a lot of typing
哪个更容易读,但仍然需要大量输入
Make Functions
使功能
GNU make supports a variety of functions for accessing information from the filesystem or other commands on the system. In this case we are interested in $(shell ...)
which expands to the output of the argument(s), and $(subst opat,npat,text)
which replaces all instances of opat
with npat
in text.
GNU make支持从文件系统或系统上的其他命令访问信息的各种函数。在本例中,我们感兴趣的是$(shell…)扩展到参数的输出,以及$(subst opat,npat,text),它用文本中的npat替换所有opat实例。
Taking advantage of this gives us:
利用这一点,我们得到:
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
tool: $(OBJS)
g++ $(LDFLAGS) -o tool tool.o support.o $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
which is easier to type and much more readable.
它更容易输入,可读性更好。
Notice that
请注意,
- We are still stating explicitly the dependencies for each object file and the final executable
- 我们仍然在显式地声明每个对象文件和最终可执行文件的依赖关系
- We've had to explicitly type the compilation rule for both source files
- 我们必须显式地为两个源文件输入编译规则
Implicit and Pattern Rules
隐式规则和模式
We would generally expect that all c++ source files should be treated the same way, and make provides three ways to state this
我们通常认为所有c++源文件都应该以相同的方式处理,make提供了三种方式来说明这一点
- suffix rules (considered obsolete in GNU make, but kept for backwards compatibility)
- 后缀规则(在GNU make中被认为是过时的,但是为了向后兼容而保留)
- implicit rules
- 隐式规则
- pattern rules
- 模式的规则
Implicit rules are built in, and a few will be discussed below. Pattern rules are specified in a form like
内建隐规则,下面将讨论一些。模式规则以类似的形式指定
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
which means that object files are generated from c source files by running the command shown, where the "automatic" variable $<
expands to the name of the first dependency.
这意味着对象文件是通过运行所示的命令从c源文件生成的,其中“自动”变量$ <扩展为第一个依赖项的名称。< p>
Built-in Rules
内置规则
Make has a whole host of built in rules that mean that very often, a project can be compile by a very simple makefile, indeed.
Make拥有大量内置的规则,这意味着通常一个项目可以通过一个非常简单的makefile进行编译。
The GNU make built in rule for c source files is the one exhibited above. Similarly we create object files from c++ source files with a rule like $(CXX) -c $(CPPFLAGS) $(CFLAGS)
GNU为c源文件构建的规则就是上面展示的那个。类似地,我们使用$(CXX) -c $(CPPFLAGS) $(CFLAGS)
Single object files are linked using $(LD) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
, but this won't work in our case, because we want to link multiple object files.
单个对象文件使用$(LD) $(LDFLAGS) n链接。o $(LOADLIBES) $(LDLIBS),但是这在我们的例子中行不通,因为我们想要链接多个对象文件。
Variables Used By Built-in Rules
内置规则使用的变量。
The built in rules use a set of standard variables that allow you to specify local environment information (like where to find the ROOT include files) without re-writing all the rules. The ones most likely to be interesting to us are:
内置规则使用一组标准变量,这些变量允许您指定本地环境信息(比如在哪里找到根包含文件),而无需重写所有规则。最有可能让我们感兴趣的是:
-
CC
-- the c compiler to use - CC——要使用的c编译器
-
CXX
-- the c++ compiler to use - CXX——使用c++编译器。
-
LD
-- the linker to use - LD——链接器
-
CFLAGS
-- compilation flag for c source files - CFLAGS——c源文件的编译标志
-
CXXFLAGS
-- compilation flags for c++ source files - CXXFLAGS——c++源文件的编译标记
-
CPPFLAGS
-- flags for the c-preprocessor (typically include file paths and symbols defined on the command line), used by c and c++ - CPPFLAGS——c-preprocessor(通常包括命令行上定义的文件路径和符号)的标志,由c和c++使用
-
LDFLAGS
-- linker flags - LDFLAGS——链接器标志
-
LDLIBS
-- libraries to link - LDLIBS——链接的库
A Basic Makefile
一个基本的Makefile
By taking advantage of the built in rules we can simplify our makefile to:
利用内置规则,我们可以将makefile简化为:
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
tool.o: tool.cc support.hh
support.o: support.hh support.cc
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) tool
We have also added several standard targets that perform special actions (like cleaning up the source directory).
我们还添加了几个执行特殊操作的标准目标(如清理源目录)。
Note that when make is invoked without an argument, it uses the first target found in the file (in this case all), but you can also name the target to get which is what makes make clean
remove the object files in this case.
注意,在没有参数的情况下调用make时,它使用文件中找到的第一个目标(在本例中是all),但是您也可以为目标命名,以便在这种情况下获取make clean删除对象文件。
We still have all the dependencies hard-coded.
我们仍然有硬编码的所有依赖项。
Some Mysterious Improvements
一些神秘的改进
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
depend: .depend
.depend: $(SRCS)
$(RM) ./.depend
$(CXX) $(CPPFLAGS) -MM $^>>./.depend;
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) *~ .depend
include .depend
Notice that
请注意,
- There are no longer any dependency lines for the source files!?!
- 源文件不再有任何依赖行!
- There is some strange magic related to .depend and depend
- 有一些奇怪的魔法与。依靠和依赖有关
- If you do
make
thenls -A
you see a file named.depend
which contains things that look like make dependency lines - 如果你确实做了ls -A,你会看到一个名为.depend的文件,它包含了看起来像依赖项的东西。
Other Reading
其他阅读
- GNU make manual
- GNU做手工
- Recursive Make Considered Harmful on a common way of writing makefiles that is less than optimal, and how to avoid it.
- 递归会被认为是有害的,以一种常见的方式编写makefile,它不是最优的,以及如何避免它。
Know Bugs and Historical Notes
了解错误和历史记录
The input language for make is whitespace sensitive. In particular the action lines following dependencies must start with a tab. But a series of spaces can look the same (and indeed there are editors that will silently convert tabs to spaces or vice versa), which results in a make file that looks right and still doesn't work. This was identified as a bug early on but (the story goes) was not fixed because there were already 10 users.
make的输入语言是空格敏感的。特别是依赖项后面的动作行必须以选项卡开头。但是,一系列的空格看起来是一样的(确实有编辑器可以悄悄地将制表符转换为空格,反之亦然),这会导致make文件看起来是正确的,但仍然不能工作。这在早期被认为是一个bug,但是(故事是这样的)并没有被修复,因为已经有10个用户了。
#2
44
I've always thought this was easier to learn with a detailed example, so here's how I think of makefiles. For each section you have one line that's not indented and it shows the name of the section followed by dependencies. The dependencies can be either other sections (which will be run before the current section) or files (which if updated will cause the current section to be run again next time you run make
).
我一直认为通过一个详细的示例可以更容易地了解这一点,因此下面是我对makefile的看法。对于每个部分,都有一行没有缩进,它显示了部分的名称和依赖项。依赖项可以是其他部分(将在当前部分之前运行)或文件(如果更新,将导致下次运行make时再次运行当前部分)。
Here's a quick example (keep in mind that I'm using 4 spaces where I should be using a tab, Stack Overflow won't let me use tabs):
这里有一个简单的例子(请记住,我使用的是4个应该使用选项卡的空格,栈溢出不会让我使用选项卡):
a3driver: a3driver.o
g++ -o a3driver a3driver.o
a3driver.o: a3driver.cpp
g++ -c a3driver.cpp
When you type make
, it will choose the first section (a3driver). a3driver depends on a3driver.o, so it will go to that section. a3driver.o depends on a3driver.cpp, so it will only run if a3driver.cpp has changed since it was last run. Assuming it has (or has never been run), it will compile a3driver.cpp to a .o file, then go back to a3driver and compile the final executable.
输入make时,它将选择第一部分(a3driver)。a3driver取决于a3driver。所以它会到那个部分。a3driver。o取决于a3driver。cpp,所以只有a3driver才能运行。cpp自上次运行以来已经发生了变化。假设它有(或者从未运行过),它将编译a3driver。cpp到.o文件,然后返回到a3driver并编译最终可执行文件。
Since there's only one file, it could even be reduced to:
由于只有一个文件,它甚至可以简化为:
a3driver: a3driver.cpp
g++ -o a3driver a3driver.cpp
The reason I showed the first example is that it shows the power of makefiles. If you need to compile another file, you can just add another section. Here's an example with a secondFile.cpp (which loads in a header named secondFile.h):
我展示第一个例子的原因是它显示了makefile的威力。如果需要编译另一个文件,只需添加另一个部分。这里有一个第二个文件的例子。cpp(装入名为secondFile.h的头文件):
a3driver: a3driver.o secondFile.o
g++ -o a3driver a3driver.o secondFile.o
a3driver.o: a3driver.cpp
g++ -c a3driver.cpp
secondFile.o: secondFile.cpp secondFile.h
g++ -c secondFile.cpp
This way if you change something in secondFile.cpp or secondFile.h and recompile, it will only recompile secondFile.cpp (not a3driver.cpp). Or alternately, if you change something in a3driver.cpp, it won't recompile secondFile.cpp.
这样,如果你在secondFile中更改了一些内容。cpp或secondFile。h和recompile,它只会重新编译secondFile。cpp(不是a3driver.cpp)。或者,如果你改变a3driver中的某些东西。cpp,它不会重新编译secondFile.cpp。
Let me know if you have any questions about it.
如果你有任何问题,请告诉我。
It's also traditional to include a section named "all" and a section named "clean". "all" will usually build all of the executables, and "clean" will remove "build artifacts" like .o files and the executables:
传统的做法还包括一个名为“all”的部分和一个名为“clean”的部分。“all”通常将构建所有可执行文件,“clean”将删除“构建构件”,如.o文件和可执行文件:
all: a3driver ;
clean:
# -f so this will succeed even if the files don't exist
rm -f a3driver a3driver.o
EDIT: I didn't notice you're on Windows. I think the only difference is changing the -o a3driver
to -o a3driver.exe
.
编辑:我没注意到你在窗户上。我认为唯一的区别是把-o a3driver改为-o a3driver.exe。
#3
26
Why does everyone like to list out source files? A simple find command can take care of that easily.
为什么每个人都喜欢列出源文件?一个简单的find命令可以轻松处理这个问题。
Here's an example of a dirt simple C++ Makefile. Just drop it in a directory containing .C
files and then type make
...
这里有一个极其简单的c++ Makefile示例。只需将其放入包含.C文件的目录中,然后键入make…
appname := myapp
CXX := clang++
CXXFLAGS := -std=c++11
srcfiles := $(shell find . -name "*.C")
objects := $(patsubst %.C, %.o, $(srcfiles))
all: $(appname)
$(appname): $(objects)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)
depend: .depend
.depend: $(srcfiles)
rm -f ./.depend
$(CXX) $(CXXFLAGS) -MM $^>>./.depend;
clean:
rm -f $(objects)
dist-clean: clean
rm -f *~ .depend
include .depend
#4
11
Old question, I know, but for posterity. You had two options.
老问题,我知道,但为了子孙后代。你有两个选择。
Option 1: simplest makefile = NO MAKEFILE.
选项1:最简单的makefile =没有makefile。
Rename "a3driver.cpp" to "a3a.cpp", then on the command line write:
重命名”a3driver。cpp”到“a3a。然后在命令行上写:
nmake a3a.exe
And that's it. If you're using gnu-make use "make" or "gmake" or whatever.
就是这样。如果你在使用gnu-make use“make”或“gmake”之类的词。
Option 2: a 2-line makefile.
选项2:两行makefile。
a3a.exe: a3driver.obj
link /out:a3a.exe a3driver.obj
Voilà.
瞧。
#5
4
Your make file will have one or two dependency rules depending on whether you compile and link with a single command, or with one command for the compile and one for the link.
您的make文件将有一个或两个依赖规则,这取决于您是使用单个命令进行编译和链接,还是使用一个命令进行编译,一个命令用于链接。
Dependency are a tree of rules that look like this:
依赖性是一棵规则树,看起来像这样:
main_target : source1 source2 etc
command to build main_target from sources
source1 : dependents for source1
command to build source1
There must be a blank line after the commands for a target, and there must not be a blank line before the commands. The first target in the makefile is the overall goal, other targets are built only if the first target depends on them.
必须在目标的命令之后有一个空行,并且在命令之前不能有空行。makefile中的第一个目标是总体目标,只有在第一个目标依赖于它们时才构建其他目标。
So your makefile will look something like this.
你的makefile会是这样的。
a3a.exe : a3driver.obj
link /out:a3a.exe a3driver.obj
a3driver.obj : a3driver.cpp
cc a3driver.cpp
#6
4
I used friedmud's answer. I looked into this for a while, and it seems to be a good way to get started. This solution also has a well defined method of adding compiler flags. I answered again because I made changes to make it work in my environment, Ubuntu and g++. More working examples are the best teacher, sometimes.
我用friedmud的回答。我研究了一会儿,这似乎是一个很好的开始。这个解决方案还有一个定义良好的添加编译器标志的方法。我再次回答,因为我做了一些修改,使它在我的环境中工作,Ubuntu和g++。更多的例子是最好的老师,有时。
appname := myapp
CXX := g++
CXXFLAGS := -Wall -g
srcfiles := $(shell find . -maxdepth 1 -name "*.cpp")
objects := $(patsubst %.cpp, %.o, $(srcfiles))
all: $(appname)
$(appname): $(objects)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)
depend: .depend
.depend: $(srcfiles)
rm -f ./.depend
$(CXX) $(CXXFLAGS) -MM $^>>./.depend;
clean:
rm -f $(objects)
dist-clean: clean
rm -f *~ .depend
include .depend
makefiles seem to be very complex. I was using one, but it was generating an error related to not linking in g++ libraries. This configuration solved that problem.
makefile似乎非常复杂。我使用了一个,但是它产生了一个与没有在g++库中链接有关的错误。这个配置解决了这个问题。
#7
2
That is a simple Makefile
:
这是一个简单的Makefile:
tool: tool.o file1.o file2.o
override CPPFLAGS += -MMD
LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
include $(wildcard *.d)
In order to have a full featured Makefile
, I suggest to also add:
为了拥有一个完整的Makefile,我建议还添加:
clean:
$(RM) *.o *.d
distclean: clean
$(RM) tool
A few notes:
一些笔记:
- We use an implicit rule to create final executable. So, in order to work, a source file must have same name than final executable (ie:
tool.c
andtool
). - 我们使用隐式规则来创建最终的可执行文件。因此,为了工作,源文件必须有与最终可执行文件(即:工具)相同的名称。c和工具)。
- By default, Makefile use
$(CC)
as linker and it does not work to link C++ objects. We modifyLINK.o
in order to force Makefile to use$(CXX)
to link objects. - 默认情况下,Makefile使用$(CC)作为链接器,它不能链接c++对象。我们修改链接。o为了强制Makefile使用$(CXX)来链接对象。
- Dependencies with header are handled automatically by adding
-MMD
flag and including generated.d
files - 通过添加-MMD标志和包含生成的.d文件,可以自动处理与header的依赖关系
- It is not necessary to declare sources. Intermediate object files are generated using implicit rule. Consequently, this
Makefile
work for C and C++ (and also for Fortran, etc...). - 没有必要声明来源。使用隐式规则生成中间对象文件。因此,这个Makefile适用于C和c++(也适用于Fortran等)。
- If you want to work with files in subdirectories, you have to keep this
Makefile
in root directory and provide path in source names (ie.subdir/file.o
) - 如果您想在子目录中处理文件,您必须将这个Makefile保存在根目录中,并在源名称中提供路径。子目录/ file.o)
- You may want to add
install:
andall:
rules - 您可能想要添加install: and all: rules
- You can add compilation and links flags in
$(CFLAGS)
,$(LDLIBS)
, etc... as usual - 您可以添加$(CFLAGS)、$(LDLIBS)等的编译和链接标志……像往常一样
- Default value of
$(RM)
isrm -f
- $(RM)的默认值是RM -f
#1
424
Copied from a wiki post I wrote for physics grad students.
抄袭了我为物理研究生写的维基文章。
Since this is for unix the executables have no extensions.
因为这是针对unix的,所以可执行文件没有扩展。
One thing to note is that root-config
is a utility which provides the right compilation and linking flags; and the right libraries for building applications against root. That's just a detail related to the original audience for this document.
需要注意的一点是,root-config是一种实用工具,它提供正确的编译和链接标志;以及针对root用户构建应用程序的正确库。这只是与本文档的原始读者相关的细节。
Make Me Baby
or You Never Forget The First Time You Got Made
或者你永远不会忘记你第一次被创造
A introductory discussion of make, and how to write a simple makefile
介绍了make,以及如何编写一个简单的makefile
What is Make? And Why Should I Care?
是做什么呢?为什么我要在乎?
The tool called make is a build dependency manager. That is, it takes care of knowing what commands need to be executed in what order to take your software project from a collection of source files, object files, libraries, headers, etc. etc.---some of which may have changed recently---and turning them into a correct up-to-date version of the program.
称为make的工具是一个构建依赖管理器。也就是说,它负责了解需要执行哪些命令,以便从源文件、对象文件、库、头文件等集合中获取软件项目所需的命令——其中一些命令最近可能已经更改了——并将它们转换为正确的程序最新版本。
Actually you can use make for other things too, but I'm not going to talk about that.
实际上你也可以用make来做其他的事情,但我不打算讲这个。
A Trivial Makefile
一个微不足道的Makefile
Suppose that you have a directory containing: tool
tool.cc
tool.o
support.cc
support.hh
, and support.o
which depend on root
and are supposed to be compiled into a program called tool
, and suppose that you've been hacking on the source files (which means the existing tool
is now out of date) and want to compile the program.
假设您有一个包含:tool工具的目录。cc的工具。o的支持。cc的支持。hh,和支持。o依赖于根,应该被编译成一个叫做tool的程序,假设您一直在对源文件进行黑客攻击(这意味着现有的工具已经过时),并希望编译这个程序。
To do this yourself you could
你可以自己做这件事
1) check if either support.cc
or support.hh
is newer than support.o
, and if so run a command like
1)检查是否有支持。cc或支持。hh比支持新。o,如果是,运行类似的命令
g++ -g -c -pthread -I/sw/include/root support.cc
2) check if either support.hh
or tool.cc
are newer than tool.o
, and if so run a command like
2)检查是否有支持。hh或工具。cc比工具更新。o,如果是,运行类似的命令
g++ -g -c -pthread -I/sw/include/root tool.cc
3) check if tool.o
is newer than tool
, and if so run a command like
3)检查工具。o比工具更新,如果是,运行类似的命令
g++ -g tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
Phew! What a hassle! There is a lot to remember and several chances to make mistakes. (BTW-- The particulars of the command lines exhibited here depend on our software environment. These ones work on my computer.)
唷!真麻烦!要记住的东西很多,犯错的机会也很多。(顺便说一句,这里展示的命令行细节取决于我们的软件环境。这些在我的电脑上工作。
Of course, you could just run all three commands every time. That would work, but doesn't scale well to a substantial piece of software (like DOGS which takes more than 15 minutes to compile from the ground up on my MacBook).
当然,您可以每次都运行这三个命令。这是可行的,但不能很好地扩展到一个重要的软件(比如狗狗,从我的MacBook上开始编译需要超过15分钟)。
Instead you could write a file called makefile
like this:
相反,您可以编写一个名为makefile的文件,如下所示:
tool: tool.o support.o
g++ -g -o tool tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
tool.o: tool.cc support.hh
g++ -g -c -pthread -I/sw/include/root tool.cc
support.o: support.hh support.cc
g++ -g -c -pthread -I/sw/include/root support.cc
and just type make
at the command line. which will perform the three steps shown above automatically.
在命令行输入make。它将自动执行上述三个步骤。
The un-indented lines here have the form "target: dependencies" and tell make that the associated commands (indented lines) should be run if any of the dependencies are newer than the target. That is the dependency lines describe the logic of what needs to be rebuilt to accommodate changes in various files. If support.cc
changes that means that support.o
must be rebuilt, but tool.o
can be left alone. When support.o
changes tool
must be rebuilt.
这里未缩进的行具有“目标:依赖项”的形式,如果任何依赖项比目标新,则告诉make应该运行相关的命令(缩进行)。这就是依赖线描述了需要重新构建的逻辑,以适应不同文件中的更改。如果支持。cc更改了这意味着支持。o必须重建,但要有工具。o可以被单独放置。当支持。o变更工具必须重建。
The commands associated with each dependency line are set off with a tab (see below) should modify the target (or at least touch it to update the modification time).
与每个依赖项行相关联的命令都设置了一个选项卡(请参见下面),该选项卡应该修改目标(或者至少触摸它以更新修改时间)。
Variables, Built In Rules, and Other Goodies
At this point, our makefile is simply remembering the work that needs doing, but we still had to figure out and type each and every needed command in its entirety. It does not have to be that way: make is a powerful language with variables, text manipulation functions, and a whole slew of built-in rules which can make this much easier for us.
此时,我们的makefile只是简单地记住需要做的工作,但是我们仍然需要找出并输入所有需要的命令。它不需要这样:make是一种功能强大的语言,带有变量、文本操作功能,以及一系列内置的规则,这些规则可以让我们变得更容易。
Make Variables
使变量
The syntax for accessing a make variable is $(VAR)
.
访问make变量的语法是$(VAR)。
The syntax for assigning to a make variable is: VAR = A text value of some kind
(or VAR := A different text value but ignore this for the moment
).
为make变量赋值的语法是:VAR =某种文本值(或VAR:=另一个文本值,但暂时忽略它)。
You can use variables in rules like this improved version of our makefile:
您可以在规则中使用变量,比如我们的makefile的这个改进版本:
CPPFLAGS=-g -pthread -I/sw/include/root
LDFLAGS=-g
LDLIBS=-L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz \
-Wl,-framework,CoreServices -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root \
-lm -ldl
tool: tool.o support.o
g++ $(LDFLAGS) -o tool tool.o support.o $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
which is a little more readable, but still requires a lot of typing
哪个更容易读,但仍然需要大量输入
Make Functions
使功能
GNU make supports a variety of functions for accessing information from the filesystem or other commands on the system. In this case we are interested in $(shell ...)
which expands to the output of the argument(s), and $(subst opat,npat,text)
which replaces all instances of opat
with npat
in text.
GNU make支持从文件系统或系统上的其他命令访问信息的各种函数。在本例中,我们感兴趣的是$(shell…)扩展到参数的输出,以及$(subst opat,npat,text),它用文本中的npat替换所有opat实例。
Taking advantage of this gives us:
利用这一点,我们得到:
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
tool: $(OBJS)
g++ $(LDFLAGS) -o tool tool.o support.o $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
which is easier to type and much more readable.
它更容易输入,可读性更好。
Notice that
请注意,
- We are still stating explicitly the dependencies for each object file and the final executable
- 我们仍然在显式地声明每个对象文件和最终可执行文件的依赖关系
- We've had to explicitly type the compilation rule for both source files
- 我们必须显式地为两个源文件输入编译规则
Implicit and Pattern Rules
隐式规则和模式
We would generally expect that all c++ source files should be treated the same way, and make provides three ways to state this
我们通常认为所有c++源文件都应该以相同的方式处理,make提供了三种方式来说明这一点
- suffix rules (considered obsolete in GNU make, but kept for backwards compatibility)
- 后缀规则(在GNU make中被认为是过时的,但是为了向后兼容而保留)
- implicit rules
- 隐式规则
- pattern rules
- 模式的规则
Implicit rules are built in, and a few will be discussed below. Pattern rules are specified in a form like
内建隐规则,下面将讨论一些。模式规则以类似的形式指定
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
which means that object files are generated from c source files by running the command shown, where the "automatic" variable $<
expands to the name of the first dependency.
这意味着对象文件是通过运行所示的命令从c源文件生成的,其中“自动”变量$ <扩展为第一个依赖项的名称。< p>
Built-in Rules
内置规则
Make has a whole host of built in rules that mean that very often, a project can be compile by a very simple makefile, indeed.
Make拥有大量内置的规则,这意味着通常一个项目可以通过一个非常简单的makefile进行编译。
The GNU make built in rule for c source files is the one exhibited above. Similarly we create object files from c++ source files with a rule like $(CXX) -c $(CPPFLAGS) $(CFLAGS)
GNU为c源文件构建的规则就是上面展示的那个。类似地,我们使用$(CXX) -c $(CPPFLAGS) $(CFLAGS)
Single object files are linked using $(LD) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
, but this won't work in our case, because we want to link multiple object files.
单个对象文件使用$(LD) $(LDFLAGS) n链接。o $(LOADLIBES) $(LDLIBS),但是这在我们的例子中行不通,因为我们想要链接多个对象文件。
Variables Used By Built-in Rules
内置规则使用的变量。
The built in rules use a set of standard variables that allow you to specify local environment information (like where to find the ROOT include files) without re-writing all the rules. The ones most likely to be interesting to us are:
内置规则使用一组标准变量,这些变量允许您指定本地环境信息(比如在哪里找到根包含文件),而无需重写所有规则。最有可能让我们感兴趣的是:
-
CC
-- the c compiler to use - CC——要使用的c编译器
-
CXX
-- the c++ compiler to use - CXX——使用c++编译器。
-
LD
-- the linker to use - LD——链接器
-
CFLAGS
-- compilation flag for c source files - CFLAGS——c源文件的编译标志
-
CXXFLAGS
-- compilation flags for c++ source files - CXXFLAGS——c++源文件的编译标记
-
CPPFLAGS
-- flags for the c-preprocessor (typically include file paths and symbols defined on the command line), used by c and c++ - CPPFLAGS——c-preprocessor(通常包括命令行上定义的文件路径和符号)的标志,由c和c++使用
-
LDFLAGS
-- linker flags - LDFLAGS——链接器标志
-
LDLIBS
-- libraries to link - LDLIBS——链接的库
A Basic Makefile
一个基本的Makefile
By taking advantage of the built in rules we can simplify our makefile to:
利用内置规则,我们可以将makefile简化为:
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
tool.o: tool.cc support.hh
support.o: support.hh support.cc
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) tool
We have also added several standard targets that perform special actions (like cleaning up the source directory).
我们还添加了几个执行特殊操作的标准目标(如清理源目录)。
Note that when make is invoked without an argument, it uses the first target found in the file (in this case all), but you can also name the target to get which is what makes make clean
remove the object files in this case.
注意,在没有参数的情况下调用make时,它使用文件中找到的第一个目标(在本例中是all),但是您也可以为目标命名,以便在这种情况下获取make clean删除对象文件。
We still have all the dependencies hard-coded.
我们仍然有硬编码的所有依赖项。
Some Mysterious Improvements
一些神秘的改进
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
depend: .depend
.depend: $(SRCS)
$(RM) ./.depend
$(CXX) $(CPPFLAGS) -MM $^>>./.depend;
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) *~ .depend
include .depend
Notice that
请注意,
- There are no longer any dependency lines for the source files!?!
- 源文件不再有任何依赖行!
- There is some strange magic related to .depend and depend
- 有一些奇怪的魔法与。依靠和依赖有关
- If you do
make
thenls -A
you see a file named.depend
which contains things that look like make dependency lines - 如果你确实做了ls -A,你会看到一个名为.depend的文件,它包含了看起来像依赖项的东西。
Other Reading
其他阅读
- GNU make manual
- GNU做手工
- Recursive Make Considered Harmful on a common way of writing makefiles that is less than optimal, and how to avoid it.
- 递归会被认为是有害的,以一种常见的方式编写makefile,它不是最优的,以及如何避免它。
Know Bugs and Historical Notes
了解错误和历史记录
The input language for make is whitespace sensitive. In particular the action lines following dependencies must start with a tab. But a series of spaces can look the same (and indeed there are editors that will silently convert tabs to spaces or vice versa), which results in a make file that looks right and still doesn't work. This was identified as a bug early on but (the story goes) was not fixed because there were already 10 users.
make的输入语言是空格敏感的。特别是依赖项后面的动作行必须以选项卡开头。但是,一系列的空格看起来是一样的(确实有编辑器可以悄悄地将制表符转换为空格,反之亦然),这会导致make文件看起来是正确的,但仍然不能工作。这在早期被认为是一个bug,但是(故事是这样的)并没有被修复,因为已经有10个用户了。
#2
44
I've always thought this was easier to learn with a detailed example, so here's how I think of makefiles. For each section you have one line that's not indented and it shows the name of the section followed by dependencies. The dependencies can be either other sections (which will be run before the current section) or files (which if updated will cause the current section to be run again next time you run make
).
我一直认为通过一个详细的示例可以更容易地了解这一点,因此下面是我对makefile的看法。对于每个部分,都有一行没有缩进,它显示了部分的名称和依赖项。依赖项可以是其他部分(将在当前部分之前运行)或文件(如果更新,将导致下次运行make时再次运行当前部分)。
Here's a quick example (keep in mind that I'm using 4 spaces where I should be using a tab, Stack Overflow won't let me use tabs):
这里有一个简单的例子(请记住,我使用的是4个应该使用选项卡的空格,栈溢出不会让我使用选项卡):
a3driver: a3driver.o
g++ -o a3driver a3driver.o
a3driver.o: a3driver.cpp
g++ -c a3driver.cpp
When you type make
, it will choose the first section (a3driver). a3driver depends on a3driver.o, so it will go to that section. a3driver.o depends on a3driver.cpp, so it will only run if a3driver.cpp has changed since it was last run. Assuming it has (or has never been run), it will compile a3driver.cpp to a .o file, then go back to a3driver and compile the final executable.
输入make时,它将选择第一部分(a3driver)。a3driver取决于a3driver。所以它会到那个部分。a3driver。o取决于a3driver。cpp,所以只有a3driver才能运行。cpp自上次运行以来已经发生了变化。假设它有(或者从未运行过),它将编译a3driver。cpp到.o文件,然后返回到a3driver并编译最终可执行文件。
Since there's only one file, it could even be reduced to:
由于只有一个文件,它甚至可以简化为:
a3driver: a3driver.cpp
g++ -o a3driver a3driver.cpp
The reason I showed the first example is that it shows the power of makefiles. If you need to compile another file, you can just add another section. Here's an example with a secondFile.cpp (which loads in a header named secondFile.h):
我展示第一个例子的原因是它显示了makefile的威力。如果需要编译另一个文件,只需添加另一个部分。这里有一个第二个文件的例子。cpp(装入名为secondFile.h的头文件):
a3driver: a3driver.o secondFile.o
g++ -o a3driver a3driver.o secondFile.o
a3driver.o: a3driver.cpp
g++ -c a3driver.cpp
secondFile.o: secondFile.cpp secondFile.h
g++ -c secondFile.cpp
This way if you change something in secondFile.cpp or secondFile.h and recompile, it will only recompile secondFile.cpp (not a3driver.cpp). Or alternately, if you change something in a3driver.cpp, it won't recompile secondFile.cpp.
这样,如果你在secondFile中更改了一些内容。cpp或secondFile。h和recompile,它只会重新编译secondFile。cpp(不是a3driver.cpp)。或者,如果你改变a3driver中的某些东西。cpp,它不会重新编译secondFile.cpp。
Let me know if you have any questions about it.
如果你有任何问题,请告诉我。
It's also traditional to include a section named "all" and a section named "clean". "all" will usually build all of the executables, and "clean" will remove "build artifacts" like .o files and the executables:
传统的做法还包括一个名为“all”的部分和一个名为“clean”的部分。“all”通常将构建所有可执行文件,“clean”将删除“构建构件”,如.o文件和可执行文件:
all: a3driver ;
clean:
# -f so this will succeed even if the files don't exist
rm -f a3driver a3driver.o
EDIT: I didn't notice you're on Windows. I think the only difference is changing the -o a3driver
to -o a3driver.exe
.
编辑:我没注意到你在窗户上。我认为唯一的区别是把-o a3driver改为-o a3driver.exe。
#3
26
Why does everyone like to list out source files? A simple find command can take care of that easily.
为什么每个人都喜欢列出源文件?一个简单的find命令可以轻松处理这个问题。
Here's an example of a dirt simple C++ Makefile. Just drop it in a directory containing .C
files and then type make
...
这里有一个极其简单的c++ Makefile示例。只需将其放入包含.C文件的目录中,然后键入make…
appname := myapp
CXX := clang++
CXXFLAGS := -std=c++11
srcfiles := $(shell find . -name "*.C")
objects := $(patsubst %.C, %.o, $(srcfiles))
all: $(appname)
$(appname): $(objects)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)
depend: .depend
.depend: $(srcfiles)
rm -f ./.depend
$(CXX) $(CXXFLAGS) -MM $^>>./.depend;
clean:
rm -f $(objects)
dist-clean: clean
rm -f *~ .depend
include .depend
#4
11
Old question, I know, but for posterity. You had two options.
老问题,我知道,但为了子孙后代。你有两个选择。
Option 1: simplest makefile = NO MAKEFILE.
选项1:最简单的makefile =没有makefile。
Rename "a3driver.cpp" to "a3a.cpp", then on the command line write:
重命名”a3driver。cpp”到“a3a。然后在命令行上写:
nmake a3a.exe
And that's it. If you're using gnu-make use "make" or "gmake" or whatever.
就是这样。如果你在使用gnu-make use“make”或“gmake”之类的词。
Option 2: a 2-line makefile.
选项2:两行makefile。
a3a.exe: a3driver.obj
link /out:a3a.exe a3driver.obj
Voilà.
瞧。
#5
4
Your make file will have one or two dependency rules depending on whether you compile and link with a single command, or with one command for the compile and one for the link.
您的make文件将有一个或两个依赖规则,这取决于您是使用单个命令进行编译和链接,还是使用一个命令进行编译,一个命令用于链接。
Dependency are a tree of rules that look like this:
依赖性是一棵规则树,看起来像这样:
main_target : source1 source2 etc
command to build main_target from sources
source1 : dependents for source1
command to build source1
There must be a blank line after the commands for a target, and there must not be a blank line before the commands. The first target in the makefile is the overall goal, other targets are built only if the first target depends on them.
必须在目标的命令之后有一个空行,并且在命令之前不能有空行。makefile中的第一个目标是总体目标,只有在第一个目标依赖于它们时才构建其他目标。
So your makefile will look something like this.
你的makefile会是这样的。
a3a.exe : a3driver.obj
link /out:a3a.exe a3driver.obj
a3driver.obj : a3driver.cpp
cc a3driver.cpp
#6
4
I used friedmud's answer. I looked into this for a while, and it seems to be a good way to get started. This solution also has a well defined method of adding compiler flags. I answered again because I made changes to make it work in my environment, Ubuntu and g++. More working examples are the best teacher, sometimes.
我用friedmud的回答。我研究了一会儿,这似乎是一个很好的开始。这个解决方案还有一个定义良好的添加编译器标志的方法。我再次回答,因为我做了一些修改,使它在我的环境中工作,Ubuntu和g++。更多的例子是最好的老师,有时。
appname := myapp
CXX := g++
CXXFLAGS := -Wall -g
srcfiles := $(shell find . -maxdepth 1 -name "*.cpp")
objects := $(patsubst %.cpp, %.o, $(srcfiles))
all: $(appname)
$(appname): $(objects)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)
depend: .depend
.depend: $(srcfiles)
rm -f ./.depend
$(CXX) $(CXXFLAGS) -MM $^>>./.depend;
clean:
rm -f $(objects)
dist-clean: clean
rm -f *~ .depend
include .depend
makefiles seem to be very complex. I was using one, but it was generating an error related to not linking in g++ libraries. This configuration solved that problem.
makefile似乎非常复杂。我使用了一个,但是它产生了一个与没有在g++库中链接有关的错误。这个配置解决了这个问题。
#7
2
That is a simple Makefile
:
这是一个简单的Makefile:
tool: tool.o file1.o file2.o
override CPPFLAGS += -MMD
LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
include $(wildcard *.d)
In order to have a full featured Makefile
, I suggest to also add:
为了拥有一个完整的Makefile,我建议还添加:
clean:
$(RM) *.o *.d
distclean: clean
$(RM) tool
A few notes:
一些笔记:
- We use an implicit rule to create final executable. So, in order to work, a source file must have same name than final executable (ie:
tool.c
andtool
). - 我们使用隐式规则来创建最终的可执行文件。因此,为了工作,源文件必须有与最终可执行文件(即:工具)相同的名称。c和工具)。
- By default, Makefile use
$(CC)
as linker and it does not work to link C++ objects. We modifyLINK.o
in order to force Makefile to use$(CXX)
to link objects. - 默认情况下,Makefile使用$(CC)作为链接器,它不能链接c++对象。我们修改链接。o为了强制Makefile使用$(CXX)来链接对象。
- Dependencies with header are handled automatically by adding
-MMD
flag and including generated.d
files - 通过添加-MMD标志和包含生成的.d文件,可以自动处理与header的依赖关系
- It is not necessary to declare sources. Intermediate object files are generated using implicit rule. Consequently, this
Makefile
work for C and C++ (and also for Fortran, etc...). - 没有必要声明来源。使用隐式规则生成中间对象文件。因此,这个Makefile适用于C和c++(也适用于Fortran等)。
- If you want to work with files in subdirectories, you have to keep this
Makefile
in root directory and provide path in source names (ie.subdir/file.o
) - 如果您想在子目录中处理文件,您必须将这个Makefile保存在根目录中,并在源名称中提供路径。子目录/ file.o)
- You may want to add
install:
andall:
rules - 您可能想要添加install: and all: rules
- You can add compilation and links flags in
$(CFLAGS)
,$(LDLIBS)
, etc... as usual - 您可以添加$(CFLAGS)、$(LDLIBS)等的编译和链接标志……像往常一样
- Default value of
$(RM)
isrm -f
- $(RM)的默认值是RM -f