【Linux + Makefile】十分钟教你学会Makefile的FORCE「建议收藏」

【Linux + Makefile】十分钟教你学会Makefile的FORCE「建议收藏」Makefile有种FORCE的写法,你了解过它的原理和用途吗?

大家好,又见面了,我是你们的朋友全栈君。

相信大家在使用Linux环境编程的时候,一定接触过Makefile这个玩意。Makefile在搭建自定义的编译环境,尤其是自动化编译、多功能一键编译等功能上,还是发挥了很大的作用。如果接触过Linux内核编译的童鞋,一定会看到编译内核中的各级Makefile中,有很多地方都会有 FORCE 这样的字段出现,那么这个 FORCE 究竟是何方神圣呢?本文将给你答案,通过阅读本文,你讲了解到以下内容:

  • Makefile的基本规则
  • FORCE 在Makefile的含义
  • FORCE在实际工程中的应用

Makefile的基本规则


Makefile的基本形式如下所示:

TARGET : DEPENDENCES
    CMD

# TARGET:生成的目标,可以是一个文件,也可以是一个虚拟符号(非真实文件)
# DEPENDENCES: 生成目标的所有依赖,它是一个集合,可以只有一个文件,或者很多文件;也可以是虚拟符号
# CMD:把所有依赖生成目标的执行命令,其中CMD前面是一个TAB键,而不能是空格

Makefile的基本规则,归纳起来就是一句话:【当一个TARGET (欲生成的目标)比它的任何一个DEPENDENCES(依赖的文件)旧时,这个TARGET就要重新生成】。

这句话读起来很简单,就是Makefile在执行编译的时候,会先去判断TARGET和其依赖文件的时间,如果TARGET的时间比较旧,意味着依赖文件有更新了,所以TARGET要重新生成;反之,如果TARGET的时间比较新,意味着在TARGET生成后,依赖文件是没有改变过的,自然就不用重新去生成TARGET。


FORCE 在Makefile的含义


有了上一小节中介绍的Makefile基本概念后,我们来进一步分析下Makefile中的FORCE,以下是FORCE在Makefile中出现的最简化版本:

file = test.txt

all: generate-a-file

generate-a-file: $(file) 

$(file):
	@echo "Force to generate a test file for every make ..."
	rm -rf $(file) && echo `date "+%Y-%m-%d %H:%M:%S"` > $(file)

FORCE:
.PHONY: FORCE

这个Makefile不是用于真正的编译工程,而是提供一个很简单的功能,生成一个test.txt,并且这个test.txt的内容是记录每次编译的时间。但是使用这个makefile执行make时,发现只有第一次make的时候,才会生成test.txt,而其他时候只要test.txt还存在都不会重新生成,如下所示:

【Linux + Makefile】十分钟教你学会Makefile的FORCE「建议收藏」

很明显,它没有达到我们期望的“每次编译都重新生成test.txt”。这个时候 FORCE 就发挥作用了,我们在 test.txt目标的后面添加 FORCE作为它的依赖试试看,即如下所示:

file = test.txt

all: generate-a-file

generate-a-file: $(file) 

$(file): FORCE  #FORCE表示每次这段都要执行
	@echo "Force to generate a test file for every make ..."
	rm -rf $(file) && echo `date "+%Y-%m-%d %H:%M:%S"` > $(file)

FORCE:
.PHONY: FORCE

执行输出如下所示: 我们可以看到,这达到了我们的目的,每次test.txt都是重新生成了,它记录了每次make的时间。

【Linux + Makefile】十分钟教你学会Makefile的FORCE「建议收藏」

这个就是要归功于 FORCE 的功劳了。我们来分析下,为何加了 FORCE 就能实现这样的功能。

我们可以注意到FORCE这个目标,它的DEPENDENCES是空的,CMD部分也是空的;这个比较特殊了,在Makefile里,像这样依赖为空、执行命令也为空的TARGET,则需要每次都重新生成,而这个TARGET不一定是一个文件,可以是任意的符号,而 FORCE 只是我们最常用的符号,理论上它可以换成任意符号,比如NO-FORCE、SOMETHING等等。


FORCE在实际工程中的应用


上一小节,我们讲到可以用Makefile配合shell命令来自动生成一些文件,自然我们很容易想到,在我们实际的编译工程中,往往需要动态生成一些配置项,然后嵌入到代码中,比如编译版本号、编译时间等。

假设我们有以下一个main.c:

#include <stdio.h>
#include "build_info.h"  #这个头文件需要每次编译时自动生成

int main(int argc, const char *argv[])
{
    printf("%s >>> APP_TIME=%s\n", __func__, APP_TIME);
    return 0;
}

示例代码很简单,就是再main函数中打印一个 build_info.h中的一个宏定义APP_TIME,这个build_info.h要求每次编译的时候都重新生成。我们给出的Makefile示例如下:

##拷贝时,注意tab键
SHELL           = /bin/bash #指定shell使用/bin/bash,否则echo -e可能会出问题
ECHO            = echo
BIN             = test
BUILG_INFO_H    = build_info.h
SRC-C-y         = main.c
SRC-O           = $(patsubst %.c, $(O)%.o, $(SRC-C-y))

all: gen_build_info $(BIN)

$(BIN) : $(SRC-O)
    gcc -o $(O)"$@" $(SRC-O)
	
%.o : %.c
    gcc -c "$<" -o "$@"
	
gen_build_info: $(BUILG_INFO_H)

$(BUILG_INFO_H): FORCE     #强制生成build_info.h
    @$(RM) $@
    @$(ECHO) '  GEN     $@'
    @$(ECHO) -e   " #ifndef __BUILD_INFO_H__\n"\
				"#define __BUILD_INFO_H__\n"\
				"#define APP_TIME        	\"`date "+%Y-%m-%d %H:%M:%S"`\"\n"\
				"#endif"  > $@

FORCE:
.PHONY: FORCE

make执行输出测试如下:

【Linux + Makefile】十分钟教你学会Makefile的FORCE「建议收藏」

从输出的测试,我们可以看出,make的每次执行都触发了生成build_info.h,但是运行编译出来的test可执行程序,我们发现并不是每次生成的build_info.h的内容都传递到了test里面;也就是当build_info.h改变的时候,test没有被重新编译。这里先留下点疑问,为何会产生这样的问题。博主将会在后续的文章中解决这个问题。


不管怎么样,经过对上文的学习,我们至少掌握了 FORCE的基本用法,而在实际项目工程中,我们也见证了它的威力;那么,你学会了吗?如果还有疑问,欢迎在评论席提出你的问题和看法,博主定会尽力解决你的困惑。

版权申明:本文为博主原创文章,转载请注明出处!【Linux + Makefile】十分钟教你学会Makefile的FORCE_架构师李肯-CSDN博客

原创作者:recan

电子邮箱:recan.szu@foxmail.com


延伸阅读:

【Linux + Makefile】Makefile的高阶用法:解决C文件包含的头文件修改了,但C文件不重新编译的问题

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/131032.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 分享一份适合练手的软件测试实战项目[通俗易懂]

    分享一份适合练手的软件测试实战项目[通俗易懂]最近,不少读者托我找一个能实际练手的测试项目。开始,我觉得这是很简单的一件事,但当我付诸行动时,却发现,要找到一个对新手友好的练手项目,着实困难。我翻了不下一百个web网页,包括之前推荐练手的政府网站(普遍会有bug),但依旧没能找到合适的。最后,在我苦苦的搜寻过程中,突然蹦跶出来一条引流广告,我随手点进去,误打误撞,发现了一个适合练手的web网页,因此推荐给还是测试新手的你。项目实战网站:吉屋网模块:房价链接:http://cd.jiwu.com/fangjia/项目简介:一个提供地区房价信

    2022年6月14日
    43
  • %date:~0,10%用法

    %date:~0,10%用法其实很简单:0,开始位置;10,取字符的个数;例如当前时间是:日期是:%date:~0,10%就是2008-05-29%time:~0,2%就是14%time:~3,2%就是13如果我们做一个备份时就显得有些用处,可以把当时做备份文件用此命名,例如:pathc:\ProgramFiles\WinRARrara.\bak%date:~0,10%

    2022年9月20日
    0
  • 关于checkbox选中问题总结「建议收藏」

    关于checkbox选中问题总结「建议收藏」(1)ng-checked的值只是用来决定初始状态时选中还是为选中,ng-model才是随着复选框是否被选中,来实时改变它绑定变量的值。(2)如果初始状态ng-checked和ng-model指令

    2022年7月1日
    20
  • java.lang_java.lang.AbstractMethodError[通俗易懂]

    java.lang_java.lang.AbstractMethodError[通俗易懂]/***用户管理*/publicvoiduserManage(){render(“userManage.html”);//renderHtml(“userManage.html”);}进入方法后出现的问题。。。。哎,,各位大神帮我分析分析可好??????用的3.33.4jfinal整合shrio插件五月14,20189:21:19下午org.apache.catalina.c…

    2022年5月22日
    34
  • tensorflow2.0手写数字识别(tensorflow手写体识别)

    本节笔记作为Tensorflow的HelloWorld,用MNIST手写数字识别来探索Tensorflow。笔记的内容来自Tensorflow中文社区和黄文坚的《Tensorflow实战》,只作为自己复习总结。

    2022年4月17日
    133
  • UVA644

    UVA644题意:输入多个序列,判断是否存在前缀关系。思路如下:现

    2022年6月16日
    28

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号