uboot提供了两种编译策略,即可以将生成的目标文件与源码混在一起,也可以将生成的目标文件与源码分开。通过对uboot Makefile的分析,笔者编写了一个简单的实现这种功能的Makfile。
顶层makefile
ifneq ($(BUILD_DIR),) saved-output := $(BUILD_DIR) # Attempt to create a output directory. $(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR}) //创建目录BUILD_DIR # Verify if it was successful. BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd) $(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist)) endif # ifneq ($(BUILD_DIR),) OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) //目标文件生成的根目录,可以认为是一个常量,区别于obj SRCTREE := $(CURDIR) //CURDIR是当前目录的路径,目录改变,它随之改变 TOPDIR := $(SRCTREE) export SRCTREE OBJTREE TOPDIR include $(TOPDIR)/config.mk //config.mk中定义了obj变量,下边的内容使用了这个变量 OBJS = add/add.o sub/sub.o test/test.o //需要生成的目标文件 OBJS := $(addprefix $(obj),$(OBJS)) //需要生成目标文件的完整路径 .PHONY : $(OBJS) //确保源文件修改了,目标文件能够自动重建 $(obj)program: $(OBJS) //在总目标前边也加上了前缀obj,以实现目标文件与目标文件在不同的目录 gcc $^ -o $@ $(OBJS): make -C $(dir $(subst $(obj),,$@)) //依次执行各个子目录中的makefile .PHONY: clean clean: make -C add clean make -C sub clean make -C test clean rm -f $(obj)program //删除时也要注意目录问题
顶层config.mk (确定当前的源文件的目录,以及要生成目标文件的完整路径,并创建这个路径)
ifneq ($(OBJTREE),$(SRCTREE)) ifeq ($(CURDIR),$(SRCTREE)) dir := else dir := $(subst $(SRCTREE)/,,$(CURDIR)) endif obj := $(if $(dir),$(OBJTREE)/$(dir)/,$(OBJTREE)/) //确定要生成目标文件的完整路径,
//注意这是个变量,在不同的子目录中,执行makefile,obj的值相应的发生变化 src := $(if $(dir),$(SRCTREE)/$(dir)/,$(SRCTREE)/) //确定当前源文件的目录 $(shell mkdir -p $(obj)) //创建目标文件的完整路径,注意gcc命令并不能自动生成缺少的路径,所以需要事先创建 else //上边的是目标文件与源文件不同的情况,下边的是相同的情况 obj := //目标文件与源文件目录相同时,obj没有必要赋值 src := endif
子目录makefile,以add/makefile为例
include $(TOPDIR)/config.mk //子目录中的makefile也调用了obj变量,所以也要包含config.mk文件 $(obj)add.o: add.c ../include/heads.h gcc -c -o $@ $< .PHONY: clean clean: rm -f $(obj)*.o
编译方法:
1、目标文件与源码混在一起
直接在顶层目录中执行:#make
2、目标文件与源码分开
方法一:
先声明个环境变量:#exprort BUILD_DIR=/tmp/build //这里以/tmp/build为例
然后在顶层目录中执行:#make
方法二:
直接在顶层目录中执行:#make BUILD_DIR=/tmp/build
下载源码链接:sometest.zip