二、主目录 Makefile 分析(2)

时间:2024-01-14 09:26:44

2.7 编译选项---config.mk

  代码 163 164 行

 # load other configuration
include $(TOPDIR)/config.mk

  此段就是包含顶层目录下的 config.mk,在顶层的  config.mk 中包含了编译选项。

2.7.1 topdir/config.mk 分析

  代码 26 到 45行:

 ifneq ($(OBJTREE),$(SRCTREE))
ifeq ($(CURDIR),$(SRCTREE))
dir :=
else
dir := $(subst $(SRCTREE)/,,$(CURDIR))
endif obj := $(if $(dir),$(OBJTREE)/$(dir)/,$(OBJTREE)/)
src := $(if $(dir),$(SRCTREE)/$(dir)/,$(SRCTREE)/) $(shell mkdir -p $(obj))
else
obj :=
src :=
endif # clean the slate ...
PLATFORM_RELFLAGS =
PLATFORM_CPPFLAGS =
PLATFORM_LDFLAGS =
  1. 代码首先判断 目标存放目录是否不等于源码目录,若不等于,则执行分支语句,等于 则不执行。
  2. 执行分支语句,判断当前目录是否等于源码目录,若等于则将 dir 置空,否则,把$(CURDIR)中的$(SRCTREE)/替换称空,然后赋给dir
  3. 执行完之后,如果 dir 不为空,则把$(OBJTREE)/$(dir)/赋给obj,否则把直接把$(OBJTREE)/赋给obj
  4. 如果src不为空,则把$(SRCTREE)/$(dir)/赋给src,否则把$(SRCTREE)/赋给src
  5. 通过一个shell 函数创建 obj 路径,obj 的路径为 $(OBJTREE)/$(dir)/ 或 $(OBJTREE)/
  6. 若是目标目录和源码目录相同,则 obj 和 src 都为空
  7. 最后清除三个 编译选项 标志

  PLATFORM_RELFLAGS、PLATFORM_CPPFLAGS 和 PLATFORM_LDFLAGS 这三个变量被置空,之后会被赋值上编译参数,接下来的 54 到 92 行都是给三个编译选项赋值参数:

  63 到 70行,是架构为ARM的赋值,但里面的 CROSS_COMPILE 不能匹配,不会执行

 ifeq ($(ARCH),arm)
ifeq ($(CROSS_COMPILE),powerpc-netbsd-)
PLATFORM_CPPFLAGS+= -D__ARM__
endif
ifeq ($(CROSS_COMPILE),powerpc-openbsd-)
PLATFORM_CPPFLAGS+= -D__ARM__
endif
endif

  76 到 92 行,会根据前面#include/config.mk 导出的环境变量参数来包含相应的 config.mk 文件

 ifdef    ARCH
sinclude $(TOPDIR)/$(ARCH)_config.mk # include architecture dependend rules
endif
ifdef CPU
sinclude $(TOPDIR)/cpu/$(CPU)/config.mk # include CPU specific rules
endif
ifdef SOC
sinclude $(TOPDIR)/cpu/$(CPU)/$(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

  根据前面的参数进行展开即可

  96 到 106 行,是给几个参数赋值,HOSTCC 赋值为 gcc,HOSTCFLAGS 和 HOSTSTRIP

  CONFIG_SHELL,涉及到  shell 语法和命令

  • if 语句的 -x 参数为测试文件对当前用户是都可执行
  • 再看一下 shell  的特殊变量:
    • $0      当前脚本的文件名
    • $n      传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
    • $#      传递给脚本或函数的参数个数。
    • $*      传递给脚本或函数的所有参数。
    • $@      传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同,下面将会讲到。
    • $?      上个命令的退出状态,或函数的返回值。一般情况下,大部分命令执行成功会返回 0,失败返回 1。
    • $$      当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。
    • $* 和 $@ 的区别 : 
      1. $* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。
      2. 但是当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。
 CONFIG_SHELL    := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
else echo sh; fi ; fi) ifeq ($(HOSTOS)-$(HOSTARCH),darwin-ppc)
HOSTCC = cc
else
HOSTCC = gcc
endif
HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
HOSTSTRIP = strip

  113 到 114行, 这是一个选项检查器,以确保我们只使用所支持的编译器,际上使用了一个shell函数,本函数使用了if-then语句,检测条件分别为"-S, -o, -xc",也用到了重定向

 cc-option = $(shell if $(CC) $(CFLAGS) $() -S -o /dev/null -xc /dev/null \
> /dev/null >&; then echo "$(1)"; else echo "$(2)"; fi ;)

  119 到 166 行,定义了交叉工具编译连,指定了交叉工具编译连的参数

 AS    = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
RANLIB = $(CROSS_COMPILE)RANLIB ifneq (,$(findstring s,$(MAKEFLAGS)))
ARFLAGS = cr
else
ARFLAGS = crv
endif
RELFLAGS= $(PLATFORM_RELFLAGS)
DBGFLAGS= -g # -DDEBUG
OPTFLAGS= -Os #-fomit-frame-pointer
ifndef LDSCRIPT
#LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug
ifeq ($(CONFIG_NAND_U_BOOT),y)
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
else
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
endif
endif
OBJCFLAGS += --gap-fill=0xff gccincdir := $(shell $(CC) -print-file-name=include) CPPFLAGS := $(DBGFLAGS) $(OPTFLAGS) $(RELFLAGS) \
-D__KERNEL__ -DTEXT_BASE=$(TEXT_BASE) \ ifneq ($(OBJTREE),$(SRCTREE))
CPPFLAGS += -I$(OBJTREE)/include2 -I$(OBJTREE)/include
endif CPPFLAGS += -I$(TOPDIR)/include
CPPFLAGS += -fno-builtin -ffreestanding -nostdinc \
-isystem $(gccincdir) -pipe $(PLATFORM_CPPFLAGS) ifdef BUILD_TAG
CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes \
-DBUILD_TAG='"$(BUILD_TAG)"'
else
CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes
endif
  • #如果函数$(findstring s,$(MAKEFLAGS))不为空,也就是说能从$(MAKEFLAGS)中找到字符s,则定义AR选项为cr,否则为 crv
  • RELFLAGS、DBGFLAGS 和 OPTFLAGS 赋值
  • 如果没有定义链接脚本(LDSCRIPT),则指定链接脚本
  • 下面的都是编译的一些标志了,不具体分析了

  227 到 244 行,则是指定编译依赖

 ifndef REMOTE_BUILD

 %.s:    %.S
$(CPP) $(AFLAGS) -o $@ $<
%.o: %.S
$(CC) $(AFLAGS) -c -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $< else $(obj)%.s: %.S
$(CPP) $(AFLAGS) -o $@ $<
$(obj)%.o: %.S
$(CC) $(AFLAGS) -c -o $@ $<
$(obj)%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
endif

  例如

  %.s: %.S

    $(CPP) $(AFLAGS) -o $@ $<

  %.s 依赖于 %.S

    -o  后面的为 $@ 为 %.s,$< 为所有依赖