Make Tutorial

Code compilation process:  

  1. Whether c, c ++, php, etc. need to first source file is compiled into intermediate code file (Object File) process, calling: compiled
    • .obj file under windows called ,
    • .O file is under unix 
    • Building Primary check the correctness of grammar
  2. A large number of intermediate code files  are combined into an executable file  of this process, calling them: [link] was also called choreography
    • The main link functions and global variables
    • Link needs to point out obvious intermediate destination file name

  ps: when too many intermediate files when compiling them very inconvenient, we'll usually packed, called library (Library File, .lib file) under windows, Unix, Archive File, which is .a file

 

Make concept


 

  Make this word in English meaning "to make." Make use of this command directly meaning, it is to make a file out. For example, I want to make a file a.txt, can be used directly   

make a.txt

 

  But if you really enter this command, it will not play any role, because Make itself does not know how to make a.txt need someone to tell it how to make a.txt file.

  Use Case a:

   a.txt file depends on b.txt and c.txt these two files, the file is a collection of two back content. So make needs to know the following rules.

  

a.txt: b.txt c.txt # Step 
    cat b.txt c.txt> a.txt # Step

  Resolution:

    The first step: Make sure b.txt and c.txt the two files must already exist.

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

  总结:

  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

  

Guess you like

Origin www.cnblogs.com/yinguohai/p/10951144.html