Makefile 概述

来源:互联网 发布:小米有淘宝店吗 编辑:程序博客网 时间:2024/06/01 20:04
        孙玉厚一听就火了,正要开口数落老婆,就听见女儿兰香在灶火圪崂里说:“妈,猪我已经喂过了……” 

    窑里所有人的目光,一齐投向这个他们谁也没有留意的十三岁的孩子。她正从筐子里往外倒柴禾。她不知什么时间已经捡回来好几筐柴禾了,足够一两天烧的。可爱的兰香默默地做着她能做的一切活。 

    孙玉厚老两口大受感动地看着他们这个最小的孩子,连一句话也说不出来了。按说,她是家里最小的娃娃,应该娇惯一些。可孩子长了这么大,还没给她扯过一件象样的衣服。现在她已经到石圪节上了初中,身上还七长八短地穿着前两年的旧衣服。                                   ----路遥 《平凡的世界》


     Makefile是个什么东东。

    我们先做个菜,香菇炖排骨。我们需要先从菜市场中n多种菜种选来香菇,排骨,各种调味品,姜,盐等材料,然后,洗好,用菜刀砍刀切好香菇,排骨,把排骨放到电砂锅中,加上水,姜,调味品放到锅中,加上水,插上电,开始炖。先高火,水开以后,加入香菇,小火,差不多一个多小时,香菇炖排骨就OK了。

    我们来分析一下这道菜:

   原材料:香菇,排骨,各种调味品,姜,盐,水

   工具:菜刀,砍刀,菜板,电砂锅 等(其他的就不说了)

   过程:买,洗,切,放,插上电等

   目的:做一道香菇炖排骨

   我们在Fedora17下,想写一个RTSP的客户端程序(不解码),需要先写好相关的源代码文件:main.cpp,rtspClient.cpp(.h),NetService.cpp(.h),parseProtocol.cpp(.h),parseRTP.cpp(.h),然后,yum install gcc的编译环境工具,编译每一文件生成.o文件,最后,和系统的动态库libthread,libc,libm,libstd++等 链接成执行程序rtspclient。

    我们也来分析一下这个程序:

     源文件:main.cpp, rtspClient.cpp(.h),NetService.cpp(.h),parseProtocol.cpp(.h),parseRTP.cpp(.h)

     工具:gcc,共享库libthread,libc,libstdc++,libc等库

     过程:编译.o文件,链接动态库

     目的:RTSP的客户端程序(不解码)

     而 Makefile的工作就是组织完成这个过程。如果没有Makefile,我们就只有一个文件一个文件的编译,最后再链接。

     综上,Makefile简单讲就是为过程制定规则,且执行:把写好的源文件(C/C++、java,c object等),通过工具链(gcc,arm gcc等)工具,通过一系列过程完成目的。

     那为什么windows下没有呢?

     其实是有的,nmake(mingw环境).只是因为在windows下有Visual Studio,Borland C++等IDE工具,它们把编辑源文件,编译器(工具链),编译过程,甚至于调试也都集成到一起了,所以,我们不必去自己写这个过程的规则。

     linux有这种IDE的工具没?有的,CodeBlocks。它也可以编译,也可以调试。甚至比这些windows IDE工具更加强大的是,可以做codeblock是还支持嵌入式的arm等平台的调试(实际上是使用gdb,gdbserver),可以指定你自己的Makefile也可以CodeBlocks帮你完成,且支持windows系统的。

    知道Makefile是什么了,现在需要知道如何写。

    任何东西都有一定的游戏规则,我总结出规则分为两大类:客观规则和主观规则。客观规则,就是我们自己不能改变的规则,比如别人提供的库的接口,posix接口,gcc的写法,嵌入式系统开机上电时的加载顺序等等。主观规则,就是我们能够制定和改变的规则。

    对于我们写makefile来说,我们不能改变的是makefile自身的规则和gcc等工具链的命令格式,gcc编译的过程(先预编译,编译成汇编,编译成机器码,最后就是链接)。

    在讲规则之前,我们先练习写一个最简单的Hello World!的简单程序,写一个最最简单的makefile。

先建立一个目录testmakefile,进入目录后,在Vi(或者其他编辑器中),编辑一个main.c的文件: 

      #include <stdio.h>


      int main(int argc, char *argv[])
     {

        printf("Hello World !\n");
        return 0;

     }

然后,再touch 一个 makefile文件。不过,这个makefile里面的内容为空的(其实可以没有这个文件,不信,你试一下)。

     现在我们看看我们目录下有几个文件:


$ ll
总用量 4
-rw-r--r-- 1 root root 101 10月 22 13:14 main.cpp
-rw-r--r-- 1 root root   0 10月 22 13:19 Makefile

 

      接下来,运行make:

$ make main
g++     main.cpp   -o main

      然后再看看目录的文件:

$ ll
总用量 12
-rwsrwsrwt 1 root root 5101 10月 22 13:23 main
-rwsrwsrwt 1 root root  101 10月 22 13:23 main.cpp
-rwsrwsrwt 1 root root    0 10月 22 13:23 Makefile

       多了一个执行程序 main。完成工作。

       运行

$ ./main
Hello World !

      这就是最简单的makefile。

      这不是坑爹嘛!makefile是空的? 其实这是使用了makefile的缺省规则(潜规则)。后面的文章在讲述这些。

      

      现在开始讲 makefile的规则:

      Target : Dependance.
      [TAB]  Command

 

       Target:目标,就是这条规则的最终目标。

       Dependance:完成这个目标所依赖的文件,或者其他目标 的列表(我 成为 条件,下同)。

       Command: 完成这个目标所需要执行的过程。

       [TAB]:规则这一行是以 [Tab]符号开始。

 

      比较抽象,我们就来写一个 刚才的Hello world的makefile.

      编辑刚才touch的文件 Makefile:

     main:main.c
        gcc -o $@ $^

      然后,删除 main 这个执行文件后,再敲make。

     $ make
     gcc -o main main.c

 

    我们来分析这个Makefile, 先讲一个原则:直接敲make,则 这个make 执行的是:找到第一个规则,完成这个规则。

    main: main.c            ## main 是目标,而它的依赖的条件是 main.c. 因为这个main.c 已经存在,则这个条件是满足的。

        gcc -o $@ $^                      ## 生成 main 所需要完成才过程。gcc 是一条shell gcc 编译命令(也可能是其他什么shell命令)

                                                   ## 注意: $@ 是 一个 目标的自动化变量,即代替 main. @^ 是一个依赖条件的自动化变量,即代替 main.c

 

       差不多,基本的东西就这么多。后续在分模块来学习。

       个人认为 makefile 你可以认为就是一种脚本语言,类似于bash,lua。就像avi,mp4,mkv都属于流媒体的封装格式,里面的核心原则是一样的,但是,使用的结构方法是不一样的。所以,我曾经用makefile写了一个脚本和bash的一个脚本用途是一模一样的。,

      makefile的难度在于“把n多个文件组合在一起,最后生成库文件或者运行程序”的这个逻辑很复杂。现在网上也有很大这种makefile的模版,看过一些,但是,因为每个项目的需求不一样,我还是愿意自己手写完成。有些需要多平台编译,有些需要在每个目录中编译,有的还需要生成日期,版本等文件,还有的需要一些校验文件等等。但总之一条,每个工程 的makefile 可以不一样,但都是按照上面这个规则去完成的。 规则简单,复杂的是逻辑(编程就是构建逻辑,所以 和程序打交道是简单的,因为它是有逻辑的,而与人打交道时,很多时候是没有逻辑的。

       Good Luck!

   

 

 

     

 

 

     

  

原创粉丝点击