如何使一个简单的C ++ Makefile? [英] How to make a SIMPLE C++ Makefile?

查看:227
本文介绍了如何使一个简单的C ++ Makefile?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们需要使用一个Makefile来为我们的项目拉出一切,但我们的教授从来没有告诉我们如何。



我只有一个文件, a3driver.cpp
驱动程序从位置/ user / cse232 / Examples / example32.sequence.cpp导入类。



这是它,其他一切都包含在 .cpp



创建一个简单的Makefile,创建一个名为 a3a.exe


的解决方案 >



因为这是unix的可执行文件没有扩展名。


$ b $需要注意的是, root-config 是一个提供正确编译和链接标志的实用程序;和根据root构建应用程序的正确库。



让我宝贝





关于make的介绍性讨论,以及如何编写一个简单的makefile



什么是Make?为什么要关心?



这个叫make的工具是一个构建依赖管理器。也就是说,它需要知道什么命令需要以什么顺序执行,从源文件,目标文件,库,标题等的集合中取得软件项目。 - 其中一些可能最近更改了---并将它们转换为正确的最新版本的程序。



实际上,你可以使用make的其他东西,但我不会



假设您有一个简单的目录包含:工具 tool.cc tool.o support.cc support.hh support.o 依赖于 root ,并且应该被编译成一个名为工具的程序,并假设你已经攻击



要执行此操作,您可以



1)检查if support.cc support.hh support.o ,如果是这样,运行命令像

  g ++ -g -c -D_REENTRANT -pthread -I / sw / include / root support.cc 

2)检查 support.hh tool.cc tool.o 更新,如果是这样, / p>

  g ++ -g -c -D_REENTRANT -pthread -I / sw / include / root tool.cc 

3)检查 tool.o 是否比 tool ,如果是这样,请运行

 命令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

什么麻烦!有很多要记住和几个机会犯错误。 (BTW--这里展示的命令行的细节取决于我们的软件环境,这些在我的电脑上工作。)



当然,你可以运行所有三命令。这将工作,但不能很好地扩展到一个实质性的软件(如DOGS,需要超过15分钟从我的MacBook上的基础上编译)。



您可以这样写一个名为 makefile 的文件:

  :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 -D_REENTRANT -pthread -I / sw / include / root tool.cc

support.o:support.hh support.cc
g ++ -g -c -D_REENTRANT -pthread -I / sw / include / root支持。 cc

并在命令中输入 make 线。它将自动执行上面显示的三个步骤。



这里的未缩进行具有形式target:dependencies如果任何依赖项比目标更新,则应运行关联的命令(缩进线)。这就是依赖行描述了需要重建以适应各种文件中的变化的逻辑。如果 support.cc 更改,这意味着必须重建 support.o ,但工具。 o 可以单独使用。当 support.o 更改工具必须重建。



与每个依赖行相关联的命令使用选项卡(见下文)应修改目标(或至少触摸它以更新修改时间)。



变量,内置规则和其他好东西



在这一点上,我们的makefile只是记住需要做的工作,但是我们仍然必须找出并输入每个需要的命令。它不一定是这样的:make是一个功能强大的语言,包含变量,文本处理函数和一系列内置的规则,可以使我们更容易。



创建变量



访问make变量的语法是 $(VAR)



分配给make变量的语法是: VAR =某种文本值
(或 VAR:=不同的文本值,但暂时忽略此)。



可以使用这样改进版本的makefile中的变量:

  CPPFLAGS = -g -D_REENTRANT -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支持。 o $(LDLIBS)

tool.o:tool.cc support.hh
g ++ $(CPPFLAGS)-c tool.cc

support.o:support .hh support.cc
g ++ $(CPPFLAGS)-c support.cc



> GNU make支持从文件系统或系统上的其他命令访问信息的各种函数。在这种情况下,我们感兴趣的扩展到参数的输出的 $(shell ...) $(subst opat ,npat,text),它将在文本中替换 opat npat / p>

利用这个优势给我们:

  CPPFLAGS = -g $ (shell root-config --cflags)
LDFLAGS = -g $(shell root-config --ldflags)
LDLIBS = $(shell root-config --libs)
$ b b 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

$ b $



请注意


  1. 我们仍然明确说明每个目标文件和最终可执行文件的依赖关系

  2. 我们必须显式地为两个源文件指定编译规则

隐式和模式规则



所有的c ++源文件应该以同样的方式处理,并且make提供三个是用来表示这个


  1. 后缀规则,但保持向后兼容)

  2. 隐式规则

  3. 模式规则

隐式规则是内置的,下面将讨论几个。模式规则以

 %。o:%.c 
$(CC)$(CFLAGS )$(CPPFLAGS)-c $&

这意味着通过运行显示的命令从c源文件生成目标文件,

内置规则

/ strong>



Make有一个内置的规则,这意味着很多时候,一个项目可以通过一个非常简单的makefile来编译。



GNU make内置的c源文件规则是上面展示的。类似地,我们使用 $(CXX)-c $(CPPFLAGS)$(CFLAGS)


$ b的规则从c ++源文件创建对象文件$ b

使用 $(LD)$(LDFLAGS)no $(LOADLIBES)$(LDLIBS)链接单个对象文件,但这不会在我们的



$ b

内置规则使用的变量 $ b

内置规则使用一组标准变量,允许您在不重写所有规则的情况下指定本地环境信息(如在哪里可以找到ROOT包含文件)。我们最有可能感兴趣的是:




  • CC - c编译器使用

  • CXX - 使用的c ++编译器

  • LD - 要使用的链接器

  • CFLAGS - c源文件的编译标志

  • CXXFLAGS - c ++源文件的编译标志

  • CPPFLAGS - c和c ++使用的c预处理程序的标志(通常包括在命令行中定义的文件路径和符号)

  • LDFLAGS - 链接标记

  • LDLIBS - 要链接的库



基本Makefile



利用内置规则我们可以将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: cc support.hh

support.o:support.hh support.cc

clean:
$(RM)$(OBJS)

dist-clean:clean
$(RM)工具

执行特殊操作的标准目标(如清理源目录)。



请注意,当调用没有参数的make时,它使用文件中找到的第一个目标在这种情况下全部),但是你也可以命名目标来获得在这种情况下 make clean 删除目标文件的原因。



我们仍然有所有的依赖项硬编码。



一些神秘的改进

  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 -f ./.depend
$(CXX)$(CPPFLAGS)-MM $ ^>> ./。depend;

clean:
$(RM)$(OBJS)

dist-clean:clean
$(RM)*〜.depend

include .depend

请注意


  1. 源文件不再有任何依赖行!?

  2. 有一些奇怪的魔法与.depend和depend有关

  3. 如果您执行 make ,然后 ls -A ,您将看到一个名为 .depend 其中包含看起来像依赖行的内容

/ strong>





知道错误和错误历史记录



make的输入语言对空格有敏感性。特别地,依赖关系之后的动作行必须以选项卡开头。但是一系列空间看起来是一样的(确实有编辑器将静默地将制表符转换为空格,反之亦然),这导致make文件看起来正确,仍然不工作。这个问题早已被确定为错误,但(故事发生)并不是固定的,因为已有10位用户。


We are required to use a Makefile to pull everything together for our project but our professor never showed us how to.

I only have ONE file, a3driver.cpp. The driver imports a class from a location "/user/cse232/Examples/example32.sequence.cpp".

That's it, everything else is contained with the .cpp.

How would I go about making a simple Makefile that creates an executable called a3a.exe?

解决方案

Copied from a wiki post I wrote for physics grad students.

Since this is for unix the executables have no extensions.

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.

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

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 you 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.

Actually you can use make for other things too, but I'm not going to talk about that.

A Trivial 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 and want to compile the program.

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

g++ -g -c -D_REENTRANT -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

g++ -g  -c -D_REENTRANT -pthread -I/sw/include/root tool.cc

3) check if tool.o is newer than tool, and if so run a command like

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).

Instead you could write a file called makefile like this:

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 -D_REENTRANT -pthread -I/sw/include/root tool.cc

support.o: support.hh support.cc
    g++ -g -c -D_REENTRANT -pthread -I/sw/include/root support.cc

and just type make at the command line. which will perform the three steps shown above automatically.

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.

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.

Make Variables

The syntax for accessing a make variable is $(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).

You can use variables in rules like this improved version of our makefile:

CPPFLAGS=-g -D_REENTRANT -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.

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

  1. We are still stating explicitly the dependencies for each object file and the final executable
  2. 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 was to state this

  1. suffix rules (considered obsolete in GNU make, but kept for backwards compatibility)
  2. implicit rules
  3. 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.

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.

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)

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.

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
  • CXX -- the c++ compiler to use
  • LD -- the linker to use
  • CFLAGS -- compilation flag for c source files
  • CXXFLAGS -- compilation flags for c++ source files
  • CPPFLAGS -- flags for the c-preprocessor (typically include file paths and symbols defined on the command line), used by c and c++
  • LDFLAGS -- linker flags
  • LDLIBS -- libraries to link

A Basic Makefile

By taking advantage of the built in rules we can simplify our makefile to:

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)

dist-clean: 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.

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 -f ./.depend
    $(CXX) $(CPPFLAGS) -MM $^>>./.depend;

clean:
    $(RM) $(OBJS)

dist-clean: clean
    $(RM) *~ .depend

include .depend

Notice that

  1. There are no longer any dependency lines for the source files!?!
  2. There is some strange magic related to .depend and depend
  3. If you do make then ls -A you see a file named .depend which contains things that look like make dependency lines

Other Reading

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.

这篇关于如何使一个简单的C ++ Makefile?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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