【Linux】制作U-Boot烧写镜像到SD卡的过程(下篇:Makefile文件)
上文讲到,如果需求仅略微修改,整个从编译到仅保留二进制文件到添加HeaderInfo
到烧写到SD卡的一系列命令都需要重新再输入一遍,这很繁琐。
如何解决这个问题呢?
制作一个bash脚本文件
制作一个bash
脚本文件,也就是制作一个批处理文件
:
#!/bin/basharm-linux-gcc -c mystart.s
arm-linux-gcc -c mylowlevel_init.s //.s文件生成.o文件arm-linux-ld -T myboot.lds -o myboot mystart.o mylowlevel_init.o //.o文件生成可执行文件arm-linux-objcopy -O binary myboot myboot.bin //只保留二进制文件./mkv210 u-boot.bin u-boot.16k //添加HeaderInfosudo dd iflag=dsync oflag=dsync if=u-boot.16k of=/dev/sdb seek=1 //烧写到SD卡
然后运行这个文件:
bash genmyboot.sh
虽然,这样也能够实现功能,但是某种程度上可以看出并不智能。什么意思呢?可能某次修改,只修改了其中的某几个文件,其他的很多文件都没有修改。但如果运行这个bash
,所有的程序都要走一遍,也就是无论文件是否被修改,都会被处理,会浪费很多的时间。
Makefile
无需畏惧Makefile
Makefile
是一个能够让初学者很挫败的文件,初看会让人头昏眼花,感觉在看“天书”。比如下面是U-Boot
的Makefile
中很少的一部分:
$(obj)u-boot.img: $(obj)u-boot.bin$(obj)tools/mkimage -A $(ARCH) -T firmware -C none \-O u-boot -a $(CONFIG_SYS_TEXT_BASE) -e 0 \-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \-d $< $@$(obj)u-boot.ubl: $(obj)spl/u-boot-spl.bin $(obj)u-boot.bin$(OBJCOPY) ${OBJCFLAGS} --pad-to=$(PAD_TO) -O binary $(obj)spl/u-boot-spl $(obj)spl/u-boot-spl-pad.bincat $(obj)spl/u-boot-spl-pad.bin $(obj)u-boot.bin > $(obj)u-boot-ubl.bin$(obj)tools/mkimage -n $(UBL_CONFIG) -T ublimage \-e $(CONFIG_SYS_TEXT_BASE) -d $(obj)u-boot-ubl.bin $(obj)u-boot.ublrm $(obj)u-boot-ubl.binrm $(obj)spl/u-boot-spl-pad.bin$(obj)u-boot.ais: $(obj)spl/u-boot-spl.bin $(obj)u-boot.img$(obj)tools/mkimage -s -n $(if $(CONFIG_AIS_CONFIG_FILE),$(CONFIG_AIS_CONFIG_FILE),"/dev/null") \-T aisimage \-e $(CONFIG_SPL_TEXT_BASE) \-d $(obj)spl/u-boot-spl.bin \$(obj)spl/u-boot-spl.ais$(OBJCOPY) ${OBJCFLAGS} -I binary \--pad-to=$(CONFIG_SPL_MAX_SIZE) -O binary \$(obj)spl/u-boot-spl.ais $(obj)spl/u-boot-spl-pad.aiscat $(obj)spl/u-boot-spl-pad.ais $(obj)u-boot.img > \$(obj)u-boot.ais
是不是很费解?Makefile
其实语法比较简单,但复杂就复杂在其中运用了许多shell
脚本和各种正则表达式等,这些混杂在一起,就会让人摸不着头脑。
如果需要详细了解Makefile
的内容,可以参考链接:跟我一起写Makefile。
Makefile的基本语法
target ... : prerequisites ...command......
具体含义为:
target
:可以是一个object file
(目标文件),也可以是一个执行文件,还可以是一个标签(label
);prerequisites
:生成该target所依赖的文件和/或target;command
:该target要执行的命令(任意的shell命令)。
这是一个文件的依赖关系,也就是说,target
这一个或多个的目标文件依赖于prerequisites
中的文件, 其生成规则定义在command
中。说白一点就是说:prerequisites
中如果有一个以上的文件比target
文件要新的话,command
所定义的命令就会被执行。
这就是Makefile
的规则,也就是Makefile
中最核心的内容。
Makefile案例
既然大致了解了Makefile
的规则,那么如何才能完成制作描述U-Boot
烧写镜像到SD卡的过程的Makefile
呢?
.s文件生成.o文件
先根据这个简单的规则,写一个简单的Makefile
。这里首先注明一下make
命令的寻找优先级,make
会在当前目录下寻找以下的Makefile
文件,优先级由高到低为:
GUNMakefile > makefile > Makefile
一般,文件命名为Makefile
。
制作一个Makefile
文件,用于将mystart.s
汇编成mystart.o
文件:
mystart.o: mystart.sarm-linux-gcc -c mystart.s
这很简单,如果同时还需要将mylowlevel_init.s
汇编成mylowlevel_init.o
文件:
mystart.o: mystart.sarm-linux-gcc -c mystart.smylowlevel_init.o: mylowlevel_init.sarm-linux-gcc -c mylowlevel_init.s
如果此时,还是运行Makefile
,会发现只运行了前一句指令,但后一句的指令并没有被运行。这是因为:Makefile
只运行第一个目标target
,其余的目标target
都不会被运行。
怎么解决呢?利用Makefile
生成一个伪目标target
,再利用伪目标target
去生成接下来的两个目标target
。方式如下:
.PHONY:all //注明all为伪目标(可写可不写)
all: mystart.o mylowlevel_init.omystart.o: mystart.sarm-linux-gcc -c mystart.smylowlevel_init.o: mylowlevel_init.sarm-linux-gcc -c mylowlevel_init.s
当make
的时候,目标all
本身不运行任何命令,但是它依赖于mystart.o
和mylowlevel_init.o
。但当前目录下并没有这两个文件,因此它就会自动在当前Makefile
中寻找是否存在目标target
,如果存在,就自动执行该目标的命令。
其余步骤
.PHONY:all //注明all为伪目标(可写可不写)
all: mystart.o mylowlevel_init.oarm-linux-ld -T myboot.lds -o myboot mystart.o mylowlevel_init.oarm-linux-objcopy -O binary myboot myboot.bin./mkv210 u-boot.bin u-boot.16kmystart.o: mystart.sarm-linux-gcc -c mystart.smylowlevel_init.o: mylowlevel_init.sarm-linux-gcc -c mylowlevel_init.s
由于烧写到SD卡的命令,需要SD卡已经插入的状态,一般而言,不会将它和这些命令都写在一起。但是,每次都输入这么麻烦的代码,也是很麻烦的事情。于是,可以用另一种方式:
.PHONY:all //注明all为伪目标(可写可不写)
all: mystart.o mylowlevel_init.oarm-linux-ld -T myboot.lds -o myboot mystart.o mylowlevel_init.oarm-linux-objcopy -O binary myboot myboot.bin./mkv210 u-boot.bin u-boot.16kmystart.o: mystart.sarm-linux-gcc -c mystart.smylowlevel_init.o: mylowlevel_init.sarm-linux-gcc -c mylowlevel_init.s.PHONY:mksd
mksd:sudo dd iflag=dsync oflag=dsync if=u-boot.16k of=/dev/sdb seek=1
创造一个伪目标,专门用于烧写镜像到SD卡中。但是,一般情况下,这句伪目标是运行不到的。那怎么样才能只运行这句伪目标呢?
只需要在make的时候,人为地指定伪目标即可:
make mksd
Makefile的改进
尽管此时Makefile
的运行没有问题,但是还是会发现一个问题。如果修改了mylowlevel_init.s
文件,只会将mylowlevel_init.s
文件会变成mylowlevel_init.o
文件,mystart.s
并不会重新汇编,这很不错;但是如果两个都不修改,此时两个.s
文件都不会会变成.o
文件,但是后面链接、只保留二进制文件、添加HeaderInfo
三句依然还是会运行!
这是为什么呢?
由于all是一个伪目标,没有办法进行目标与依赖之间的新旧关系,因此就会一直都会运行后面的三句。
改进后的代码为:
.PHONY:all //注明all为伪目标(可写可不写)
all: mybootmystart.o: mystart.sarm-linux-gcc -c mystart.smylowlevel_init.o: mylowlevel_init.sarm-linux-gcc -c mylowlevel_init.smyboot: mystart.o mylowlevel_init.o myboot.ldsarm-linux-ld -T myboot.lds -o myboot mystart.o mylowlevel_init.oarm-linux-objcopy -O binary myboot myboot.bin./mkv210 u-boot.bin u-boot.16k.PHONY:mksd
mksd:sudo dd iflag=dsync oflag=dsync if=u-boot.16k of=/dev/sdb seek=1
如此便好,也就是说,最好让伪目标没有命令可以执行。
Makefile的自动化变量
尽管上文的Makefile
看起来比较“优雅”了,但是还是存在问题的:如果存在100个.s
文件需要汇编成.o
文件,那么需要写100条类似于如下的代码。
mystart.o: mystart.sarm-linux-gcc -c mystart.s
这想一想,也是非常繁琐。于是,Makefile
就引进了:
- 自动化变量:$@(所有目标target集合)、$^(所有依赖集合)、$<(所有依赖集合中的第一个)
- 模式匹配:%.x(当前目录下所有.x结尾的文件)
有了自动化变量和模式匹配,就可以写出更加简洁的Makefile
了:
.PHONY:all //注明all为伪目标(可写可不写)
all: myboot%.o: %.sarm-linux-gcc -c $<myboot: mystart.o mylowlevel_init.o myboot.ldsarm-linux-ld -T myboot.lds -o myboot mystart.o mylowlevel_init.oarm-linux-objcopy -O binary myboot myboot.bin./mkv210 u-boot.bin u-boot.16k.PHONY:mksd
mksd:sudo dd iflag=dsync oflag=dsync if=u-boot.16k of=/dev/sdb seek=1
同样,可以使用变量来代替某些内容,有点类似于宏定义的样子。一般采用:=
来赋值,引用的时候需要用$()
来引用:
CC := arm-linux-gcc.PHONY:all //注明all为伪目标(可写可不写)
all: myboot%.o: %.s$(CC) -c $<myboot: mystart.o mylowlevel_init.o myboot.ldsarm-linux-ld -T myboot.lds -o myboot mystart.o mylowlevel_init.oarm-linux-objcopy -O binary myboot myboot.bin./mkv210 u-boot.bin u-boot.16k.PHONY:mksd
mksd:sudo dd iflag=dsync oflag=dsync if=u-boot.16k of=/dev/sdb seek=1
当然,U-Boot
的Makefile
肯定比本文的要复杂得多的多,之后的博文会对此进行详细分析。
【Linux】制作U-Boot烧写镜像到SD卡的过程(下篇:Makefile文件)相关推荐
- 【Linux】制作U-Boot烧写镜像到SD卡的过程(中篇:LDS文件)
上一篇文章,讲述了制作U-Boot烧写镜像到SD卡的过程,其中运用make的方式来进行将.s文件编译成.bin文件,那make是什么意思?它主要实现了什么? 先讲一下,如果不采用make的方式该怎样实 ...
- 【Linux】制作U-Boot烧写镜像到SD卡的过程(上篇)
在嵌入式Linux操作系统中,需要将三样东西(BootLoader.内核kernel.根文件系统)传输到目标板中.一般而言,U-Boot烧写到SD卡中,而内核.根文件系统都采用TFTP的方式传输到目标 ...
- raspberry 烧写镜像到SD卡
刚开始接触树莓派,需要烧写系统镜像到SD卡,网上找了些资料,记录于此. raspberry镜像下载: https://www.raspberrypi.org/downloads/ 烧写工具: wid3 ...
- x210项目重新回顾之十四烧写镜像到SD卡
九鼎公司提供的sd_fusing.sh默认只生成一个分区,这在在sd_fdisk.c中可见前3行被注释, //encode_partitionInfo(partInfo[0], &mbr[0x ...
- pcDuino入门指南+如何烧写系统(SD卡-卡刷)
第一章:初识pcDuino 一.概述: pcDuino是一款高性能的,性价比极高的迷你PC平台,它能运行像 Linux 3.0和Ubuntu 12.10这样的操作系统.通过内置HDMI接口即可直接输出 ...
- 【烧写Uboot到SD卡,打开 SD-bl1-8k.bin 失败,failed to open‘SD-bl1-8k.bin】
烧写Uboot到SD卡,打开 SD-bl1-8k.bin 失败,failed to open'SD-bl1-8k.bin 在进行X210烧入镜像时出现了一下错误,之前烧入时是正常的,不知道为什么就报错 ...
- Jetson-Xavier-NX使用教程(这里说插上烧好镜像的SD卡上电就可以直接用了)
这里说插上烧好镜像的SD卡上电就可以直接用了,似乎是不需要特意更改或者设置什么的. 转载自:https://mp.weixin.qq.com/s/Lhm9FFctl7BShdnBwmCV4w Jets ...
- 【Tiny4412】烧写Android系统(SD卡)
00. 目录 文章目录 00. 目录 01. 编译内核 02. 安装dnw工具 03. 安装Android_tools 04. 烧写Android系统 05. 问题解决 06. 附录 01. 编译内核 ...
- rockpi4b 烧写固件到SD卡
rockpi官方烧写文档 点我直达 烧写自己编译的固件 1.选择固件 Y:\RK3399_ROCKPI4B_ANDROID11_USERDEBUG_RK3399-ROCKPI-4B_ENG-20220 ...
最新文章
- 2019年第一个工作日!
- linux | 网卡驱动
- verilog扰码器设计及仿真
- python 多继承的问题
- android 用户界面教程实例汇总
- Encapsulate Field
- 调制方式性能比较--BER,频带效率的极限
- 微信小程序服装商城+后台管理系统
- 猿创征文|计算机专业硕博研究生提高效率的10款科研工具
- 解决复制网页文本多一个空格的问题
- C语言小技巧之如何求平均数
- java第十一次作业
- 2020年个人年终总结
- 高考临近,各地考点附近1公里范围内的酒店房量处于紧张状态
- 以下是两段c语言代码 函数arith(),第二章习题-ddg.doc
- 通过Windows批处理脚本批量修改DNS
- 加载Glove预训练词向量到字典
- [转载]扩展Log4Net中的ILog实现自定义日志字段
- linux系统编程3—文件存储函数
- Java Web 开发实战经典 基础篇(1)
热门文章
- matlab图像处理代码实例,MATLAB图像处理375例-程序代码
- 软件测试面试题:你们公司的测试流程是怎么样的?
- android启动其他apk,Android 启动apk的常用方法
- 常见python爬虫模板_常见的Python爬虫框架有几个?
- opengl 读取obj模型
- Redisson(2-2)分布式锁实现对比 VS Java的ReentrantLock之带超时时间的tryLock
- PADS如何导出BOM清单
- 手机下载神器批量下载图片教程
- 统一认证授权平台keycloak太牛了,我要搞一搞
- 计算机教程文档,计算机应用基础教程-20210323002444.doc-原创力文档