zoukankan      html  css  js  c++  java
  • makefile 学习(一)

    一、Makefile的基本规则

    GNU make 规则:
    target ... : prerequisites ...
        command
        ....
        ....
    target — 目标文件, 可以是Object File 也可以是可执行文件,还可也是标签Label(标签内容在“伪目标”章节);
    prerequisites—生成target所需的文件或目标;
    command—make需要执行的命令,可以是任何shell命令。

    二、一个简单的例子

    创建一个名为count_word.c的文件,代码如下
    1. #include <stdio.h>  
    2. extern int fee_count, fie_count, foe_count, fum_count;  
    3. extern int yylex( void );  
    4.   
    5. int main( int argc, char ** argv ){  
    6.     yylex( );  
    7.     printf( "%d %d %d %d ", fee_count, fie_count, foe_count, fum_count );  
    8.     return( 0 );  
    9. }  
    另外创建一个lexer.l文件,其中所有的空白均为tab键
    1.         int fee_count = 0;  
    2.         int fie_count = 0;  
    3.         int foe_count = 0;  
    4.         int fum_count = 0;  
    5. %%  
    6. fee     fee_count++;  
    7. fie     fie_count++;  
    8. foe     foe_count++;  
    9. fum     fum_count++;  
    最后创建makefile文件,内容为:
    1. count_words: count_words.o lexer.o -lfl  
    2.         gcc count_words.o lexer.o -lfl -o count_words  
    3. count_words.o: count_words.c  
    4.         gcc -c count_words.c  
    5. lexer.o: lexer.c  
    6.         gcc -c lexer.c  
    7. lexer.c: lexer.l  
    8.         flex -t lexer.l > lexer.c  
    9. clean:  
    10.         rm lexer.c lexer.o count_words.o count_words  
    以上内容保存在Makefile或者是makefile都可以,直接输入make命令就可以生成可执行文件count_words了;
    gcc -c count_words.c
    flex -t lexer.l > lexer.c
    gcc -c lexer.c
    gcc count_words.o lexer.o -lfl -o count_words
    
    如果要删除执行文件和中间的目标文件,那么就执行一下make clean。

    注意1: 当依赖关系定好后,下面一行就是如何生成目标文件的操作系统命令了,一定要以一个Tab键开头。 另外,make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期比targets文件新,或者targets不存在,那么make就会执行这下面一行的系统命令。
    注意2: clean不是一个文件,它是一个动作名,冒号后面什么都没有,make就不会自动去找它的依赖性,也不会执行它后面的系统命令。因此,要执行clean就需要显式的指出make clean。
    注意3: 如果报错,可能需要先安装flex:
    [plain] view plaincopy
    1. sudo apt-get install flex  
    注意4: 运行count_works后,它会回显你的输出并统计'fee','fie','foe','fum'的次数。结束统计需要按Ctrl+d,然后会输出四个单词出现的次数。

    三、make 如何工作

    默认方式

    直接输入make,则
    1. make会在当前的目录下找到名为“Makefile”或者“makefile”的文件。
    2. 如果找到,它会把文件中第一个target作为最终的目标文件(如上面例子中的count_words)。
      1. 首先,make会检查目标count_words的prerequisite文件count_words.o, lexer.o 和 -lfl。
      2. count_words.o通过编译count_words.c生成
      3. lexer.o通过编译lexer.c 生成,但是lexer.c 并不存在,因此会继续寻找lexer.c的生成方式,并找到了通过flex程序将lexer.l生成为lexer.c。
      4. 最后,make会检查-lfl,-l是gcc的一个命令选项,表示将系统库链接到程序。而"fl"对应的是libfl.a的库。(GNU make 可以识别这样的命令,当一个prerequisite是以这种-l<name>的形式表示出来的时候,make会自己搜索lib<name>.so的库文件,如果没找到则继续搜索lib<name>.a的库文件)。这里make找到的是/usr/lib/libfl.a文件,并将它与程序进行连接。
    3. 如果count_words文件不存在,或者count_words所依赖的后面的.o文件的修改时间比count_words本身更加新,那么,它会执行后面定义的命令来生成这个count_words文件。如果count_words所依赖的.o文件也不存在,那么make会继续按照前面的方式生成.o文件。
    4. 找到相应的.c和.h,用来生成.o,然后再用.o完成make的最终任务。

    关于依赖关系

    make会一层一层的去找文件的依赖关系,最终编译出第一个目标文件。

    关于重新编译

    只要任何prerequisite 比 target新,那么这个目标文件就会被下面的命令重新生成。每一个命令都会被传递到shell中,并在自己的子shell里面执行。

    关于错误

    如果在寻找过程中出现错误,如文件找不到,则make会直接退出并报错。对于所定义的命令错误或者编译不成功,make是不会理会的,它只负责文件的依赖性。

    四、变量使用

    上面的例子可以看到,文件或者目标的名字几乎都毫无例外的出现了至少两次,甚至如果算上clean的内容,有些文件名出现了三次。然而,在一个大型的工程中这种情况会更加复杂,任何不经意的错误都会导致编译失败。为了让makefile更容易维护,在makefile中我们可以使用变量,或者更确切的说是一个字符串,类似c语言中的宏。例如:
    1. CC = gcc  
    2. object = lexer.o count_words.o  
    3. count_words: $(object) -lfl  
    4.         $(CC) $(object) -lfl -o count_words  
    5. count_words.o: count_words.c  
    6.         $(CC) -c count_words.c  
    7. lexer.o: lexer.c  
    8.         $(CC) -c lexer.c  
    9. lexer.c: lexer.l  
    10.         flex -t lexer.l > lexer.c  
    11. clean:  
    12.         rm lexer.c $(object) count_words  

    五、自动推导依赖关系

    GNU make可以根据.o文件的文件名自动推导出同名的.c文件并加入依赖关系,不需要我们手动注明。并且gcc -c也会被自动推导出来,于是我们的makefile就变成了
    1. CC = gcc  
    2. object = lexer.o count_words.o  
    3. count_words: $(object) -lfl  
    4.         $(CC) $(object) -lfl -o count_words  
    5. count_words.o:   
    6. lexer.o:  
    7. lexer.c: lexer.l  
    8.         flex -t lexer.l > lexer.c  
    9. clean:  
    10.         rm lexer.c $(object) count_words  
    这种方法也叫“隐式规则”。

    六、关于Clean

    一个好习惯是每个makefile都要写clean规则,这样不仅可以方便重编译,也有利于保持文件路径的清洁。一般的风格是:
    1. clean:  
    2.         rm lexer.c $(object) count_words  
    但是,更为稳妥的做法是:
    1. .PHONY: clean  
    2. clean:  
    3.         -rm lexer.c $(object) count_words  
    .PHONY表示clean是一个“伪目标”,而rm命令前面的减号则表示,不管出现什么问题都要继续做后面的事情。
    注意:clean规则不要放在makefile的开头,不然就会变成make的默认目标了。
  • 相关阅读:
    5-python基础—获取某个目录下的文件列表(适用于任何系统)
    Automated, Self-Service Provisioning of VMs Using HyperForm (Part 1) (使用HyperForm自动配置虚拟机(第1部分)
    CloudStack Support in Apache libcloud(Apache libcloud中对CloudStack支持)
    Deploying MicroProfile-Based Java Apps to Bluemix(将基于MicroProfile的Java应用程序部署到Bluemix)
    Adding Persistent Storage to Red Hat CDK Kit 3.0 (在Red Hat CDK Kit 3.0添加永久性存储)
    Carve Your Laptop Into VMs Using Vagrant(使用Vagran把您笔记本电脑刻录成虚拟机)
    使用Python生成一张用于登陆验证的字符图片
    Jupyter notebook的安装方法
    Ubuntu16.04使用Anaconda5搭建TensorFlow使用环境 图文详细教程
    不同时区的换算
  • 原文地址:https://www.cnblogs.com/nktblog/p/4027117.html
Copyright © 2011-2022 走看看