Make 教程

代码的编译过程:  php

  1. 不管是c , c++ , php , 等 首先须要将源文件编译成中间代码文件 (Object File) 此过程 ,美其名曰:编译
    • windows 下称为 .obj 文件
    • unix  下是 .o 文件 
    • 编译主要检查语法的正确性
  2. 大量的中间代码文件 合并成可执行文件  此过程,美其名曰:连接 【也有人叫编排】
    • 主要连接函数和全局变量
    • 连接须要明显指出中间目标文件名称

  ps: 当中间文件太多的时候编译起来就很不方便,一般咱们会将其打包,windows 下叫库文件(Library File , .lib 文件),Unix 下 是 Archive File , 也就是  .a 文件html

 

Make 概念node


 

  Make 这个词,英语意思为“制做”。 Make 命令直接使用了这个意思,就是要作出某个文件出来。 好比我要作出文件  a.txt ,就能够直接使用   c++

make a.txt

 

  可是,若是你真的输入这条命令,它不会起到任何做用,由于 Make 自己并不知道,如何作出  a.txt 须要有人告诉它怎么去作出a.txt 文件。shell

  用例一:windows

   a.txt 文件依赖于  b.txt 和  c.txt 这两个文件,是后面两个文件内容的集合。那么make 须要知道下面的规则。bash

  

a.txt: b.txt c.txt  #第一步
    cat b.txt c.txt > a.txt #第二步

  解析:函数

    第一步:确认 b.txt 和  c.txt 这两个文件必须已经存在。工具

    第二步:  使用cat 命令将这两个文件合并起来了,输出为新文件。ui

  总结:

  1. 像上面描述的这种规则默认都写在了一个叫 Makefile 的文件中,而咱们大名鼎鼎的 make 命令就依赖这个文件进行构建。
  2. Makefile 也能够写成  makefile 
  3. 若是你实在不想使用makefile 或者 Makefile 来命名你的规则文件,例如使用  aaaa.txt  ,你能够使用 make  的 -f  参数来指定 :  make  -f  aaaa.txt
  4. make 只是一个根据指定Shell 命令进行构建的工具而已,它的规则:
    • 你规定要构建哪些文件 【 target】
    • 它依赖于哪些源文件 【 prerequisits】
    • 当哪些文件由变更是,如何从新构建它 【 commands】

 

Makefile 文件格式


 

  构建规则都写在了Makefile 文件中,要学会如何Make 命令,就必须先学会如何编写Makefile 文件

 

概述:


 

  Makefile 文件由一系列规则构成,格式:

<target>  :<prerequisites>

    <commands>

  解析:

    target  :  目标,必须的

    prerequisites: 前置条件,可选

    commands: 命令,它前面须要跟着一个空格 , 可选

 

目标<target>


  一个目标(target) 就构成了一个规则,目标一般是文件名,指明make 命令所要构建的对象,好比上文的  a.txt 。  目标能够是一个文件名,也能够是多个文件名,之间用空格隔开。

  除了文件名,目标还能够是操做名或任意字母组成的字符串,这类目标称为 “伪目标” (phony target)

  

 

  上面代码的目标是  bb , 它不是文件名 , 而是一个操做名,属于“伪目标” , 做用是列举根目下的文件或目录

  ps :  伪目标,系统是不会去检查bb 文件是否存在的。而是每次执行都执行对应的命令。

  可是,若是目录中恰好有个文件就叫bb , 那么bb 也就变成了“目标”了,避免这种状况,能够使用以下命令

.PHONY: bb
clean:
  ls /

  经过 ".PHONY" 能够用来指定伪目标,这种内置目标名还有不少,能够查看手册  

 

前置条件   prerequisites


  前置条件一般是一组文件名,之间用空格分隔。它指定了“目标” , 是否重现构建的判断标准:只要有一个前置文件不存在或者被更新了,目标就须要从新构建

  用例一:

result.txt:  source.txt
  cp source.txt  result.txt

  

  解析:

    上面的代码中,构建了目标  result.txt   ,  它的前置条件是  source.txt   已经存在了,那么 make  result.txt  能够正常运行,不然必须再写一条规则,来生成  source.txt 

 

  用例二:

 source.txt:
  echo " hello world" >  source.txt

  解析:

    上面的代码中,source.txt 后面没有前置条件 , 这意味着这个“source.txt”目标不依赖其它文件,直接运行它的  commands  就行了。只要source.txt 不存在 , 每次调用  make  source.txt 它都会生成 source.txt

    若是你连续执行两次  make  source.txt , 它只会执行第一次就不会再执行了

  

  用例三:  

source: a.txt  b.txt  c.txt

  解析:

    source  是一个伪目标 , 它只有三个前置条件 , 没有任何的 commands 。做用:一次性建立a.txt , b.txt , c.txt 这三个文件。 

 

命令(commands)


 

  命令就是一堆shell  命令组成的,它是构建“目标” 的具体指令,它的运行结果一般就是生成目标文件。每行命令以前必须有一个tab键,若是要使用其它键,能够使用内置变量 .RECIPEPREFIX 声明

  用例一:

.RECIPEPREFIX = >
all:
> echo Hello , world

  解析:

    上面的代码就是用 .RECIPEPREFIX 来指定了每行命令开头 是  而再也不是 tab键

   

  用例二:

var-lost:
  export foo=bar
  echo "foo=[$$foo]"

  解析:

    commands 中的每条独自换行的命令都是独立分开的,不在同一个进程了,因此数据也是不共享的

    第一行的 定义的变量  foo  是不能在  第二行中使用的

    解决办法就是: 

    1. 将这两个shell命令合并为一条,中间用  分号 ";"  隔开 
    2. 若是感受太才了,那么就就能够在  分号 后面加个  反斜杆进行转义  "  \ "
    3. 感受加 \  太扯,那么你能够使用 内置命令  .ONESHELL 来指定
var-kept:
  export foo=bar; echo "foo=[$$foo]"

或者

var-kept:
  export foo=bar;\
  echo "foo=[$$foo]"

或者

.ONESHELL
var-kept:
  export foot=bar;
  echo "foo=[$$foo]"

Makefile 文件的语法  


 

 

注释  : 


 

  在Makefile 文件中 注释符是:   # 

 

回声:


 

  正常状况下 , make 会 打印每条命令 , 而后再执行, 这叫作回声(echoing).

  若是你想关闭回声,直接在shell  命令行前面加一个 @  符号就行了

test:
  # this is test
  @echo TODO

  

通配符:


 

  通配符 , 用来指定符合条件的文件名的。 Makefile 的通配符与Bash  一致 , 主要有  *  ,  ?   好比以o 结尾的文件  能够这样  *.o

 

模式匹配


 

  Make 命令 容许 对文件名 , 进行相似正则运算的匹配 , 主要用到的匹配符是  %  , 好比须要找到 当前目录下 有  f1.c  和 f2.c 两个源码文件,须要将它们编译伪对应的对象文件

%.o : %.c

等同于

f1.o :f1.c
f2.o :f2.c

  

变量和赋值符


 

  Makefile 中容许使用   等号 “ = ” 来 自定义变量

bb = Hello  World
test:
  @echo $(bb)
  @echo $$HOME

  解析:

    变量bb  等于 Hello  World  ,  变量调用是经过   $()  来调用的。

    若是你要调用Shell  自带的一些变量,那么你须要在  美圆符号前面再加一个美圆符号, 由于  Makefile 中会对美圆符号进行转义

  

  Makefile 中提供了  4中赋值运算符(  =  ,  :=  , ?=  , += )  :

#执行时扩展, 容许递归扩展

key = value 

 

#定义是扩展

key := value

 

#只有在该变量为空时才设置值

key ?= value

 

#将值追加到变量的尾端

key += value

 

内置变量


 

Make  命令提供了一系列的内置变量,详情见手册 

 

自动变量


 

  Make 命令提供了一些自动变量,他们的值与当前规则有关。

  (1)$@ :  

      代指当前目标,就是Make  命令当前构建的那个目标, 好比  make foo  的  $@ 就值  foo

a.txt  b.txt:
  touch $@

等同于

a.txt: 
  touch a.txt

b.txt: 
  touch b.txt

  (2) $<

    代指第一个前置条件

a.txt : b.txt c.txt
  cp $< $@

等同于

a.txt: b.txt c.txt
  cp b.txt a.txt  

  (3) $?

    代指比目标更新的全部前置条件 【即:更新的依赖文件】,好比,  t1: p1 p2 ,  p2 的时间戳比t1 新,那么 $? 就代指  p2

 

  (4) $^

    代指全部前置条件

  

     (5) $*

    代指匹配符 % 匹配成功的部分 , 好比   %匹配  f1.txt 中的  f1 , 那么  $* 就表示   f1

 

     (6) $(@D)  和 $(@F)

     $(@D)  和 $(@F) 分别代指:  $@ 的目录名和文件名

    (7)$(<D)  和  $(<F)

     $(<D)  和  $(<F) 分别代指: $<  的目录名和文件名

   其它的自动变量请查看手册 

  

  用例一:

dest/%.txt:  src/%.txt
  @[ -d dest ] || mkdir dest
  cp $< $@

  解析:

    1. 上面的代码就是将  src  目录下的  txt 文件 拷贝到 dest  目录下 。 

    2.  @[-d dest] ||  mkdir dest  :   是说  判断 dest 目录是否存在,不存在则建立之 , 而且关闭回声

    3.  cp $<  $@ :  将 src 中的 txt  拷贝到  dest 目录下

 

判断和循环


  Makefile  使用Bash 语法,完成了 判断和循环

  用例一:

ifeq ($(CC),gcc)
  libs=$(libs_for_gcc)

else
  libs=$(normal_libs)
endif

  

  用例二:

   

LIST = one  two three
test:
  for i in $(LIST); do \
    echo $$i; \
  done

等同于

test:
  for i in one two three; do \
    echo $i; \
  done

  

函数


 

  Makefile 还能够使用函数 , 它许多内置函数  见手册

  格式:

$(function arguments)

或者

${function arguments}

  

 

Makefile 实例


 

  编译 c语言项目

edit: main.o  kbd.o  command.o  display.o
  cc -o edit main.o kbd.o command.o display.o
main: main.c defs.h
  cc -c main.c
kdb.o: kbd.c defs.h  command.h
  cc -c kbd.c
command.o: command.c defs.h  command.h
  cc -c command.c
display.o: display.c defs.h
  cc -c display.c
clean:
  rm edit main.o kbd.o command.o display.o
.PHONY: edit clean
相关文章
相关标签/搜索