2014-10 u-boot make过程分析
ALL-y += u-boot.srec u-boot.bin System.map binary_size_check
u-boot.srec: u-boot FORCE
$(call if_changed,objcopy)
u-boot.bin: u-boot FORCE
$(call if_changed,objcopy)
$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
$(BOARD_SIZE_CHECK)
System.map: u-boot
@$(call SYSTEM_MAP,$<) > $@
@file_size=$(shell wc -c u-boot.bin | awk '{print $$1}') ; \
map_size=$(shell cat u-boot.map | \
awk '/_image_copy_start/ {start = $$1} /_image_binary_end/ {end = $$1} END {if (start != "" && end != "") print "ibase=16; " toupper(end) " - " toupper(start)}' \
| sed 's/0X//g' \
| bc); \
if [ "" != "$$map_size" ]; then \
if test $$map_size -ne $$file_size; then \
echo "u-boot.map shows a binary size of $$map_size" >&2 ; \
echo " but u-boot.bin shows $$file_size" >&2 ; \
exit 1; \
fi \
fi
u-boot:$(u-boot-init) $(u-boot-main) u-boot.lds
$(call if_changed,u-boot__)
u-boot-init := $(head-y)
head-y := $(CPUDIR)/start.o
u-boot-main := $(libs-y)
libs-y += lib/
libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
libs-y += $(CPUDIR)/
ifdef SOC
libs-y += $(CPUDIR)/$(SOC)/
endif
libs-y += arch/$(ARCH)/lib/
include$(srctree)/config.mk
u-boot.lds: $(LDSCRIPT) prepare FORCE
$(call if_changed_dep,cpp_lds)
514 # If there is no specified link script, we look in a number of places for it
515 ifndef LDSCRIPT
516 ifeq ($(wildcard $(LDSCRIPT)),)
517 LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot.lds
518 endif
519 ifeq ($(wildcard $(LDSCRIPT)),)
520 LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot.lds
521 endif
522 ifeq ($(wildcard $(LDSCRIPT)),)
523 LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot.lds
524 endif
525 endif
prepare:prepare0
prepare0: archprepare FORCE
$(Q)$(MAKE)$(build)=.
archprepare: prepare1 scripts_basic
$(version_h): include/config/uboot.release FORCE
$(call filechk,version.h)
version_h:= include/generated/version_autogenerated.h
$(timestamp_h): $(srctree)/Makefile FORCE
$(call filechk,timestamp.h)
timestamp_h := include/generated/timestamp_autogenerated.h
prepare2: prepare3 outputmakefile
prepare3: include/config/uboot.release
include/config/%.conf:$(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
现在仍然假设 auto.conf 和 auto.conf.cmd 还没有生成,那么由上面的 $(KCONFIG_CONFIG) include/config/auto.conf.cmd: ; 这条语句知道,该语句中的目标没有依赖,也没有生成它的规则命令,所以可想 GNU Make 本身无法生成 auto.conf.cmd 的。然后该条语句后面的一个分号表明,这两个目标被强制是最新的,所以下面这条命令得以执行:
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
这里我们看到要生成一个目标 silentoldconfig ,这个目标定义在 scripts/kconfig/Makefile 中。因为这里使用 -f 选项重新指定了顶层 Makefile,而目标又是 silentoldconfig ,所以该命令最终会在顶层 Makefile 的 462-464 这里执行:
|
1
2
3
|
%config: scripts_basic outputmakefile FORCE $(Q)mkdir -p include/linux include/config $(Q)$(MAKE) $(build)=scripts/kconfig $@ |
这时,我们来到 scripts/kconfig/Makefile 文件里。在该文件的 32-34 行看到:
|
1
2
3
|
silentoldconfig: $(obj)/conf $(Q)mkdir -p include/generated $< -s $(Kconfig) |
从上面看到,silentoldconfig 目标需要依赖 conf 这个程序,该程序也在 scripts/kconfig 目录下生成。
$< -s $(Kconfig) 该条命令相当于 conf -s $(Kconfig) ,这里 $(Kconfig) 是位于不同平台目录下的 Kconfig 文件,比如在 x86 平台就是 arch/x86/Kconfig 。
conf 程序的源代码的主函数在同目录的 conf.c 文件中,在 main() 函数中看到:
|
1
2
3
4
5
6
7
8
9
10
|
while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) { switch (opt) { case 'o': input_mode = ask_silent; break; case 's': input_mode = ask_silent; sync_kconfig = 1; break;... ... |
所以,在使用 s 参数时,sync_kconfig 这个变量会为 1 。同样在 main() 函数还看到:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
if (sync_kconfig) { name = conf_get_configname(); if (stat(name, &tmpstat)) { fprintf(stderr, _("***\n" "*** You have not yet configured your kernel!\n" "*** (missing kernel config file \"%s\")\n" "***\n" "*** Please run some configurator (e.g. \"make oldconfig\" or\n" "*** \"make menuconfig\" or \"make xconfig\").\n" "***\n"), name); exit(1); } } |
上面代码中,如果我们从未配置过内核,那么就会打印出错误信息,然后退出。这里假设已经配置过内核,并生成了 .config 文件,那么在 main() 函数中会来到:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
switch (input_mode) { case set_default: if (!defconfig_file) defconfig_file = conf_get_default_confname(); if (conf_read(defconfig_file)) { printf(_("***\n" "*** Can't find default configuration \"%s\"!\n" "***\n"), defconfig_file); exit(1); } break; case ask_silent: case ask_all: case ask_new: conf_read(NULL); break;... ... |
由于使用 s 选项,则 input_mode 为 ask_silent,所以这里会执行 conf_read(NULL); 函数。
conf_read(NULL); 函数用来读取 .config 文件。读取的各种相关内容主要存放在一个 struct symbol 结构链表里,而各个结构的相关指针则放在一个 symbol_hash[] 的数组中,对于数组中元素的寻找通过 fnv32 哈希算法进行定位。
最后会来到 conf.c 中的底部:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
if (sync_kconfig) { /* silentoldconfig is used during the build so we shall update autoconf. * All other commands are only used to generate a config. */ if (conf_get_changed() && conf_write(NULL)) { fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n")); exit(1); } if (conf_write_autoconf()) { fprintf(stderr, _("\n*** Error during update of the kernel configuration.\n\n")); return 1; } } else { if (conf_write(NULL)) { fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n")); exit(1); } } |
在 if (conf_get_changed() && conf_write(NULL)) 这个判断里,conf_get_changed() 函数判断 .config 文件是否做过变动,如果是,那么会调用 conf_write(NULL) 来重新写 .config 文件。实际上,对于 defconfig, oldconfig, menuconfig 等目标来说,conf 程序最终也是调用 conf_write() 函数将配置结果写入 .config 文件中(最后那个 else 里的内容便是)。
确保了 .config 已经最新后,那么调用 conf_write_autoconf() 生成 auto.conf,auto.conf.cmd 以及 autoconf.h 这 3 个文件。
来到 conf_write_autoconf() 函数:j
在 conf_write_autoconf() 里,调用 file_write_dep("include/config/auto.conf.cmd"); 函数将相关内容写入 auto.conf.cmd 文件。在生成的 auto.conf.cmd 文件中可以看到:
|
1
2
|
include/config/auto.conf: \ $(deps_config) |
可以看到 auto.conf 文件中的内容依赖于 $(deps_config) 变量里定义的东西,这些东西基本上是各个目录下的 Kconfig 以及其它一些相关文件。
auto.config 和 .config 的差别是在 auto.config 里去掉了 .config 中的注释项目以及空格行,其它的都一样。
仍然在 conf_write_autoconf() 里,分别建立了 .tmpconfig,.tmpconfig_tristate 和 .tmpconfig.h 这 3 个临时文件:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
out = fopen(".tmpconfig", "w"); if (!out) return 1; tristate = fopen(".tmpconfig_tristate", "w"); if (!tristate) { fclose(out); return 1; } out_h = fopen(".tmpconfig.h", "w"); if (!out_h) { fclose(out); fclose(tristate); return 1; } |
然后将文件头的注释部分分别写入到这几个临时文件中:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
sym = sym_lookup("KERNELVERSION", 0); sym_calc_value(sym); time(&now); fprintf(out, "#\n" "# Automatically generated make config: don't edit\n" "# Linux kernel version: %s\n" "# %s" "#\n", sym_get_string_value(sym), ctime(&now)); fprintf(tristate, "#\n" "# Automatically generated - do not edit\n" "\n"); fprintf(out_h, "/*\n" " * Automatically generated C config: don't edit\n" " * Linux kernel version: %s\n" " * %s" " */\n" "#define AUTOCONF_INCLUDED\n", sym_get_string_value(sym), ctime(&now)); |
接着在 for_all_symbols(i, sym) 这个循环里(是一个宏)里将相关内容分别写入到这几个文件中。
在最后一段代码中,将这几个临时文件进行改名:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
name = getenv("KCONFIG_AUTOHEADER"); if (!name) name = "include/generated/autoconf.h"; if (rename(".tmpconfig.h", name)) return 1; name = getenv("KCONFIG_TRISTATE"); if (!name) name = "include/config/tristate.conf"; if (rename(".tmpconfig_tristate", name)) return 1; name = conf_get_autoconfig_name(); /* * This must be the last step, kbuild has a dependency on auto.conf * and this marks the successful completion of the previous steps. */ if (rename(".tmpconfig", name)) return 1; |
上面代码中的 conf_get_autoconfig_name() 实现为:
|
1
2
3
4
5
6
|
const char *conf_get_autoconfig_name(void){ char *name = getenv("KCONFIG_AUTOCONFIG"); return name ? name : "include/config/auto.conf"; } |
从上面可以看到,分别生成了以下几个文件:
引用include/generated/autoconf.h
include/config/tristate.conf
include/config/auto.conf
其中 include/generated/autoconf.h 头文件由内核本身使用,主要用来预处理 C 代码。比如在 .config 或 auto.conf 中定义要编译为模块的项,如:
CONFIG_DEBUG_NX_TEST=m
在 autoconf.h 中会被定义为:
#define CONFIG_DEBUG_NX_TEST_MODULE 1
在 .config 或 auto.conf 后接字符串值的项,如:
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
在 autoconfig.h 中会被定义为:
#define CONFIG_DEFCONFIG_LIST "/lib/modules/$UNAME_RELEASE/.config"
同样对应于 int 型的项如 CONFIG_HZ=1000 在 autoconf.h 中被定义为 #define CONFIG_HZ 1000 。
2014-10 u-boot make过程分析的更多相关文章
- Contest - 2014 SWJTU ACM 手速测试赛(2014.10.31)
题目列表: 2146 Problem A [手速]阔绰的Dim 2147 Problem B [手速]颓废的Dim 2148 Problem C [手速]我的滑板鞋 2149 Problem D [手 ...
- Linux - Eclipse CDT + GCC 安装(2014.10.2)
Eclipse CDT + GCC 安装 (2014.10.2) 本文地址:http://blog.csdn.net/caroline_wendy 1. 安装Eclipse,在官方站点下载Eclips ...
- App Store审核指南中文版(2014.10.11更新)
App Store审核指南中文版(2014.10.11更新) 2014-10-11 16:36 编辑: suiling 分类:AppStore研究 来源:CocoaChina 2 8657 App ...
- phpStudy + JspStudy 2014.10.02 下载
phpStudy + JspStudy 2014.10.02 下载 目标:让天下没有难配的php环境. phpStudy Linux版&Win版同步上线 支持Apache/Nginx/Teng ...
- 2014.10.5 再次学习LINUX
mesg 发送信息给root y n write/talk 写消息给 wall 给所有用户发送消息 ps -aux ps -elF pstree 命令行跳转:CTRL+a行首 CTRL+e行尾 CTR ...
- 【spring boot】10.spring boot下的单元测试
spring boot下的单元测试,思前想后还是需要单独用一章篇幅来看看. 然后在看了介绍和使用时候,我感觉并不想多去看了. 但是还是给后来人留下参考的路径: 官网说明:https://spring. ...
- iPhone屏幕适配,历史及现状(http://hjcapple.github.io/2014/10/10/iphone-screen.html)
iPhone屏幕适配,历史及现状 初代iPhone 2007年,初代iPhone发布,屏幕的宽高是320×480像素.下文也是按照宽度,高度的顺序排列.这个分辨率一直到iPhone 3GS的也保持不变 ...
- Cheatsheet: 2014 10.01 ~ 10.30
.NET ASP.NET Web Api: Unwrapping HTTP Error Results and Model State Dictionaries Client-Side HTTP 20 ...
- 2014.10.09 Andrew 学习 WPF(刘铁锰) 笔记分享
引言 主要是讲了关于WPF只是表现层的工具. 第一章: XAML : 可扩张应用程序标记语言 Extensible Application Markup Language 什么是XAML? X ...
- 基于Android的ELF PLT/GOT符号和重定向过程ELF Hook实现(by 低端农业代码 2014.10.27)
介绍 技术原因写这篇文章,有两种: 一个是在大多数在线叙述性说明发现PLT/GOT第二十符号重定向过程定向x86的,例<Redirecting functions in shared ELF l ...
随机推荐
- 【Android】利用服务Service创建标题栏通知
创建标题栏通知的核心代码 public void CreateInform() { //定义一个PendingIntent,当用户点击通知时,跳转到某个Activity(也可以发送广播等) Inten ...
- android service总结
1.通过startservice方法启动一个服务.service不能自己启动自己.若在一个服务中启动一个activity则,必须是申明一个全新的activity任务TASK.通过startservic ...
- 解析“extern”
解析“extern” 1. 声明外部变量 现代编译器一般採用按文件编译的方式,因此在编译时,各个文件里定义的全局变量是 互相透明的,也就是说,在编译时,全局变量的可见域限制在文件内部.以下举一个简单的 ...
- SVN 冲突文件快速解决方法
精简的美丽...... 现在几乎没有几个写代码的人不用snv来存储代码了吧! 但是,在实际操作中,多人对同一文件读写造成冲突是时有发生的事.这个时候解决的方法就是打开文件找出冲突的地方.如果冲突的部分 ...
- jQuery Mobile 连接外部连接或切换动画
jQuery Mobile不同网页之间的跳转问题 jQuery Mobile,一个新的手机终端脚本开发库,从名字可以看出,它是基于jQuery:目前支持很多种手机设备,包括IOS/Android/Bl ...
- linux:ifconfig命令
许多windows非常熟悉ipconfig命令行工具,它被用来获取网络接口配置信息并对此进行修改.Linux系统拥有一个类似的工具,也就是ifconfig(interfaces config).通常需 ...
- ASP.NET MVC 4 如何避免数据库被自动创建或自动迁移
保哥说要想避免数据库被自动创建或自动迁移,可以在Global.asax文件里的Application_Start方法中加入: System.Data.Entity.Database.SetInitia ...
- github/hexo搭建个人博客几个问题总结
问题一:hexo ERROR Deployer not found: github or hexo ERROR Deployer not found: git npm install hexo-dep ...
- WampServer下修改和重置MySQL密码(转)
转自:www.2cto.com/database/201504/387589.html WampServer安装后密码是空的, 修改一般有两种方式: 一是通过phpMyAdmin直接修改: 二是使用W ...
- BZOJ 2962
2962: 序列操作 Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 618 Solved: 225[Submit][Status][Discuss] ...