大约一年多以前,还在移植u-boot,当时参考了u-boot的Makefile,做了一个多目录的Makefile模板。如今,一年过去了,本篇文章还是折腾Makefile模板,本人的水平由此可见一斑。当时的模板没有考虑很多东西,比如将源代码文件及目标文件分离。此次再写一个相对复杂的Makefile模板,自此之后,估计不想再折腾了。

本文的Makefile跟以往的模板一样,都是参考u-boot的做法(u-boot项目无论代码还是文件组织,都有很多值得学习的地方)。由下列文件组成:

1、配置文件config.mk,主要是编译器、编译选项、头文件路径、目标文件、源文件路径,等等;
2、依赖规则rules.mk,主要是产生depend文件,有了depend文件,当修改了头文件后,包含该头文件的源文件都会被重新编译。
3、主Makefile,或称为总Makefile,此文件调用其它目录的Makefile以及上述文件,以产生库及可执行文件。
4、子目录Makefile,各模块的Makefile,主要是生成静态库。

除子目录Makefile在各个模块目录中外,其它文件都在项目的当前目录。

Makefile模板应用场合及特点缺点说明如下:

1、头文件统一在include目录(或其它自定义的目录),子模块分布于各子目录,该目录的Makefile将模块编译成静态库,主代码(包括main函数及其它的代码)文件在独立目录,该目录的Makefile为总Makefile(或称主Makefile)。
2、修改头文件后,所有依赖该文件者均重新编译。
3、可指定编译后的文件所在目录,如不指定,则在原目录下生成目标文件(.o、.out文件)。指定方式如下:
1)、命令行:$ make O=../build
2)、$ export BUILD_DIR=../build ; make
3)、直接在主Makefile指定目录
4、自动识别编译C、C++文件。

下面分别解释一下各个文件

1、配置文件config.mk

模板如下:

#
# (C) Copyleft 2011 
# Late Lee from http://www.latelee.org 
#  
# A simple file to specify compier and macros and flags
# and ways to compile .c & .cpp 
#

# cross compile... 
CROSS_COMPILE =

CC = $(CROSS_COMPILE)gcc
CXX = $(CROSS_COMPILE)g++
AR = $(CROSS_COMPILE)ar

ARFLAGS = cr
RM = -rm -rf
MAKE = make

CFLAGS =  #-Wall 
debug = y

ifeq ($(debug), y)
CFLAGS += -g
else
CFLAGS += -O2 -s
endif

DEFS =

CFLAGS += $(DEFS)

LDFLAGS = $(LIBS)

# include path here 
INCDIRS = $(SRCTREE)/./include/

CFLAGS += -I$(INCDIRS)

###############################################################################

ifneq ($(OBJTREE),$(SRCTREE))
ifeq ($(CURDIR),$(SRCTREE))
dir :=
else
dir := $(subst $(SRCTREE)/,,$(CURDIR))
endif

obj := $(if $(dir),$(OBJTREE)/$(dir)/,$(OBJTREE)/)
src := $(if $(dir),$(SRCTREE)/$(dir)/,$(SRCTREE)/)

$(shell mkdir -p $(obj))
else
obj :=
src :=
endif

suffix = $(notdir $(CURDIR))
export suffix

# test of shell script 
MKCONFIG    := $(SRCTREE)/mkconfig
export MKCONFIG

# export to other Makefile 
export CC
export CFLAGS
export INCDIRS
export AR
export ARFLAGS
export RM

###############################################################################

# make all .c or .cpp 
$(obj)%.o: %.c
        @echo "Compling: " $(addsuffix .c, $(basename $(notdir $@)))
        @$(CC) $(CFLAGS) -c $< -o $@

$(obj)%.o: %.cpp
        @echo "Compling: " $(addsuffix .cpp, $(basename $(notdir $@)))
        @$(CXX) $(CFLAGS) -c $< -o $@

主要分3部分:

第一部分指定编译器及编译选项,可以选择交叉编译器,头文件路径由INCDIRS 宏指定,这里有的编译选项CFLAGS处理得不太好,比如debug版本及release版本是通过“-g”和“-O2 -s”来区别的,但这里是直接指定,并不能在make时指定。
第二部分指定了源代码目录及目标文件目录,这些目录由主Makefile给出,或者在make时给出。
第三部分是编译c或c++源代码的规则。

实际使用中,此文件需要根据实际情况修改编译器及编译选项。

2、依赖规则rules.mk

内容如下:

#
# (C) Copyleft 2011 
# Late Lee from http://www.latelee.org 

# A simple way to generate depend file(.depend) for .c & .cpp,
# so you change the head file, it will recompile the 
# file(s) which include the head file. 
#

_depend: $(obj).depend

$(obj).depend: $(SRCTREE)/config.mk $(SRC_C) $(SRC_CPP)
        @rm -f $@
        @for f in $(SRC_C); do \
                g=`echo $$f | sed -e 's/\(.*\)\.\w/\1.o/'`; \
                $(CC) -MM $(CFLAGS) -E -MQ $(obj)$$g $$f >> $@ ; \
        done
        @for f in $(SRC_CPP); do \
                g=`echo $$f | sed -e 's/\(.*\)\...\w/\1.o/'`; \
                $(CC) -MM $(CFLAGS) -E -MQ $(obj)$$g $$f >> $@ ; \
        done

该文件主要是产生.depend依赖文件,依赖文件的作用在前面已经说过,此处不再提及。实际使用中,经文件无需修改。

3、主Makefile

内容如下:

#
# (C) Copyleft 2011 
# Late Lee from http://www.latelee.org 
#  
# A simple Makefile for multi-directory 
# Most idea comes from U-boot project 
#

# object file directory, eg 
# $ make O=../build 
# $ export BUILD_DIR=../build ; make 
# or modify BUILD_DIR here 
ifdef O
ifeq ("$(origin O)", "command line")
BUILD_DIR := $(O)
endif
endif

ifneq ($(BUILD_DIR),)
saved-output := $(BUILD_DIR)

# Attempt to create a output directory. 
$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${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))
SRCTREE     := $(CURDIR)
TOPDIR      := $(SRCTREE)
LNDIR       := $(OBJTREE)
export        TOPDIR SRCTREE OBJTREE
export        TOPDIR SRCTREE OBJTREE

include $(TOPDIR)/config.mk

###############################################################################
# libs 
### your libs here 
LIBS :=

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

LDFLAGS = $(LIBS)

# source file(s), including c file(s) cpp file(s)
# you can also use $(wildcard *.c), etc. 
### main source here 
MAIN_DIR =  #main/ 
SRC_C   := 
SRC_CPP := $(wildcard $(MAIN_DIR)*.cpp)

$(if $(MAIN_DIR), $(shell mkdir -p $(addprefix $(obj),$(MAIN_DIR))),)

# object file(s) 
OBJ_C   := $(addprefix $(obj),$(patsubst %.c,%.o,$(SRC_C)))
OBJ_CPP := $(addprefix $(obj),$(patsubst %.cpp,%.o,$(SRC_CPP)))

# executable file here 
target = $(obj)a.out

###############################################################################

all: config $(target)

config: 
        @echo "Generating... hello.h"
        @$(MKCONFIG)

$(target)$(LIBS) exe

exe: $(OBJ_CPP) 
        @echo "Generating executable file..." $(notdir $(target))
        @$(CXX) $(CFLAGS) $(OBJ_CPP) -o $(target) $(LIBS)

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

clean: 
        @echo "cleaning..."
        @$(RM) $(target)
        @$(RM) hello.h
        @find $(OBJTREE) -type f \
                \( -name 'core' -o -name '*.bak' -o -name '*~' \
                -o -name '*.o'  -o -name '*.a' -o -name '*.exe' -o -name '.depend' \) -print \
                | xargs rm -f
distclean: 
        @echo "distcleaning..."
        @$(RM) $(target)
        @$(RM) hello.h
        @find $(OBJTREE) -type f \
                \( -name 'core' -o -name '*.bak' -o -name '*~' \
                -o -name '*.o'  -o -name '*.a' -o -name '*.exe' -o -name '.depend' \) -print \
                | xargs rm -f
        @$(RM) $(obj)

.PHONY: all clean distclean $(LIBS) exe

该文件也可分为三部分。第一部分指定源代码目录及目标文件目录,第二部分指定了工程所需的静态库以及主代码所在目录,第三部分编译规则,包括make all,make clean,等等命令的规则。实际使用中,需要根据实际情况添加子模块静态库名称、主代码名称。

4、子目录Makefile

内容如下:

#
# (C) Copyleft 2011 
# Late Lee from http://www.latelee.org 
#  
# A simple Makefile for lib(libxxx.a) 
# You just need to change library name and source file(s)
#

include $(TOPDIR)/config.mk

# here you can set your own flags 
CFLAGS +=  # -D_A_

# static library name 
LIB =   # $(obj)libfoo.a

# source file(s), including c file(s) cpp file(s)
# you can also use $(wildcard *.c), etc. 
SRC_C   :=  # foo.c 
SRC_CPP :=

# object file(s) 
OBJ_C   := $(addprefix $(obj),$(patsubst %.c,%.o,$(SRC_C)))
OBJ_CPP := $(addprefix $(obj),$(patsubst %.cpp,%.o,$(SRC_CPP)))

all: $(obj).depend $(LIB)

$(LIB)$(OBJ_C) $(OBJ_CPP)
        @echo "Generating static library: " $(notdir $@)
        @$(AR) $(ARFLAGS) $@ $^

clean: 
        @echo "Cleaning..."
        @$(RM) $(OBJ_C) $(OBJ_CPP) $(LIB) *.bak *~ *.d *.o $(obj).depend

.PHONY: all clean

#########################################################################

include $(TOPDIR)/rules.mk

sinclude $(obj).depend

#########################################################################

子目录的Makefile比较简单,因为编译配置及depend文件都在其它文件中,这里直接包含进来即可。
实际使用中,需要修改的地方有:
1、配置文件config.mk,指定头文件路径,编译选项,额外库,等等。
2、主Makefile,指定各子模块的库名称及生成可执行文件名称
3、子Makefile,指定静态库名称即可,每一个模块目录都需要一个Makefile。

文中的Makefile模板,远远不如IDE方便,因此,用与不用,则仁者见仁了。

本文语法着色由迟思堂工作室提供高亮工具手工完成。

本文所涉及的Makefile模块及示例压缩包:coming soon...

复杂多目录的Makefile模板及示例-转相关推荐

  1. 复杂多目录的Makefile模板及示例

    大约一年多以前,还在移植u-boot,当时参考了u-boot的Makefile,做了一个多目录的Makefile模板.如今,一年过去了,本篇文章还是折腾Makefile模板,本人的水平由此可见一斑.当 ...

  2. GNU/Linux智能Makefile模板(多目录,多文件)

    本文提供一个在GNU/Linux环境下通用的智能Makefile模板,用户可以将其引入到自己的工程当中.即使用户对此 Makefile的工作原理不甚了解,但是只需要修改少数几个关键变量,就可以满足不同 ...

  3. 关于中型工程的Makefile模板

    我们定义的中型工程 可能会有多层嵌套的源代码文件夹 一个源代码文件夹下可能有多个源代码子文件夹 中间文件应当在其源文件所在目录生成,而不是同一生成到一个目录下(如统一生成到obj目录下) (大多数情况 ...

  4. 一个适用各类场合的Makefile模板

    1.写在前面 对于Windows下开发,很多IDE都集成了编译器,如Visual Studio,提供了"一键编译",编码完成后只需一个操作即可完成编译.链接.生成目标文件.Linu ...

  5. 一个STM32编译Makefile模板

    最近突然对STM32感兴趣,研究了一下.STM32的编译方式非常多,由于一直对gcc情有独钟,所以还是喜欢使用Makefile+gcc编译的方法.当时从51单片机转向AVR单片机开发时,也是通过这种方 ...

  6. Makefile模板的继续改进

    layout: post title: category : linux系统 tags : [Makefile] 上一文章的Makefile,存在一个比较大的问题,那就是生成可执行的二进制文件时,会链 ...

  7. 一个使用多年的Makefile模板

    layout: post title: category : linux系统 tags : [Makefile] 许久以前,一直使用自己总结的Makefile模板,这个模板也是基于现有资料整理而成的. ...

  8. 通用Makefile模板

    #################################################################################################### ...

  9. 万能 Makefile 模板

    在 Linux 编程时,对于很多小工程来说,很多时候似乎没有必要用 autoconf 和 automake 工具来生成 Makefile,反而自己写一个 Makefile 更省事.这里给大家提供一个简 ...

最新文章

  1. oracle schedule stop,Oracle调度Schedule特性(第八部分)-Windows和Window Groups
  2. 新BOJ 88. 最值问题
  3. 决策树(CART算法)针对中文文本分类
  4. 一道大题决定去留:为什么synchronized无法禁止指令重排,却能保证有序性?
  5. leetcode 1185 python
  6. 电脑字体在哪个文件夹_壹心奇妙体下载 壹心奇妙体 字体下载
  7. solaris常用系统命令
  8. 最新北京人才公寓申请流程,技术员的福利~
  9. 云原生IDE:iVX首个通用且强大无代码开发平台
  10. 在浏览器上打开、预览Excel xlsx表格文件
  11. 2016年11月整理的最新php免杀一句话木马, 2017php免杀一句话(php过狗一句话,过狗菜刀,2016过狗一句话,2016php免杀一句话,php过waf一句话)
  12. 传说之下三重审判用计算机怎么弹,传说之下三重审判无限血
  13. Ubuntu系统迁移至固态硬盘(生产环境勿用)
  14. Dessert Café
  15. 华东师大在职计算机分数线,关于在职研究生华东师范大学分数线的详细介绍!...
  16. html文件无法找到,html文件无法打开
  17. 终于鼓起勇气,辞掉了第一份工作
  18. stream流的使用说明书
  19. 《春夜洛城闻笛 / 春夜洛阳城闻笛》古诗鉴赏
  20. ddos攻击的简单应急处理办法

热门文章

  1. 对象可以创建数组吗_电脑零基础可以学习创建网站吗?
  2. Android 屏幕(View)坐标系统
  3. Android studio for mac
  4. 听听【八年阿里架构师】怎样讲述Dubbo和Spring Cloud微服务架构
  5. 附加数据库后登陆报错
  6. 《基于MFC的OpenGL编程》Part 18 Reading objects from the OBJ File Format
  7. iOS WKWebView和JS交互的两种方式
  8. 【CF】304 E. Soldier and Traveling
  9. 国产平板面临变局挑战,谁能撑起民族大旗?
  10. 索要ValidateTextBox控件Source Code的朋友rickel****@gmail.com,邮件退回了。各位,与我通信,请不要使用GMAIL,烦。...