您的位置:首页 > 产品设计 > UI/UE

makefile学习五

2011-09-20 22:21 246 查看
前面两篇都是在说配置是怎么解析的,以及配置参数是怎么得到了。有了这些配置信息,接下来就是根据这些配置信息编译了。首先需要的是建立适当的环境,包括交叉编译环境,然后确定要编译的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))))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息