zoukankan      html  css  js  c++  java
  • 一个简易makefile教程

     
    转:http://www.paeonia.me/Blog/2012/05/13/%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84makefile%E6%95%99%E7%A8%8B/

    写Makefile是一个非常便利的编译方法,由于以前习惯把所有的代码都集中在一个文件中,体现不出make的优势,当把源代码拆分成若干个源文件,Makefile就显得必要了。以下是一份简单的Makefile的教程,参考自A Simple Makefile Tutorial。正如原文所说,这份教程只是打算让初学者快速入门,写自己的makefile,来维护中小型的项目。

    一个简单的例子,用K&R C中4.5那个例子:主程序(main.c)、函数代码(getop.c, stack.c, getch.c)、头文件(calc.h)。
    一般的,我们会使用

    1
    gcc -o calc main.c getch.c getop.c stack.c -I.

    来编译。-I.是指gcc在当前目录(.)下寻找include文件。如果不用makefile,在测试-修改-调试过程中,如果我们不想重敲那条 编译指令的话,我们必须不停地在终端中按上下键来寻找最后的那条编译指令。不幸的是,这种编译方法有两个缺陷:1. 当你把编译指令丢失或者换电脑的时候,这样效率会很低;2. 当我们只修改了一个.c文件时,每一次都将必须重新编译所有的文件,这非常耗时,不划算。现在是切入主题的时候了 :P

    最简单的makefile写法:
    Version 1

    1
    2
    calc: main.c getch.c getop.c stack.c
        gcc -o calc main.c getch.c getop.c stack.c -I.

    如果把这些语句写入一个叫Makefile或者makefile的文件,然后在终端中输入make,她将会按你在makefile中要求地编译。注 意:第一行中并没有任何参数,只是在冒号(:)后列出编译中所需的文件,当第一行中的任何文件中更改时,make就知道calc需要重新编译了。现在我们 已经解决了问题1,不用上下按箭头了,但是对于问题2依旧没有很好地解决。注意,非常重要:gcc前面必须有一个tab,在任何指令之前都要有一个 tab,不然make就会罢工的。

    让事情变得更有效率一点:
    Version 2

    1
    2
    3
    4
    5
    CC = gcc
    CFLAGS = -I.
     
    calc: main.c getch.c getop.c stack.c
        $(CC) -o calc main.c getch.c getop.c stack.c $(CFLAGS)

    现在我们新定义了两个常量CC和CFLAGS。这些是与make交流的特殊的常量,让make知道我们要怎么编译.c文件。CC是C编译器所使用的,CFLAGS是编译用的参数。make会先分别编译.c文件,然后生成可执行文件calc。

    这种形式的makefile在小项目中非常有效,但是有一个遗憾:include文件的变动。如果我们修改了calc.h文件,make是不会重新 编译.c文件的,事实上我们需要重新编译。为了解决这一问题,我们必须告诉make所有的.c文件依赖于.h文件。我们可以在makefile中增加一条 规则:
    Version 3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    CC = gcc
    CFLAGS = -I.
    DEPS = calc.h
     
    %.o: %.c $(DEPS)
        $(CC) -c -o $@ $< $(CFLAGS)
     
    calc: main.o getch.o getop.o stack.o
        $(CC) -o calc main.o getch.o getop.o stack.o $(CFLAGS)

    首先宏定义DEPS,声明.c文件所依赖的.h文件。然后我们定义一条规则,为所有的.c文件生成一个.o文件。规则描述:.o文件依赖于.c文件 和DEPS中声明的.h文件,为了产生.o文件,make需要使用CC中声明的编译器来编译.c文件。-c 意味着产生object文件,-o $@ 意思是编译生成的文件用上面的%.o来命名,$< 指依赖关系中的第一项(%.c)CFLAGS的定义和之前一样。

    最后为了简化,我们使用特殊的宏定义 $@ 和 $^ ,分别表示冒号(:)的左右两边。为了让make中所有的规则更具通用性,在Version 4中,我们把所有的include文件作为DEPS的一部分,所有的object文件作为OBJ的一部分:
    Version 4

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    CC = gcc
    CFLAGS = -I.
    DEPS = calc.h
    OBJ = main.o getch.o getop.o stack.o
     
    %.o: %.c $(DEPS)
        $(CC) -c -o $@ $< $(CFLAGS)
     
    calc: $(OBJ)
        $(CC) -o $@ $^ $(CFLAGS)

    如果我们想把.h文件放在include目录下,.c文件放在src目录下以及一些本地的库放在lib目录下,同时我们想把.o文件整理一下,避免 整个目录的凌乱。在Version 5中,定义了include,lib的目录,并把object文件放到了src目录下的obj子目录,同时还包含了任何我们想要包含的库(比如说math 库-lm)。这份makefile将放在src目录下。值得注意的是,在这一版本中添加了一条clean的规则,使make clean得以运行。目录结构如下:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    IDIR = ../include
    CC = gcc
    CFLAGS = -I$(IDIR)
     
    ODIR = obj
    LDIR = ../lib
     
    LIBS = -lm
     
    _DEPS = calc.h
    DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
     
    _OBJ = main.o getch.o getop.o stack.o
    OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
     
    $(ODIR)/%.o: %.c $(DEPS)
        $(CC) -c -o $@ $< $(CFLAGS)
     
    calc: $(OBJ)
        gcc -o $@ $^ $(CFLAGS) $(LIBS)
     
    .PHONY: clean
     
    clean:
        rm -f $(ODIR)/*.o *~ core $(IDIR)/*~

    其中patsubst函数包含3个参数:需要匹配的式样,用什么来替换它,需要被处理的由空格分隔的字符串。

    现在我们已经有了一个不错的makefile,根据这个,我们能维护中小型的工程。当然我们能增加一些更复杂的规则;甚至创造一些规则。更多关于makefile和make请参考GNU Make Manual

  • 相关阅读:
    ASP.NET 页面访问控制
    数据库设计——范式
    C#接口
    员工签到签退
    sharepoint content type publishing
    安卓自动化测试环境搭建
    SharePoint 2016 Document Center Send To Connection
    ADO.NET DBHelper 类库
    SQL语句总结
    移动端屏幕适配问题
  • 原文地址:https://www.cnblogs.com/guosj/p/4654845.html
Copyright © 2011-2022 走看看