makefile学习

2023-11-10

基本介绍

  1. makefile编写的关键在于解决源文件的“文件依赖性”
  2. 编译链接过程:源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数,变量是否被声明。如果函数未声明,编译器会给出一个警告,但可以生成object file。而在链接程序时,链接器会在所有的object file中寻找函数的实现,如果找不到,那到就会报链接错误码linker error.
  3. makefile最核心的内容:prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。
  4. clean不是一个文件,只是一个动作名字,类似地,我么可以在一个makefile中定义不用地编译或是和编译无关地命令,比如程序地打包,程序的备份。
  5. 使用变量:
    objs = a.o b.o
    c.o d.o
    program: $(objs)
    main: $(objs)
    cc -o program $(objs)
  6. make自动推导
    make看到a.o就会自动寻找a.c
  7. “隐晦规则”和“伪目标文件”
    .PHONY
    $(objects) : defs.h
    可以用共同的依赖头文件,但是会使得关系变得混乱
  8. 清理目标文件的规则
    .PHONY : clean
    clean :
    -rm edit $(objects)
    而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。不成文的规矩是——“clean从来都是放在文件的最后”。
  9. makefile主要包含了五个东西:显示规则,隐晦规则,变量定义,文件指示,和注释
  10. 引用其他的makefile
  • 通过include
    如include foo.make *,mk $(bar)
  • 如果有-I或–include-dir参数,那么make就会在参数指定的目录下去寻找
  • 如果目录是/include(一般是/usr/local/bin或/usr/include存在的话,make也会去找
  • -include <filename> 会忽略找不到的文件而不会因找不到文件而出现致命信息
  • 环境变量:如果环境变量定义了MAKEFILES,那么,make会把这个变量的值当作一个类似于include的动作,但建议不要使用

make的工作方式

GNU的make工作执行步骤如下:

  1. 读入所有的Makefile
  2. 读入被include的其它Makefile
  3. 初始化文件中的变量
  4. 推导隐晦规则,并分析所有规则
  5. 为所有的目标文件创建依赖关系链
  6. 根据依赖关系,决定哪些目标要重新生成
  7. 执行生成命令

书写规则

依赖关系,生成目标的方法

  • 在规则中使用通配符
    支持三种*,?,[…], ~的特殊用途

    • /test",表示当前用户$HOME目录下的test目录。而"hchen/test"则表示用户hchen的宿主目录下的test目录.
  • makefile中的变量其实就是c++/c中的宏
    objects = *.o并不会展开
    使用关键字才会展开
    objects := $(wildcard *.o)

文件搜寻

  1. 指定搜寻变量
    VPATH = src:…/headers
    上面的的定义指定两个目录,“src”和“…/headers”,make会按照这个顺序进行搜索。目录由“冒号”分隔。当前目录永远是最高优先搜寻的地方
  2. 另一个设置文件搜索路径的方法是使用make的“vpath”关键字
    1、vpath
    为符合模式的文件指定搜索目录。
    2、vpath
    清除符合模式的文件的搜索目录。
    3、vpath
    清除所有已被设置好了的文件搜索目录。
    vapth使用方法中的需要包含“%”字符。“%”的意思是匹配零或若干字符,例如,“%.h”表示所有以“.h”结尾的文件
    vpath %.h …/headers
    vpath %.c foo:bar
    vpath % blish
    而上面的语句则表示“.c”结尾的文件,先在“foo”目录,然后是“bar”目录,最后才是“blish”目录。

伪目标

伪目标一般没有依赖的文件。但是,我们也可以为伪目标指定所依赖的文件。伪目标同样可以作为“默认目标”,只要将其放在第一个。一个示例就是,如果你的Makefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事,并且,所有的目标文件都写在一个Makefile中,那么你可以使用“伪目标”这个特性
all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o utils.o
cc -o prog1 prog1.o utils.o
prog2 : prog2.o
cc -o prog2 prog2.o
prog3 : prog3.o sort.o utils.o
cc -o prog3 prog3.o sort.o utils.o

多目标

bigoutput littleoutput : text.g
generate text.g - ( s u b s t o u t p u t , , (subst output,, (substoutput,,@) > @ 上 述 规 则 等 价 于 : b i g o u t p u t : t e x t . g g e n e r a t e t e x t . g − b i g > b i g o u t p u t l i t t l e o u t p u t : t e x t . g g e n e r a t e t e x t . g − l i t t l e > l i t t l e o u t p u t 其 中 , − @ 上述规则等价于: bigoutput : text.g generate text.g -big > bigoutput littleoutput : text.g generate text.g -little > littleoutput 其中,- @bigoutput:text.ggeneratetext.gbig>bigoutputlittleoutput:text.ggeneratetext.glittle>littleoutput(subst output, @ ) 中 的 “ @)中的“ @)”表示执行一个Makefile的函数,函数名为subst,后面的为参数

静态模式

objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
另一个例子:
files = foo.elc bar.o lose.o
( f i l t e r (filter %.o, (filter(files)): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
( f i l t e r (filter %.elc, (filter(files)): %.elc: %.el
emacs -f batch-byte-compile $<

自动生成依赖性

我们可以使用C/C++编译的一个功能。大多数的C/C++编译器都支持一个“-M”的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。
例如,如果我们执行下面的命令:
cc -M main.c
其输出是:
main.o : main.c defs.h
需要提醒一句的是,如果你使用GNU的C/C++编译器,你得用“-MM”参数,不然,“-M”参数会把一些标准库的头文件也包含进来。
%.d: %.c
@set -e; rm -f $@;
$(CC) -M $(CPPFLAGS) $< > @ . @. @.$KaTeX parse error: Undefined control sequence: \ at position 3: ; \̲ ̲sed 's,\($*\)\.…KaTeX parse error: Can't use function '$' in math mode at position 4: > $̲@; \ rm -f $@.$$

第六章 书写命令

显示目录

@echo 正在编译XXX模块…
如果make执行时,带入make参数“-n”或“–just-print”,那么其只是显示命令,但不会执行命令,这个功能很有利于我们调试我们的Makefile,看看我们书写的命令是执行起来是什么样子的或是什么顺序的。
而make参数“-s”或“–slient”则是全面禁止命令的显示。

命令执行

需要注意的是,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。比如你的第一条命令是cd命令,你希望第二条命令得在cd之后的基础上运行,那么你就不能把这两条命令写在两行上,而应该把这两条命令写在一行上,用分号分隔。
exec:
cd /home/hchen; pwd
为了做到忽略命令的出错,我们可以在Makefile的命令行前加一个减号“-”(在Tab键之后),标记为不管命令出不出错都认为是成功的。
clean:
-rm -f *.o
还有一个全局的办法是,给make加上“-i”或是“–ignore-errors”参数,那么,Makefile中所有命令都会忽略错误。而如果一个规则是以“.IGNORE”作为目标的,那么这个规则中的所有命令将会忽略错误。这些是不同级别的防止命令出错的方法,你可以根据你的不同喜欢设置。
还有一个要提一下的make的参数的是“-k”或是“–keep-going”,这个参数的意思是,如果某规则中的命令出错了,那么就终目该规则的执行,但继续执行其它规则。
例如,我们有一个子目录叫subdir,这个目录下有个Makefile文件,来指明了这个目录下文件的编译规则。那么我们总控的Makefile可以这样书写:
subsystem:
cd subdir && $(MAKE)
等价于
subsystem:
$(MAKE) -C subdir
我们把这个Makefile叫做“总控Makefile”,总控Makefile的变量可以传递到下级的Makefile中(如果你显示的声明),但是不会覆盖下层的Makefile中所定义的变量,除非指定了“-e”参数。
如果你要传递变量到下级Makefile中,那么你可以使用这样的声明:
export <variable …>
如果你不想让某些变量传递到下级Makefile中,那么你可以这样声明:
unexport <variable …>
需要注意的是,有两个变量,一个是SHELL,一个是MAKEFLAGS,这两个变量不管你是否export,其总是要传递到下层Makefile中,特别是MAKEFILES变量,其中包含了make的参数信息,如果我们执行“总控Makefile”时有make参数或是在上层Makefile中定义了这个变量,那么MAKEFILES变量将会是这些参数,并会传递到下层Makefile中,这是一个系统级的环境变量。
但是make命令中的有几个参数并不往下传递,它们是“-C”,“-f”,“-h”“-o”和“-W”(有关Makefile参数的细节将在后面说明),如果你不想往下层传递参数,那么,你可以这样来:
subsystem:
cd subdir && $(MAKE) MAKEFLAGS=
如果你定义了环境变量MAKEFLAGS,那么你得确信其中的选项是大家都会用到的,如果其中有“-t”,“-n”,和“-q”参数,那么将会有让你意想不到的结果,或许会让你异常地恐慌。
“/home/hchen/gnu/make”,如果我们使用“make -w”来执行,那么当进入该目录时,我们会看到:
make: Entering directory /home/hchen/gnu/make'. 而在完成下层make后离开目录时,我们会看到: make: Leaving directory/home/hchen/gnu/make’
当你使用“-C”参数来指定make下层Makefile时,“-w”会被自动打开的。如果参数中有“-s”(“–slient”)或是“–no-print-directory”,那么,“-w”总是失效的。

定义命令包

如果Makefile中出现一些相同命令序列,那么我们可以为这些相同的命令序列定义一个变量。定义这种命令序列的语法以“define”开始,以“endef”结束

第七章 使用变量

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

makefile学习 的相关文章

随机推荐

  • MVC模式实现简单的访问数据库(JSP+Servlet+JavaBean)

    MVC模式 MVC模式一般由JSP Servlet JavaBean组成 其中JSP用于表示数据 Servlet用于处理客户请求 充当控制器的角色 JavaBean用于数据的存取 其运行机制如下 下面用一个简单的留言板例子来实现一下MVC模
  • exe文件 上传 服务器,域服务器exe文件发布教程.doc

    exe文件的发布 我以 winrar exe 的发布举例 步骤1 在C盘根目录新建一个 soft 目录 并共享该目录 如下图 步骤2 把 winrar exe 软件放到共享文件夹 soft 里面 步骤3 在soft目录里
  • vue中用Element-ui封装表单(form)和表格(table)组件动态渲染数据展示

    老样子 先来个效果图 查询表单数据和表格的列信息以及表格数据都是从后端拿到后自动渲染成下面的格式 一 先创建表格和表单组件 下面的form和table组件 可以直接复制使用的 如果你需要 form vue
  • python 类装饰器的好处_python 装饰器重要在哪

    1 什么是装饰器 要理解什么是装饰器 您首先需要熟悉Python处理函数的方式 从它的观点来看 函数和对象没有什么不同 它们有属性 可以重新分配 def func print hello from func func gt hello fr
  • 在QT的信号槽中使用自定义数据类型

    qt中使用信号槽来处理GUI与后台数据同步是不错的 耗时的任务可以在处理完数据后使用信号通知UI更新 对于qt中的已有类型 可以直接使用 但 多数时候都需要用到自定义类型 如果像内建类型那样使用 编译时正常 但运行时会报错 QObject
  • javax.xml.parsers.FactoryConfigurationError: Provider for javax.xml.parsers.

  • linux 打开.v文件,构建riscv上运行的linux系统

    在qemu上启动linux kernel 总述 最终目标还是要在RTL上跑linux系统 但做这个之前第一步先把系统工具链整清楚很重要 所以先在qemu上把相关的工具链 镜像搞定 为了完全这项任务 我们需要安装几个工具 qemu for r
  • VIM编辑命令

    转载 进入编辑模式 vim命令模式 vim实践 吉米乐享驿站 博客园 cnblogs com 5 5 进入编辑模式 所谓编辑模式就是进入到一个可以编辑文本文档的模式 常规的方式就是按小i进入编辑模式 左下角显示 insert插入 状态 此时
  • Java基础篇——入门

    转眼间这已经是自己工作的第五个年头了 期间做过安卓 做过web 现在又加入了小程序的阵营 可谓是历尽各种坎坷啊 让我不由得想起了 红楼梦 的开篇之句 满纸荒唐言 一把辛酸泪 期间的艰难困苦 实属夸张之感慨 无病呻吟 哈哈 只有自己能够体味啊
  • 语义分割制作自己的数据集——训练集、验证集、测试集

    用于语义分割的VOC数据集格式 语义分割任务voc数据集主要包括JPEGImages 存放原始图像 SegmentationClass 存放label ImageSets Segmentation 存放划分的数据集 包括train txt
  • VS2008, MFC 文件的操作3 - Win32 API 方式 文本方式打开

    接上一节笔记 VS2008 MFC 文件的操作2 C 语言方式 文本方式打开 1 代码 void Cvs2008 SX jiaocheng12View OnFileWritefile TODO 在此添加命令处理程序代码 Win32 API
  • cuda编程学习笔记 第二章 cuda memory management

    应用的性能可能有 75 都花费在内存相关问题上 NVPROF and NVVP 这俩是调试工具 不知道是不是基于CUPTI CUDA Profiler Tools Interface NVPROF是命令行工具 nvvp是可视化工具 nvvp
  • 12、适配器

    文章目录 package com example demo designpattern 又叫包装模式 Wrapper 各种 wrapper bridge 就是适配器模式 jbdc odbc bridge io 字节流字符流转换 角色 tar
  • STM32-ESP8266-12F与PC通信

    1 默认ESP8266的波特率是115200 2 指令及其返回值 3 使用PC的网络调试助手 协议类型选择TCP Server 端口号以80开头 表示TCP协议 如8080 8040等等 IP地址填PC的WI F网口的IP地址 配置完成后点
  • 解决浏览器设置代理IP无法上网的问题

    大家都知道 在当今信息时代 互联网已经成为了我们生活必不可少的一部分 而浏览器作为我们上网的窗口 更是被广泛使用 有时候 我们会遇到一些问题 例如设置了代理IP后无法正常上网 那么该如何解决这个问题呢 别担心 本文将为您一一解答 首先 让我
  • 易优cms:guestbookform 留言表单标签

    guestbookform 留言表单标签 基础用法 名称 guestbookform 功能 留言表单提交 语法 eyou guestbookform type default
  • 计算机组成中的阶符是什么意思,计算机中阶符,阶码,数符,尾数是什么?

    一般地 任一个二进制N 可表示为N 2j S 其中J为二进制数 叫阶码 J如果有正负号的话 正负号就叫阶符 S为纯小数 叫做尾数 数符 指的是N整个数的符号 二进制的 00101000 直接可以转换成16进制的 28 字节是电脑中的基本存储
  • 详解 Android 是如何启动的

    详解 Android 是如何启动的 2016 08 12 唐琪森 安卓开发 javascript void 0 来自 石头铺 微信号 Android Programmer 网站 www woaitqs cc 本文是 Android 系统学习
  • xilinx平台下DDR3映射为VFIFO

    FPGA开发中 数据采集 数据分析场景下需要用对高速ADC数据缓存 FPGA片内RAM无法做到大的容量 基于MIG IP做了个DDR3映射成FIFO的模块 以完成高速 量大的数据缓存应用 背景和选择 part1 官方也提供了类似功能的IP
  • makefile学习

    基本介绍 makefile编写的关键在于解决源文件的 文件依赖性 编译链接过程 源文件首先会生成中间目标文件 再由中间目标文件生成执行文件 在编译时 编译器只检测程序语法 和函数 变量是否被声明 如果函数未声明 编译器会给出一个警告 但可以