浏览一下U-Boot各个子目录下的Makefile可以看到,几乎他们都会包含$(TOPDIR)/config.mk,那么这个文件进行了什么操作呢?简单概括:读入include/config.mk、include/autoconf.mk,指定ARCH CPU SoC Board等重要信息,并且加入各个层次上的编译选项;初始化编译处理选项、链接选项;最后有一个很重要的变量定义:

  cmd_link_o_target = $(if $(strip $1),\

            $(LD) $(LDFLAGS) -r -o $@ $1, \

            rm -f $@; $(AR) rcs $@)

  其实就是将输入的参数$1部分链接成目标,如果输入目标无效,则删除相关的目标,并且建立一个新的归档文件,与目标同名。

  该文件中涉及大量编译、链接选项,篇幅较大,因此不深究它们,只是分析关键步骤。

 ifeq ($(CURDIR),$(SRCTREE))
dir :=
else
dir := $(subst $(SRCTREE)/,,$(CURDIR))
endif ifneq ($(OBJTREE),$(SRCTREE))
# Create object files for SPL in a separate directory
ifeq ($(CONFIG_SPL_BUILD),y)
obj := $(if $(dir),$(SPLTREE)/$(dir)/,$(SPLTREE)/)
else
obj := $(if $(dir),$(OBJTREE)/$(dir)/,$(OBJTREE)/)
endif
src := $(if $(dir),$(SRCTREE)/$(dir)/,$(SRCTREE)/) $(shell mkdir -p $(obj))
else
# Create object files for SPL in a separate directory
ifeq ($(CONFIG_SPL_BUILD),y)
obj := $(if $(dir),$(SPLTREE)/$(dir)/,$(SPLTREE)/) $(shell mkdir -p $(obj))
else
obj :=
endif
src :=
endif

  CURDIR是Makefile内置变量,表示该Makefile的绝对路径,相当于执行pwd得到的输出,这里通过subst函数将CURDIR中的SRCTREE部分去掉,这样dir就表示当前路径相对于源码根目录的相对路径。

  接下来是obj和src的处理,这里SRCTREE和OBJTREE相同,而且CONFIG_SPL_BUILD没定义,因此上述两个变量是空字符串。

 CC_OPTIONS_CACHE_FILE := $(OBJTREE)/include/generated/cc_options.mk
CC_TEST_OFILE := $(OBJTREE)/include/generated/cc_test_file.o -include $(CC_OPTIONS_CACHE_FILE) cc-option-sys = $(shell mkdir -p $(dir $(CC_TEST_OFILE)); \
if $(CC) $(CFLAGS) $(1) -S -xc /dev/null -o $(CC_TEST_OFILE) \
> /dev/null 2>&1; then \
echo 'CC_OPTIONS += $(strip $1)' >> $(CC_OPTIONS_CACHE_FILE); \
echo "$(1)"; fi) ifeq ($(CONFIG_CC_OPT_CACHE_DISABLE),y)
cc-option = $(strip $(if $(call cc-option-sys,$1),$1,$2))
else
cc-option = $(strip $(if $(findstring $1,$(CC_OPTIONS)),$1,\
$(if $(call cc-option-sys,$1),$1,$2)))
endif # cc-version
# Usage gcc-ver := $(call cc-version)
cc-version = $(shell $(SHELL) $(SRCTREE)/tools/gcc-version.sh $(CC))
binutils-version = $(shell $(SHELL) $(SRCTREE)/tools/binutils-version.sh $(AS))

  这里相当于定义了两个小函数cc-option-sys,cc-option,其中后者调用前者,因此虽然前者提供了接口,但是并不使用,我不知道CONFIG_CC_OPT_CACHE_DISABLE是不是y,但是这里的核心操作就是,将要添加的CC编译选项以参数的形式传进去,然后尝试加入该选项来编译/dev/null,丢弃所有stdout/stderr输出。这里比较有意思的是,编译的源文件是/dev/null,估计作者的意思是,只要加入的这个选项存在,是编译器支持的就可以,而不是要求达到何种效果。如果选项有效,则向include/generated/cc_options.mk中写入该选项。

  接着又定义了两个函数cc-version、binutils-version,两者都是通过执行shell脚本得到的,没用到,暂不分析。

 AS  = $(CROSS_COMPILE)as

 # Always use GNU ld
LD = $(shell if $(CROSS_COMPILE)ld.bfd -v > /dev/null 2>&1; \
then echo "$(CROSS_COMPILE)ld.bfd"; else echo "$(CROSS_COMPILE)ld"; fi;) CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
LDR = $(CROSS_COMPILE)ldr
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
RANLIB = $(CROSS_COMPILE)RANLIB
DTC = dtc

  上面就很简单了,指明使用的各个工具,这是每个子Makefile都要包含config.mk的重要原因之一。

 # Load generated board configuration
sinclude $(OBJTREE)/include/autoconf.mk
sinclude $(OBJTREE)/include/config.mk

  这里虽然就两行,但是很重要,经过上一篇文章的分析,我们知道mkconfig s5p_goni_config的重要输出文件有两个:include/config.mk include/config.h,这里使用第一个,它指明了ARCH CPU SOC VENDOR BOARD,autoconf.mk目前还不知道是如何产生的,但是浏览以下可以知道里面的信息很多很重要,很多功能配置,这是子Makefile要包含config.mk的另一个重要原因。

 CPUDIR=arch/$(ARCH)/cpu/$(CPU)
ifneq ($(SRCTREE)/$(CPUDIR),$(wildcard $(SRCTREE)/$(CPUDIR)))
CPUDIR=arch/$(ARCH)/cpu
endif sinclude $(TOPDIR)/arch/$(ARCH)/config.mk # include architecture dependend rules
sinclude $(TOPDIR)/$(CPUDIR)/config.mk # include CPU specific rules ifdef SOC
sinclude $(TOPDIR)/$(CPUDIR)/$(SOC)/config.mk # include SoC specific rules
endif
ifdef VENDOR
BOARDDIR = $(VENDOR)/$(BOARD)
else
BOARDDIR = $(BOARD)
endif
ifdef BOARD
sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk # include board specific rules
endif

  概括一下,上面的语句就是读入了几个config.mk:

sinclude arch/arm/config.mk  这是加入架构层次上的配置,比如设定CROSS_COMPILE ?= arm-linux-,比如通过上面的cc-option函数加入arm架构的编译选项:

              $(call cc-option -marm)

sinclude arch/arm/cpu/armv7/config.mk  这是加入cpu层次上的配置,加入指令集上的配置选项,如$(call cc-option, -march=armv7-a, -march=armv5)

sinclude arch/arm/cpu/armv7/s5pc1xx/config.mk  这是加入soc层次上的配置,检查发现目录下没有此文件,但并不报错,sinclude和-include用法一样,当被包含的文件不

                   存在的时候,不报错,继续执行。

sinclude board/samsung/goni/config.mk   这是在board层次上加入配置,因为板卡资源决定了我们的内存容量和起始地址,所以这里指定了u-boot镜像的链接地址CONFIG_SYS_TEXT_BASE = 0x34800000,这个信息是board-specific。

 ARFLAGS = $(error update your Makefile to use cmd_link_o_target and not AR)
RELFLAGS= $(PLATFORM_RELFLAGS)
DBGFLAGS= -g # -DDEBUG
OPTFLAGS= -Os #-fomit-frame-pointer OBJCFLAGS += --gap-fill=0xff gccincdir := $(shell $(CC) -print-file-name=include) CPPFLAGS := $(DBGFLAGS) $(OPTFLAGS) $(RELFLAGS) \
-D__KERNEL__

  注意ARFLAGS被设置成了makefile的error函数输出错误信息,这是提醒用户,在对目标文件归档的时候不要使用$(AR)了,要使用$(LD)。

  接下来就是编译链接选项的设置,有太多选项了,什么SPL启动、VENDOR address等等,不细细分析了。

 export  HOSTCC HOSTCFLAGS HOSTLDFLAGS PEDCFLAGS HOSTSTRIP CROSS_COMPILE \
AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP MAKE
export CONFIG_SYS_TEXT_BASE PLATFORM_CPPFLAGS PLATFORM_RELFLAGS CPPFLAGS CFLAGS AFLAGS

  export到全局的变量如上所示。

  终于到了最后!

 # The _DEP version uses the $< file target (for dependency generation)
# See rules.mk
EXTRA_CPPFLAGS_DEP = $(CPPFLAGS_$(BCURDIR)/$(addsuffix .o,$(basename $<))) \
$(CPPFLAGS_$(BCURDIR))
$(obj)%.s: %.S
$(CPP) $(ALL_AFLAGS) -o $@ $<
$(obj)%.o: %.S
$(CC) $(ALL_AFLAGS) -o $@ $< -c
$(obj)%.o: %.c
$(CC) $(ALL_CFLAGS) -o $@ $< -c
$(obj)%.i: %.c
$(CPP) $(ALL_CFLAGS) -o $@ $< -c
$(obj)%.s: %.c
$(CC) $(ALL_CFLAGS) -o $@ $< -c -S ######################################################################### # If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $1),\
$(LD) $(LDFLAGS) -r -o $@ $1,\
rm -f $@; $(AR) rcs $@ )

  这里很重要,是一些静态模式描述,分析这里的时候,着实让我纠结了一阵子。以前自己写Makefile的时候也会用静态模式,但理解是很不准确的,写依赖的时候理所当然地写$<,不知原因。举例,test.o处理依赖test.c以外,还依赖它所包含的头文件,所以该文件的完整约束描述为:

test.o: test.c  \

header1path/header1.h

header2path/header2.h

...

  上述依赖格式也正是CC -M的输出格式,而在编译生成test.o的时候,只需要test.c就够了,这就是$<的含义:依赖集中的第一个依赖。

  最后那个函数在文章开始的时候已经分析过了。

  ok.

U-Boot Makefile分析(2) config.mk分析的更多相关文章

  1. uboot总结:uboot配置和启动过程3(config.mk分析)

    说明:文件位置:在uboot的目录下,文件名为:config.mk.是一个makefile文件,以后会被主Makefile调用. 它的主要作用的是: (1)具体的设置交叉编译工具链接(主Makefil ...

  2. 2014-10 u-boot 顶层config.mk分析

    /** ****************************************************************************** * @author    Maox ...

  3. uboot顶层config.mk分析

    uboot顶层目录中的config.mk定义了确定了当前执行makefile所对应的源文件目录.目标文件目录,编译的程序编译.连接的选项,以及目标文件生成的规则等等.它被包含在顶层的makefile以 ...

  4. u-boot顶层目录config.mk分析

    1. 设置obj与src ifneq ($(OBJTREE),$(SRCTREE)) ifeq ($(CURDIR),$(SRCTREE)) dir := else dir := $(subst $( ...

  5. U-Boot Makefile分析(3) rules.mk分析

    浏览各个子Makefile可以发现,他们都会在文件的后面包含rules.mk,这个文件的作用就是更新源文件的依赖,并生成各种.depend文件. _depend: $(obj).depend # Sp ...

  6. Spring Boot 启动(一) SpringApplication 分析

    Spring Boot 启动(一) SpringApplication 分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html ...

  7. Spring Boot 揭秘与实战 源码分析 - 工作原理剖析

    文章目录 1. EnableAutoConfiguration 帮助我们做了什么 2. 配置参数类 – FreeMarkerProperties 3. 自动配置类 – FreeMarkerAutoCo ...

  8. Spring Boot 揭秘与实战 源码分析 - 开箱即用,内藏玄机

    文章目录 1. 开箱即用,内藏玄机 2. 总结 3. 源代码 Spring Boot提供了很多”开箱即用“的依赖模块,那么,Spring Boot 如何巧妙的做到开箱即用,自动配置的呢? 开箱即用,内 ...

  9. Spring Boot自动装配原理源码分析

    1.环境准备 使用IDEA Spring Initializr快速创建一个Spring Boot项目 添加一个Controller类 @RestController public class Hell ...

随机推荐

  1. kafka创建会话,报Error while executing topic command : Replication factor: 1 larger than available brokers: 0.

     bin/kafka-topics.sh --create --zookeeper es1:2181 --replication-factor 1 --partitions 1 --topic top ...

  2. fiddler抓取https请求

    Fiddler抓取https设置详解(图文):https://www.cnblogs.com/joshua317/p/8670923.html Fiddler要抓取到https请求我们还需要Fiddl ...

  3. kettle使用笔记1--基本安装和使用

    参考来源 https://blog.csdn.net/qq_36698956/article/details/80751655,在这个文章基础上实际使用增加的. 一,安装,采用的是下载官方网站的win ...

  4. python的可变对象与不可变对象

    a = 1print(id(a))def fun(a): a = 2 print(a,id(a))fun(a)print(a,id(a)) # 1#为什么这里的a的值没有改变#因为在函数里变量赋值(内 ...

  5. Django form表单功能的引用(注册,复写form.clean方法 增加 验证密码功能)

    1. 在app下 新建 forms.py 定义表单内容,类型models from django import forms class RegisterForm(forms.Form): userna ...

  6. VXLAN实验

    拓扑图: SPINE配置: hostname SPINE-1vdc SPINE-1 id 1 limit-resource vlan minimum 16 maximum 4094 limit-res ...

  7. vue props命名最好直接使用kebab-case (短横线隔开式) 命名

    vue官方解释,props使用驼峰命名的话,在html中使用时也需要转化成短横线命名,否则报错.个人比较喜欢上下文统一,直接在props命名时就把它命名成短横线隔开式吧.

  8. 关于HTML5中的sessionStorage的会话级缓存使用

    sessionStorage作为HTML5的Web Storage的两种存储方式之一.    用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数 ...

  9. 对palindrome的常用判断

    判断String是否为palindrome:Two Pointers(left & right) 同时边扫边check 当前两边的char是否相同 code public boolean is ...

  10. 《Java从入门到精通》学习总结1

    1. Java既是编译型语音,也是解释型语言:先将源代码编译成Java字节码,然后Java虚拟机对Java字节码进行解释运行 2. 使用命令行编译Java源代码时,如果代码中有中文,在编译时需要指定编 ...