Makefile基础学习

理论知识

  • makefile关系到了整个工程的编译规则。一个工程中的源文件不计其数,并且按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个 Shell脚本一样,其中也可以执行操作系统的命令。
  • makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。

书写规则和语法

  • 规则包含两个部分,一个是依赖关系,一个是生成目标的方法。

makefile写法为:

targets : prerequisites
command
...

或是这样

targets : prerequisites ; command
command
...

targets是文件名,以空格分开,可以使用通配符。一般来说,我们的目标基本上是一个文件,但也有可能是多个文件。

command是命令行,如果其不与“targets:prerequisites”在一行,那么,必须以[Tab键]开头,如果和prerequisites在一行,那么可以用分号做为分隔。(见上)

prerequisites也就是目标所依赖的文件(或依赖目标)。

实例学习

  • 参考GCC基础知识学习中『一个实例:-I参数的使用』,写出编译例子中vi编辑代码的makefile,编译出来的目标文件为testmymath, 只用显式规则就可以。

首先,我们可以vim Makefile或者vim makefile来新建打开一个makefile。

我们先得到几个文件的依赖关系:testmymath依赖五个.o文件,五个.o文件分别依赖相应的.c文件和head.h文件。

第一步要写出最终目标:

testmymath: main.o add.o sub.o mul.o div.o //最终目标文件:依赖文件
gcc main.o add.o sub.o mul.o div.o -o testmymath//以tab键开头,写出命令行,即得到testmymath的命令

接下来是各个.o文件的生成(规则同上):

main.o: main.c head.h
gcc -c main.c
add.o: add.c head.h
gcc -c add.c
sub.o: sub.c head.h
gcc -c sub.c
mul.o: mul.c head.h
gcc -c mul.c
div.o: div.c head.h
gcc -c div.c

最后就可以完整的得到makefile文件啦!

testmymath: main.o add.o sub.o mul.o div.o
gcc main.o add.o sub.o mul.o div.o -o testmymath
main.o: main.c head.h
gcc -c main.c
add.o: add.c head.h
gcc -c add.c
sub.o: sub.c head.h
gcc -c sub.c
mul.o: mul.c head.h
gcc -c mul.c
div.o: div.c head.h
gcc -c div.c

makefile中使用变量

  • 在上面的例子中,我们可以看到[.o]文件的字符串被重复了两次,如果我们的工程需要加入一个新的[.o]文件,那么我们需要在两个地方加。当然,我们的makefile并不复杂,所以在两个地方加也不累,但如果makefile变得复杂,那么我们就有可能会忘掉一个需要加入的地方,而导致编译失败。所以,为了makefile的易维护,在makefile中我们可以使用++变量++。makefile的变量也就是一个字符串,理解成C语言中的宏可能会更好。

比如,我们声明任意一变量名,叫objects, OBJECTS, objs, OBJS, obj, 或OBJ,只要能够表示obj文件即可。我们在makefile起始处按如下定义此变量:

objects = main.o add.o sub.o mul.o div.o

于是,我们就可以很方便地在我们的makefile中以“$(objects)”的方式来使用这个变量了,于是我们的改良版makefile变为如下:

objects = main.o add.o sub.o mul.o div.o

testmymath : $(objects)
gcc -o testmymath $(objects)
main.o: main.c head.h
gcc -c main.c
add.o: add.c head.h
gcc -c add.c
sub.o: sub.c head.h
gcc -c sub.c
mul.o: mul.c head.h
gcc -c mul.c
div.o: div.c head.h
gcc -c div.c

make是如何工作的

  • 在默认的方式下,也就是我们只输入make命令。那么,
  1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
  2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“testmymath”这个文件,并把这个文件作为最终的目标文件。
  3. 如果testmymath文件不存在,或是testmymath所依赖的后面的 .o 文件的文件修改时间要比testmymath这个文件新,那么,他就会执行后面所定义的命令来生成testmymath这个文件。
  4. 如果testmymath所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程)
  5. 当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件生成make的终极任务,也就是执行文件testmymath了。
  • 我们还可以在makefile中写一条clean的命令来一次性删除所有.o文件和testmymath,以便进行重新编译:
clean:
rm testmymath *.o

像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,因此,我们可以显式要make执行,即命令make clean

如果使用变量,也可以写为:

clean:
rm testmymath $(objects)

这样我们可以得到一个比较完整的makefile:

objects = main.o add.o sub.o mul.o div.o

testmymath : $(objects)
gcc -o testmymath $(objects)
main.o: main.c head.h
gcc -c main.c
add.o: add.c head.h
gcc -c add.c
sub.o: sub.c head.h
gcc -c sub.c
mul.o: mul.c head.h
gcc -c mul.c
div.o: div.c head.h
gcc -c div.c
clean:
rm testmymath $(objects)

接下来我们测试一下写的makefile,这里建议大家到head.h所在的目录下使用mv head.h /src所在的路径,也就是把头文件和.c文件放到一个目录下。因为如果不在一个目录下,会出现make找不到头文件不成功的情况。

  • 我们make一下,可以看到make在自动执行了,并产生了.o文件和 testmymath。
  • 也可以使用 make clean一下子删除了想删除的文件。

  • 那么如果不把头文件放到src下,该怎么做呢?
  • 我们可以在makefile中加一句:
CFLAGS = -I/(头文件所在路径)

然后在相应执行语句中加入$(CFLAGS)即可,如:

main.o: main.c head.h
gcc $(CFLAGS) -c main.c

Makefile基础学习的更多相关文章

  1. opengl基础学习专题 (一 )编程环境搭建

    题外话: 第一次在博客园上同大家分享博文.水的的地方,错别字的地方.环境交流.批评.知道了马上改. 以前在百度空间中写技术分享博文,后来百度啥也没说就把整个空间封了.当时感觉 还是有点寒心.只想黑一下 ...

  2. salesforce 零基础学习(五十二)Trigger使用篇(二)

    第十七篇的Trigger用法为通过Handler方式实现Trigger的封装,此种好处是一个Handler对应一个sObject,使本该在Trigger中写的代码分到Handler中,代码更加清晰. ...

  3. 如何从零基础学习VR

    转载请声明转载地址:http://www.cnblogs.com/Rodolfo/,违者必究. 近期很多搞技术的朋友问我,如何步入VR的圈子?如何从零基础系统性的学习VR技术? 本人将于2017年1月 ...

  4. IOS基础学习-2: UIButton

    IOS基础学习-2: UIButton   UIButton是一个标准的UIControl控件,UIKit提供了一组控件:UISwitch开关.UIButton按钮.UISegmentedContro ...

  5. HTML5零基础学习Web前端需要知道哪些?

    HTML零基础学习Web前端网页制作,首先是要掌握一些常用标签的使用和他们的各个属性,常用的标签我总结了一下有以下这些: html:页面的根元素. head:页面的头部标签,是所有头部元素的容器. b ...

  6. python入门到精通[三]:基础学习(2)

    摘要:Python基础学习:列表.元组.字典.函数.序列化.正则.模块. 上一节学习了字符串.流程控制.文件及目录操作,这节介绍下列表.元组.字典.函数.序列化.正则.模块. 1.列表 python中 ...

  7. python入门到精通[二]:基础学习(1)

    摘要:Python基础学习: 注释.字符串操作.用户交互.流程控制.导入模块.文件操作.目录操作. 上一节讲了分别在windows下和linux下的环境配置,这节以linux为例学习基本语法.代码部分 ...

  8. CSS零基础学习笔记.

    酸菜记 之 CSS的零基础. 这篇是我自己从零基础学习CSS的笔记加理解总结归纳的,如有不对的地方,请留言指教, 学前了解: CSS中字母是不分大小写的; CSS文件可以使用在各种程序文件中(如:PH ...

  9. Yaf零基础学习总结5-Yaf类的自动加载

    Yaf零基础学习总结5-Yaf类的自动加载 框架的一个重要功能就是类的自动加载了,在第一个demo的时候我们就约定自己的项目的目录结构,框架就基于这个目录结构来自动加载需要的类文件. Yaf在自启动的 ...

随机推荐

  1. Linux背背背(3)

    目录 1.文件操作命令 2.文件夹操作命令 文件操作命令 创建 命令:touch 语法:#touch 文件的名字      文件名可以是一个完整的路径 如果后面的参数文件名指定了路径,则表示在指定的路 ...

  2. 分布式计算课程补充笔记 part 4

    ▶ 并行通讯方式: map 映射 全局一到一 全局单元素计算操作 transpose 转置 一到一 单元素位移 gather 收集 多到一 元素搬运不计算 scatter 分散 一到多 元素搬运不计算 ...

  3. 10. 批量插入List<String>

    List<String> iscBusOrgIdList = getIscOrgIdList();List<Map<String, Object>> iscBusO ...

  4. ListView的基本使用方法和RecyclerView的基本使用方法

    ListView是一种用于列表显示数据内容的控件,它可以通过适配器实现对于数据的列表显示,而RecyclerView是对于ListView优化后的列表数据显示控件. 个人对于List的使用经历多半在新 ...

  5. 尚硅谷springboot学习30-docker安装mysql示例

    docker pull mysql 错误的启动示例 错误日志:需要设置密码 正确的启动 但还不能直接使用,因为没有做端口映射,外界无法连接 可用的启动 连接成功 几个高级的操作 指定配置文件 dock ...

  6. python中类与对象之继承

    面对对象的三大特性之继承 1.什么是继承? 在程序中,继承指的是class与class之间的关系 继承是一种关系,必须存在两个class才能产生这种关系:被继承的class称为父类,继承的class称 ...

  7. ceph结构详解

    引言 那么问题来了,把一份数据存到一群Server中分几步? Ceph的答案是:两步. 计算PG 计算OSD 计算PG 首先,要明确Ceph的一个规定:在Ceph中,一切皆对象. 不论是视频,文本,照 ...

  8. SpringMVC处理XML格式的数据

    1.搭建SpringMVC+spring环境 2.web.xml,Springmvc-config.xml.springMVC提供了处理xml格式请求响应的HttpMessageConverter,s ...

  9. python的条件语句

    Python程序语言指定任何非0和非空(null)值为true,0 或者 null为false. Python 编程中 if 语句用于控制程序的执行,基本形式为: if 判断条件: 执行语句…… el ...

  10. 整合SpringMVC框架和Spring框架

    -------------------------siwuxie095                                 整合 SpringMVC 框架和 Spring 框架       ...