整体简介
本笔记为记录嵌入式Linux的uboot部分基础知识,结合源码对uboot的实现原理和应用展开学习
授课老师:朱有鹏
记录少女:宕机酱=v=
2017.03
本part讲uboot的使用和相关概念。
后面会讲uboot的设计和组成原理,再往后就是移植过程。
我们的目的就是把ARM端的操作系统搭建起来,以后呢,就不玩裸机了喂。
笔记正文
一、学习前传
1.1为什么要有uboot
uboot是用来 启动操作系统内核 的!还有别的辅助功能。
1启动操作系统内核
2部署计算机系统
3操作Flash等上硬盘驱动
4提供命令行界面
uboot类似于PC机系统中的BIOS设计。典型的嵌入式系统的部署是uboot在一块支持启动的Flash上,OS部署在Flash(通常是另一块Flash,NandFlash or iNand,慢慢会发展成一块儿)。
其中,环境变量和命令是uboot的重要部分。此外uboot对于Flash和DDR有管理功能。
启动过程
step1: 先执行uboot
step2: uboot初始化DDR,初始化Flash
step3: 将OS从Flash读取到DDR中,启动OS。启动完成后uboot就无用了。
总结:嵌入式系统启动其实和PC没两样
只是BIOS代替成uboot
硬盘替换成了Flash
1.2 uboot之发展历史
uboot经过多年发展,已经成为事实上业内的bootloader标准。
uboot的版本号问题
早期的uboot版本号类似于:
uboot1.3.4 //这个1.3.4是最后的老版本
从2008左右开始就不是这样子了,后来变成了类似于:
uboot-2010-06
(后缀带有 -rc 的是非正式版本)
核心部分就几乎没变化,越新版本支持的开发板越多。当然也不是越新越好,新的东西有很多冗余。
uboot可移植理解
universal bootloader(通用的启动代码),具有可移植性。
注意:并不是说在哪个开发板都可以随便用。而是具有在源代码级别的移植能力。如果没有移植的话就可以直接用的。代码必然是要修改的!不是下载下来就能用。
uboot的成功:时势造英雄,他的出现是一种必然。如果没有uboot也会有另一个bootloader代替。
在那个年代嵌入式疯狂的发展,很需要一种bootloader能够移植上去,启动操作系统。所以uboot站出来了
1.4 uboot工作方式
uboot是一个单线程裸机程序。一旦运行uboot就不能运行别的 程序。
入口是开机自动启动
出口是唯一出口,启动内核
内核启动之后,uboot就会结束,而且不再重生。除非下一次开机。
uboot没有运行时表现为uboot.bin,放在存储介质里,运行时被加载入内存,逐步执行。
1.5 常用命令
uboot的命令和环境变量机制几乎和OS完全一样,连题目的名称都不带变的。
命令使用行缓冲。 //linux缓冲方式还有无缓冲和全缓冲
简写命令:
printenv = print //打印环境变量
setenv = set //设置环境变量
注意:自己尝试过,pri就能自己打印出printenv的内容
命令族
有些命令有衍生的 多个命令
如 movi
movi init,movi read等。命令一样,参数不一样。
环境变量和全局变量的不同
环境变量生命周期长,他存储在FLash的一块专门区域。而全局变量在程序结束后消亡。
理论上讲,环境变量在更改后,下一次开机依然保留才对,但是我试过的和老朱说的不一样。
是因为我们没有保存!命令:save/saveenv
我们操作的环境变量的是DDR中的环境变量,
DDR断电不保存,save命令是就把运行时内存中的环境变量写回Flash
注意这里的 save,会让原来的Flash中环境变量完全重写。
Flash里面有好多分区
完整Linux系统分区简表(按顺序,uboot为最开始)
序号 |
分区名 |
简写名 |
1
uboot
uboot
2
环境变量
env
3
操作系统内核
kernel
4
根文件系统
rootfs
1.9 uboot指令
指令规范
movi read {aaa | bbb} [xxxx]
//movi read 是必填,{ }里面的内容多选一,[ ]的内容是选填
uboot默认数字问题
命令行中,uboot中所有的数字都会被当做16进制处理!!
uboot中没有默认十进制的。uboot中出现数字90%的情况都是地址,是有意义的。
【movi read】
movi read u-boot 0x30000000
//将iNand中的u-boot分区读到DDR的0x30000000处,注意读的是分区
//也许uboot本身不大,但分区有1M那么这里还是读1M大小过去
//在uboot代码中,iNand被分成了很多个分区,每个分区都有独自的地址和名称。
movi read {sector#} {byte(hex)} {addr}
//sector是扇区,读某扇区多少字节,读到哪个地址。
【nand】
//完全类似movi,操作NandFlash
【内存操作指令:mm mw md】
内存是没有分区的,我们要注意防止越界,越界会踩到别人。操作系统中不容易越界,但uboot是裸机程序,因此我们使用uboot时不注意,就可能发生自己把自己数据给覆盖了的问题。
我们之前usb下载放在0x23E00000地址处就是放在了一个低地址。(也和虚拟地址映射有关)
md,memory display
mw,写内存,一般用的很少
mm,批量写内存
【启动内核指令:bootm, go】
bootm是能够传参的,他其实是正宗的启动命令
go不能传参,他本身不是为了启动内核用的,内部就是吧pc跳转到一个内存地址去执行。
go可以在uboot中执行任何的裸机程序
有一种调试裸机程序的方法就是事先启动uboot,然后再uboot中下载裸机程序 ,用go命令执行裸机程序。
1.10 uboot常用环境变量
ipaddr:开发板ip地址
serverip:tftp服务器的ip地址
gatewayip:开发板的本地网关地址
ethaddr:开发板本地网卡的MAC地址。
Tips:重装系统为什么MAC地址会变?是因为驱动重新安装了
启动内核的最关键环境变量
bootcmd(重要)自动运行命令设置
uboot启动后会倒数秒数,如果没有人按下回车键打断则会启动内核
这个 启动内核的 功能其实内部就是执行了bootcmd
查一下:
bootcmd=movi read kernel 30008000
//读iNand中内核分区到30008000
movi read rootfs 30B00000 300000; //读根文件系统
bootm 30008000 30B00000 //启动内核和根文件系统
//iNand,可以简单的看成SD卡或MMC卡芯片化
bootargs(重要)
bootargs是uboot给kernel传参用的。linux内核与uboot有约定好的参数。这样的设计是为了灵活,为了内核在不重新编译的条件下以不同方式启动。
bootargs=console=ttySAC2,115200
root=/dev/mmcblk0p2 rw
init=/linuxrc
rootfstype=ext3
内核传参是非常重要的,新手经常忘记和内核传参,或者传参不对,造成内核启动失败。
【新建、删除环境变量】
set var value
set var
1.12.uboot中对Flash和DDR的管理
uboot对Flash和内存进行分区。
分区方法不是一定的,不是固定的,是可以变动的。但是在一个移植中必须事先设计好定死,一般在设计系统移植时就会定好,定的标准是:
uboot:uboot必须从Flash起始地址开始存放(也许是扇区0,也许是扇区1,也许是其他,取决于SoC的启动设计),uboot分区的大小必须保证uboot肯定能放下,一般设计为512KB或者1MB(因为一般uboot肯定不足512KB,给再大其实也可以工作,但是浪费);
环境变量:环境变量分区一般紧贴着uboot来存放,大小为32KB或者更多一点。
kernel:kernel可以紧贴环境变量存放,大小一般为3MB或5MB或其他。
rootfs:rootfsl可以紧贴kernel存放
再往后面:则是自由分区。
总结:一般规律如下:
(1)各分区彼此相连,前面一个分区的结尾就是后一个分区的开头。
(2)整个flash充分利用,从开头到结尾。
(3)uboot必须在Flash开头,其他分区相对位置是可变的。
(4)各分区的大小由系统移植工程师自己来定,一般定为合适大小(不能太小,太小了容易溢出;不能太大,太大了浪费空间)
(5)分区在系统移植前确定好,在uboot中和kernel中使用同一个分区表。将来在系统部署时和系统代码中的分区方法也必须一样。
12.2、uboot阶段DDR的分区
(1)DDR的分区和Flash的分区不同,因为Flash是掉电存在的,而DDR是掉电消失,因此可以说DDR是每次系统运行时才开始部署使用的。
(2)内存的分区主要是在linux内核启动起来之前,linux内核启动后内核的内存管理模块会接管整个内存空间,那时候就不用我们来管了。
(3)注意内存分区关键就在于内存中哪一块用来干什么必须分配好,以避免各个不同功能使用了同一块内存造成的互相踩踏。譬如说我们tftp 0x23E00000 zImage去下载zImage到内存的0x23E00000处就会出错,因为这个内存处实际是uboot的镜像所在。这样下载会导致下载的zImage把内存中的uboot给冲掉。
2.1.shell介绍
shell是操作系统的终端命令行
系统提供给用户操作的命令行界面,是人机交互的一种方式
shell用来干什么?
在linux下创建100个文件,分别为a1.c a2.c…..a100.c。最好的做法就是把创建过程写成一 个shell脚本程序。
shell是一类编程语言,而不是一个语言。
shell语言,又叫脚本语言。常用shell语言:sh、bash、csh、ksh、perl、python等
perl、python等高级shell语言,常用在网络管理配置等领域,系统运维人员一般要学习这些。
脚本语言一般在嵌入式中应用,主要是用来做配置。
linux下最常用的脚本就是bash,我们学习也是以bash为主。
shell脚本的运行机制:解释运行
C语言(C++)这种编写过程是:编写出源代码(源代码是不能直接运行的)然后编译链接形成可执行二进制程序,然后才能运行;脚本程序编写好后源代码即可直接运行(没有编译链接过程)
所谓解释运行就是说当我们执行一个shell程序时,shell解析器会逐行的解释shell程序代码,然后一行一行的去运行。
CPU实际只认识二进制代码,根本不认识源代码。脚本程序源代码其实也不是二进制代码,CPU也不认识,也不能直接执行。【shell程序的编译链接过程不是以脚本程序源代码为单位进行的,而是在脚本运行过程中逐行的解释执行时完成二进制转化,进而无需编译链接,而是调用他。】
2.2.动手写第一个shell
编辑器 vim
编译器 无
运行方法如下
第一种:./xx.sh,这样运行shell要求shell程序必须具有可执行权限。
第二种:source xx.sh,source是linux的执行脚本程序命令。不需要脚本具有可执行权限。
第三种:bash xx.sh,bash是一个脚本程序解释器,本质上是一个可执行程序。这样执行相当于我们执行了bash程序,然后把xx.sh作为argv[1]传给他运行。
shell程序的第一行一般都是: #!/bin/sh
指定shell程序执行时被哪个解释器解释执行
可以将第一行写为:#!/bin/bash来指定使用bash执行该脚本。
注意:在ubuntu上面默认使用的默认脚本解释器sh其实不是bash,而是dash!
脚本中的注释使用#,例如“#same as ‘//’ ”,和C语言的//是一样的
2.3.shell编程学习1
shell中的变量定义和引用
shell是弱类型语言(语言中的变量如果有明确的类型则属于强类型语言)
和C语言不同。在shell编程中定义变量不需要制定类型,也没有类型这个概念。
变量定义时可以初始化,使用=进行初始化赋值。在shell中赋值的=两边是不能有空格的
注意:shell对语法非常在意,非常严格。很多地方空格都是必须没有或者必须有,而且不能随意有没有空格。
变量引用
shell中引用一个变量必须使用符号,符号就是变量解引用符号。
注意:$符号后面跟一个字符串,这个字符串就会被当作变量去解析。如果这个字符串本身没有定义,执行时并不会报错,而是把这个变量解析为空。
注意:变量引用的时候可以var,也可以{var}。这两种的区别是在某些情况下只能用var而不能简单的var。var可用的情况下,{var}是肯定能用的。
什么情况下$var是不能用的呢?
eg:
var="hello"
echo "$varyou"
则打印不出东西,因为找不到varyou这个变量
正确写法:
echo "${var}you"
打印出:helloyou
变量定义、初始化
string="hello world"
echo $string
如果echo string(不加$),那么解释器就会将string当成一个新的变量,打印一个string出来。
单引号:完全字面替换 ‘23"33’ 就会打印出23"33
双引号:
$加变量名可以取变量的值
$表示$的字面值 输出$符号
`表示`的字面值
"表示"的字面值
\表示的字面值
示例 打印结果
echo new string new string
echo 'new "string' new "string
echo "new "string" new "string
echo "$string" hello world
PWD=`pwd`
echo $PWD
//打印命令pwd的返回值。返回当前路径
反引号括起来执行。有时候我们在shell中调用linux命令是为了得到这个命令的返回值(结果值),这时候就适合用一对反引号(键盘上ESC按键下面的那个按键,和~在一个按键上)来调用执行命令。
shell中的分支结构
if语法很多,只介绍重要部分。
典型if语言格式。
if [表达式]; then
xxx
else
xxx
fi
判断文件是否存在。(-f),注意[]里面前后都有空格,不能省略。 file
判断目录是否存在 (-d) diractory
判断字符串是否相等(”str1” = “str2”),注意用一个等号而不是两个
判断数字是否相等(-eq)、大于(-gt)、小于(-lt)、大于等于(-ge)、小于等于(-le)
while [ $# -gt 0 ] ; do
判断式中使用“-o”表示逻辑或
if [ -f a.c ]; then
ehco yes
【注意】:[ -f a.c ]
-f前面有空格!!!
a.c后面有空格!!! 不写空格会报错
if [ 12 - eq 12 -o "abcd" = "abcd" ]; then
ehco "yes"
else ...
fi
逻辑&&和逻辑||在shell中的独特用法
话说&& 和 || 在shell中也有,出现在shell中简写的if表达式:没有if,只有中括号
[ -z $str ] || echo "233"
//str如果为空,就不显示233;如果不为空则显示233
2.5.shell中的循环结构
for循环
能看懂、能改即可。不要求能够完全不参考写出来
for i in 1 2 3 4 5
do
echo $i
done
//循环打印12345。1 2 3 4 5,这里的数字是我们遍历的集合,没有边界,不需要用()、[]和{}
for i in `ls`
do
echo $i
done
while循环
(1)和C语言的循环在逻辑上无差别。while后面的[]两边都有空格。i++的写法中有两层括号。
i=1
j=11
while [ $i -lt $j ]; do
echo $i
i=$(($i + 1))
done
打印信息传入一个文件
echo "start" > a.txt //创建一个a.txt,把start写进去
i=1
j=11
while [ $i -lt $j ]; do
echo $i >> a.txt
i=$(($i + 1))
done
打印1到10开始,大于8和等于4 的数
#!/bin/sh
str="deep"
str="打印出的是:"
i=0
touch test.txti
while [ $i -lt 10 -o $i -eq 10 ]; do
if [ $i -eq 4 -o $i -gt 8 ]; then
echo $str$i >> test.txt
fi
i=$(($i + 1))
done
case的用法
var=1
case var in
1) echo "1" ;;
2) echo "2" ;;
esac
bash中的传参
$# 传参个数,注意只考虑真正的参数个数。
$1 $2 $3 参数
eg
echo $# $0 $1 $2
sh a.sh aa bb cc 执行sh :# = 3。0是执行shell的应用程序名字,如bash
break跳出在shell中不是用于case的,而是跳出循环的。(因为case是不用break的)
C语言的argv是 只读的,是不可改的。而在shell中,$1是可以用shift改的。
echo $# $1
shift;
echo $# $1
上例中输入source a.sh aa bb cc
打印
3 aa
2 bb
可见shift有点像左移运算符。把shell的传参左移了一个移出去。原来的2变成了原来的1。
2.7 Makefile
kernel 的 本质是C语言的项目,由很多个文件组成,因此都需要Makefile的管理。
分析uboot必须对Makefile有所了解
目标、依赖、命令是Makefile中的三个最主要的成分
目标是我们要去make xxx的那个,是最后生成的东西
依赖是用来生成目标的原材料。
命令就是对原材料的加工方法。
%通配符 和 自动推导
示例:ARM裸机中的makefile
led.bin: start.o
arm-linux-ld -Ttext 0x0 -o led.elf $^
arm-linux-objcopy -O binary led.elf led.bin
arm-linux-objdump -D led.elf > led_elf.dis
gcc mkv210_image.c -o mkx210
./mkx210 led.bin 210.bin
%.o : %.S
arm-linux-gcc -o $@ $< -c -nostdlib
%.o : %.c
arm-linux-gcc -o $@ $< -c -nostdlib
clean:
rm *.o *.elf *.bin *.dis mkx210 -f
Makefile知道要得到什么,需要先得到什么,他会自己一步一步去推导。还是挺聪明的。
自动推导就是把目标文件往规则上套,如果找到了就生成。
@:规则的目标文件名<: 规则的依赖文件名
$^: 依赖的文件集合
makefile 定义和使用变量
类似shell,没有变量类型,引用时候用 $var
伪目标(.PHONY)
伪目标本身不代表一个文件,而是单纯的执行命令。不生成文件或得到某个东西。
伪目标没有依赖。
为了明确声明这是伪目标,一般会在前面加一个
eg:
.PHONY
clean //声明伪目标
clean:
rm *.o *.elf *.bin *.dis mkx210 -f
【makefile的引用】
有时候makefile总体比较复杂,因此makefile有时候 会引用其他makefile
include,和C语言一样,也是原地展开。
例如uboot中有一个:
include $(obj)include/config.mk
【makefile条件语句】
ifeq ($(xxx),var)
xxx = 1
endif
2.8 Makefile 补充学习
【注释用#】
【@命令:静默执行。】
示例:不使用静默执行
all:
echo "helloworld"
打印信息:
echo “helloworld”
helloworld
可见:makefile是默认打印命令的。如果不想看到命令本身,只想看到执行,那么静默执行即可。
all:
@echo "helloworld"
变量赋值运算符
(1)= 最简单的赋值 //他的值取决于最后一次赋值时的值
(2):= 一般也是赋值 //就地直接解析
以上这两个大部分情况下效果是一样的,但是有时候不一样。
用=赋值的变量,取决于最后一次赋值时的值,不能只往前面看,还要往后面看。
用:=来赋值的,则是就地直接解析,只用往前看即可。
(3)?= 如果变量未定义则执行这条赋值,若定义了则本行被忽略。【注意空值也算赋值过】
(4)+= 用来给一个已经赋值的变量接续赋值,意思就是把这次的值加到原来的值的后面,有点类似于strcat。(在shell makefile等文件中,可以认为所有变量都是字符串,+=就相当于给字符串stcat接续内容)(注意一个细节,+=续接的内容和原来的内容之间会自动加一个空格隔开)
注意:Makefile中并不要求赋值运算符两边一定要有空格或者无空格,这一点比shell的格式要求要松一些。
重点:关于=和:=
eg:
A=ABC
B=$(A)DEF
A=GH
all:
echo $(B)
结果:GHDEF
说明猜测是正确的。A=ABC要看最后一次A是什么。在被解析时取决最后一次!!
【关于uboot中的makefile】
一共3000多行,真正有意义的差不多就是470行。用=赋值的变量在uboot中真不好分析。
我们能看懂就行了,但是这个=没:=安全。
对于安全的代码做到什么程度呢?其实想保留B赋值A的原始值,只需要B用:=即可
A=ABC
B:=$(A)DEF
A=GH
all:
echo $(B)
这种情况打印出的值就是 ABCDEF
【makefile 的环境变量】
用export导出的就是环境变量。一般情况下要求环境变量名用大写,普通变量名用小写。
环境变量 类似于整个工程中所有Makefile之间可以共享的全局变量
普通变量 只是当前本Makefile中使用的局部变量
注意定义环境变量可能会影响一个工程中的其他makefile,因此要小心。
有一些环境变量可能是makefile本身自己定义的内部的环境变量
这就好像C语言中编译器预定义的宏__LINE__ __FUNCTION__等一样。
有一些环境变量可能是当前的执行环境提供的环境变量
譬如我们在make执行时给makefile传参。
make CC=arm-linux-gcc
这里给当前Makefile传了一个环境变量CC,值是arm-linux-gcc。用make传参优先级最高。
CC =arm-linux-gcc
export CC
关于make给环境变量传参
CC =gcc
all:
echo $(CC)
1 make打印结果:gcc
2 make CC=arm-linux-gcc 打印结果:arm-linux-gcc (覆盖前环境变量值)
makefile常见通配符
* 若干个任意字符
? 1个任意字符
[] 将[]中的字符依次去和外面的结合匹配
% 也是通配符,表示任意多个字符,和*很相似,但是%一般只用于规则描述中,又叫做规则通配符。
all :1.c 2.c 12.c test.h
echo *.c
echo ?.c
echo [12].c
打印
1.c 2.c 12.c
1.c 2.c
1.c 2.c
【自动变量】
自动变量的含义:预定义的特殊意义的符号。就类似于C语言编译器中预制的那些宏FILE一样。
文件集合中文件非常多,描述的时候很麻烦。
@、<、$^ 就是典型自动变量
led.bin: start.o
arm-linux-ld -Ttext 0x0 -o led.elf $^
#$^代表start.o
%.o : %.c
arm-linux-gcc -o $@ $< -c -nostdlib
#$@代表.o文件
#$<代表.c文件
常见自动变量:
@规则的目标文件名< 规则的依赖文件名
$^ 依赖的文件集合
all :1.c 2.c 12.c test.h
echo $@
echo $<
echo $^
打印结果:
all
1.c
1.c 2.c 12.c test.h
【关于<需要注意】在目标和依赖中<代表第一个依赖
在规则中$<代表的是所有的依赖!
3.1 uboot实践
【关于tar】
tar -jxvf //解压
tar -cjx //打包
bsp是板级支持包
选用的uboot是 B盘 linux/qt4.8/bsp
uboot在任意文件夹下解压,tar -jxvf qt_x210v3.tar.bz2
注意uboot和linux kernel等复杂项目都不能直接编译,需要事先配置。
进入uboot的根目录
执行:make x210_sd_config。 //执行了就配置完了
编译得到uboot.bin
编译前要注意:
1 一定要检查arm-linux-gcc,我们用的是arm-2009q3。
2 还有注意makefile中关于交叉编译工具链的设置:
(第147行) CROSS_COMPILE = 。。。
要保证这一行的交叉编译工具路径和我们的工具链路径一致,否则不能工作
我们放置在/usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi
我自己防止/usr/local/arm/arm-2009q3/bin,路径相同
以上做完之后即可编译
make
//多线程编译(4核心编译)
du -h u-boot.bin
//查看编译生成的uboot.bin大小,视频中是384KB
uboot分uboot官方、SoC级uboot和开发板uboot
smdkv210是三星官方制定的开发板,昂贵且庞大。
三星的uboot有68个对象,九鼎有31个,可以说九鼎包括的功能是三星的子集
gitignore 版本管理的
config.mk arm_config.mk 某个makefile中调用的
COPYING 版权声明,GPL许可,即开源项目
credit 鸣谢
image_split 分割uboot到 BL1的
Makefile ! 很重要,主makefile,我们就是用这个mkfile编译的
mkconfig ! 很重要,uboot的可移植性就是通过此配置脚本维护的
rules.mk 很重要,但不学习他
./mk 快速编译:先清理再设置后编译
mkmovi SD卡启动相关
文件夹
api. 硬件无关的api,是uboot本身使用的,移植不用管
common 【重要】硬件无关。普遍适用代码。环境变量和命令系统。
board 【重要】子文件夹非常多,每一个文件夹代表一个支持的开发板
这么多文件夹还能找到,要归功于配置过程。配置就是定要用于哪个文件夹
【配置】说白了配置就是确定路径,这个路径的确定过程保证了可移植。
【历史】以前是board下存放芯片型号,后来太多了就改成了厂家目录。但为了向前兼容, 还是把以前放在外面的芯片没有动。因为挪了位置很可能就不能用了。
smdkc110:是遗留问题。uboot中的borad下没有s5pv210是因为c110先出的,服务于手 机。c110和s5pv210有99%的相似度。
cpu 【重要】与SoC有关,初始化和控制代码
drivers 【重要】linux中抠出来 的驱动。如网卡、iNand等
(uboot的驱动其实是linux驱动的一部分。)
sd_fusing【重要】刷写sd卡的。实现了烧录uboot镜像到SD卡。其实以前在linux下刷机时就用了。
include 【重要】头文件目录
lib_ 【重要】架构相关的库文件。如lib_arm就算是arm相关的库文件。移植不用管。
libfdt 设备树相关。
linux在3.1以前的版本使用传参的方式启动。
3.1之后的版本采用设备树的机制进行硬件信息描述
目前用到的芯片使用的内核版本都低于3.4,故暂时不讨论设备树,以后讲通过专题。
net 网络相关的,里面的tftp等功能实现就用这个。程序很精小,学网络相关可以看这个。
fs 也是从linux移植过来的,文件系统,管理Flash的
tools 有用的工具
nand_spl onenand post 略
3.6 SourceInsight,简称SI
真正的项目往往有庞大数量的文件。而且代码之间的关联非常复杂。所以读代码是问题。
sourceinsight有方便我们跳转的功能。
【创建工程】
1 首先要创建工程。New project
工程名字和路径
注意:工程项目文件和源代码的目录可以不一样,但是建议放在一起
eg
;老朱自己有一个uboot的项目,习惯在uboot下创建一个“SI_Proj”文件夹
2 新工程设置,一般不管
3 向项目中添加文件
左边是被选的文件,右边是添加了的文件。选中整个项目的文件夹,Add Tree
然后就添加了好多文件。总视窗右边就出现了我们添加了的文件。
4 遗留问题:SI找不到未知文件类型的文件
比如start.s就不在其中,因为SI不认识。
解决方法1:选项 - 文档选项,选择C源码,后缀添加*.S
然后就能搜到了。告诉SI,*.S是一个c文件,随之当做C语言处理
这还是欺骗SI的小技巧,但是很好使。
解决方法2:选项 - 装入设置,装入。装入朱有鹏给