GCC+Make 自动生成 Makefile 依赖
本文内容基于 GNU MAKE。
BASIS
一些 makefile 的基础知识。
wildcard
假设当前目录下有文件 a.cpp 和 b.cpp,定义:
eg1=*.cpp
eg2=$(wildcard *.cpp)
则 rm $(eg1) 的展开为 rm *.cpp,rm $(eg2) 的展开为 rm a.cpp b.cpp
.PHONY
.PHONY 用于表示其后的目标文件是一个伪目标文件。
在 makefile 的一般格式 targets : prerequisitions 中,targets 为目标文件,一般是实际存在的文件,如 a.o 等;但有些规则并不生成实际存在的文件或不生成文件 targets 中指定的文件,这样的目标文件称为伪目标文件。
典型例子如常用于清理中间文件的伪目标文件 clean 。通常其生成命令并不生成一个名为“clean”的文件。此时若不将其指定为伪目标文件,且项目当前目录下恰好存在一个目录或文件名为“clean”,则 make clean 时 make 会检查该目录或文件的时效性,故有可能直接提醒目标文件“clean”已经最新而不执行编写的命令。
静态模式
<targets ...>: <target-pattern>: <prereq-patterns ...>
<commands>
...
直接用例子说明
objects = foo.o bar.o
$(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
常用自动变量
本节摘自:陈皓《跟我一起写 Makefile》
$@表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。$<依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。$^所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。$+这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标$*目标模式中通配符%之前的部分,例如目标是dir/a.foo.b,模式为a.%.b,则$*的值就是dir/a.foo
此外,自动变量后可加 D 或 F 以实现取目录部分或文件部分。例如,当 $@ 为 dir/foo.o 时,$(@D) 为 dir,$(@F) 为 foo.o。对用当前目录,取目录时值为 .。
自动生成依赖(GCC)
-M 参数
GCC 的 -M 和 -MM 参数可以生成指定源文件的依赖项。如,在 a.cpp 中 include a.h 和 b.h,则执行以下命令
g++ -MM a.cpp
会得到输出如下
a.o : a.h b.h
-MM 生成的依赖项不包含标准库等依赖,而 -M 包含。
编写 Makefile
GNU 建议对每个源文件生成一个 .d 后缀的依赖说明文件,内容即上节编译器生成的内容。
直接 include 上一节中生成的依赖就可以通过 make 的自动推导进行编译了,但如果需要指定编译参数、在 make 过程中加入回显,可以考虑在 .d 直接加入命令。
对每个源文件建立 .d 依赖文件会使得项目文件翻倍,因此此处将所有的 .d 文件合并为一个文件。这样做带来的缺点是每次 make 依赖项都需要全部重新生成。
下面直接给出 makefile。
sources=a.cpp b.cpp c.cpp
# 替换后缀
dependencies=$(sources:.cpp=.d)
$(dependencies) : %.d : %.cpp
@set -e; \
g++ -MM $(flags) $< > $@.$$$$; \
sed 's,$(*F).o,$*.o,g' < $@.$$$$ > $@; \
echo ' @g++ -c $< -o $(@:.d=.o) $(flags)' >> $@; \
cat $@ >> dependencies.d; \
rm -f $@.$$$$; rm -f $@
cleand:
rm -f dependencies.d; \
dependencies.d : cleand $(dependencies)
include dependencies.d
Makefile 细节说明
*.d 文件是生成的临时依赖项,最终会被删除。$$$$ 展开为随机的数字,用于建立临时文件。
$(depencencies) 的生成命令中,第三行用于在单个文件的依赖项中补全路径。例如,执行 g++ -MM src/a.cpp 后,GCC 给出的依赖项会是 a.o : xxx ,但项目中需要 src/a.o : xxx 的形式以避免命名冲突。sed 是 Linux 指令,此处用于进行文本替换。
生成命令的第四行向依赖文件中写入编译命令,此处也可以使用 echo 报告进度。第五行将该文件的依赖写入总的依赖文件。
最后 include 总的依赖文件。第一次执行 make 时依赖文件不存在,因此定义生成生成依赖文件的规则。生成前需要先删除旧的依赖文件,因为生成时使用的是追加方式。
注意使用这种方式编写的 makefile 在第一次 make 时由于不存在依赖会导致编译失败,第二次即可恢复正常,因为此时依赖文件 dependencies.d 就已经建立了。
其他
以下 Makefile 是对每个源文件生成 .d 依赖文件的版本。
$(dependencies) : %.d : %.cpp
@set -e; rm -f $@; \
g++ -MM $(flags) $< >> $@; \
sed 's,\($*\)\.o[ :]*,\1.o : $@ ,g' < $@ > $@.$$$$; \
sed 's,$(*F).o,$*.o,g' < $@.$$$$ > $@; \
echo ' @g++ -c $< -o $(@:.d=.o) $(flags)' >> $@; \
rm -f $@.$$$$
include $(dependencies)
GCC+Make 自动生成 Makefile 依赖的更多相关文章
- 自动生成 Makefile (automake/autoconf 入门)
作为Linux 下的程序开发人员,大家一定都遇到过Makefile ,用make 命令来编译自己写的程序确实是很方便.一般情况下,大家都是手工写一个简单Makefile ,如果要想写出一个符合自由软件 ...
- 自动生成makefile
原文 http://www.laruence.com/2009/11/18/1154.html 作为Linux下的程序开发人员,大家一定都遇到过Makefile,用make命令来编译自己写的程序确实 ...
- 如何自动生成Makefile
作为Linux下的程序开发人员,大家一定都遇到过Makefile,用make命令来编译自己写的程序确实是很方便.一般情况下,大家都是手工写一个简单Makefile,如果要想写出一个符合自由软件惯例的M ...
- 自动生成Makefile时,关于Makefile.am编写
最近编译一个项目的程序时,二十几个源代码文件放在六个文件夹中,而且各个文件中头文件互相包含.以前写过编译这样组织的源码的makefile,所以这次也就直接写了. 确实因为各个文件间的头文件互相包含,造 ...
- 手把手教你自动生成Makefile
概述:autoconf/automake工具用于自动创建功能完善的Makefile文件,接下来简单介绍一下,如何使用上述工具 自动生成Makefile 前提:安装autoconf工具(ubuntu:s ...
- 一个简单的执行程序的GNU automake自动生成Makefile的方法及案例
一个简单的执行程序的GNU automake自动生成Makefile的方法及案例 在GNU的世界里,存在Automake这样的工具进行自动生成Makefile文件,automake是由Perl语言编写 ...
- 使用autotools自动生成Makefile并在此之上使用dh-make生成可发布的deb程序包(详解)
转自:http://blog.csdn.net/longerzone/article/details/12705507 一.前言 本文将介绍如何使用autotools生成一个Makefile文件,并在 ...
- linux下使用automake工具自动生成makefile文件
linux环境下,当项目工程很大的时候,编译的过程很复杂,所以需要使用make工具,自动进行编译安装,但是手写makefile文件比较复杂,所幸在GNU的计划中,设计出了一种叫做Autoconf/Au ...
- 使用automake等命令自动生成Makefile文件 (转载)
使用automake等命令自动生成Makefile文件 Linux下编程时,为了方便编译,往往使用Makefile文件自动完成编译,但是Makefile文件本身的书写十分复杂,规则很多.好在Lin ...
随机推荐
- centos7中使用yum安装tomcat mysql 等
安装Tomcat 进入 # cd /usr/local/tomcat # wget http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-7 ...
- python生成二维码图片
依赖Pillow库. import qrcode # 简单用法 img = qrcode.make('Hello World!') img.save('qr_code.png') # 高级用法 qr ...
- OpenCV笔记(2)(高斯平滑、腐蚀和膨胀、开闭运算、礼帽和黑帽、Sobel及其他算子)
一.高斯平滑(模糊) def gaussian_blur(image): # 设置ksize来确定模糊效果 img = cv.GaussianBlur(image, (5, 5), 0) cv.ims ...
- ZJOI2010 诸神眷顾的幻想乡
题目链接:戳我 非常不好意思,因为想要排版,所以今天先只把代码贴出来,明天补题解. #include<iostream> #include<cstdio> #include&l ...
- Vue组件使用
一.组件概念 有html模板,有css样式,有js逻辑的集合体 每一个组件都是一个vue实例 每个组件均具有自身的模板template,根组件的模板就是挂载点 每个组件模板只能拥有一个根标签 子组件的 ...
- 删除全局安装的npm包
方法一 : 使用命令 npm uninstall -g 包名 方法二: 直接找到对应包删除 C:\Users\自己用户的文件夹\AppData\Roaming\npm 将对应的包删除即可
- Unity3D_(游戏)卡牌03_选关界面
启动屏界面.主菜单界面.选关界面.游戏界面 卡牌01_启动屏界面 传送门 卡牌02_主菜单界面 传送门 卡牌03_选关界面 传送门 卡牌04_游戏界面 传送门 选关界面效果 (鼠标放在不同关 ...
- postman教学视频百度网盘转载分享
百度云盘教学视频分享:https://pan.baidu.com/s/1r_e08FOkvQBZcC5-vU5M4w postman官网及下载地址:https://www.getpostman.com ...
- sqli-libs(2)
Lesson2:数字型注入我们先来测试一下 http://127.0.0.1/sql1/Less-2/?id=1%20and%201=1 发现未报错 这里知道我们的数字型注入是不需要 进行单引号闭合的 ...
- linux 实现U盘自动挂载
某些场景下,服务器可能没有必要的键盘等输入设备.屏幕等输出设备.此时需要在没有人为干预的情况下实现当插入U盘或者硬盘后自动挂载,并执行某些脚本动作.以下是我的实践过程. 必要组件 udev,udisk ...