复杂多⽬录的Makefile模板及⽰例
⼤约⼀年多以前,还在移植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
#
# A simple file to specify compier and macros and flags
# and ways to compile .c & .cpp
#
#
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
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))
makefile phony
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
#
# 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
#
# 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:
@ hello.h"
@ $(MKCONFIG)
$(target):  $(LIBS) exe
exe:  $(OBJ_CPP)
@echo"Generating " $(notdir  $(target))
@echo"Generating " $(notdir  $(target))
@ $(CXX)$(CFLAGS)$(OBJ_CPP) -o  $(target)$(LIBS)
$(LIBS):
$(MAKE) -C $(dir $(subst  $(obj),, $@))
clean:
@"
@ $(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:
@"
@ $(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
内容如下:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。

发表评论