【版权声明:转载请保留出处:周学伟:http://www.cnblogs.com/zxouxuewei/】

一般一个稍大的linux项目会有很多个源文件组成,最终的可执行程序也是由这许多个源文件编译链接而成的。编译是把一个.c或.cpp文件编译成中间代码.o文件,链接是就使用这些中间代码文件生成可执行文件。比如在当前项目目录下有如下源文件:

    # ls  common.h  debug.c  debug.h  ipc.c  ipc.h  main.c  tags  timer.c  timer.h  tools.c  tools.h   #

以上源代码可以这样编译:

# gcc -o target_bin main.c debug.c ipc.c timer.c tools.c

如果之后修改了其中某一个文件(如tools.c),再执行一下上一行代码即可,但如果有成千上万个源文件这样编译肯定是不够合理的。此时我们可以按下面步骤来编译:

然后在命令行上执行命令:

    # make   gcc -c main.c  gcc -c debug.c  gcc -c ipc.c  gcc -c timer.c  gcc -c tools.c  gcc -o target_bin main.o debug.o ipc.o timer.o tools.o  #  # ls  common.h  common.h~  debug.c  debug.h  debug.o  ipc.c  ipc.h  ipc.o  main.c  main.o  Makefile  Makefile~  tags  target_bin  timer.c  timer.h  timer.o  tools.c  tools.h  tools.o  # 

可见在该目录下生成了.o文件以及target_bin可执行文件。现在我们只需要执行一个make命令就可以完成所有编译工作,无需像之前一样手动执行所有动作,make命令会读取当前目录下的Makefile文件然后完成编译步骤。从编译过程输出到屏幕的内容看得到执行make命令之后所做的工作,其实就是我们之前手动执行的那些命令。现在来说一下什么是Makefile?

所谓Makefile我的理解其实就是由一组组编译规则组成的文件,每条规则格式大致为:

    target ... : prerequisites ...   >---command  ...  

其中target是目标文件,可以为可执行文件、*.o文件或标签。Prerequisites是产生target所需要的源文件或*.o文件,可以是另一条规则的目标。commond是要产生该目标需要执行的操作系统命令,该命令必须以tab(文中以>---标示tab字符)开头,不可用空格代替。

说白了就是要产生target,需要依赖后面的prerequisites文件,然后执行commond来产生来得到target。这和我们之前手动执行每条编译命令是一样的,其实就是定义好一个依赖关系,我们把产生每个文件的依赖文件写好,最终自动执行编译命令。

比如在我们给出的Makefile例子中target_bin main.o等就是target,main.o debug.o ipc.o timer.o tools.o是target_bin的prerequisites,gcc -o target_bin main.o debug.o ipc.o timer.o tools.o就是commond,把所有的目标文件编译为最终的可执行文件target,而main.c common.h是main.o的prerequisites,其gcc -c main.c命令生成target所需要的main.o文件。

在该例子中,Makefile工作过程如下:

1. 首先查找第一条规则目标,第一条规则的目标称为缺省目标,只要缺省目标更新了就算完成任务了,其它工作都是为这个目的而做的。 该Makefile中第一条规则的目标target_bin,由于我们是第一次编译,target_bin文件还没生成,显然需要更新,但此时依赖文件main.o debug.o ipc.o timer.o tools.o都没有生成,所以需要先更新这些文件,然后才能更新target_bin。

2. 所以make会进一步查找以这些依赖文件main.o debug.o ipc.o timer.o tools.o为目标的规则。首先找main.o,该目标也没有生成,该目标依赖文件为main.c common.h,文件存在,所以执行规则命令gcc -c main.c,生成main.o。其他target_bin所需要的依赖文件也同样操作。

3. 最后执行gcc -o target_bin main.o debug.o ipc.o timer.o tools.o,更新target_bin。

在没有更改源代码的情况下,再次运行make:

    # make  make: `target_bin' is up to date.  #

得到提示目标target_bin已经是最新的了。

如果修改文件main.c之后,再运行make:

    # vim main.c  # make  gcc -c main.c  gcc -o target_bin main.o debug.o ipc.o timer.o tools.o  #

此时make会自动选择受影响的目标重新编译:

首先更新缺省目标,先检查target_bin是否需要更新,这需要检查其依赖文件main.o debug.o ipc.o timer.o tools.o是否需要更新。

其次发现main.o需要更新,因为main.o目标的依赖文件main.c最后修改时间比main.o晚,所以需要执行生成目标main.o的命令:gcc -c main.c更新main.o。

最后发现目标target_bin的依赖文件main.o有更新过,所以执行相应命令gcc -o target_bin main.o debug.o ipc.o timer.o tools.o更新target_bin。

总结下,执行一条规则步骤如下:

1. 先检查它的依赖文件,如果依赖文件需要更新,则执行以该文件为目标的的规则。如果没有该规则但找到文件,那么该依赖文件不需要更新。如果没有该规则也没有该文件,则报错退出。

2. 再检查该文件的目标,如果目标不存在或者目标存在但依赖文件修改时间比他要晚或某依赖文件已更新,那么执行该规则的命令。

由此可见,Makefile可以自动发现更新过的文件,自动重新生成目标,使用Makefile比自己手动编译比起来,不仅效率高,还减少了出错的可能性。

Makefile中有很多目标,我们可以编译其中一个指定目标,只需要在make命令后面带上目标名称即可。如果不指定编译目标的话make会编译缺省的目标,也就是第一个目标,在本文给出的Makefile第一个目标为target_bin。如果只修改了tools.c文件的话,我们可能只想看看我们的更改的源代码是否有语法错误而又不想重新编译这个工程的话可以执行如下命令:

# make tools.o
gcc -c tools.c
#

编译成功,这里又引出一个问题,如果继续执行同样的命令:

    # make tools.o  make: `tools.o' is up to date.  #

我们先手动删掉tools.o文件再执行就可以了,怎么又是手动呢?我们要自动,要自动!!好吧,我们加一个目标来删除这些编译过程中产生的临时文件,该目标为clean。

我们在上面Makefile最后加上如下内容:

    clean:  >---rm *.o target_bin  

当我们直接make命令时不会执行到该目标,因为没有被默认目标target_bin目标或以target_bin依赖文件为目标的目标包含在内。我们要执行该目标需要在make时指定目标即可。如下:

# make clean
rm *.o target_bin
#

可见clean目标被执行到了,再执行make时make就会重新生成所有目标对应的文件,因为执行make clean时,那些文件被清除了。

clean目标应该存在与你的Makefile当中,它既可以方便你的二次编译,又可以保持的源文件的干净。该目标一般放在最后,不可放在最开头,否则会被当做缺省目标被执行,这很可能不是你的意愿。

最后总结一下,Makefile只是告诉了make命令如何来编译和链接程序,告诉make命令生成目标文件需要的文件,具体的编译链接工作是你的目标对应的命令在做。

给一个今天完整的makefile:

target_bin : main.o debug.o ipc.o timer.o tools.o
>---gcc -o target_bin main.o debug.o ipc.o timer.o tools.o  main.o: main.c common.h
>---gcc -c main.c  debug.o: debug.c debug.h common.h
>---gcc -c debug.c  ipc.o: ipc.c ipc.h common.h
>---gcc -c ipc.c  timer.o: timer.c timer.h common.h
>---gcc -c timer.c  tools.o: tools.c tools.h common.h
>---gcc -c tools.c  clean:
>---rm *.o target_bin

转载于:https://www.cnblogs.com/zxouxuewei/p/5107477.html

Makefile--基本规则(零)相关推荐

  1. 【开发工具】之makefile基本规则

    参考网址:https://www.w3cschool.cn/mexvtg/dsiguozt.html 参考网址:https://blog.csdn.net/lizhiqiang5846/article ...

  2. 复习(二)—— Makefile工具使用

    人们通常利用 make 工具来自动完成编译工作.这些工作包括:如果仅修改了某几个源文件,则只重新编译这几个源文件:如果某个头文件被修改了,则重新编译所有包含该头文件的源文件.利用这种自动编译可大大简化 ...

  3. 【Linux】Makefile文件

    Makefile文件 1. Makefile定义 一个工程中的源文件不计其数,其按类型.功能.模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译 ...

  4. 简单Makefile编写教程

    Makefile编写 1. make和Makefile的介绍 1.1 make工具 利用make工具可以自动完成编译工作.这些工作包括: 如果仅仅修改了某几个源文件,则只重新编译这几个源文件: 如果某 ...

  5. Makefile初级语法1

    Makefile基本规则 基本规则如下: target [target...] : [dependent ...][ command ...] # command前必须是TAB 语法示例分析: hel ...

  6. 20135203齐岳 信息安全系统设计基础期中总结

    20135203齐岳 信息安全系统设计基础期中总结 一.学习目标 复习前面Linux 命令,Linux 编程基础,教材前七章内容 二.学习资源 教材 答案解析见http://group.cnblogs ...

  7. Ubuntu怎么用c/c++编程

    https://jingyan.baidu.com/article/48b37f8d23a2a61a646488db.html ···································· ...

  8. 0x300-从头开始写操作系统-内核

    目录 回顾 今日目标 必要工具的安装及介绍 工具一览 工具介绍 GCC Hosted Environment Freestanding Environment Linker C 语言编译(gcc 的临 ...

  9. Linux 读书笔记 二

    一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou,密码shiyanlou 若不小心登出后,直接刷新页面即可 2. 环境使用 完成实验后可以点击桌面上方的"实验截图 ...

  10. C++教程网编程视频

    C++教程网(www.cppcourse.com)致力于打造成C++一站式教学网,这里是已经录制好的视频汇总,更多视频将陆续推出... 视频购买地址:http://cppcourse.taobao.c ...

最新文章

  1. WWDC上这个神级功能,一言不合又要改变未来购物趋势
  2. java 访问私有成员,在Java中访问私有方法?
  3. IOT(33)---NB-IOT通用物联解决方案
  4. C++数据结构01--顺序线性表实现
  5. VB判断文件及目录的存在性
  6. 很久之前写的【成绩管理系统】的数据库
  7. 那些月入5000的人,凭什么比你更早买房买车?
  8. [转]使用C#开发一个简单的P2P应用
  9. Cent OS 6.X 开机错误修复
  10. 微信小程序自定义字体及自定义图标问题说明
  11. 效果器的使用技巧-与调音台的无缝连接
  12. android投屏到电脑
  13. linux系统ss命令详解,linux 下 ss命令详解
  14. jQuery siblings() 方法
  15. ubantu 安装 mosquitto时 connection refused 的解决办法
  16. 新开通了我的CSDN博客,写个处女篇
  17. 无题--仅以此文来总结我过去的五年
  18. jquery 录屏_Fundebug录屏插件更新至0.6.0
  19. ElasticSearch 升级过程中给涉及到的术语-1、同步刷新synced  flush
  20. 用最优的定位方式,获得经度、纬度

热门文章

  1. BenchmarkSQL 测试Oracle 12c TPC-C 性能
  2. 【文本处理】格式crs_stat输出
  3. 浅谈javascript的面向对象(OOP)
  4. ToolStripContainer
  5. 数据库事务的四大特性以及隔离级别
  6. Linux 升级glibc-2.14 失败 我遇到的问题
  7. 获取当前时间---年月日时分秒------iOS
  8. iOS Nib文件一览
  9. 关于sharepoint2013的SPUtility.GetGenericSetupPath()方法过期解决办法
  10. Selenium ide及webDriver使用