makefile学习五

前面两篇都是在说配置是怎么解析的,以及配置参数是怎么得到了。有了这些配置信息,接下来就是根据这些配置信息编译了。首先需要的是建立适当的环境,包括交叉编译环境,然后确定要编译的objs,最后就是编译objs。还是参考源码来看:

OBJTREE        := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
SPLTREE        := $(OBJTREE)/spl
SRCTREE        := $(CURDIR)
TOPDIR        := $(SRCTREE)

LNDIR        := $(OBJTREE)

首先是建立源码,目标等路径。接下来是生产的config.mk包含进来,# load ARCH, BOARD, and CPU configuration
include $(obj)include/config.mk
export    ARCH CPU BOARD VENDOR SOC

至此确定了编译需要的关键几个变量ARCH、CPU、BOARD、VENDOR、SOC。然后就是包含include $(TOPDIR)/config.mk,这个文件非常重要,主要任务是建立环境。

AS    = $(CROSS_COMPILE)as
LD    = $(CROSS_COMPILE)ld
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

这几个确定了常用的编译、链接。CROSS_COMPILE是跟cpu arch所决定的,在x86上面为“”,其他平台都会加个前zui,如arm-linux-none-等,因此需要包含特定arch、cpu下的配置:

sinclude $(TOPDIR)/arch/$(ARCH)/config.mk    # include architecture dependend rules
sinclude $(TOPDIR)/$(CPUDIR)/config.mk        # include  CPU    specific rules

我们以arm为例看看,到底里面需要做些什么?

CROSS_COMPILE ?= arm-linux-

ifndef CONFIG_STANDALONE_LOAD_ADDR
ifeq ($(SOC),omap3)
CONFIG_STANDALONE_LOAD_ADDR = 0x80300000
else
CONFIG_STANDALONE_LOAD_ADDR = 0xc100000
endif
endif

PLATFORM_CPPFLAGS += -DCONFIG_ARM -D__ARM__

# Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb:
PLATFORM_CPPFLAGS += $(call cc-option,-marm,)

# Try if EABI is supported, else fall back to old API,
# i. e. for example:
# - with ELDK 4.2 (EABI supported), use:
#    -mabi=aapcs-linux -mno-thumb-interwork
# - with ELDK 4.1 (gcc 4.x, no EABI), use:
#    -mabi=apcs-gnu -mno-thumb-interwork
# - with ELDK 3.1 (gcc 3.x), use:
#    -mapcs-32 -mno-thumb-interwork
PLATFORM_CPPFLAGS += $(call cc-option,\
                -mabi=aapcs-linux -mno-thumb-interwork,\
                $(call cc-option,\
                    -mapcs-32,\
                    $(call cc-option,\
                        -mabi=apcs-gnu,\
                    )\
                ) $(call cc-option,-mno-thumb-interwork,)\
            )

# For EABI, make sure to provide raise()
ifneq (,$(findstring -mabi=aapcs-linux,$(PLATFORM_CPPFLAGS)))
# This file is parsed many times, so the string may get added multiple
# times. Also, the prefix needs to be different based on whether
# CONFIG_SPL_BUILD is defined or not. 'filter-out' the existing entry
# before adding the correct one.
ifdef CONFIG_SPL_BUILD
PLATFORM_LIBS := $(SPLTREE)/arch/arm/lib/eabi_compat.o \
    $(filter-out %/arch/arm/lib/eabi_compat.o, $(PLATFORM_LIBS))
else
PLATFORM_LIBS := $(OBJTREE)/arch/arm/lib/eabi_compat.o \
    $(filter-out %/arch/arm/lib/eabi_compat.o, $(PLATFORM_LIBS))
endif
endif

ifdef CONFIG_SYS_LDSCRIPT
# need to strip off double quotes
LDSCRIPT := $(subst ",,$(CONFIG_SYS_LDSCRIPT))
else
LDSCRIPT := $(SRCTREE)/$(CPUDIR)/u-boot.lds
endif

# needed for relocation
ifndef CONFIG_NAND_SPL
LDFLAGS_u-boot += -pie
endif

主要是交叉编译器服了初值,以及添加arch相关的编译、链接选项。另外还包含soc、board等相关的mk

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

接下来是确定需要编译那些obj:主要包括文件系统、常用lib函数,drivers、架构相关的库函数等。这里uboot 只是简单的把各个目录下的目标包含了下。以lib库为例,LIBS包含了drivers、lib以及文件系统等obj。它的依赖关系如下:

$(LIBS):    depend $(SUBDIRS)
        $(MAKE) -C $(dir $(subst $(obj),,$@))

这里生成LIBS库的方法是去到相应的lib目录下执行makefile。我们以一个driver的例子说明,以drivers下fpga的生成为例

include $(TOPDIR)/config.mk

LIB    := $(obj)libfpga.o

ifdef CONFIG_FPGA
COBJS-y += fpga.o
COBJS-$(CONFIG_FPGA_SPARTAN2) += spartan2.o
COBJS-$(CONFIG_FPGA_SPARTAN3) += spartan3.o
COBJS-$(CONFIG_FPGA_VIRTEX2) += virtex2.o
COBJS-$(CONFIG_FPGA_XILINX) += xilinx.o
COBJS-$(CONFIG_FPGA_LATTICE) += ivm_core.o lattice.o
ifdef CONFIG_FPGA_ALTERA
COBJS-y += altera.o
COBJS-$(CONFIG_FPGA_ACEX1K) += ACEX1K.o
COBJS-$(CONFIG_FPGA_CYCLON2) += cyclon2.o
COBJS-$(CONFIG_FPGA_STRATIX_II) += stratixII.o
endif
endif

由于uboot每个lib都会可以独立编译的,所以第一句就是先把交叉编译环境建立起来。接下来定义要编译的lib名字,uboot采用了一种非常简单的命名规则,即lib明是lib+目录名组成的。接下来把根据配置信息把需要编译的c目标文件包含进来。

COBJS    := $(COBJS-y)
SRCS    := $(COBJS:.o=.c)
OBJS    := $(addprefix $(obj),$(COBJS))

同时获取相应.c和目标文件。

接下来就是如何编译了:

$(LIB):    $(obj).depend $(OBJS)
    $(call cmd_link_o_target, $(OBJS))

这里调用了$TOP/config.mk,完成生成库。

下面是编译规则和依赖

include $(SRCTREE)/rules.mk

sinclude $(obj).depend

rules里面的定义了依赖关系是怎么产生的:

$(obj).depend:    $(src)Makefile $(TOPDIR)/config.mk $(SRCS) $(HOSTSRCS)
        @rm -f $@
        @touch $@
        @for f in $(SRCS); do \
            g=`basename $$f | sed -e 's/\(.*\)\.[[:alnum:]_]/\1.o/'`; \
            $(CC) -M $(CPPFLAGS) -MQ $(obj)$$g $$f >> $@ ; \
        done
        @for f in $(HOSTSRCS); do \
            g=`basename $$f | sed -e 's/\(.*\)\.[[:alnum:]_]/\1.o/'`; \
            $(HOSTCC) -M $(HOSTCPPFLAGS) -MQ $(obj)$$g $$f >> $@ ; \
        done

这里主要是使用了gcc的一个特性-M -MQ生成依赖关系。至于.c怎么生成.o等规则在$TOP/config.mk中已经定义了。

这里在学习一下依赖关系是怎么生成的,在uboot里面有两种方式:第一种是直接使用depend这个关键字。像前面LIBS生成那样,由编译器自动生成相关的依赖;第二种是自己生成依赖文件,make会在编译的时候自己去寻找对应的规则。在上面fpga下的depend是由用户自己生成的。当然整个工程也可以只生成一个.d文件,只要把相关的依赖输入到这个文件即可,make会自动找。这里创建依赖关系是通过gcc的编译选项来完成的,以hello.c为例:

alloc@linux-erlo:~/test> cc -M  -MQ a hello.c
a: hello.c /usr/include/stdio.h /usr/include/features.h \
 /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
 /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
 /usr/lib64/gcc/x86_64-suse-linux/4.5/include/stddef.h \
 /usr/include/bits/types.h /usr/include/bits/typesizes.h \
 /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
 /usr/lib64/gcc/x86_64-suse-linux/4.5/include/stdarg.h \
 /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h file1.h

这里列出了所有的依赖关系,MQ后面是obj,接下来是源文件。接下来我们再看看这个依赖关系在uboot下面是怎么完成的。首先它需要知道生成的目标,它通过源文件而得到。首先通过basename函数得到了.c部分,然后通过sed将前面部分取出来作为参数,然后调用gcc命令得到依赖关系。其实获取这个名字也可以使用makefile的函数实现:

o= $(addsuffix .o,$(notdir $(basename $(SRCS))))

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值