• Make 教程


    代码的编译过程:  

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

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

    Make 概念


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

    make a.txt

      但是,如果你真的输入这条命令,它不会起到任何作用,因为 Make 本身并不知道,如何做出  a.txt 需要有人告诉它怎么去做出a.txt 文件。

      用例一:

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

      

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

      解析:

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

        第二步:  使用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
    

      

  • 相关阅读:
    Wannafly挑战赛21A
    luoguP4000 斐波那契数列
    关于斐波那契数模意义下的循环节问题
    Codeforces Round #501 (Div. 3) F. Bracket Substring
    1257: [CQOI2007]余数之和
    51nod1380 夹克老爷的逢三抽一
    51nod1423 最大二"货" 单调栈
    51nod1624 取余最长路 前缀和 + set
    51nod1437 迈克步 单调栈
    51nod1515 明辨是非 并查集 + set
  • 原文地址:https://www.cnblogs.com/yinguohai/p/10951144.html
Copyright © 2020-2023  润新知