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的默认目标了。
  • 相关阅读:
    使用 SVN Hook 实现服务器端代码自动更新
    在Windows下配置svn服务端钩子程序(部分)
    @RequestParam,@PathParam,@PathVariable等注解区别
    @ConditionalOnProperty 详解
    Spring MVC之@RequestParam @RequestBody @RequestHeader 等详解
    Ajax中Delete请求参数 后台无法获取的解决方法(Restful风格)
    原生JS和jQuery版实现文件上传功能
    捡芝麻与捡西瓜
    在行动中思考
    日常相关的标准技术和组织
  • 原文地址:https://www.cnblogs.com/nktblog/p/4027117.html
Copyright © 2011-2022 走看看