u-boot(2014.04)是通过顶层makefile调用各子目录中的makefile来实现整个工程的编译的,实际上子目录的makefile是include进来的。这里仿照这种结构写个模板测试一下。

目录结构:

mytest:

  add:

    mul:

      Makefile

      mul.c

      mul.h

    add.c

    add.h

    Makefile

  main:

    main.c

    Makefile

  scripts:

    Makefile.build

    Makefile.clean

    Makefile.lib

  sub:

    div

      div.c

      div.h

      Makefile

    sub.c

    sub.h

    Makefile

顶层Makefile:

 CC := gcc
LD := ld CFLAGS := -g PHONY := all target := mainApp # default target
all: $(target) # dirs to be compiled
src-dirs += add/
src-dirs += sub/
src-dirs += main/ # libs to be linked
libs-y := $(patsubst %/,%/built-in.o,$(src-dirs)) src-dirs := $(patsubst %/,%,$(src-dirs)) # include dirs
inc-dirs := $(addprefix -I,$(src-dirs)) # the Makefile for building
build := -f scripts/Makefile.build obj CFLAGS += $(inc-dirs)
export CC LD CFLAGS PHONY += $(src-dirs) # linking
$(target): $(src-dirs)
$(CC) -o $@ $(libs-y) # compiling source dirs
$(src-dirs):
make $(build)=$@ # Clean
clean-dirs := $(foreach f,$(src-dirs),$(if $(wildcard $f/Makefile),$f))
clean-dirs := $(addprefix _clean_, $(clean-dirs))
PHONY += clean $(clean-dirs) # descending to subdirs for cleaning
$(clean-dirs):
make $(clean)=$(patsubst _clean_%,%,$@) # just simply remove .o and target
clean: $(clean-dirs)
@find . \( -name '*.o' -o -name '$(target)' \) -type f | xargs rm -f clean := -f scripts/Makefile.clean obj
.PHONY : $(PHONY)

顶层Makefile确定target,要编译的源码目录,include的路径。

第41行使用scripts/Makefile.build对各个源码目录进行编译,Makefile.build为实际编译代码的makefile,内容如下:

 src := $(obj)

 PHONY := __build

 obj-y := 

 # include the Makefile in the $(obj) dir
build-dir := $(src)
build-file := $(build-dir)/Makefile
include $(build-file) # include scripts/Makefile.lib
include scripts/Makefile.lib build := -f scripts/Makefile.build obj ifneq ($(strip $(obj-y)),)
builtin-target := $(obj)/built-in.o
endif # default target
__build: $(builtin-target) $(subdir)
@: # compiling .c files
$(obj)/%.o: $(src)/%.c
$(CC) -c $(CFLAGS) $< -o $@ # subdir object
$(subdir-obj-y): $(subdir) ; # linking objs
$(builtin-target): $(obj-y)
$(LD) -r -o $@ $^ PHONY += $(subdir) # descending to subdirs
$(subdir):
make $(build)=$@ .PHONY : $(PHONY)

obj变量为需要编译的源码目录,例如add,第10行将add/目录下的Makefile目录包含进来,add/Makefile内容如下:

 obj-y += add.o
obj-y += mul/

这里仅仅确定需编译的文件以及子目录,回到makefile.build,第13行,包含scripts/Makefile.lib文件,内容如下:

 subdir := $(patsubst %/,%,$(filter %/, $(obj-y)))
obj-y := $(patsubst %/,%/built-in.o, $(obj-y))
subdir-obj-y := $(filter %/built-in.o, $(obj-y)) subdir := $(addprefix $(obj)/,$(subdir))
obj-y := $(addprefix $(obj)/,$(obj-y))
subdir-obj-y := $(addprefix $(obj)/, $(subdir-obj-y))

obj-y表示要编译的目标文件,如果是目录,如mul/,则表示mul/built-in.o;subdir表示要继续编译的子目录;subdir-obj-y表示子目录下的built-in.o

回到makefile.build,第18行,每个要编译的源码目录编译之后都将会产生一个built-in.o的文件,第27行,对.c文件进行编译,即由obj-y变量所确定的文件。第40行,对子目录执行同样的过程。第33行,对每个目录链接出一个built-in.o文件,这个built-in.o由当前目录下.o文件和子目录下的.built-in.o文件链接而成。

在所有的源码目录都经过编译之后,回到顶层makefile执行最后的链接,得到target。

再看看clean目标,第49行,首先在需要进行clean的目录下使用scripts/Makefile.clean执行clean,需要clean的目录为含有makefile的源码目录。Makefile.clean内容如下:

 src := $(obj)

 PHONY := __clean

 # default target
__clean: clean := -f scripts/Makefile.clean obj # include the Makefile in the $(obj) dir
build-dir := $(src)
build-file := $(build-dir)/Makefile
include $(build-file) # subdir to be cleaned
subdir := $(patsubst %/,%,$(filter %/,$(obj-y)))
subdir := $(addprefix $(obj)/,$(subdir)) __clean-files :=
__clean-files := $(addprefix $(obj),$(__clean-files)) __clean-dirs :=
__clean-dirs := $(addprefix $(obj),$(__clean-dirs)) __clean: $(subdir)
ifneq ($(strip $(__clean-files)),)
rm -f $(__clean-files)
endif ifneq ($(strip $(__clean-dirs)),)
rm -rf $(__clean-dirs)
endif PHONY += $(subdir)
$(subdir):
make $(clean)=$@ .PHONY: $(PHONY)

这里也是一个逐步往下clean的过程,要clean的文件由__clean-files变量指定。

回到顶层makefile,简单的一个find操作,删除目录下所有.o文件和目标。

关于include路径,u-boot讲所有头文件都集中放在了某几个目录下,于是源码中要包含其他头文件的时候是这样子做的xxx/xxx/xxx.h,我这里的main.c如下,其中对与mul和div的包含也是类似。

 #include <stdio.h>
#include "add.h"
#include "sub.h"
#include "mul/mul.h"
#include "div/div.h" void main(void)
{
int a = ;
int b = ;
printf("a = %d, b = %d\n", a, b);
printf("a + b = %d\n", add(a, b));
printf("a - b = %d\n", sub(a, b));
printf("a * b = %d\n", mul(a, b));
printf("a / b = %d\n", div(a, b));
}

u-boot的makefile对我来说还是太复杂了,这里仅仅是它的冰山一角,可是我已经吃不消了。。。

模仿u-boot的makefile结构的更多相关文章

  1. Spring boot 梳理 - 代码结构(Main类的位置)

    Spring boot 对代码结构无特殊要求,但有个套最佳实践的推荐 不要使用没有包名的类.没有包名时,@ComponentScan, @EntityScan, or @SpringBootAppli ...

  2. ltp-ddt的makefile结构

    顶层makefile COMMON_TARGETS        := pan utils COMMON_TARGETS    += tools testcases/ddt COMMON_TARGET ...

  3. spring boot的项目结构问题

    问题:spring boot项目能够正常启动,但是在浏览器访问的时候会遇到404的错误,Whitelable Error Page 404 分析及解决方案:首先Application文件要放在项目的外 ...

  4. spring boot项目基本结构

    /==================================Controller @Controller public class SimpleController { @Autowired ...

  5. boot.img格式文件拆解实例结构解析

    以msm8226为例,讲解android源码编译生成boot.img的结构.boot.img包括boot.img header.kernel以及ramdisk文件系统.下面是对boot.img的结构进 ...

  6. (DT系列一)DTS结构及其编译方法

    DTS结构及其编译方法 一:主要问题 1,需要了解dtsi与dts的关系 2,dts的结构模型 3,dts是如何被编译的,以及编译后会生成一个什么文件. 二:参考文字 1,DTS(device tre ...

  7. 【转】(DT系列一)DTS结构及其编译方法----不错

    原文网址:http://www.cnblogs.com/biglucky/p/4057476.html DTS结构及其编译方法 一:主要问题 1,需要了解dtsi与dts的关系 2,dts的结构模型 ...

  8. DTS结构及其编译方法

    一.主要问题1,需要了解dtsi与dts的关系2,dts的结构模型3,dts是如何被编译的,以及编译后会生成一个什么文件. 二.参考文字1,DTS(device tree source).dts文件是 ...

  9. linux内核的makefile.txt讲解

    linux内核的linux-3.6.5\Documentation\kbuild\makefiles.txt Linux Kernel Makefiles This document describe ...

随机推荐

  1. MFC 实现CTreeCtrl单选

    void CDepartmenManager::SetUncheck(HTREEITEM hTree) { if (!hTree){ return; } m_DePartmentView.SetChe ...

  2. 一、SAP中添加一个模块到收藏夹后,显示事务代码

    一.在SAP中,如果添加一个模块到收藏夹,默认是看不到事务代码的,如图: 二.我们在附件->设置中勾选显示技术名称 三.保存之后,就会显示出事务代码,如图所示: 不忘初心,如果您认为这篇文章有价 ...

  3. 发送邮件的几种方法(C#发邮件 和 js前台实现都有)C#后台自动发邮件 js发邮件

    1.后台自动发邮件 1)首先设置邮件参数,这里写在configuration里面 <appSettings> <add key="SMTP" value=&quo ...

  4. POJ 1149 网络流 合并建图

    这个题目我敲了一个简单的EK,这不是难点 难点在于建图,按题目的要求 每个猪圈和顾客都建点的话,那也太多了...我看了Edelweiss里面的缩点方法才建好的图,哎,惭愧啊 实际那些猪圈根本不需要单独 ...

  5. maven的理解和使用

    一.maven是什么? maven是项目管理工具 二.maven为什么要用? 在做开发的时候常常会用到外部的工具包(jar包),这就需要你一个一个的去他们的官网下工具包,然后在项目里依赖他们,比较的麻 ...

  6. 启动mysql遇到问题Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

    在mysql的启动过程中有时会遇到下述错误 Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) 请问mys ...

  7. GTK入门

    环境准备 官网下载 GTK 源码包,因为本机 GLib 版本不够,下载一个非最新版的 GTK3.8.0 先学习用 直接阅读 "/gtk+-3.8.0/docs/reference/gtk/h ...

  8. SpringCloud学习之Hystrix请求熔断与服务降级(六)

    我们知道大量请求会阻塞在Tomcat服务器上,影响其它整个服务.在复杂的分布式架构的应用程序有很多的依赖,都会不可避免地在某些时候失败.高并发的依赖失败时如果没有隔离措施,当前应用服务就有被拖垮的风险 ...

  9. Javascript object.constructor属性与面向对象编程(oop)

    定义和用法 在 JavaScript 中, constructor 属性返回对象的构造函数. 返回值是函数的引用,不是函数名: JavaScript 数组 constructor 属性返回 funct ...

  10. .NET技术-5.0. NETCORE设置返回数据字段的大小写

    .NET技术-5.0. NETCORE设置返回数据字段的大小写 问题来源于我写了一个接口,接口的返回类型是JsonResult,但是对接之后反应返回结果的首字母全小写了, 后来查了写资料返现.net ...