Writing MakeFile

  1. Example program:

    Here, we will use a program that deals with some geometric shapes toillustrate writing a make file to compile a program.

    The program is made up of 5 source files:

    • main.cpp, a main program.
    • Point.h, header file for the Point class.
    • Point.cpp, implementation file for the Point class.
    • Rectangle.h, header file for the Rectangle class.
    • Rectangle.cpp, implementation file for the Rectangle class.

    These files are available to download.

  2. Compiling source code separately:

    Let's review what we need to do to compile this programseparately (i.e., to intermediateobject files) andthen link it into an executable namedmain.

    To just compile source code, use the -c flag with thecompiler...

    % g++ -c main.cpp
    % g++ -c Point.cpp
    % g++ -c Rectangle.cpp
    

    This will generate the object files:

    • main.o (for main.cpp),
    • Point.o (for Point.cpp), and
    • Rectangle.o (for Rectangle.cpp)

    Then, to link the object files (.o) into an executable, weuse the compiler again (although this time it will just pass the.o files on to thelinking stage):

    % g++ -o main main.o Point.o Rectangle.o
    
  3. Dependency chart:

    We would like to know what files need to be regenerated when we changecertain parts of our program. We can determine this by creating adependency chart.

    Let's start from our goal (i.e., to have an executable namedmain)...

    Linking Dependencies
    The executable main is generated from 3 object files,main.o,Point.o andRectangle.o. Thus,maindepends on those 3 files.

    To generate main from those files, we link themtogether.

    Compiling Dependencies
    Next, the object (.o) files depend on the.cpp files. Namely:
    • main.o depends on main.cpp,
    • Point.o depends on Point.cpp, and
    • Rectangle.o depends on Rectangle.cpp.

    You generate these object files by compiling the corresponding.cpp files.

    Include Dependencies
    Finally, source code files (.cpp and .h) dependon header files (.h) that they include:
    • 3 source code files include Point.h and
    • 2 files include Rectangle.h.

    Notice that there may be additional indirect include dependencies(e.g.,Rectangle.cpp depends onPoint.h sinceRectangle.cpp includesRectangle.h, whichincludesPoint.h).


    Note:Include dependencies are a little different since the .hfiles aren't used to generate other files, unlike .cppand.o files.

    Here is the complete dependency chart...

    Dependency Chart for main Executable
    Dependencies go downward.
    How to "get" or generate files goes upward.

    Note:We've just listed all the dependencies for the executablemain. The executable depends on some thingsdirectly (like the.o files) and some thingsindirectly (i.e., you need the.cpp files to generatethe .o files to generate the executable).
  4. Using dependency chart:

    With such a dependency chart, we can answer questions about whatneeds to be regenerated if certain files change.

    For example, suppose we change the filemain.cpp...What has to be regenerated?

    Answer: First, recompile main.cpp to getmain.o. Then, relink all the object files togetheragain to get the executablemain.

    Now, suppose we changed Point.h?


    Note:When either a .cpp file changes or a header file included(directly or indirectly) by a.cpp file changes, we haveto regenerate the corresponding.o file.
  5. Make utility and make files:

    Since it is tedious to recompile pieces of a program when somethingchanges, people often use themake utility instead.

    Make needs a make file that encodes both thedependencies between files and the commands needed to generate files.

    When you run the make utility, it examines themodification times of files and determines what needs to beregenerated. Files that areolder than the files they dependon must be regenerated. Regenerating one file may cause others tobecomeold, so that several files end up being regenerated.


    Aside:Note the difference between the make utility (a program yourun) and amake file (that tells themake utilityhow to compile/link a specific program).

    A make file should be named either Makefile (first letteruppercase) ormakefile (all lowercase). The make file should bein the same directory as the source code files.


    Aside:Make files can have other file names, but then you'll have totell themake utility what the name of the make file is (usinga commandline option).

    Finally, it is easiest if the make file is in the same directory as thesource code files.

  6. Writing a make file:

    You can create a make file in any text editor.For this example, we will examine the parts of thisMakefile, which generates the executablemain.Go ahead a download that make file.

    Simple make files have at least 2 parts:

    • A set of variables, which specify things like the C++compiler/linker to use, flags for the compiler, etc.
    • A set of targets, i.e., files that have to be generated.

    Make files may have comments that (hopefully) add to readability. Anyline starting with a pound sign (#) is a comments. Notethat our make file has some comments.


    Note:Keep in mind that make files use their own language, so don't expect things in them to look like programming languages youknow.
    Variables
    The first variable listed in our make file is for the compiler to use...
    CXX = g++
    

    In general, the form for setting a variable is:

    VARNAME = value
    

    (The space around the = is optional for our version ofmake, but adds to readability).

    The second variable says what flags to pass to the C++ compiler...

    CXXFLAGS = -Wall -g
    

    Here, the variable includes the flag for all warnings and theone that addsdebugging information (so that the executable canlater be run under a debugger).

    The 2 variables, CXX and CXXFLAGS, are theones that our version ofmake expects to be set for the C++compiler and flags to the C++ compiler, respectively.


    Aside:You can add your own variables, but make has a set of standardvariables, like these, which it uses for the compiler, flags, etc.
    Targets
    With the needed variables, we can deal with the targets, which arefiles that must begenerated.

    For each target, there are typically 1 or 2 lines in a make file.Those lines specify:

    1. its dependencies (easy to determine from a dependency chart)
    2. and possibly a command to generate the target (easy to determinefrom knowledge ofseparate compilation).

    By default, the first target in the make file is the one that getsgenerated when you just say "make" at the commandline, soit should be the name of the executable.

    Target: Executable
    Let's examine the first target in our make file (i.e., formain)...

    For a target's dependency line, the target file name should be listed,followed by a colon (:) and the files it depends on:

    main: main.o Point.o Rectangle.o
    

    For a target that is an executable, we just list the object files itdepends on.

    On the next line, there should be a command that generates the target:

    <Tab>$(CXX) $(CXXFLAGS) -o main main.o Point.o Rectangle.o
    

    Note:This line MUST start with a <Tab> (i.e., hitthe Tab key)...it cannot start with a regular space!

    Note that the variables CXX and CXXFLAGSare used, which means that the command is really:

    g++ -Wall -g -o main main.o Point.o Rectangle.o
    

    Note:Using a variable in a make file involves using the dollar sign($) and then the variable name in parentheses.
    Targets: Object Files
    Our next target is the object file, main.o.

    For a target that is an object file, we list all files it depends on.This means its corresponding.cpp file, plus any headerfiles its.cpp file includes (i.e., include directly orindirectly, but not system header files likeiostream thataren't going to change).

    So, the dependencies line looks like:

    main.o: main.cpp Point.h Rectangle.h
    

    The generation command for this target is:

    <Tab>$(CXX) $(CXXFLAGS) -c main.cpp
    
    Make is kinda smart
    We could have written the main.o target more simply.Make already knows how to generate certain kinds of files.Let's take advantage ofmake's smarts for the next target...

    The next object file, Point.o depends on Point.cpp,however,make already knows that.o files can begenerated from their corresponding.cpp files, so all we needis:

    Point.o: Point.h
    

    Note:Although some make utilities can automatically determine what.h files a file depends on, some cannot, so you shouldlist theinclude dependencies.

    We don't need any generation line since we set up thevariables CXX and CXXFLAGS. Makewill use them to figure out a compilation command.

    Finally, there is only one target left, Rectangle.o.Taking advantage ofmake's smarts, it only requires:

    Rectangle.o: Rectangle.h Point.h
    

    Note that Rectangle.o depends on Point.hindirectly (i.e., recall thatRectangle.cpp includesRectangle.h, which includesPoint.h).


    That's all for the make file!!! It just encodes the dependencies andthe generation commands for 1 executable and its 3 object files.
  7. Using a make file:

    With a make file for our executable, it is easy to compile thatexecutable.

    Try using the make file we've given you.First, remove the old executable and object files (if there are any):

    % rm main *.o
    

    Run make with the command:

    % make
    

    Remember that this will cause make to generate the firsttarget in the make file, which ismain.

    Since nothing has been compiled/linked, it will do:

    g++ -Wall -g -c main.cpp
    g++ -Wall -g   -c -o Point.o Point.cpp
    g++ -Wall -g   -c -o Rectangle.o Rectangle.cpp
    g++ -Wall -g -o main main.o Point.o Rectangle.o
    

    I.e., compile the 3 .cpp files into object files, and thenlink the object files into an executable namedmain.

    (If you have trouble, be sure that the make file is named Makefileand is in the same directory as the source code files.)

    Now, type the make command again (let's explicitly tell it whattarget to generate this time) and you get:

    % make main
    make: `main' is up to date.
    

    Here, make tells you nothing has changed, so it has no work to do.

    Next, suppose we change the program by adding some code to the end ofmain() (inmain.cpp) to move the rectangleand then print out its new top right point:

    r1.move(2, 3);
    cout << "\nRectangle r1 moved by 2, 3--top right now at " 
         << r1.get_top_right().get_x() << ", "
         << r1.get_top_right().get_y() << endl;
    
    Edit main.cpp, adding those lines, and then save to disk.

    After the change, when we use make:

    % make
    g++ -Wall -g -c main.cpp
    g++ -Wall -g -o main main.o Point.o Rectangle.o
    

    it doesn't bother regenerating Point.o orRectangle.o, since the files those depend on have notchanged.

    Finally, try changing Point.h and then re-make...

    % make
    g++ -Wall -g -c main.cpp
    g++ -Wall -g   -c -o Point.o Point.cpp
    g++ -Wall -g   -c -o Rectangle.o Rectangle.cpp
    g++ -Wall -g -o main main.o Point.o Rectangle.o
    

    Since all the .cpp files depend on that header (eitherdirectly or indirectly), they all have to be recompiled and linkedtogether.

  8. Additional notes on make:

    Other versions of make may use different variables for C++instead of CXX and CXXFLAGS.

    In a make file, if you need to continue a line, you cannot justcontinue it on the next line. You must end a line with a\(backslash, not the forward slash) to tellmake that the linecontinues. Only break lines where space would normally go.

    So, the first target could have been written:

            main: main.o \
                 Point.o \
                 Rectangle.o
           <Tab>$(CXX) $(CXXFLAGS) -o main \
                          main.o Point.o Rectangle.o

  1. We have only described the basics of make here. Most versionsof make have additional capabilities.

    原文地址:http://www.cs.bu.edu/teaching/cpp/writing-makefiles/

补充以下几点:

Makefile规则语法

通常规则的语法格式如下:

TARGETS : PREREQUISITES

COMMAND

...

或者:

TARGETS : PREREQUISITES ; COMMAND

COMMAND

...

 

规则中“TARGETS”可以是空格分开的多个文件名,也可以是一个标签(例如:执行清空的“clean”)。“TARGETS”的文件名可以使用通配符,格式“A(M)”表示档案文件(Linux下的静态库.a文件)的成员“M”(关于静态库的重建可参考第十一章使用make更新静态库文件)。通常规则只有一个目标文件(建议这么做),偶尔会在一个规则中需要多个目标。

书写规则是我们需要注意的几点:

1.        规则的命令部分有两种书写方式:a.命令可以和目标:依赖描述放在同一行。命令在依赖文件列表后并使用分号(;)和依赖文件列表分开。b.命令在目标:依赖的描述的下一行,作为独立的命令行。当作为独立的命令行时此行必须以[Tab]字符开始。在Makefile中,在第一个规则之后出现的所有以[Tab]字符开始的行都会被当作命令来处理。

2.        Makefile中符号“$”有特殊的含义(表示变量或者函数的引用),在规则中需要使用符号“$”的地方,需要书写两个连续的(“$$”)。

3.        前边已提到过,对于Makefile中一个较长的行,我们可以使用反斜线“\”将其书写到几个独立的物理行上。虽然make对Makefile文本行的最大长度是没有限制的,但还是建议这样做。不仅书写方便而且更有利于别人的阅读(这也是一个程序员修养的体现)。

一个规则告诉“make”两件事:1.目标在什么情况下已经过期; 2. 如果需要重建目标时,如何去重建这个目标。目标是否过期是由那些使用空格分割的规则的依赖文件所决定的。当目标文件不存在或者目标文件的最后修改时间比依赖文件中的任何一个晚时,目标就会被创建或者重建。就是说执行规则命令行的前提条件是以下两者之一:1.目标文件不存在; 2. 目标文件存在,但是规则的依赖文件中存在一个依赖的最后修改时间比目标的最后修改时间晚。

规则的中心思想是:目标文件的内容是由依赖文件文件决定,依赖文件的任何一处改动,将导致目前已经存在的目标文件的内容过期。规则的命令为重建目标提供了方法。这些命令运行在系统shell之上。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值