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

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

问题描述

我们被要求使用Makefile将所有内容整合到我们的项目中,但是我们的教授从未向我们展示如何操作.

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

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

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

就是这样.其他所有内容都包含在.cpp中.

That's it. Everything else is contained with the .cpp.

我该如何制作一个简单的Makefile来创建名为a3a.exe的可执行文件?

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

推荐答案

由于这是针对Unix的,因此可执行文件没有任何扩展名.

Since this is for Unix, the executables don't have any extensions.

要注意的一件事是root-config是提供正确的编译和链接标志的实用程序.以及用于针对root用户构建应用程序的正确库.那只是与该文档的原始读者有关的一个细节.

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的介绍性讨论,以及如何编写简单的makefile

An introductory discussion of make, and how to write a simple makefile

什么是品牌?而我为什么要在意呢?

名为制作的工具是构建依赖项管理器.也就是说,它需要知道从源文件,目标文件,库,头文件等的集合中以什么顺序执行您的软件项目需要执行哪些命令-其中一些可能已更改最近-并将它们转换为该程序的正确最新版本.

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.

简单的Makefile

假设您有一个目录,其中包含:tool tool.cc tool.o support.cc support.hhsupport.o,它们依赖于root并且应该被编译成名为tool的程序,并假设您一直在黑客攻击源文件(这意味着现有的tool现在已过时)并且想要编译该程序.

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.

您可以自己执行此操作

  1. 检查support.ccsupport.hh是否比support.o更新,如果是,请运行类似命令

  1. Check if either support.cc or support.hh is newer than support.o, and if so run a command like

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

  • 检查support.hhtool.cc是否比tool.o更新,如果是,请运行类似命令

  • Check if either support.hh or tool.cc are newer than tool.o, and if so run a command like

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

  • 检查tool.o是否比tool更新,如果是,请运行类似的命令

  • 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
    

  • Ph!真麻烦!有很多要记住的地方,也有很多犯错误的机会. (顺便说一句,这里显示的命令行的详细信息取决于我们的软件环境.这些可以在我的计算机上工作.)

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

    当然,您每次可以只运行所有三个命令.那行得通,但不能很好地扩展到大量软件(例如DOGS,从我的MacBook到完全编译需要15分钟以上的时间).

    Of course, you could just run all three commands every time. That would work, but it 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).

    相反,您可以这样编写一个名为makefile的文件:

    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 -pthread -I/sw/include/root tool.cc
    
    support.o: support.hh support.cc
        g++ -g -c -pthread -I/sw/include/root support.cc
    

    ,然后在命令行中键入make.它将自动执行上面显示的三个步骤.

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

    此处的无缩进行的格式为目标:依赖项" ,并告诉Make如果有任何依赖关系比目标新,则应运行关联的命令(缩进行).也就是说,依赖关系行描述了需要重新构建以适应各种文件中的更改的逻辑.如果support.cc更改,则意味着必须重新构建support.o,但可以单独保留tool.o.当support.o更改时,必须重新构建tool.

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

    在这一点上,我们的makefile只是记住需要做的工作,但是我们仍然必须弄清楚并键入每个需要的命令的全部内容.不必一定是这样:Make是一种功能强大的语言,具有变量,文本操作功能以及一整套内置规则,可以使我们轻松得多.

    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变量的语法为$(VAR).

    The syntax for accessing a make variable is $(VAR).

    分配给Make变量的语法是:VAR = A text value of some kind (或VAR := A different text value but ignore this for the moment).

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

    您可以在规则中使用变量,例如我们的makefile的改进版本:

    You can use variables in rules like this improved version of our 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

    启用功能

    GNU make支持多种功能,用于从文件系统或系统上的其他命令访问信息.在这种情况下,我们感兴趣的是$(shell ...)扩展为参数的输出,而$(subst opat,npat,text)则将opat的所有实例替换为文本中的npat.

    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 $(OBJS) $(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.

    注意

    1. 我们仍在明确说明每个目标文件和最终可执行文件的依赖关系
    2. 我们必须为两个源文件明确输入编译规则

    隐含和模式规则

    我们通常希望所有C ++源文件都应以相同的方式对待,而Make提供了三种方式来声明这一点:

    We would generally expect that all C++ source files should be treated the same way, and Make provides three ways to state this:

    1. 后缀规则(在GNU make中被认为已过时,但为了向后兼容而保留)
    2. 内隐规则
    3. 样式规则

    内置隐式规则,下面将讨论其中的一些规则.模式规则以类似

    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 $<
    

    这意味着通过运行所示命令从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.

    内置规则

    Make具有大量的内置规则,这意味着通常情况下,一个项目实际上可以通过一个非常简单的makefile进行编译.

    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.

    上面展示的一种用于C源文件的GNU内置规则.同样,我们使用$(CXX) -c $(CPPFLAGS) $(CFLAGS)之类的规则从C ++源文件创建目标文件.

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

    使用$(LD) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)链接了单个目标文件,但是在我们的情况下,这是行不通的,因为我们要链接多个目标文件.

    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.

    内置规则使用的变量

    内置规则使用一组标准变量,这些变量允许您指定本地环境信息(例如在何处查找ROOT包含文件)而无需重写所有规则.我们最可能感兴趣的是:

    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-要使用的C编译器
    • CXX-要使用的C ++编译器
    • LD-要使用的链接器
    • CFLAGS-C源文件的编译标志
    • CXXFLAGS-C ++源文件的编译标志
    • CPPFLAGS-C和C ++使用的C预处理器的标志(通常包括命令行中定义的文件路径和符号)
    • LDFLAGS-链接器标记
    • LDLIBS-链接的库
    • 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

    基本Makefile

    通过利用内置规则,我们可以将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)
    
    distclean: clean
        $(RM) tool
    

    我们还添加了一些执行特殊操作(例如清理源目录)的标准目标.

    We have also added several standard targets that perform special actions (like cleaning up the source directory).

    请注意,在不带参数的情况下调用make时,它将使用文件中找到的第一个目标(在本例中为全部),但是您也可以命名要获取的目标,这就是使make clean删除目标文件的原因.这种情况.

    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.

    一些神秘的改进

    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
    

    注意

    1. 源文件不再有任何依赖项行!?!
    2. 有一些与.depend和depend相关的奇妙魔术
    3. 如果您执行make然后ls -A,您会看到一个名为.depend的文件,其中包含看起来像make依赖行的内容
    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

    其他读物

    • GNU make manual
    • Recursive Make Considered Harmful on a common way of writing makefiles that is less than optimal, and how to avoid it.

    了解错误和历史记录

    Make的输入语言对空格敏感.特别是,依赖项之后的动作行必须以制表符开头.但是一系列空格看起来可能是相同的(实际上,有一些编辑器会将制表符默默地转换为空格,反之亦然),这将导致Make文件看起来正确但仍然不起作用.早期发现它是一个错误,但是(故事不断发展)它不是固定的,因为已经有10个用户.

    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) it was not fixed, because there were already 10 users.

    (摘录自我为物理研究生写的一个Wiki帖子.)

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

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