target := exe

source_code = hello.c

OBJS = $(source_code:.c=.o)

$(target):$(OBJS)
gcc $^ -o $@ clean:
$(RM) $(target) $(OBJS)

一上来直接展示一份makefile代码。

功能: 从功能角度来说,这份makefile代码可以编译出对应的目标文件,并且顺利执行。

思考: 这其实是一份质量不合格的makefile代码。请仔细观察。

。。。。 什么 ?  你看着这个makefile却一点都不觉得奇怪吗?(好吧,难道你平时写makefile都是这样写的?  )

下面我们通过实验来讲解。

做点简单修改,还是上面这份makefile,只修改编译器, 更换为交叉编译器来试试,贴代码:

target := exe

source_code = hello.c

OBJS = $(source_code:.c=.o)

$(target):$(OBJS)
/usr/external-toolchain/bin/arm-linux-gnueabi-gcc $^ -o $@ clean:
$(RM) $(target) $(OBJS)

功能:请问现在更换为交叉编译器,还能编译出正确的目标文件吗?

编译观察:

令人吃惊的答案:编译报错!

解答:

 当前截图make报错显示:不是有效格式的.o文件。 
这里的玄机是makefile的一个暗黑操作:隐式规则。 

做一下简单修改即可:使用预定义的CC 这会改变隐式规则的行为。修改为如下图所示代码:

target := exe

CC := /usr/external-toolchain/bin/arm-linux-gnueabi-gcc

source_code = hello.c

OBJS = $(source_code:.c=.o)

$(target):$(OBJS)
$(CC) $^ -o $@
clean:
$(RM) $(target) $(OBJS)

这样就能顺利编译出目标文件了。

虽然可以通过增加CC变量进行简单修改,达到顺利生成目标文件的目的,但是这样的makefile仍旧不被推荐使用,因为使用了有可能产生隐式规则行为的代码

这里通过使用CC变量能够顺利编译出目标文件, 本质还是使用了隐式规则,即makefile在执行make对应的规则内的命令时,发现却没有有效的汇编文件:

于是通过默认的gcc编译器尝试将本地的XX.c文件去编译为XX.o文件。

如果本地没有XX.c文件,有一个XX.p或者XX.cpp文件,make的这种隐式规则也会去将其编译为汇编文件。

如果XX.p和XX.cpp同时存在,是选择XX.p还是XX.cpp,这由make的隐式规则决定。

可以通过 make -p|grep "文件格式" 查看隐式规则的这部分相关内容:

 上面是正面讲解makefile隐式规则, 下面我侧面证明一下makefile隐式规则的存在。 
还是使用这份代码来分析。注意:我们使用的编译器是交叉编译器哦!
 
 虽然make这个makefile时报错,但还是生成了hello.o(我自己先写一个hello.c放在与makefile的同一路径下), 我们来打印一下这个hello.o的部分二进制:
 
 完成了上面的步骤,我们直接手动使用gcc编译出一个汇编文件: 
 
 观察总结:
我们这份makefile内根本就没有出现使用gcc的代码啊,我们使用的是交叉编译器啊!,竟然出现了gcc编译出来的汇编文件! 这说明什么?
这说明当前的这份makefile在make后发生了隐式规则的执行!
makefile的隐式规则是大型makefile工程应注意极力避免的,这很可能导致无法解决的bug!大家需要了解一下makefile的隐式规则,避免写下的makefile出现隐式规则的行为
 
这也是本博客最开头的例子使用gcc没暴露出问题的原因,换成交叉编译器去尝试后,就会发现问题所在。
 
总结:
 
重点是要先生成有效的依赖。本例的最佳改进是再增加一条包含%.o:%.c 的规则去得到有效的汇编文件。参考我之前的makefile博客,那里有正规的makefile的写法。

.

makefile的隐式规则的更多相关文章

  1. makefile如果没有符合的显式规则将会使用隐式规则

    举例: 当前目录下有个Makefile和jello.c文件,其中有这样的规则jello.o:%.c %.h Makefile (静态模式规则),表明的含义为:要生成的jello.o目标依赖jello. ...

  2. 第十五篇 make中的隐式规则概述

      前面我们讲到了makefile的依赖拆分的知识,现在可以引申出这样一个问题,如果同一个目标的不同命令拆分的写到不同地方会发生什么?下面我们给出程序和执行结果:   可见后面的命令会覆盖前面的命令, ...

  3. 第15课 - make的隐式规则(上)

    第15课 - make的隐式规则(上) 1. 问题 如果把同一个目标的命令拆分的写到不同地方,会发生什么? 执行make all 这个实验表明了:如果同一个目标的命令拆分的写到不同地方,那么 make ...

  4. 第16课 - make的隐式规则(下)

    第16课 - make的隐式规则(下) 1

  5. 无法执行 varchar 值到 varchar 的隐式转换,原因是,由于排序规则冲突,该值的排序规则未经解析。

    SELECT CONVERT(VARCHAR(100), 列名) FROM Table 提示错误: 无法执行 varchar 值到 varchar 的隐式转换,原因是,由于排序规则冲突,该值的排序规则 ...

  6. Android学习笔记_17_Intent匹配规则(隐式意图)

    Android基本的设计理念是鼓励减少组件间的耦合,因此Android提供了Intent (意图) ,Intent提供了一种通用的消息系统,它允许在你的应用程序与其它的应用程序间传递Intent来执行 ...

  7. MySQL隐式转化整理

    MySQL隐式转化整理 前几天在微博上看到一篇文章:价值百万的 MySQL 的隐式类型转换感觉写的很不错,再加上自己之前也对MySQL的隐式转化这边并不是很清楚,所以就顺势整理了一下.希望对大家有所帮 ...

  8. 利用UICollectionViewFlowLayout的隐式动画实现UICollectionView的layout的动画调整(外加放大指定cell效果)

    前几天在gitHub看到个不错的效果,就是DaiExpandCollectionView,效果如图:   所以赶紧下下来源码看看他怎么实现的,打开源码看了半天,发现他没写什么关于动画的代码啊... 经 ...

  9. 深入理解javascript原型和闭包(4)——隐式原型

    注意:本文不是javascript基础教程,如果你没有接触过原型的基本知识,应该先去了解一下,推荐看<javascript高级程序设计(第三版)>第6章:面向对象的程序设计. 上节已经提到 ...

随机推荐

  1. 学习seo技术要不断地扩大思维和思路

    http://www.wocaoseo.com/thread-148-1-1.html        目前学习seo技术的人员是越来越多了,通过查看seo这个词的指数,就能发现一些状况,从最初的每天3 ...

  2. 超简单!基于Python搭建个人“云盘”

    1. 简介 当我们想要从本地向云服务器上传文件时,比较常用的有pscp等工具,但避免不了每次上传都要写若干重复的代码,而笔者最近发现的一个基于Python的工具updog,可以帮助我们在服务器上搭建类 ...

  3. 3D人物移动控制实现方案

    要控制3D人物在3D世界中进行正常的移动.转向,一般有两种情况: 1.使用人物动画控制人物 的移动 转向 2.使用脚本控制人物 的移动.转向 对方案一: Animator 组件勾选上 Apply Ro ...

  4. 初识ABP vNext(8):ABP特征管理

    Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 定义特征 应用特征 用户数量 社交登录 最后 前言 上一篇提到了ABP功能管理(特征管理),它来自ABP的Featur ...

  5. Educational Codeforces Round 68 (Rated for Div. 2)-C-From S To T

    You are given three strings ss, tt and pp consisting of lowercase Latin letters. You may perform any ...

  6. 小程序开发-媒体组件image

    image 图片组件,支持 JPG.PNG.SVG.WEBP.GIF 等格式,2.3.0 起支持云文件ID. 所有属性如下: Tips image组件默认宽度320px.高度240px image组件 ...

  7. C001:打印勾

    程序: #include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { printf(" *\n"); p ...

  8. vps+v_2_ray+proxychains

    电脑系统换到Linux快半年了,之前一直没有解决的问题是怎么上google,毕竟有些东西还是google上好找一点.最近不想复习,没想到自己成功搭了个梯子,着实把惊喜了我一把.下面记录一下过程. 首先 ...

  9. VMware虚拟中输入ifconfig提示not found解决办法

    1. 查看虚拟机是否没有IP地址:命令行中输入ip addr,如图红框所示,若无是需要设置. 2. 进入sbin目录确认ifconfig是否安装:可以通过命令[ls | grep 'if']来看 3. ...

  10. Java 多线程实现多窗口同时售票简单功能

    package day162020072701.day1603; import java.util.concurrent.locks.Lock; import java.util.concurrent ...