Makefile--基本规则(零)

【版权声明:转载请保留出处:周学伟: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
时间: 2024-08-26 16:37:25

Makefile--基本规则(零)的相关文章

从头开始写项目Makefile(零):前言

[版权声明:转载请保留出处:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] 一不小心工作三年了,也就是写了三年代码了,码农生活过的真快.最近发现我们项目的Makefile不够好,于是着手改了一下,以前Makefile写好后就很少动它了,直接在项目之间拷来拷去直接拿来用,这次重新修改项目Makefile,发现自己又学到不少东西,于是乎决定总结一下记录下来与各位苦逼的程序猿一道分享一下. 其实各大论坛博客已经有很多关于Makefile的文章

[Erlang_Question34]erlang.mk的源码阅读1-入门makefile

通过erlang.mk项目,掌握基本的makefile语法,可以自己定制makefile. 1. makefile 基本规则: 1. 所有的源文件没有被编译过,则对各个源文件进行编译并进行链接,生成最后的可执行程序; 2. 每一个在上次执行make之后修改过的源代码文件在本次执行make时将会 被重新编译; 3. 头文件在上一次执行make之后被修改.则所有包含此头文件的源文件在本次执行 make 时将会被重新编译. 2. 基本格式: TARGET... : PREREQUISITES... C

erlang.mk和makefile语法剖析

1. makefile 基本规则: 1. 所有的源文件没有被编译过,则对各个源文件进行编译并进行链接,生成最后的可执行程序; 2. 每一个在上次执行make之后修改过的源代码文件在本次执行make时将会 被重新编译; 3. 头文件在上一次执行make之后被修改.则所有包含此头文件的源文件在本次执行 make 时将会被重新编译. 2. 基本格式: TARGET... : PREREQUISITES... COMMAND ... 2.1 target(目标)通常是最后需要生成的文件名或者为了实现这个

信息安全系统设计基础期中总结

Chapter 00 Linux基础 man命令调用手册页 man <command_name> 手册通常被分为8个区段,要查看相应区段的内容,就在 man 后面加上相应区段的数字即可: 1 一般命令 2 系统调用 3 库函数,涵盖了C标准函数库 4 特殊文件(通常是/dev中的设备)和驱动程序 5 文件格式和约定 6 游戏和屏保 7 杂项 8 系统管理命令和守护进程 man有一个-k 选项用起来非常好,这个选项让你学习命令.编程时有了一个搜索引擎,可以举一反三.结合后面学习的grep 命令和

2014025670(12)《嵌入式系统程序设计》第二周学习总结

这周学习了gcc和gdb的使用还有makefile. 教材学习内容总结 教材内容开始看的有些吃力,很多地方都不太懂,网上查询和询问同学和老师之后,了解了很多,但是具体操作和实现方面还是比较难. 教材学习中问题和解决过程 对于gcc的操作在实验楼的学习中还是比较顺利,gdb的操作感觉有些村存在问题-----gdb的调试方面有些吃力,应该是自己没努力的结果,打算把问题汇总一下,再试试实验. 课后作业中的问题和解决过程 应用实验楼的第二周,第一周的内容感觉简单,消化很快,没想到第二周就感觉有些吃力,不

2014025658《嵌入式系统程序设计》第二周学习总结

本周所学内容如下: 1.学会使用gcc编译器: 2.学会使用GDB调试器: 3.学会C程序的编写(包括系统调用和函数调用) 4.学会Makefile基本规则: 5.学会make命令的使用方法: 6.学会使用Makefile程序的编写. 7.使用gcc编译器编译C语言程序文件生成可执行文件的过程,是要经历四个相互关联的步骤:预处理.编译.汇编和链接. 8.gdb是GNU开源组织开发的一个强大的Linux下的程序调试工具,它主要完成:启动被调试程序,按照要求运行程序.让被调试的程序在指定的位置停住.

20145216史婧瑶 《信息安全系统设计基础》第2周学习总结

20145216史婧瑶 <信息安全系统设计基础>第2周学习总结 教材学习内容总结 一.VIM 1.hjkl所表示的即为光标 ←↓↑→,前提是要在normal的状态下.方便记忆j像一个笔就像下箭头. ·i → Insert 模式,可插入文本.按 ESC 回到 Normal 模式. ·A → 输入欲添加文本(在一行后添加文本).按 ESC 回到 Normal 模式. ·x → 删当前光标所在的一个字符. ·:wq → 存盘 + 退出 (:w 存盘, :q 退出) 2.删除类命令: 该命令为操作符d

20135304刘世鹏——信息安全系统设计基础第二周学习总结

第一节.Linux基础 1.Linux命令 Linux中命令格式为:command [options] [arguments] 选项:是调整命令执行行为的开关,选项不同决定了命令的显示结果不同 参数:决定了命令的显示结果不同 例如:ls .中.为参数:ls -a中-a为选项 2.man命令 1 Executable programs or shell commands(普通的Linux命令) 2 System calls (系统调用,操作系统的提供的服务接口) 3 Library calls (

20135218 信息安全系统设计基础第二周学习总结

深入理解计算机系 Linux基础 一.实验说明 环境登录  无需密码自动登录,系统用户名shiyanlou,密码shiyanlou 二.实验步骤 三种知识: 元知识:这门课程思考问题框架是什么?遇到老问题,它会怎样分析?遇到新问题,它会怎样分析? 硬知识:这门课程的主要知识点是什么?适合用思维导图组织吗? 软知识:这门课程的哪些知识点需要哪些实践环节来强化理解和记忆? 1. Linux命令 Linux学习应用的一个特点是通过命令行进行使用. 登录Linux后,我们就可以在#或$符后面去输入命令,

2014025665《嵌入式》第2周学习总结

学习内容概总 1.学会使用gcc编译器和GDB调试器 2.学会编写C程序和使用Makefile基本规则 3.学会make命令使用方法和使用Makefile编写程式 4.使用gcc编译器编写c语言程序文件生成可执行文件的过程 经历四个步骤:预处理.编译.汇编.链接 5.gdb是GNU开源组织开发的一款程序调试工具,可以完成:启动被调试程序,按照要求运行程序,可以让被调试程序在指定位置停止,被调试程序停止时可以检查被调试状态和变量的值等内容.动态改变被调试程序的运行环境等. 6.Makefile是用