搜档网
当前位置:搜档网 › Makefile源码分析_U-boot

Makefile源码分析_U-boot

Makefile源码分析_U-boot
Makefile源码分析_U-boot

Makefile源码分析-Uboot

作者:李想

创建时间:2010-03-20

更新时间:2010-07-08

https://www.sodocs.net/doc/de14855479.html,/User/lvembededsys/Article/4355_1.htm

https://www.sodocs.net/doc/de14855479.html,/BoySKung/archive/2008/11/03/3211988.aspx

U-boot版本:u-boot-2009.08

一、总体介绍

这里主要涉及到如下几个文件:

主目录中的Makfile、mkconfig、config.mk以及各子目录中的Makefile。

首先大概介绍一下这几个文件:

1、主目录中的Makefile是对整个工程的编译链接规则进行了描述。

2、子目录中的Makfile主要是编译一些源文件并进行归档,生成一些静态库。

3、主目录中的config.mk定义了主目录和子目录makefile通用的变量。

4、主目录中的Mkconfig是个脚本文件,负责对主目录中makefile进行配置的文件。创建一些符号链接,并在include目录下创建了两个文件:config.mk和config.h。config.mk 包含了uboot运行的环境,包括体系结构、处理器和板子。config.h中指明了板子相关的配置头文件。

二、顶层Makefile分析

以smdk2410板为例,编译的过程分两部:

# make smdk2410_config

# make (或make all)

1、定义和输出3个变量:HOSTARCH(主机体系结构),HOSTOS(主机操作系统),SHELL

HOSTARCH := $(shell uname -m | \

sed -e s/i.86/i386/ \

-e s/sun4u/sparc64/ \

-e s/arm.*/arm/ \

-e s/sa110/arm/ \

-e s/powerpc/ppc/ \

-e s/ppc64/ppc/ \

-e s/macppc/ppc/)

HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \

sed -e 's/\(cygwin\).*/cygwin/')

SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \

else if [ -x /bin/bash ]; then echo /bin/bash; \

else echo sh; fi; fi)

export HOSTARCH HOSTOS SHELL

2、Makefile中定义了源码及生成的目标文件存放的目录,目标文件存放目录BUILD_DIR 可以通过make O=dir 指定。如果没有指定,则设定为源码顶层目录。一般编译的时候不指定输出目录,则BUILD_DIR为空。其它目录变量定义如下:

#OBJTREE和LNDIR为存放生成文件的目录,TOPDIR与SRCTREE为源码所在目录

OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))

SRCTREE := $(CURDIR)

TOPDIR := $(SRCTREE)

LNDIR := $(OBJTREE)

export TOPDIR SRCTREE OBJTREE

3、定义变量MKCONFIG:这个变量指向一个脚本,即顶层目录的mkconfig。

MKCONFIG := $(SRCTREE)/mkconfig

export MKCONFIG

在编译U-BOOT之前,先要执行

# make smdk2410_config

smdk2410_config是Makefile的一个目标,定义如下:

smdk2410_config : unconfig

@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 samsung s3c24x0

unconfig::

@rm -f $(obj)include/config.h $(obj)include/config.mk \

$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp

显然,执行# make smdk2410_config时,先执行unconfig目标,unconfig下面的命令清理上一次执行make *_config时生成的头文件和makefile的包含文件。主要是include/config.h 和include/config.mk文件。然后才执行命令:

@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 samsung s3c24x0 MKCONFIG 是顶层目录下的mkcofig脚本文件,后面是传入的六个参数:

$1:$(@:_config=)获得目标板,即smdk2410_config中去掉”_config”的部分smdk2410.

$2:arm CPU的架构(ARCH)

$3:arm920t CPU的类型(CPU)

$4:smdk2410 对应在board目录下建立新的开发板项目的目录(BOARD)$5:samsung:新开发板项目目录的上级目录,如直接在board下建立新的开发板项目的目录,则这里就为NULL(VENDER)

$6:s3c24x0:CPU型号(SOC)

★下面分析mkconfig源代码,对于smdk2410_config而言,mkconfig主要做三件事:#默认创建新的配置文件

APPEND=no # Default: Create new config file

# $#是输入参数的个数,所带参数中没有“--”,”-a”,”-n”所以不执行while这段

while [ $# -gt 0 ] ; do #当参数个数大于0时

case "$1" in #检测第一个参数的值

--) shift ; break ;; #参数左移一个,然后退出

-a) shift ; APPEND=yes ;; #参数左移一个,设APPEND的值

-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;

*) break ;; #不是以上的值就退出

esac

done

#赋值给BOARD_NAME

[ "${BOARD_NAME}" ] || BOARD_NAME="$1"

#参数个数小于4或大于6,退出

[ $# -lt 4 ] && exit 1

[ $# -gt 6 ] && exit 1

(1)在include文件夹下建立相应的文件(夹)软连接:

cd ./include

rm -f asm

ln -s asm-$2 asm

rm -f asm-$2/arch

if [ -z "$6" -o "$6" = "NULL" ] ; then

ln -s ${LNPREFIX}arch-$3 asm-$2/arch

else

ln -s ${LNPREFIX}arch-$6 asm-$2/arch

fi

if [ "$2" = "arm" ] ; then

rm -f asm-$2/proc

ln -s ${LNPREFIX}proc-armv asm-$2/proc

fi

rm -f asm-$2/arch

ln -s arch-$3 asm-$2/arch

(2)生成Makefile包含文件include/config.mk,内容很简单,定义了五个变量:echo "ARCH = $2" > config.mk

echo "CPU = $3" >> config.mk

echo "BOARD = $4" >> config.mk

[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk

[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk

(3)创建一个头文件include/config.h

#根据APPEND的值决定是否创建新的文件

if [ "$APPEND" = "yes" ] # Append to existing config file

then

echo >> config.h

else

> config.h # Create new config file

fi

#下面两行向config.h中添加内容

echo "/* Automatically generated - do not edit */" >>config.h

echo "#include " >>config.h #这里包含了板子相关的配置文件

echo "#include " >>config.h #?

4、判断$(obj)include/config.mk是否存在

ifeq ($(obj)include/config.mk,$(wildcard $(obj)include/config.mk))

#'wildcard' 的函数,它有一个参数,功能是展开成一列所有符合由其参数描述的文件名,

#文件间以空格间隔。

5、包含include/autoconf.mk.dep和include/autoconf.mk

# Include autoconf.mk before config.mk so that the config options are available

# to all top level build files. We need the dummy all: target to prevent the

# dependency target in autoconf.mk.dep from being the default.

all:

sinclude $(obj)include/autoconf.mk.dep

sinclude $(obj)include/autoconf.mk

6、包含include/config.mk,其实也就相当于在Makefile里定义了上面五个变量而已。

# load ARCH, BOARD, and CPU configuration

include $(obj)include/config.mk

export ARCH CPU BOARD VENDOR SOC

7、此处不做任何修改,相应体系结构的交叉编译器已在/lib_$(ARCH)/config.mk中定义

# set default to nothing for native builds,

# CROSS_COMPILE is defined in /lib_$(ARCH)/config.mk

ifeq ($(HOSTARCH),$(ARCH))

CROSS_COMPILE ?=

Endif

8、包含顶层目录下的config.mk(里面主要定义了交叉编译器及选项和编译规则)

一般每个子目录中的Makefile都要包含这个config.mk,因为这个config.mk里面定义了一些变量(主要是一些交叉编译器及选项和编译规则),这些变量对这些子目录的Makefile是有意义的,如$obj, $src等都定义了子目录的目标文件和源码路径,这些是依据CURDIR变量来推算的,因为子目录一般都是由父目录掉用make -C过来的,当进入

子目录开始make后,CURDIR自动就成为了当前的working dir,因此就可以推算出当前子目录的路径。另外config.mk还将不同ARCH、CPU、SOC、BOARD目录下的原有的config.mk包含进来。

# load other configuration

include $(TOPDIR)/config.mk

★下面分析config.mk源代码

# clean the slate ...

PLATFORM_RELFLAGS =

PLATFORM_CPPFLAGS =

PLATFORM_LDFLAGS =

# Option checker (courtesy linux kernel) to ensure

# only supported compiler options are used

cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \

> /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)

(1)定义交叉编译链工具

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

(2)包含include/autoconf.mk

# Load generated board configuration

sinclude $(OBJTREE)/include/autoconf.mk

(3)包含体系,开发板,CPU特定的规则文件

# ARM:设置CROSS_COMPILE、PLATFORM_CPPFLAGS和LDSCRIPT变量

ifdef ARCH

sinclude $(TOPDIR)/lib_$(ARCH)/config.mk

endif

# arm920t:设置PLATFORM_RELFLAGS和PLATFORM_CPPFLAGS变量

ifdef CPU

sinclude $(TOPDIR)/cpu/$(CPU)/config.mk

Endif

# s3c24x0:实际上不存在cpu/arm920t/s3c24x0/config.mk

ifdef SOC

sinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk

endif

# smdk2410:指定特定板子的镜像连接时的内存基地址,TEXT_BASE = 0x33F80000 ifdef VENDOR

BOARDDIR = $(VENDOR)/$(BOARD)

else

BOARDDIR = $(BOARD)

endif

ifdef BOARD

sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk

endif

(4)定义AR选项ARFLAGS,调试选项DBGFLAGS,优化选项OPTFLAGS

预处理选项CPPFLAGS,C编译器选项CFLAGS,连接选项LDFLAGS等

#定义AR选项ARFLAGS

ifneq (,$(findstring s,$(MAKEFLAGS)))

ARFLAGS = cr

else

ARFLAGS = crv

Endif

#定义RELFLAGS、调试选项DBGFLAGS、优化选项OPTFLAGS

RELFLAGS= $(PLATFORM_RELFLAGS)

DBGFLAGS= -g # -DDEBUG

OPTFLAGS= -Os #-fomit-frame-pointer

#LDSCRIPT已经在lib_$(ARCH)/config.mk定义,此处代码不执行

ifndef LDSCRIPT

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

OBJCFLAGS += --gap-fill=0xff

#定义预处理选项CPPFLAGS

gccincdir := $(shell $(CC) -print-file-name=include)

CPPFLAGS := $(DBGFLAGS) $(OPTFLAGS) $(RELFLAGS) \ -D__KERNEL__

ifneq ($(TEXT_BASE),)

CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) # 预编译时指定生成代码基地址endif

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)

#C编译器选项CFLAGS

ifdef BUILD_TAG

CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes \

-DBUILD_TAG='"$(BUILD_TAG)"'

else

CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes

endif

CFLAGS += $(call cc-option,-fno-stack-protector)

#定义汇编器选项AFLAGS

AFLAGS_DEBUG :=

AFLAGS := $(AFLAGS_DEBUG) -D__ASSEMBLY__ $(CPPFLAGS)

#定义连接选项LDFLAGS

LDFLAGS += -Bstatic -T $(obj)u-boot.lds $(PLATFORM_LDFLAGS)

ifneq ($(TEXT_BASE),)

LDFLAGS += -Ttext $(TEXT_BASE) #链接时指定生成代码基地址为TEXT_BASE endif

(5)输出config.mk定义的变量

export HOSTCC HOSTCFLAGS CROSS_COMPILE \

AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP MAKE export TEXT_BASE PLATFORM_CPPFLAGS PLATFORM_RELFLAGS \

CPPFLAGS CFLAGS AFLAGS

(6)指定基本的编译规则

# Allow boards to use custom optimize flags on a per dir/file basis

BCURDIR := $(notdir $(CURDIR))

$(obj)%.s: %.S

$(CPP) $(AFLAGS) $(AFLAGS_$(@F)) $(AFLAGS_$(BCURDIR)) -o $@ $< $(obj)%.o: %.S

$(CC) $(AFLAGS) $(AFLAGS_$(@F)) $(AFLAGS_$(BCURDIR)) -o $@ $< -c $(obj)%.o: %.c

$(CC) $(CFLAGS) $(CFLAGS_$(@F)) $(CFLAGS_$(BCURDIR)) -o $@ $< -c $(obj)%.i: %.c

$(CPP) $(CFLAGS) $(CFLAGS_$(@F)) $(CFLAGS_$(BCURDIR)) -o $@ $< -c $(obj)%.s: %.c

$(CC) $(CFLAGS) $(CFLAGS_$(@F)) $(CFLAGS_$(BCURDIR)) -o $@ $< -c -S

9、返回Makefile,介绍U-boot需要的目标文件和库文件

OBJS = cpu/$(CPU)/start.o # 必须放在第一个

OBJS := $(addprefix $(obj),$(OBJS))

# 以下是u-boot需要的库文件

LIBS = lib_generic/libgeneric.a

LIBS += lib_generic/lzma/liblzma.a

LIBS += lib_generic/lzo/liblzo.a

LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo \ "board/$(VENDOR)/common/lib$(VENDOR).a"; fi)

LIBS += cpu/$(CPU)/lib$(CPU).a

ifdef SOC

LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a

endif

LIBS += lib_$(ARCH)/lib$(ARCH).a

LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a \

fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a \

fs/yaffs2/libyaffs2.a fs/ubifs/libubifs.a

LIBS += net/libnet.a

LIBS += disk/libdisk.a

LIBS += drivers/bios_emulator/libatibiosemu.a

LIBS += drivers/block/libblock.a

LIBS += drivers/dma/libdma.a

LIBS += drivers/fpga/libfpga.a

LIBS += drivers/gpio/libgpio.a

LIBS += drivers/hwmon/libhwmon.a

LIBS += drivers/i2c/libi2c.a

LIBS += drivers/input/libinput.a

LIBS += drivers/misc/libmisc.a

LIBS += drivers/mmc/libmmc.a

LIBS += drivers/mtd/libmtd.a

LIBS += drivers/mtd/nand/libnand.a

LIBS += drivers/mtd/onenand/libonenand.a

LIBS += drivers/mtd/ubi/libubi.a

LIBS += drivers/mtd/spi/libspi_flash.a

LIBS += drivers/net/libnet.a

LIBS += drivers/net/phy/libphy.a

LIBS += drivers/net/sk98lin/libsk98lin.a

LIBS += drivers/pci/libpci.a

LIBS += drivers/pcmcia/libpcmcia.a

LIBS += drivers/power/libpower.a

LIBS += drivers/spi/libspi.a

LIBS += drivers/rtc/librtc.a

LIBS += drivers/serial/libserial.a

LIBS += drivers/twserial/libtws.a

LIBS += drivers/usb/gadget/libusb_gadget.a

LIBS += drivers/usb/host/libusb_host.a

LIBS += drivers/usb/musb/libusb_musb.a

LIBS += drivers/video/libvideo.a

LIBS += drivers/watchdog/libwatchdog.a

LIBS += common/libcommon.a

LIBS += libfdt/libfdt.a

LIBS += api/libapi.a

LIBS += post/libpost.a

LIBS := $(addprefix $(obj),$(LIBS))

.PHONY : $(LIBS) $(TIMESTAMP_FILE) $(VERSION_FILE)

LIBBOARD = board/$(BOARDDIR)/lib$(BOARD).a

LIBBOARD := $(addprefix $(obj),$(LIBBOARD))

根据上面的include/config.mk文件定义的ARCH、CPU、BOARD、SOC、VENDOR 这些变量。硬件平台依赖的目录文件可以根据这些定义来确定。SMDK2410平台相关目录及对应生成的库文件如下。

board/samsung/smdk2410/ :库文件board/samsung/smdk2410/libsmdk2410.a

cpu/arm920t/ :库文件cpu/arm920t/libarm920t.a

cpu/arm920t/s3c24x0/ :库文件cpu/arm920t/s3c24x0/libs3c24x0.a

lib_arm/ :库文件lib_arm/libarm.a

下面的代码暂时未做细致分析

# Add GCC lib

ifdef USE_PRIVATE_LIBGCC

ifeq ("$(USE_PRIVATE_LIBGCC)", "yes")

PLATFORM_LIBGCC = -L $(OBJTREE)/lib_$(ARCH) -lgcc

else

PLATFORM_LIBGCC = -L $(USE_PRIVATE_LIBGCC) -lgcc

endif

else

PLATFORM_LIBGCC = -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc

endif

PLATFORM_LIBS += $(PLATFORM_LIBGCC)

export PLATFORM_LIBS

# Special flags for CPP when processing the linker script.

# Pass the version down so we can handle backwards compatibility

# on the fly.

LDPPFLAGS += \

-include $(TOPDIR)/include/u-boot/u-boot.lds.h \

$(shell $(LD) --version | \

sed -ne 's/GNU ld version \([0-9][0-9]*\)\.\([0-9][0-9]*\).*/-DLD_MAJOR=\1 -DLD_MINOR=\2/p')

ifeq ($(CONFIG_NAND_U_BOOT),y)

NAND_SPL = nand_spl

U_BOOT_NAND = $(obj)u-boot-nand.bin

endif

ifeq ($(CONFIG_ONENAND_U_BOOT),y)

ONENAND_IPL = onenand_ipl

U_BOOT_ONENAND = $(obj)u-boot-onenand.bin

endif

__OBJS := $(subst $(obj),,$(OBJS))

__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))

10、各种镜像文件的生成,主要介绍u-boot的生成规则

# Always append ALL so that arch config.mk's can add custom ones

ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) \ $(U_BOOT_ONENAND)

all: $(ALL)

$(obj)u-boot.hex: $(obj)u-boot

$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@

$(obj)u-boot.srec: $(obj)u-boot

$(OBJCOPY) -O srec $< $@

$(obj)u-boot.bin: $(obj)u-boot

$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@

$(obj)u-boot.ldr: $(obj)u-boot

$(obj)tools/envcrc --binary > $(obj)env-ldr.o

$(LDR) -T $(CONFIG_BFIN_CPU) -c $@ $< $(LDR_FLAGS)

$(obj)u-boot.ldr.hex: $(obj)u-boot.ldr

$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ -I binary

$(obj)u-boot.ldr.srec: $(obj)u-boot.ldr

$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@ -I binary

$(obj)u-boot.img: $(obj)u-boot.bin

./tools/mkimage -A $(ARCH) -T firmware -C none \

-a $(TEXT_BASE) -e 0 \

-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \

sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \

-d $< $@

$(obj)u-boot.sha1: $(obj)u-boot.bin

$(obj)tools/ubsha1 $(obj)u-boot.bin

$(obj)u-boot.dis: $(obj)u-boot

$(OBJDUMP) -d $< > $@

$(obj)System.map: $(obj)u-boot

@$(call SYSTEM_MAP,$<) > $(obj)System.map

# u-boot镜像文件生成规则

GEN_UBOOT = \

UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \

sed -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\

cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \

--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \

-Map u-boot.map -o u-boot

$(obj)u-boot: depend $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) \

$(obj)u-boot.lds

$(GEN_UBOOT)

(1)依赖目标depend:生成各个子目录的.depend文件,.depend列出当前子目录下每个目标文件对应的依赖文件,对应子目录下的Makefile文件中都会包含此文件。生成方法暂时不清楚,调用每个子目录的make _depend。注意$(obj)include/autoconf.mk这个依赖,后面会详细分析。

depend dep: $(TIMESTAMP_FILE) $(VERSION_FILE) $(obj)include/autoconf.mk for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done

(2)伪目标SUBDIRS:执行tools ,examples 子目录下面的make文件。

SUBDIRS = tools \

examples/standalone \

examples/api

.PHONY : $(SUBDIRS)

$(SUBDIRS): depend

$(MAKE) -C $@ all

(3)依赖目标$(OBJS):生成cpu/start.o

$(OBJS): d epend

$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))

(4)依赖目标$(LIBS):这个目标太多,都是每个子目录的库文件*.a ,通过执行相应子目录下的make来完成。

$(LIBS): depend $(SUBDIRS)

$(MAKE) -C $(dir $(subst $(obj),,$@))

$(LIBBOARD): depend $(LIBS)

$(MAKE) -C $(dir $(subst $(obj),,$@))

(5)依赖目标$(LDSCRIPT):连接脚本文件在lib_arm/config.mk中定义,“LDSCRIPT := $(SRCTREE)/cpu/$(CPU)/u-boot.lds”

$(LDSCRIPT): depend

$(MAKE) -C $(dir $@) $(notdir $@) # 编译u-boot.lds文件

★u-boot.lds文件内容如下:

# 指定输出可执行文件是elf格式,32位ARM指令,小端

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

# 指定输出文件的平台体系是ARM

OUTPUT_ARCH(arm)

# 指定可执行映像文件的起始段的段名是_start

ENTRY(_start)

SECTIONS

{

# 指定可执行image文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置。

# 必须使编译器知道这个地址,通常都是修改此处来完成。

. = 0x00000000;

. = ALIGN(4); # 字对齐,即就是4字节对齐

.text : # 代码段

{

cpu/arm920t/start.o (.text) # 代码段第一部分代码,

#Nand boot时需要在此指明第二部分代码*(.text) # 其余代码段

}

. = ALIGN(4);

.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } # 只读数据段

. = ALIGN(4);

.data : { *(.data) } # 随机读写数据段

. = ALIGN(4);

.got : { *(.got) } # 指定got段, got段式是uboot自定义的一个段, 非标准段

. = .;

# 把__u_boot_cmd_start赋值为当前位置, 即起始位置。

__u_boot_cmd_start = .;

# u_boot_cmd段,所有的u-boot命令相关的定义都放在这个位置,因为每个命令定义等长,

# 所以只要以__u_boot_cmd_start为起始地址进行查找就可以很快查找到某一个命令的定

# 义,并依据定义的命# 令指针调用相应的函数进行处理用户的任务。

.u_boot_cmd : { *(.u_boot_cmd) }

# u_boot_cmd段结束位置,由此可以看出,这段空间的长度并没有严格限制,用户可以添加

# 一些u-boot的命令,最终都会在连接是存放在这个位置。

__u_boot_cmd_end = .;

. = ALIGN(4);

# 把__bss_start赋值为当前位置,即bss段的开始位置。

__bss_start = .;

# 指定bss段,这里NOLOAD的意思是这段不需装载,仅在执行域中才会有这段。

.bss (NOLOAD) : { *(.bss) . = ALIGN(4); }

# 把_end赋值为当前位置,即bss段的结束位置

_end = .;

}

(6)执行连接命令:其实就是把start.o和各个子目录makefile生成的库文件按照LDFLAGS连接在一起,生成ELF文件u-boot 和连接时内存分配图文件u-boot.map。

cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \

--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \

-Map u-boot.map -o u-boot

11、生成include/autoconf.mk文件。

其实这里会生成两个文件autoconf.mk and autoconf.mk.dep:

autoconf.mk.dep:autoconf.mk的依赖文件,包含common.h依赖的所有的文件(基本是一些头文件,其中包括include/config.h)以及common.h本身。此依赖文件只被顶层Makefile包含,来决定什么时候更新autoconf.mk。

autoconf.mk:每个makefile都要包含此文件。它的生成是通过将include/common.h 中带CONFIG_的宏(即用户自己定义的宏)筛选出来得到的,同时以

autoconf.mk.dep为依赖文件。

common.h的依赖的所有的文件,包括common.h都被写入include/autoconf.mk.dep 文件。这样include/autoconf.mk依赖于common.h以及common.h中的一些依赖,而接下来的一些要被编译的target有全都依赖于include/autoconf.mk,因此,一旦common.h有所修改,全部都的重新编译。

$(obj)include/autoconf.mk.dep: $(obj)include/config.h include/common.h @$(XECHO) Generating $@ ; \

set -e ; \

: Generate the dependancies ; \

$(CC) -x c -DDO_DEPS_ONLY -M $(HOSTCFLAGS) $(CPPFLAGS) \

-MQ $(obj)include/autoconf.mk include/common.h > $@

$(obj)include/autoconf.mk: $(obj)include/config.h

@$(XECHO) Generating $@ ; \

set -e ; \

: Extract the config macros ; \

$(CPP) $(CFLAGS) -DDO_DEPS_ONLY -dM include/common.h | \

sed -n -f tools/scripts/define2mk.sed > $@.tmp && \

mv $@.tmp $@

12、最后是是各种不同的开发板的*_config:目标的定义和一些伪目标的定义,如clean。

三、各子目录的makefile文件

主要是生成*.o文件然后执行AR生成对应的库文件,详细分析在具体移植过程中。

四、u-boot Makefile总结

概括起来,工程的编译流程也就是通过执行执行一个make *_config传入ARCH,CPU,BOARD,VENDOR、SOC参数,mkconfig根据参数将include头文件夹相应的头文件夹连接好,生成config.h。然后执行make分别调用各子目录的makefile 生成所有的obj文件和obj库文件*.a. 最后连接所有目标文件,生成镜像。不同格式的镜像都是调用相应工具由elf镜像直接或者间接生成的。

手动建立makefile简单实例解析

手动建立makefile简单实例解析 假设我们有一个程序由5个文件组成,源代码如下:/*main.c*/ #include "mytool1.h" #include "mytool2.h" int main() { mytool1_print("hello mytool1!"); mytool2_print("hello mytool2!"); return 0; } /*mytool1.c*/ #include "mytool1.h" #include void mytool1_print(char *print_str) { printf("This is mytool1 print : %s ",print_str); } /*mytool1.h*/ #ifndef _MYTOOL_1_H #define _MYTOOL_1_H void mytool1_print(char *print_str); #endif /*mytool2.c*/ #include "mytool2.h" #include void mytool2_print(char *print_str) { printf("This is mytool2 print : %s ",print_str); }

/*mytool2.h*/ #ifndef _MYTOOL_2_H #define _MYTOOL_2_H void mytool2_print(char *print_str); #endif 首先了解一下make和Makefile。GNU make是一个工程管理器,它可以管理较多的文件。我所使用的RedHat 9.0的make版本为GNU Make version 3.79.1。使用make的最大好处就是实现了“自动化编译”。如果有一个上百个文件的代码构成的项目,其中一个或者几个文件进行了修改,make就能够自动识别更新了的文件代码,不需要输入冗长的命令行就可以完成最后的编译工作。make执行时,自动寻找Makefile(makefile)文件,然后执行编译工作。所以我们需要编写Makefile文件,这样可以提高实际项目的工作效率。 在一个Makefile中通常包含下面内容: 1、需要由make工具创建的目标体(target),通常是目标文件或可执行文件。 2、要创建的目标体所依赖的文件(dependency_file)。 3、创建每个目标体时需要运行的命令(command)。 格式如下: target:dependency_files command target:规则的目标。通常是程序中间或者最后需要生成的文件名,可以是.o文件、也可以是最后的可执行程序的文件名。另外,目标也可以是一个make执行的动作的名称,如目标“clean”,这样的目标称为“伪目标”。 dependency_files:规则的依赖。生成规则目标所需要的文件名列表。通常一个目标依赖于一个或者多个文件。 command:规则的命令行。是make程序所有执行的动作(任意的shell命令或者可在shell下执行的程序)。一个规则可以有多个命令行,每一条命令占一行。注意:每一个命令行必须以[Tab]字符开始,[Tab]字符告诉make此行是一个命令行。make按照命令完成相应的动作。这也是书写Makefile中容易产生,而且比较隐蔽的错误。命令就是在任何一个目标的依赖文件发生变化后重建目标的动作描述。一个目标可以没有依赖而只有动作(指定的命令)。比如Makefile中的目标“clean”,此目标没有依赖,只有命令。它所指定的命令用来删除make过程产生的中间文件(清理工作)。 在Makefile中“规则”就是描述在什么情况下、如何重建规则的目标文件,通常规则

UBoot移植详解

u-boot 移植步骤详解 1 U-Boot简介 U-Boot,全称Universal Boot Loader,是遵循GPL条款的开放源码项目。从FADSROM、8xxROM、PPCBOOT逐步发展演化而来。其源码目录、编译形式与Linux内核很相似,事实上,不少U-Boot源码就是相应的Linux内核源程序的简化,尤其是一些设备的驱动程序,这从U-Boot源码的注释中能体现这一点。但是U-Boot不仅仅支持嵌入式Linux 系统的引导,当前,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS嵌入式操作系统。其目前要支持的目标操作系统是OpenBSD, NetBSD, FreeBSD,4.4BSD, Linux, SVR4, Esix, Solaris, Irix, SCO, Dell, NCR, VxWorks, LynxOS, pSOS, QNX, RTEMS, ARTOS。这是U-Boot中Universal的一层含义,另外一层含义则是U-Boot除了支持PowerPC系列的处理器外,还能支持MIPS、x86、ARM、NIOS、XScale等诸多常用系列的处理器。这两个特点正是U-Boot项目的开发目标,即支持尽可能多的嵌入式处理器和嵌入式操作系统。就目前来看,U-Boot对PowerPC系列处理器支持最为丰富,对Linux的支持最完善。其它系列的处理器和操作系统基本是在2002年11 月PPCBOOT 改名为U-Boot后逐步扩充的。从PPCBOOT向U-Boot的顺利过渡,很大程度上归功于U-Boot的维护人德国DENX软件工程中心Wolfgang Denk[以下简称W.D]本人精湛专业水平和持着不懈的努力。当前,U-Boot项目正在他的领军之下,众多有志于开放源码BOOT LOADER移植工作的嵌入式开发人员正如火如荼地将各个不同系列嵌入式处理器的移植工作不断展开和深入,以支持更多的嵌入式操作系统的装载与引导。 选择U-Boot的理由: ①开放源码; ②支持多种嵌入式操作系统内核,如Linux、NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS; ③支持多个处理器系列,如PowerPC、ARM、x86、MIPS、XScale; ④较高的可靠性和稳定性; ④较高的可靠性和稳定性; ⑤高度灵活的功能设置,适合U-Boot调试、操作系统不同引导要求、产品发布等; ⑥丰富的设备驱动源码,如串口、以太网、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、键盘等; ⑦较为丰富的开发调试文档与强大的网络技术支持; 2 U-Boot主要目录结构 - board 目标板相关文件,主要包含SDRAM、FLASH驱动; - common 独立于处理器体系结构的通用代码,如内存大小探测与故障检测;

linux驱动的Makefile分析

第6行,判断KERNELRELEASE是否为空,该变量是描述内核版本的字符串。只有执行make命令的当前目录为内核源代码目录时,该变量才不为空字符。 第7、8行定义了KERNELDIR和PWD变量。KERNELDIR是内核路径变量,PWD是由执行pwd命令得到的当前模块路径。 第11行make的语法是”Make –C 内核路径M=模块路径modules”,该语法会执行内核模块的编译 第13行是将模块安装到对应的路径中,当在命令执行make modules_install时,执行该命令,其他时候不执行 第24行,意思是将hello.o编译成hello.ko模块。如果要编译其他模块时,只要将hello.o中的hello改成模块的文件名就可以了 Makefile的执行过程: 执行make命令后,将进入Makefile文件。此时KERNELRELEASE变量为空,此时是第一次进入Makefile文件。当执行完变量赋值代码后,会根据make参数执行不同的逻辑。 如下: make modules_install 命令,将执行13、15行将模块安装到操作系统中。 make clean命令,会删除目录中的所有临时文件。 make命令,会执行10、11行编译模块。首先$(MAKE) -C $(KERNELDIR) M=$(PWD) modules 中的-C $(KERNELDIR)选项,会使编译器进入内核源码目录/home/zzc/linux-2.6.31,读取Makefile文件,从中得到一些信息,例如变量KERNELRELEASE将在这里赋值。当内核源码目录中的Makefile文件读取完成后,编译器会根据选项M=$(PWD)第二次进入模块所在的目录,并再一次执行Makefie文件。当第二次执行Makefile文件时,变量KERNELRELEASE

u-boot启动分析

背景: Board →ar7240(ap93) Cpu →mips 1、首先弄清楚什么是u-boot Uboot是德国DENX小组的开发,它用于多种嵌入式CPU的bootloader程序, uboot不仅支持嵌入式linux系统的引导,当前,它还支持其他的很多嵌入式操作系统。 除了PowerPC系列,还支持MIPS,x86,ARM,NIOS,XScale。 2、下载完uboot后解压,在根目录下,有如下重要的信息(目录或者文件): 以下为为每个目录的说明: Board:和一些已有开发板有关的文件。每一个开发板都以一个子目录出现在当前目录中,子目录存放和开发板相关的配置文件。它的每个子文件夹里都有如下文件(以ar7240/ap93为例): Makefile Config.mk Ap93.c 和板子相关的代码 Flash.c Flash操作代码 u-boot.lds 对应的链接文件 common:实现uboot命令行下支持的命令,每一条命令都对应一个文件。例如bootm命令对应就是cmd_bootm.c cpu:与特定CPU架构相关目录,每一款Uboot下支持的CPU在该目录下对应一个子目录,比如有子目录mips等。它的每个子文件夹里都有入下文件: Makefile Config.mk Cpu.c 和处理器相关的代码s Interrupts.c 中断处理代码 Serial.c 串口初始化代码 Start.s 全局开始启动代码 Disk:对磁盘的支持

Doc:文档目录。Uboot有非常完善的文档。 Drivers:Uboot支持的设备驱动程序都放在该目录,比如网卡,支持CFI的Flash,串口和USB等。 Fs:支持的文件系统,Uboot现在支持cramfs、fat、fdos、jffs2和registerfs。 Include:Uboot使用的头文件,还有对各种硬件平台支持的汇编文件,系统的配置文件和对文件系统支持的文件。该目下configs目录有与开发板相关的配置文件,如 ar7240_soc.h。该目录下的asm目录有与CPU体系结构相关的头文件,比如说mips 对应的有asm-mips。 Lib_xxx:与体系结构相关的库文件。如与ARM相关的库放在lib_arm中。 Net:与网络协议栈相关的代码,BOOTP协议、TFTP协议、RARP协议和NFS文件系统的实现。 Tools:生成Uboot的工具,如:mkimage等等。 3、mips架构u-boot启动流程 u-boot的启动过程大致做如下工作: 1、cpu初始化 2、时钟、串口、内存(ddr ram)初始化 3、内存划分、分配栈、数据、配置参数、以及u-boot代码在内存中的位置。 4、对u-boot代码作relocate 5、初始化malloc、flash、pci以及外设(比如,网口) 6、进入命令行或者直接启动Linux kernel 刚一开始由于参考网上代码,我一个劲的对基于smdk2410的板子,arm926ejs的cpu看了N 久,启动过程和这个大致相同。 整个启动中要涉及到四个文件: Start.S →cpu/mips/start.S Cache.S →cpu/mips/cache.S Lowlevel_init.S →board/ar7240/common/lowlevel_init.S Board.c →lib_mips/board.c 整个启动过程分为两个阶段来看: Stage1:系统上电后通过汇编执行代码 Stage2:通过一些列设置搭建了C环境,通过汇编指令跳转到C语言执行. Stage1: 程序从Start.S的_start开始执行.(至于为什么,参考u-boot.lds分析.doc) 先查看start.S文件吧!~ 从_start标记开始会看到一长串莫名奇妙的代码:

LINUX编程 Makefile中的变量详解应用

第六章:Makefile中的变量 -------------------------------------------------------------------------------- 在Makefile中,变量就是一个名字(像是C语言中的宏),代表一个文本字符串(变量的值)。在Makefile的目标、依赖、命令中引用一个变量的地方,变量会被它的值所取代(与C语言中宏引用的方式相同,因此其他版本的make也把变量称之为“宏”)。在Makefile中变量的特征有以下几点: 1. Makefile中变量和函数的展开(除规则的命令行以外),是在make读取makefile文件时进行的,这里的变量包括了使用“=”定义和使用指示符“define”定义的。 2. 变量可以用来代表一个文件名列表、编译选项列表、程序运行的选项参数列表、搜索源文件的目录列表、编译输出的目录列表和所有我们能够想到的事物。 3. 变量名是不包括“:”、“#”、“=”、前置空白和尾空白的任何字符串。需要注意的是,尽管在GNU make中没有对变量的命名有其它的限制,但定义一个包含除字母、数字和下划线以外的变量的做法也是不可取的,因为除字母、数字和下划线以外的其它字符可能会在以后的make版本中被赋予特殊含义,并且这样命名的变量对于一些shell来说不能作为环境变量使用。 4. 变量名是大小写敏感的。变量“foo”、“Foo”和“FOO”指的是三个不同的变量。Makefile 传统做法是变量名是全采用大写的方式。推荐的做法是在对于内部定义定义的一般变量(例如:目标文件列表objects)使用小写方式,而对于一些参数列表(例如:编译选项CFLAGS)采用大写方式,这并不是要求的。但需要强调一点:对于一个工程,所有Makefile中的变量命名应保持一种风格,否则会显得你是一个蹩脚的程序员(就像代码的变量命名风格一样)。 5. 另外有一些变量名只包含了一个或者很少的几个特殊的字符(符号)。称它们为自动化变量。像“$<”、“$@”、“$?”、“$*”等。 6.1 变量的引用 当我们定义了一个变量之后,就可以在Makefile的很多地方使用这个变量。变量的引用方式是:使用“$(VARIABLE_NAME)”或者“${ VARIABLE_NAME }”来引用一个变量的定义。例如:“$(foo) ”或者“${foo}”就是取变量“foo”的值。美元符号“$”在Makefile中有特殊的含义,所有在命令或者文件名中使用“$”时需要用两个美元符号“$$”来表示。对一个变量的引用可以在Makefile的任何上下文中,目标、依赖、命令、绝大多数指示符和新变量的赋值中。这里有一个例子,其中变量保存了所有.o文件的列表: objects = program.o foo.o utils.o program : $(objects) cc -o program $(objects)

UBoot源码分析1

?UBoot源码解析(一)

主要内容 ?分析UBoot是如何引导Linux内核 ?UBoot源码的一阶段解析

BootLoader概念?Boot Loader 就是在操作系统内核运行之前运行 的一段小程序。通过这段小程序,我们可以初始 化硬件设备、建立内存空间的映射图,从而将系 统的软硬件环境带到一个合适的状态,以便为最 终调用操作系统内核准备好正确的环境 ?通常,Boot Loader 是严重地依赖于硬件而实现 的,特别是在嵌入式世界。因此,在嵌入式世界 里建立一个通用的Boot Loader 几乎是不可能的。 尽管如此,我们仍然可以对Boot Loader 归纳出 一些通用的概念来,以指导用户特定的Boot Loader 设计与实现。

UBoot来源?U-Boot 是 Das U-Boot 的简称,其含义是 Universal Boot Loader,是遵循 GPL 条款的开放源码项目。最早德国 DENX 软件工程中心的 Wolfgang Denk 基于 8xxROM 和 FADSROM 的源码创建了 PPCBoot 工程项目,此后不断 添加处理器的支持。而后,Sysgo Gmbh 把 PPCBoot 移 植到 ARM 平台上,创建了 ARMBoot 工程项目。最终, 以 PPCBoot 工程和 ARMBoot 工程为基础,创建了 U- Boot 工程。 ?而今,U-Boot 作为一个主流、通用的 BootLoader,成功地被移植到包括 PowerPC、ARM、X86 、MIPS、NIOS、XScale 等主流体系结构上的百种开发板,成为功能最多、 灵活性最强,并且开发最积极的开源 BootLoader。目前。 U-Boot 仍然由 DENX 的 Wolfgang Denk 维护

嵌入式Linux之我行 史上最牛最详细的uboot移植,不看别后悔

嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(一) 嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤。一为总结经验,二希望能给想入门嵌入式Linux 的朋友提供方便。如有错误之处,谢请指正。 ?共享资源,欢迎转载:https://www.sodocs.net/doc/de14855479.html, 一、移植环境 ?主机:VMWare--Fedora 9 ?开发板:Mini2440--64MB Nand,Kernel:2.6.30.4 ?编译器:arm-linux-gcc-4.3.2.tgz ?u-boot:u-boot-2009.08.tar.bz2 二、移植步骤 本次移植的功能特点包括: ?支持Nand Flash读写 ?支持从Nor/Nand Flash启动 ?支持CS8900或者DM9000网卡 ?支持Yaffs文件系统 ?支持USB下载(还未实现) 1.了解u-boot主要的目录结构和启动流程,如下图。

u-boot的stage1代码通常放在cpu/xxxx/start.S文件中,他用汇编语言写成;u-boot的stage2代码通常放在lib_xxxx/board.c文件中,他用C语言写成。各个部分的流程图如下:

2. 建立自己的开发板项目并测试编译。 目前u-boot对很多CPU直接支持,可以查看board目录的一些子目录,如:board/samsung/目录下就是对三星一些ARM 处理器的支持,有smdk2400、smdk2410和smdk6400,但没有2440,所以我们就在这里建立自己的开发板项目。 1)因2440和2410的资源差不多,主频和外设有点差别,所以我们就在board/samsung/下建立自己开发板的项目,取名叫my2440 2)因2440和2410的资源差不多,所以就以2410项目的代码作为模板,以后再修改

iTop4412的uboot第一阶段

2 uboo t 源码分析 2.5.1.star t.S 2.5.1.star t.S 引入引入 2.5.1.1、u-boot.lds中找到start.S入口 (1)在C语言中整个项目的入口就是 main函数(这是 个.c文件的项目,第一个要分析的文件就是包含了C语言规定的),所以譬如说一 个有 main函数的那个文件。 10000 ( 2 方。ENTRY(_start)因此 _start 符号所在的文件就是整个程序的起始文 件, _sta rt 所在处的 代码就是整个程序的起始代码。 2.5.1.2、SourceInsight中如何找到 文件 (1)当前状况:我们知道在uboot中的1000多个文件中有一个符号 叫 _start,但是我们不知道 这个符号在哪个文件中。这种情况下要查找一个符号在所有项目中文件中的引用,要使用SourceInsight的搜索功能。 (2)start.s 在cpu/arm_cortexa9/start.s (3)然后进入start.S文件中,发现 个uboot的入口代码,就是第57 57行中就 是行。_sta rt 标号的定义处,于是乎我们就找到了整 2.5.1.3、SI中找文件技巧 (1)以上,找到了start.S文件,下面我们就从start.S文件开始分析uboot第一阶段。 (2)在SI中,如果我们知道我们要找的文件的名字,但是我们又不知道他在哪个目录下,我 们要怎样找到并打开这个文件?方法是在 SI中先打开右边的工程项目管理栏目,然后点击 最左边那个(这个是以文件为单位来浏览的),然后在上面输入栏中输入要找的文件的名 字。我们在输入的时候,SI在不断帮我们进行匹配,即使你不记得文件的全名只是大概记 得名字,也能帮助你找到你要找的文件。 2.5.2.start.S解析1 2.5.2.1、不简单的头文件包含

模块驱动笔记

驱动模块装载全纪录 模块驱动源代码demo.c如下: /* ************************************************************************* * *my first linux driver * ************************************************************************* */ //#ifndef_KERNEL_ //#define_KERNEL_/*缂..杩..??/ //#endif #ifdef MODULE/*浠ユā?..寮.?璇./ #include #ifdef CONFIG_DEVFS_FS #include/*璁惧??.欢绯荤?澶存.浠?/ #endif #include/*初始化相关头文件*/ #include/*与printk()等函数有关的头文件*/ #include/*与kmalloc()等函数有关的头文件*/ #include/*与文件系统有关的头文件*/ #include/*错误代码处理头文件error codes*/ #include/*数据类型头文件size_t*/ #include/*与进程调度相关的头文件*/ #include/*O_ACCMODE*/ #include/*COPY_TO_USER*/ #include/*cli(),*_flag*/ #define DEVICE_NAME"ZJD demo"/*该驱动的设备名*/ #define DEMORAW_MINOR1 #define DEMO_Devfs_path"demo/0"/*驱动目录*/ //#define demo_MAJOR254/*主设备号*/ //#define demo_MINOR0/*次设备号*/ static int demoMajor=0;

make_Makefile 结构分析

Makefile结构分析 -----uClinux (2.6.x内核)系统映像过程 刘江欧阳昭暐吕熙隆 1、源代码文件及目录构成 解压缩uClinux-dist-20070130.tar.gz压缩文件,在uClinux-dist原始子目录下主要有:config、Bin、linux-2.4.x、linux-2.6.x 、lib、tools、Include、user和vendors,以及文件Makefile。另外,在编译后生成子目录images和romfs,以及文件autoconfig.h、config.in和两个隐含文件:.config和.depend。 config子目录包含文件及下一级子目录,如 config.in、configure.help、Fixconfig、Makefile、 Mkconfig、Setconfig所有这些文件及子目录 Scripts均与系统配置有关; linux-2.6.x子目录是嵌入式操作系统 uClinux-2.6.x的核心目录,包括下一级子目录 arch、include、init、drivers、fs、ipc、kernel、 lib、Mm、scripts和关键文件Makefile、 rules.make,编译后还要生成新文件romfs.o、linux 和system.map;lib子目录为嵌入式操作系统提供 压缩和改进了的函数库支持;tools子目录包含 romfs-inst.sh文件,通过调用此文件,可以把目录 或文件加入到romfs子目录中;user子目录包含各 种驱动程序文件目录,根据用户的配置情况,不同的 驱动程序会被编译进最后形成的操作系统中; vendors子目录包括与特定硬件平台相关的分类目录 组。目录结构如图1所示。 Makefile的详细介绍情况在 uClinux-dist\linux-2.6.x\Documentation\kbuil d中,如图2所示。图1、目录结构即Linux 内核中的 Makefile 以及与 Makefile 直接相关的文件有:

Linux系统的Makefile和Kconfig及模块简介

Linux系统的Makefile、Kconfig和模块 1Makefile 1.1Makefile组织层次 Linux的Make体系由如下几部分组成: ?顶层Makefile 顶层Makefile通过读取配置文件,递归编译内核代码树的相关目录,从而产生两个重要的目标文件:vmlinux和模块。 ?内核相关Makefile 位于arch/$(ARCH) 目录下,为顶层Makefile提供与具体硬件体系结构相关的信息。?公共编译规则定义文件。 包括Makefile.build 、Makefile.clean、Makefile.lib、Makefile.host等文件组成。这些文件位于scripts目录中,定义了编译需要的公共的规则和定义。 ?内核配置文件 .config 通过调用make menuconfig或者make xconfig命令,用户可以选择需要的配置来生成期望的目标文件。 ?其他Makefile 主要为整个Makefile体系提供各自模块的目标文件定义,上层Makefile根据它所定义的目标来完成各自模块的编译。 1.2Makefile的使用 在编译内核之前,用户必须首先完成必要的配置。Linux内核提供了数不胜数的功能,支持众多的硬件体系结构,这就需要用户对将要生成的内核进行裁减。内核提供了多种不同的工具来简化内核的配置。 make config,字符界面下命令行工具,这个工具会依次遍历内核所有的配置项,要求用户进行逐项的选择配置。这个工具会耗费用户太多时间,除非万不得以(你的编译主机不支持其他配置工具)一般不建议使用。 make menuconfig,基于ncurse库编制的图形界面工具,一般台式机使用该工具。 make xconfig,基于X11的图形配置工具,一般用于工作站环境。

Makefile 语法分析

Makefile 语法分析第一部分 VERSION = 2 # 给变量VERSION赋值 PATCHLEVEL = 6 # 给变量PATCHLEVEL赋值 SUBLEVEL = 22 # 给变量SUBLEVEL赋值 EXTRAVERSION = .6 # 给变量EXTRAVERSION赋值 NAME = Holy Dancing Manatees, Batman! # 给变量NAME赋值 # *DOCUMENTATION* # To see a list of typical targets execute "make help" # More info can be located in ./README # Comments in this file are targeted only to the developer, do not # expect to learn how to build the kernel reading this file. # Do not: # o use make's built-in rules and variables # (this increases performance and avoid hard-to-debug behavour); # o print "Entering directory ..."; MAKEFLAGS += -rR --no-print-directory # 操作符“+=”的作用是给变量(“+=”前面的MAKEFLAGS)追加值。 # 如果变量(“+=”前面的MAKEFLAGS)之前没有定义过,那么,“+=”会自动变成“=”; # 如果前面有变量(“+=”前面的MAKEFLAGS)定义,那么“+=”会继承于前次操作的赋值符;# 如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符 # 在执行make时的命令行选项参数被通过变量“MAKEFLAGS”传递给子目录下的make程序。# 对于这个变量除非使用指示符“unexport”对它们进行声明,它们在整个make的执行过程中始终被自动的传递给所有的子make。 # 还有个特殊变量SHELL与MAKEFLAGS一样,默认情况(没有用“unexport”声明)下在整个make的执行过程中被自动的传递给所有的子make。 # # -rR --no-print-directory # -r disable the built-in impilict rules. # -R disable the built-in variable setttings. # --no-print-directory。 # We are using a recursive build, so we need to do a little thinking # to get the ordering right. # # Most importantly: sub-Makefiles should only ever modify files in # their own directory. If in some directory we have a dependency on # a file in another dir (which doesn't happen often, but it's often # unavoidable when linking the built-in.o targets which finally # turn into vmlinux), we will call a sub make in that other dir, and

AM335x uboot spl分析

AM335x uboot spl分析 芯片到uboot启动流程 ROM → SPL→ uboot.img 简介 在335x 中ROM code是第一级的bootlader。mpu上电后将会自动执行这里的代码,完成部分初始化和引导第二级的bootlader,第二级的bootlader引导第三级bootader,在 ti官方上对于第二级和第三级的bootlader由uboot提供。 SPL To unify all existing implementations for a secondary program loader (SPL) and to allow simply adding of new implementations this generic SPL framework has been created. With this framework almost all source files for a board can be reused. No code duplication or symlinking is necessary anymore. 1> Basic ARM initialization 2> UART console initialization 3> Clocks and DPLL locking (minimal) 4> SDRAM initialization 5> Mux (minimal) 6> BootDevice initialization(based on where we are booting from.MMC1/MMC2/Nand/Onenand) 7> Bootloading real u-boot from the BootDevice and passing control to it. uboot spl源代码分析 一、makefile分析 打开spl文件夹只有一个makefile 可见spl都是复用uboot原先的代码。 主要涉及的代码文件为u-boot-2011.09-psp04.06.00.03/arch/arm/cpu/armv7 u-boot-2011.09-psp04.06.00.03/arch/arm/lib u-boot-2011.09-psp04.06.00.03/drivers LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-spl.lds 这个为链接脚本 __image_copy_end _end 三、代码解析 __start 为程序开始(arch/arm/cpu/armv7/start.S) .globl _start 这是在定义u-boot的启动定义入口点,汇编程序的缺省入口是 start 标号,用户也可以在连接脚本文件中用ENTRY标志指明其它入口点。

linux设备驱动程序的hello模块编译过程

linux设备驱动程序的hello模块编译过程 今天把linux设备驱动程序(第三版)的第一个模块hello模块编译通过了,这个东西卡了我好长时间了,期间我又花了很多时间去看linux程序设计(第二版),终于今天机械性地完成了这个试验。 编译环境:虚拟机linux2.6.18内核,(如果内核不是2.6的,可以参考我的内核升级过程,另外一篇文章有详细记录) 源程序hello.c: ///////////////////////////////////////////////////////////////////// /////// #include #include #include MODULE_LICENSE("Dual BSD/GPL"); static int hello_init(void) //有的上面定义的是init_modules(void)是通不过编译的 { printk(KERN_ALERT "Hello, world\n"); return 0; } static void hello_exit(void) { printk(KERN_ALERT "Goodbye, world\n"); } module_init(hello_init); module_exit(hello_exit); ///////////////////////////////////////////////////////////////////// /// Makefile的内容: ifneq ($(KERNELRELEASE),) obj-m := hello.o else KDIR:=/lib/modules/$(shell uname -r)/build PWD:=$(shell pwd)

uboot版本文件结构

uboot版本文件结构的更新改变 分类:ARM2011-09-22 12:57 339人阅读评论(0) 收藏举报本来是开始分析uboot代码的,但是无论是教材还是网上资料都对于我最新下的uboot原码结构不同,对于还是小白的我不容易找到相应的文件,下面是uboot版本中文件组织结构的改变,,,,, u-boot版本情况 网站:http://ftp.denx.de/pub/u-boot/ 1、版本号变化: 2008年8月及以前 按版本号命名:u-boot-1.3.4.tar.bz2(2008年8月更新) 2008年8月以后均按日期命名。 目前最新版本:u-boot-2011.06.tar.bz2(2011年6月更新) 2、目录结构变化: u-boot目录结构主要经历过2次变化,u-boot版本第一次从u-boot-1.3.2开始发生变化,主要增加了api的内容;变化最大的是第二次,从2010.6版本开始。 u-boot-2010.03及以前版本 ├── api存放uboot提供的接口函数 ├── board根据不同开发板定制的代码,代码也不少 ├── common通用的代码,涵盖各个方面,已命令行处理为主 ├── cpu与体系结构相关的代码,uboot的重头戏 ├── disk磁盘分区相关代码 ├── doc文档,一堆README开头的文件 ├── drivers驱动,很丰富,每种类型的设备驱动占用一个子目录 ├── examples示例程序 ├── fs文件系统,支持嵌入式开发板常见的文件系统 ├── include头文件,已通用的头文件为主 ├── lib_【arch】与体系结构相关的通用库文件 ├── nand_spl NAND存储器相关代码 ├── net网络相关代码,小型的协议栈 ├── onenand_ipl

makefile 中文手册 第六章 _ Makefile中的变量

第六章:Makefile中的变量 在Makefile中,变量是一个名字(像是C语言中的宏),代表一个文本字符串(变量的值)。在Makefile的目标、依赖、命令中引用变量的地方,变量会被它的值所取代(与C语言中宏引用的方式相同,因此其他版本的make也把变量称之为“宏”)。在Makefile中变量有以下几个特征: 1.Makefile中变量和函数的展开(除规则命令行中的变量和函数以外),是在make读取makefile文件时 进行的,这里的变量包括了使用“=”定义和使用指示符“define”定义的。 2.变量可以用来代表一个文件名列表、编译选项列表、程序运行的选项参数列表、搜索源文件的目录列 表、编译输出的目录列表和所有我们能够想到的事物。 3.变量名是不包括“:”、“#”、“=”、前置空白和尾空白的任何字符串。需要注意的是,尽管在GNU make中没有对变量的命名有其它的限制,但定义一个包含除字母、数字和下划线以外的变量的做法也是不可取的,因为除字母、数字和下划线以外的其它字符可能会在make的后续版本中被赋予特殊含义,并且这样命名的变量对于一些shell来说是不能被作为环境变量来使用的。 4.变量名是大小写敏感的。变量“foo”、“Foo”和“FOO”指的是三个不同的变量。Makefile传统做 法是变量名是全采用大写的方式。推荐的做法是在对于内部定义定义的一般变量(例如:目标文件列表objects)使用小写方式,而对于一些参数列表(例如:编译选项CFLAGS)采用大写方式,但这并不是要求的。但需要强调一点:对于一个工程,所有Makefile中的变量命名应保持一种风格,否则会显得你是一个蹩脚的程序员(就像代码的变量命名风格一样)。 5.另外有一些变量名只包含了一个或者很少的几个特殊的字符(符号)。称它们为自动化变量。 像“$<”、“$@”、“$?”、“$*”等。 6.1变量的引用 当我们定义了一个变量之后,就可以在Makefile的很多地方使用这个变量。变量的引用方式 是:“$(VARIABLE_NAME)”或者“${ VARIABLE_NAME }”来引用一个变量的定义。例如:“$(foo)”或者“${foo}”就是取变量“foo”的值。美元符号“$”在Makefile中有特殊的含义,所有在命令或者文件名中使用“$”时需要用两个美元符号“$$”来表示。对一个变量的引用可以在Makefile的任何上下文中,目标、依赖、命令、绝大多数指示符和新变量的赋值中。这里有一个例子,其中变量保存了所有.o文件的列表: objects = program.o foo.o utils.o program : $(objects) cc -o program $(objects) $(objects) : defs.h 变量引用的展开过程是严格的文本替换过程,就是说变量值的字符串被精确的展开在变量被引用的地方。因此规则: foo = c prog.o : prog.$(foo) $(foo) $(foo) -$(foo) prog.$(foo) 被展开后就是:

LN电机驱动模块详解

L298N电机驱动器使用说明书 注意:本说明书中添加超链接的按CTRL并点击连接,即可看到内容。

1.信号电源引入端 2.控制信号输入端 3.直流电机调速PWM脉宽信号输入 端。(控制步进电机或者控制直流电机 无需调速时,保持此状态) 4.控制信号指示灯 5. 光电隔离(抗干扰) 6.核心芯片(L298N) 7.二极管桥式续流保护8.电源滤波9.端子接线 实例一:步进电机的控制实例

步进电机是数字控制电机,它将脉冲信号转变成角位移,即给一个脉冲信号,步进电机就转动一个角度,因此非常适合于单片机控制。步进电机可分为反应式步进电机(简称VR)、永磁式步进电机(简称PM)和混合式步进电机(简称HB)。 一、步进电机最大特点是: 1、它是通过输入脉冲信号来进行控制的。 2、电机的总转动角度由输入脉冲数决定。 3、电机的转速由脉冲信号频率决定。 二、步进电机的驱动电路 根据控制信号工作,控制信号由单片机产生。(或者其他信号源) 三、基本原理作用如下: 两相四拍工作模式时序图:

(1)控制换相顺序 1、通电换相这一过程称为脉冲分配。 例如: 1、两相四线步进电机的四拍工作方式,其各相通电顺序为(A-B-A’ -B’)通电控制脉冲必须严格按照这一顺序分别控制A,B相的通断。) 2、两相四线步进电机的四拍工作方式,其各相通电顺序为: (A-AB-B-BA’-A’-A’B’-B’-B’ 依次循环。(出于对力矩、平稳、噪音及减少角度等方面考虑。往往采用八拍工作方式) (2)控制步进电机的转向 如果给定工作方式正序换相通电,步进电机正转,如果按反序通电换相,则电机就反转。如:正转通电顺序是:(A-B-A’-B’依次循环。)则反转的通电顺序是:(B‘-A’-B-A依次循环。) 参考下例:

相关主题