How to write a Makefile

转载 2004年09月10日 11:15:00

How to write a Makefile


Make is one of the original Unix tools for Software Engineering. By S.I. Feldman of AT&T Bell Labs circa 1975. But there are public domain versions (eg. GNU) and versions for other systems (eg. Vax/VMS).

Related tools are the language compilers (cc, f77, lex, yacc, etc.) and shell programming tools (eg. awk, sed, cp, rm, etc.). You need to know how to use these.

Important adjuncts are lint (source code checking for obvious errors) ctags (locate functions, etc. in source code) and mkdepend. These are nice, and good programmers use them.

Important, and related tools, are the software revision systems SCCS (Source Code Control System) and RCS (Revision Control System -- the recommended choice)

The idea is to automate and optimize the construction of programs/files -- ie. to leave enough foot prints so that others can follow.

Makefile Naming

make is going to look for a file called Makefile, if not found then a file called makefile. Use the first (so the name stands out in listings).

You can get away without any Makefile (but shouldn't)! Make has default rules it knows about.

Makefile Components

  • Comments

    Comments are any text beginning with the pound (#) sign. A comment can start anywhere on a line and continue until the end of the line. For example:

    # $Id: slides,v 1.2 1992/02/14 21:00:58 reggers Exp $
  • Macros

    Make has a simple macro definition and substitution mechanism. Macros are defined in a Makefile as = pairs. For example:

    MACROS=  -me
    PSROFF=  groff -Tps
    DITROFF= groff -Tdvi
    CFLAGS= -O -systype bsd43
    There are lots of default macros -- you should honor the existing naming conventions. To find out what rules/macros make is using type:
    % make -p
    NOTE: That your environment variables are exported into the make as macros. They will override the defaults.

    You can set macros on the make command line:

    % make "CFLAGS= -O" "LDFLAGS=-s" printenv
       cc -O printenv.c -s -o printenv
  • Targets

    You make a particular target (eg. make all), in none specified then the first target found:

    paper.dvi: $(SRCS)
           $(DITROFF) $(MACROS) $(SRCS) >paper.dvi
    NOTE: The the line beginning with $(DITROFF) begins with TAB not spaces.
    The target is made if any of the dependent files have changed. The dependent files in this case are represented by the $(SRCS) statement.

  • Continuation of Lines

    Use a back slash (/). This is important for long macros and/or rules.

  • Conventional Macros

    There are lots of default macros (type "make -p" to print out the defaults). Most are pretty obvious from the rules in which they are used:

    AR = ar
    GFLAGS =
    GET = get
    MAS = mas
    AS = as
    FC = f77
    CFLAGS =
    CC = cc
    LD = ld
    LFLAGS =
    LEX = lex
    YFLAGS =
    YACC = yacc
    MAKE = make
    MAKEARGS = 'SHELL=/bin/sh'
    SHELL = /bin/sh
  • Special Macros

    Before issuing any command in a target rule set there are certain special macros predefined.

    1. $@ is the name of the file to be made.
    2. $? is the names of the changed dependents.

    So, for example, we could use a rule

    printenv: printenv.c
            $(CC) $(CFLAGS) $? $(LDFLAGS) -o $@
    printenv: printenv.c
            $(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@
    There are two more special macros used in implicit rules. They are:

    1. $< the name of the related file that caused the action.
    2. $* the prefix shared by target and dependent files.

  • Makefile Target Rules

    The general syntax of a Makefile Target Rule is

        target [target...] : [dependent ....]
        [ command ...]
    Items in brackets are optional, ellipsis means one or more. Note the tab to preface each command is required.

    The semantics is pretty simple. When you say "make target" make finds the target rule that applies and, if any of the dependents are newer than the target, make executes the com- mands one at a time (after macro substitution). If any dependents have to be made, that happens first (so you have a recursion).

    A make will terminate if any command returns a failure sta- tus. That's why you see rules like:

            -rm *.o *~ core paper
    Make ignores the returned status on command lines that begin with a dash. eg. who cares if there is no core file?

    Make will echo the commands, after macro substition to show you what's happening as it happens. Sometimes you might want to turn that off. For example:

            @echo You must be root to install
  • Example Target Rules

    For example, to manage sources stored within RCS (sometimes you'll need to "check out" a source file):

    SRCS=x.c y.c z.c
            co $@
    To manage sources stored within SCCS (sometimes you'll need to "get" a source file):
            sccs get $@
    Alternativley, to manage sources stored within SCCS or RCS let's generalize with a macro that we can set as required.
    SRCS=x.c y.c z.c
    # GET= sccs get
    GET= co
            $(GET) $@
    For example, to construct a library of object files
    lib.a: x.o y.o z.o
            ar rvu lib.a x.o y.o z.o
            ranlib lib.a
    Alternatively, to be a bit more fancy you could use:
    OBJ=x.o y.o z.o
    lib.a: $(OBJ)
            $(AR) rvu $@ $(OBJ)
            ranlib $@
    Since AR is a default macro already assigned to "ar" you can get away without defining it (but shouldn't).

    If you get used to using macros you'll be able to make a few rules that you can use over and over again.
    For example, to construct a library in some other directory

            cd $(INC); make lib.a
    Beware:, the following will not work (but you'd think it should)
            cd $(INC)
            make lib.a
    Each command in the target rule is executed in a separate shell. This makes for some interesting constructs and long continuation lines.

    To generate a tags file

    SRCS=x.c y.c z.c
    CTAGS=ctags -x >tags
    tags:   $(SRCS)
            ${CTAGS} $(SRCS)
    On large projects a tags file, that lists all functions and their invocations is a handy tool.
    To generate a listing of likely bugs in your problems
            lint $(CFLAGS) $(SRCS)
    Lint is a really good tool for finding those obvious bugs that slip into programs -- eg. type classes, bad argu- ment list, etc.

  • Some Basic Make Rule

    People have come to expect certain targets in Makefiles. You should always browse first, but it's reasonable to expect that the targets all (or just make), install, and clean will be found.

    1. make all -- should compile everything so that you can do local testing before installing things.
    2. make install -- should install things in the right places. But watch out that things are installed in the right place for your system.
    3. make clean -- should clean things up. Get rid of the executables, any temporary files, object files, etc.

    You may encounter other common targets, some have been already mentioned (tags and lint).

  • An Example Makefile for printenv

    # make the printenv command
    CTAGS= ctags -x >tags
    CFLAGS= -O
    LDFLAGS= -s
    DEPEND= makedepend $(CFLAGS)
    all:    printenv
    # To get things out of the revision control system
            $(GET) $@
    # To make an object from source
           $(CC) $(CFLAGS) -c $*.c
    # To make an executable
    printenv: $(OBJS)
            $(CC) $(LDFLAGS) -o $@ $(OBJS)
    # To install things in the right place
    install: printenv
            $(INSTALL) -c -o $(OWNER) -g $(GROUP) -m 755 printenv $(BINDIR)
            $(INSTALL) -c -o $(OWNER) -g $(GROUP) -m 644 $(MANDIR)
    # where are functions/procedures?
    tags: $(SRCS)
            $(CTAGS) $(SRCS)
    # what have I done wrong?
    lint: $(SRCS)
            lint $(CFLAGS) $(SRCS)
    # what are the source dependencies
    depend: $(SRCS)
            $(DEPEND) $(SRCS)
    # to make a shar distribution
    shar:   clean
            $(SHAR) README Makefile $(SRCS) >shar
    # clean out the dross
            -rm printenv *~ *.o *.bak core tags shar
    # DO NOT DELETE THIS LINE -- make depend depends on it.
    printenv.o: /usr/include/stdio.h
  • Makefile Implicit Rules

    Consider the rule we used for printenv

    printenv: printenv.c
            $(CC) $(CFLAGS) printenv.c $(LDFLAGS) -o printenv
    We generalized a bit to get
    printenv: printenv.c
            $(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@
    The command is one that ought to work in all cases where we build an executable x out of the source code x.c This can be stated as an implicit rule:
            $(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@
    This Implicit rule says how to make x out of x.c -- run cc on x.c and call the output x. The rule is implicit because no particular target is mentioned. It can be used in all cases.

    Another common implicit rule is for the construction of .o (object) files out of .c (source files).

            $(CC) $(CFLAGS) -c $<
            $(CC) $(CFLAGS) -c $*.c
  • Make Dependencies

    It's pretty common to have source code that uses include files. For example:

    % cat program.c
    #include        "defs.h"
    #include        "glob.h"
    The implicit rule only covers part of the source code depen- dency (it only knows that program.o depends on program.c). The usual method for handling this is to list the dependen- cies separately;
            $(CC) $(CFLAGS) -c $*.c
    program.o: program.c defs.h glob.h
    Usually an implicit rule and a separate list of dependencies is all you need. And it ought to be easy enough to figure out what the dependencies are.

    However, there are a number of nice tools around that will automatically generate dependency lists for you. For example (trivial):

    DEPEND= makedepend $(CFLAGS)
    # what are the source dependencies
    depend: $(SRCS)
            $(DEPEND) $(SRCS)
    printenv.o: /usr/include/stdio.h
    These tools (mkdepend, mkmkf, etc.) are very common these days and aren't too difficult to use or understand. They're just shell scripts that run cpp (or cc -M, or etc.) to find out what all the include dependencies are. They then just tack the dependency list onto the end of the Makefile.

Based on Make and Makefiles by
Reg Quinton
Computing and Communications Services
The University of Western Ontario
London, Ontario N6A 5B7

In the company, how to write an E-mail(在公司里,如何写好一封电子邮件)

看到一篇很不错的文章,分享给大家。 定义电子邮件的「好」是很难的。 若你写了一封「加薪申请」给老板,哪怕对方只回复俩字「OK」,那也算是好得令人动容。但如果邮件来自...
  • mad1989
  • mad1989
  • 2013年08月12日 09:41
  • 6585


  • nirendao
  • nirendao
  • 2016年02月06日 13:08
  • 1064


在用实验室的服务器进行C++编译的时候,由于没有图形界面,只能在shell中进行操作,因此需要学习用gcc(g++)进行编译,如果命令多的话,就要用到makefile来完成批量的shell命令。 《...
  • forzhangtao
  • forzhangtao
  • 2014年10月30日 15:21
  • 699

《how tomcat works》翻译开篇

《how tomcat work》翻译此书只为学习,有错误,不到位之处,请指出。文笔欠佳,请多海涵。简介概述欢迎来到《how tomcat works》,这本书剖析了当下免费的 ,开源的,并且是最为流...
  • tomcat_how_work
  • tomcat_how_work
  • 2015年11月01日 23:26
  • 658


文件夹建立 mongodb@bd-qa-mongodb-85:/opt/app/mongodb$ls config  data  keyfile  log  mongodb-linux-x86_6...
  • u010522235
  • u010522235
  • 2016年05月28日 13:36
  • 1642


Week 5 > Table startsWith endsWith Exercises > ProblemsQ1: Write code to print all the rows where th...
  • Herbe_chanceux
  • Herbe_chanceux
  • 2017年04月03日 16:17
  • 2091

关于coursera上Learning How to Learn课程的读书笔记

为了考研累死累活的一年终于过去了,现在在静候15号成绩出来。 在此空闲之际除了打游戏看电影的颓废之外,早早就开始注意到coursera上Learning How to Learn课程,但拖了很久都没有...
  • jixichenghao
  • jixichenghao
  • 2016年02月13日 20:29
  • 2305

陈越何欣铭老师数据结构PTA08-图8 How Long Does It Take

题目:      08-图8 How Long Does It Take   (25分) Given the relations of all the activities of a proje...
  • winnerCLAY
  • winnerCLAY
  • 2017年05月04日 17:39
  • 883

makefile 详细用法之二

最近在学习Linux下的C编程,买了一本叫《Linux环境下的C编程指南》读到makefile就越看越迷糊,可能是我的理解能不行。             于是google到了以下这篇文章。通俗易懂...
  • dapengbusi
  • dapengbusi
  • 2016年09月18日 16:37
  • 1138

矩阵十大经典题目之八-hdu-2157-How many ways??

题目大意:给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值 把 给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j。令C=A*A,那么C(i,j)=...
  • rowanhaoa
  • rowanhaoa
  • 2014年03月13日 01:00
  • 2585
您举报文章:How to write a Makefile