Linux Makefile 中的陷阱【转】

转自:https://blog.csdn.net/QQ1452008/article/details/52247944

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/QQ1452008/article/details/52247944

前言

每个编写过Makefile的程序员都可能遇见过Makefile中内含的陷阱,本博文旨在展现陷阱,提醒自己,也供大家一起学习。

本博文会随所遇见的Makefile陷阱有关的问题而进行后续的更新。


陷阱一:在定义变量的语句后面空格之后使用了‘#’注释符

结果:导致变量的值并不是你所赋值的,而是把值与注释符之间的空格一起赋值给了变量,使得执行违背自己的意愿,而不容易察觉。

实例说明如下(Makefile版本:GNU MAKE 3.81):

TmpDir = /Source  #此处随意定义了一个目录,#为了验证此陷阱,特意在赋值语句后空几格并进行注释,ifeq ($(TmpDir), /Source)
Result = They are equal
else
Result = They are not equal endif all: @echo $(TmpDir)||||||| @echo $(Result)

 

make之后其结果为 : 
/Source  |||||||      (注意:/Source与|之间的空格,其实是属于TmpDir变量的)
They are not equal若把 
ifeq ($(TmpDir), /Source) 
改为
ifeq ($(TmpDir), /Source  )  
说明:/Source后面的空格需要跟定义TmpDir与注释符之间的空格数相等如此一来,再次make,结果为:They are equal

扩展一:其实验证的过程中也引申出了另一个陷阱,ifeq()语句中的陷阱,见陷阱二
扩展二 : 变量赋值语句存在这个陷阱,那宏定义语句呢?及类似于如下语句

CFLAGS  += -DTMP=1   #注释语句
INCFLAGS += -I$(APP_COMMON_SRC_DIR)/Include #注释语句 main:mian.o gcc $< $(CFLAGS) $(INCFLAGS) -o $@ 

 

其实经过实测表明,这样并不会影响宏定义“TMP”在源文件中的值, 以及“INCFLAGS ”所在的路径值。

心得: 通过以上求证,注释符会影响到Makefile文件内部定义使用的变量的值,而不会影响到诸如 -D , -I 后面的值。所以建议Makefile中注释都不要写在语句后面,而是语句的前一行,来避免类似的问题出现


陷阱二:ifeq语句的括号里面,不要随意使用空格

结果:makefile会吧参数后面的空格也当作参数的一部分来进行比较,导致结果违背自己的意愿。

实例说明如下(Makefile版本:GNU MAKE 3.81):

TmpDir = /Source#下方的/Source后面空了几格
ifeq ($(TmpDir), /Source )  
Result = They are equal
else
Result = They are not equal endif all: @echo $(Result)
make之后其结果为 : 
They are not equal若把 
ifeq ($(TmpDir), /Source ) 
改为
ifeq ($(TmpDir), /Source)  如此一来,再次make,结果为:They are equal

经过实测表明,$(TmpDir)后面空几格没有影响,唯独/Source后面空格就会有影响了

心得 : 在Makefile中,最好保证参数的一致性,是否空格等,不像C语言等语言编程一样,那么宽松。


陷阱三:在mingw环境下使用路径时的陷阱

详情:在正确使用并能生成.d依赖文件,理论上使得修改任一 .h 或者 .c 文件都能自动进行编译的情况下,其结果偏偏就是在修改了.h文件而不能编译与之相关的.c文件,即没有检查到有文件更新,从而没有进行编译。待仔细查看Makefile的内容,也不能轻易看出端倪。其实这背后存在一个不易察觉的陷阱。

例子大概如下:

TARGET = Temp
# abspath 函数:获取其参数中的文件或者目录的绝对路径
APP_BASE = $(abspath ../..) DEV_BLD_DIR = $(APP_BASE)/$(TARGET)/Build TEMP = $(APPSRC:.c=.o) APPOBJS_TMP = $(TEMP:.S=.o) # addprefix 函数:把 APPOBJS_TMP 中的文件一一添加前缀 $(DEV_BLD_DIR)/ APPOBJS := $(addprefix $(DEV_BLD_DIR)/,$(APPOBJS_TMP)) APPDEPS_TMP = $(APPOBJS_TMP:.o=.d) APPDEPS := $(addprefix $(DEV_BLD_DIR)/,$(APPDEPS_TMP)) all: Tmp.bin -include $(APPDEPS) ...... #省略了若干内容 ...... # subst 函数:把$@中的 Source 替换成 Build # 该编译的命令,在编译源文件的同时,也生成了.d 依赖文件 $(DEV_BLD_DIR)/%.o: %.c $(info Compiling $< ...) $(CC) -c -o $(subst Source,Build,$@) $(CFLAGS) $(INCFLAGS) $< -MD -MF $(DEV_BLD_DIR)/$*.d -MP

 

请点击进入 .d依赖文件 相关内容介绍

其实从结果上便能大致推测是.d依赖文件部分出现了问题,因为改写任一文件都要能重新编译,本身就是.d依赖文件所要赋予的功能。

陷阱:目标路径的问题,即同一文件目标的引用时要保持路径一致。mingw环境下,windows路径(e.g. c:\agc.o) 和 mingw路径(/c/agc.o)都能够识别,对于make而言, c:\abc.o 和 /c/abc.o 是两个不同的目标。若要是不知道这一知识要点,很难发现 .d 文件开头 c:\ 和 /c/ 的区别。(个人疑点:同一环境,不同工程,有些生成的.d依赖文件中.o目标路径和make中引用的路径是一样的,目前也不知是什么原因,总之这个陷阱还是存在的。)

实例陷阱说明:

#以下行将导入所有的.d依赖文件的内容,即以 /c/...开头的内容
-include $(APPDEPS)
#而以下目标依赖关系中,指明目标的路径则是以 c:\...开头的路径
$(DEV_BLD_DIR)/%.o: %.c
#其结果就是导致了因路径表示的不同,而认为不是同一目标的情况出现
#使得make不能找到.o目标文件依赖的所有依赖源文件,其中包括.h头文件
#自然而然,也就不能因为.h文件的更新,而重新编译对应的.c文件来生成.o文件

 

解决方法:
既然知道了陷阱所在,就可以利用如下命令来解决该问题:

#通过增加sed命令,把生成的.d依赖文件中的.o目标路径改写就可以了。
$(DEV_BLD_DIR)/%.o: %.c$(info Compiling $< ...) $(CC) -c -o $(subst Source,Build,$@) $(CFLAGS) $(INCFLAGS) $< -MD -MF $(DEV_BLD_DIR)/$*.d.tmp -MP sed 's,.*\.o[ :]*,$@:,g' < $(DEV_BLD_DIR)/$*.d.tmp > $(DEV_BLD_DIR)/$*.d;\ rm -f $(DEV_BLD_DIR)/$*.d.tmp @echo

 

心得:以后出现类似该情况,即表面上 makefile 中没有什么问题,但在使用了依赖文件,并修改.h 文件后,不重新编译的情况,这个时候要考虑路径问题。不同路径的表示方法,所表示的目标文件在make中会认为不是同一文件。

--------------------- 本文来自 Jerry_yl_ 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/QQ1452008/article/details/52247944?utm_source=copy 

转载于:https://www.cnblogs.com/sky-heaven/p/9735196.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/277168.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html锚点

设置锚点的两种方式 1.设置一个锚点链接<a href"#wang">去找汪星人</a> 在页面中需要的位置设置锚点<a name"wang">汪星人基地</a> 2.设置一个锚点链接<a href"#miao">去找喵星人</a> 在页面中需要的位置设…

大学生计算机课程考试试题,大学生计算机基础课程考试系统研究与实现

摘要&#xff1a;本文主要针对教学评测领域中的主观题评测等难点展开研究.过去在教育评测领域虽然广泛使用测试系统,但由于无法对主观题进行准确有效的判断,造成了以客观题为主的测试局限性.本课题引入智能的算法以实现全自动教学评测,对于教育测试工作有着深远的现实意义. 本系…

初学Vue.js--数据绑定与文本插值

(一)数据双向绑定 数据的双向绑定是Vue.js的核心功能在上一篇记录中已经简单创建了一个Vue实例如下 var myVuenew Vue({ el:#myvue//myvue是已经存在的div&#xff0c;其id值为myvue }) 使用选项el挂载成功后&#xff0c;我们可以通过myVue.$el来访问该元素&#xff0c;如果需要…

网页色彩搭配的内涵

网页的色彩搭配往往是网友们感到头疼的问题&#xff0c;尤其是那些完全没有美术基础的网友。到底用什么色彩搭配好看呢&#xff1f;让我们来看看网友54雨寒的高见吧&#xff01; 一、红色的色感温暖&#xff0c;性格刚烈而外向&#xff0c;是一种对人刺激性很强的色。红色容易引…

VS历程简单记录

当时一开始装VS2015&#xff0c;是用了很长时间了。装了之后是可以用的&#xff0c;打了不少代码的。 后来很长一段时间没用它了&#xff0c;时隔良久&#xff0c;双击快捷方式竟然打开不了&#xff0c;让我“重装”。 其实也不用重装&#xff0c;本机用的Win10&#xff0c;去控…

计算机考研分数2019,2019考研分数线和国家线有什么关系

2019考研学校分数线和国家线有什么区别。国家线即全国硕士研究生考生进入复试基本分数要求&#xff0c;是基础分数线&#xff0c;要有资格参加复试必须过了这条线。国家线今天大概在3月中旬公布。学校分数线(简称学校线)是各招生单位在国家线的基础上&#xff0c;根据本校有关专…

记录一次react项目配置过程

1.为什么要配置react而不是脚手架 因为要知其然,最好还要知其所以然&#xff01; 2.配置对象 webpack webpack-dev-server babel eslint 3.配置过程 1.webpack 第一步:引入必须文件 const path require("path"); const webpack require("webpack");//为了…

智能文件名排序

默认排序问题 windows排序 Windows的资源管理中&#xff0c;提供了文件名的智能排序功能&#xff0c;可以识别出文件名中数字&#xff08;数字位数不相同&#xff09;&#xff0c;然后比较数字大小进行排序&#xff0c;如下图&#xff1a; 代码默认排序 但在C#中的列表排序中则…

VS2005 Web Application Project启用WSE(Ver 3.0)的方法

使用过WSE的朋友都知道&#xff0c;若要启用Server端Projects的WSE功能&#xff0c;需要选中如下所示的两个单选框:Enable this project for Web Services Enhancements和Enable Microsoft Web Services Enhancement Soap Protocol Factory.但是在WSE3.0中对于Web Application …

计算机英语课程背景,专家讲座第十五讲:信息化背景下高质量大学英语课程建设与教学设计...

11月27日下午&#xff0c;南京大学王海啸教授应邀到我院开展题为“信息化背景下高质量大学英语课程建设与教学设计”学术讲座。讲座由外国语言文学学院胡元江副院长和鲍贵教授共同主持&#xff0c;学院全体教师和研究生参加了本次学术活动。王海啸教授目前兼任教育部高等学校大…

ORA-28001: the password has expired

原创文章地址:https://blog.csdn.net/zdw_wym/article/details/38066745 Oracle提示错误消息 ORA-28001: the password has expired&#xff0c;是由于Oracle11G的新特性所致&#xff0c;Oracle11G创建用户时缺省密码过期限制是180天&#xff08;即6个月&#xff09;&#xff0…

使用c#操作IBM WebSphere MQ

IBM WebSphere MQ 5.3升级到CSD05之后&#xff0c;提供了使用.net操作MQ的类库&#xff0c;安装完成之后&#xff0c;会在MQ的安装目录的bin文件夹下面多出一个amqmdnet.dll文件&#xff0c;把这个DLL作为引用添加到你的.net工程中&#xff0c;你的.net程序中就可以操作IBM Web…

【SpringBoot】在IOC之外的类中使用IOC内部的Bean

某些时候&#xff0c;某些类是不归IOC管的&#xff0c;如我们的一些Util&#xff0c;如何使用IOC中的Bean&#xff1f; 1、写一个SpringUtil类&#xff0c;该类用于操纵Spring的ApplicationContext Component的注解是需要的&#xff0c;该Util是要被Spring管理的。 Component p…

计算机office二级app,计算机二级office

计算机二级office是一款为用户提供各种计算机二级知识的软件&#xff0c;用户可以在应用中快速的学习计算机二级office知识&#xff0c;顺利通过二级考试&#xff1b;应用拥有海量的精选计算机二级考试题库&#xff0c;不放过每一个考题&#xff0c;让用户全面的学习二级知识&a…

Obj-C 实现设计模式 -- Observer

观察者模式&#xff0c;采用气象站的例子来说明&#xff0c;本质上跟Java来实现差不多。只不过是针对协议&#xff08;Delegate&#xff09;来编程。 简单说下需求&#xff0c;气象显示版向气象站注册成功订阅者&#xff08;观察者&#xff09;&#xff0c;气象站监测到气温发生…

影响员工敬业度的三大因素

敬业的员工通常业绩比较突出&#xff0c;对企业做的贡献很大。经理人当然希望自己的员工个个都是敬业的员工&#xff0c;但实际上&#xff0c;在中国只有8%的员工具有敬业精神&#xff0c;相比全球的平均水平14%还有很大的差距。 是什么因素造成员工不敬业呢&#xff1f;根据世…

cf914D. Bash and a Tough Math Puzzle(线段树)

题意 题目链接 Sol 直接在线段树上二分 当左右儿子中的一个不是\(x\)的倍数就继续递归 由于最多递归到一个叶子节点&#xff0c;所以复杂度是对的 开始时在纠结如果一段区间全是\(x\)的两倍是不是需要特判&#xff0c;实际上是不需要的。 可以这么想&#xff0c;如果能成功的话…

计算机答辩答不上来怎么回答,答辩答不上来怎么办

论文答辩成为了不少同学的最后一次考试&#xff0c;从开题报告、论文定稿到格式排版大家一定都花费了大量的时间和精力&#xff0c;然而有时也会有一点小错误。所以&#xff0c;答辩前怎么准备&#xff0c;答辩的时候应该怎么灵活表现才能让自己最有可能通过答辩呢&#xff1f;…

urllib2.urlopen超时问题

urllib2.urlopen超时问题 没有设置timeout参数&#xff0c;结果在网络环境不好的情况下&#xff0c;时常出现read()方法没有任何反应的问题&#xff0c;程序卡死在read()方法里&#xff0c;搞了大半天&#xff0c;才找到问题&#xff0c;给urlopen加上timeout就ok了&#xff0c…

git 关联远程分支

问题解析&#xff1a; git本地新建一个分支后&#xff0c;必须要做远程分支关联。如果没有关联&#xff0c; git 会在下面的操作中提示你显示的添加关联。关联目的是如果在本地分支下操作&#xff1a; git pull, git push &#xff0c;不需要指定在命令行指定远程的分支&#x…