makefile 文件中最难写的是各种规则,但是我们的图丁系统已经提供了常用的所有规则(在
/tdGUI/x86/output/rules.mk 文件中),

 

# zhangjie design 2.2
#########################################################################################
# CROSS: 交叉编译时的gcc前缀(默认没有)
# DEBUG: 编译是否带调试信息(默认没有,即编译优化版本-O3)
# EXTRACFLAGS: 额外的编译选项
# EXTRALDFLAGS: 额外的链接选项
# CPPFLAGS: C++文件的编译选项
# STATICLIB: 是否编译成静态库(默认没有,即编译成动态库)
# (建议都编译成动态库,因为静态库的函数属性__attribute__((constructor))在函数不使用时无效)
# EXE2PIE: 可执行程序是否编译成位置无关的(-fPIE, -pie)
# LIB_UNDEFINED: 创建动态链接库时,允许有未定义的符号(ld的默认情况)
#
# TD_PKG_PATH: 该目录下的include,lib也加入编译目录,要加在最后
#
# OUTPUT: 全局系统配置目录,该目录中有全局编译配置文件config.mk和rules.mk
# TOP: 该软件包的顶层目录,该目录中有该软件包的默认配置文件def_config.mk文件,
# 该文件中可以定义一系列的XXXX1=y XXXX2=n ...等变量来配置编译过程,
# 并且可以定义CONFIG_H=XXXX1 XXXX2 ...来自动生成一个包含这些宏定义的头文件CONFIG_H_FILE
#
# OUTPUT目录和TOP目录必须定义,内容可以相同
# 编译生成的文件自动放在TOP目录下
#
# INSTALL_NAME: 该软件包安装的子目录名, 如果没有设置,默认为$(shell basename "$(TOP)")
# INSTALL_TOP: 软件包的安装目录, $(TOP)/{bin,include,lib,etc} --> $(INSTALL_TOP)/$(INSTALL_NAME)/
#
# 如果要把一个目录下的多个软件包安装到同一个目录,
# 比如要把 apps/{app1,app2,...} 都要安装到$(INSTALL_TOP)/group/中,
# 那么app1,app2,...编译时就在自己的makefile中设置INSTALL_NAME:=group,
#
# INSTALL_TOP目录是全局设置的,如果没有设置就没有install
# INSTALL_NAME是软件包自己设置的,如果没有设置默认是TOP的目录名
#
# 如果设置了INSTALL_TO_OUTPUT, 即直接安装在$(OUTPUT)目录
#
# CONFIG_H_FILE
#
# EXENAME 指明生成的可执行文件名
# EXESRCS 指定要编译的源代码文件
# EXECFLAGS 指定编译时的参数
# EXELDFLAGS 指定链接时的参数
#
# LIBNAME
# LIBSRCS
# LIBCFLAGS
# LIBLDFLAGS
# LIBARFLAGS
# LIBVERSION
# LIBVERSION_SUB
#
# 在Makefile中首先定义OUTPUT目录和TOP目录
# 第一次包含rules.mk: 包含$(OUTPUT)/config.mk和$(TOP)/def_config.mk
# 第二次包含rules.mk: 根据EXENAME和LIBNAME 做编译安装的工作
# 变量总是先定义后使用,先确定变量的值再写依赖
#########################################################################################

ifeq ($(origin ALREADYFIRST),undefined)
#@@@@@@@@@@@@@@@@ 第一次包含rules.mk, 做默认配置的工作 @@@@@@@@@@@@@@@@@@@
ALREADYFIRST := Y

TOP := $(strip "$(TOP)")
ifeq ("$(TOP)",)
$(error "you are not set TOP dir")
endif
ifneq ($(shell if [ -d "$(TOP)" ]; then echo true; fi),true)
$(error "TOP directory $(TOP) does not exist")
endif
TOP := $(shell cd "$(TOP)" && /bin/pwd)

OUTPUT := $(strip $(OUTPUT))
ifeq ($(OUTPUT),)
$(error "you are not set OUTPUT directory")
endif
ifneq ($(shell if [ -d "$(OUTPUT)" ]; then echo true; fi),true)
$(error "OUTPUT directory $(OUTPUT) does not exist")
endif
OUTPUT := $(shell cd $(OUTPUT) && /bin/pwd)

-include $(OUTPUT)/config.mk
-include $(TOP)/def_config.mk

CC := $(CROSS)gcc
CCP := $(CROSS)g++
LD := $(CROSS)ld
AR := $(CROSS)ar
RANLIB := $(CROSS)ranlib
STRIP := $(CROSS)strip

CCEXE := $(CC)
CCLIB := $(CC)

#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
else
#@@@@@@@@@@@@@ 第二次包含rules.mk,做编译安装的工作,一直到该文件尾 @@@@@@@@@

ifeq ($(INSTALL_TO_OUTPUT),Y)

INSTALL := $(OUTPUT)

else

INSTALL :=
INSTALL_TOP := $(strip $(INSTALL_TOP))
ifneq ($(INSTALL_TOP),)
ifneq ($(shell if [ -d "$(INSTALL_TOP)" ]; then echo true; fi),true)
$(error "INSTALL_TOP directory $(INSTALL_TOP) does not exist")
endif
INSTALL_TOP := $(shell cd $(INSTALL_TOP) && /bin/pwd)
INSTALL_NAME := $(strip $(INSTALL_NAME))
ifeq ($(INSTALL_NAME),)
INSTALL_NAME := $(shell basename "$(TOP)")
endif
INSTALL := $(INSTALL_TOP)/$(INSTALL_NAME)
endif

endif

EXEOBJS := $(patsubst %.c, %.o, $(EXESRCS))
LIBOBJS := $(patsubst %.c, %.lo, $(LIBSRCS))
EXEDEPS := $(patsubst %.c, %.d, $(EXESRCS))
LIBDEPS := $(patsubst %.c, %.d, $(LIBSRCS))

EXEOBJS := $(patsubst %.cpp, %.oo, $(EXEOBJS))
LIBOBJS := $(patsubst %.cpp, %.loo, $(LIBOBJS))
EXEDEPS := $(patsubst %.cpp, %.dd, $(EXEDEPS))
LIBDEPS := $(patsubst %.cpp, %.dd, $(LIBDEPS))

#GCOVFILES:=$(patsubst %.c, %.gc*, $(EXESRCS)) $(patsubst %.c, %.gc*, $(LIBSRCS)) $(patsubst %.c, %.c.gcov, $(EXESRCS)) $(patsubst %.c, %.c.gcov, $(LIBSRCS)) 

ifeq ($(findstring .cpp, $(EXESRCS)), .cpp)
CCEXE := $(CCP)
endif

ifeq ($(findstring .cpp, $(LIBSRCS)), .cpp)  
CCLIB := $(CCP)
endif

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

CFLAGS := -DLINUX=1 -DUNIX=1 -Dlinux -Dunix -Wall -D_GNU_SOURCE -D_REENTRANT
LDFLAGS := 

ifeq ($(DEBUG),Y)
CFLAGS += -DTD_DEBUG -O0 -ggdb3
#CFLAGS += -pg -fprofile-arcs -ftest-coverage
#LDFLAGS += -pg -fprofile-arcs -ftest-coverage
else
CFLAGS += -DNDEBUG -O3 -fomit-frame-pointer
endif

CFLAGS += "-I$(TOP)/include"
LDFLAGS += "-L$(TOP)/lib"

ifneq ($(INSTALL),)
ifneq ("$(TOP)",$(INSTALL))
CFLAGS += -I$(INSTALL)/include
LDFLAGS += -L$(INSTALL)/lib
endif
endif

ifneq ("$(TOP)",$(OUTPUT))
ifneq ($(INSTALL),$(OUTPUT))
CFLAGS += -I$(OUTPUT)/include
LDFLAGS += -L$(OUTPUT)/lib
endif
endif

ifneq ($(TD_PKG_PATH),)
CFLAGS += -I$(TD_PKG_PATH)/include
LDFLAGS += -L$(TD_PKG_PATH)/lib
endif

################################################
ifneq ($(LIBNAME),)

$(shell mkdir -p "$(TOP)/lib")
LIBCFLAGS += -fPIC -DPIC

ifeq ($(STATICLIB),Y)
#=====================如果是编译静态链接库===================

ifeq ($(EXE2PIE),Y)
LIBCFLAGS += -fPIE
endif

REALLIBNAME = $(LIBNAME).a
$(LIBNAME): $(CONFIG_H_FILE) $(LIBDEPS) $(LIBOBJS)
    $(AR) cr $(REALLIBNAME) $(LIBOBJS) $(LIBARFLAGS)
    $(RANLIB) $(REALLIBNAME)
    mv -f $(REALLIBNAME) "$(TOP)/lib/"
    @echo -e '\e[32m' ========= generate static libray $@ end ========= '\e[0m'

else
#=====================如果是编译动态链接库===================

REALLIBNAME = $(LIBNAME).so
ifneq ($(LIBVERSION),)
SETSONAME := -Wl,-soname,$(LIBNAME).so.$(LIBVERSION)
REALLIBNAME = $(LIBNAME).so.$(LIBVERSION)
SIMPLE_LIBNAME = $(LIBNAME).so
ifneq ($(LIBVERSION_SUB),)
SOLIBNAME = $(LIBNAME).so.$(LIBVERSION)
REALLIBNAME = $(LIBNAME).so.$(LIBVERSION).$(LIBVERSION_SUB)
endif
endif

ifeq ($(LIB_UNDEFINED),)
LIBLDFLAGS += -Wl,--no-undefined
endif

$(LIBNAME): $(CONFIG_H_FILE) $(LIBDEPS) $(LIBOBJS)
    $(CCLIB) -shared -Wl,-Bsymbolic -Wl,-Bsymbolic-functions $(SETSONAME) -o $(REALLIBNAME) $(LIBOBJS) $(LIBLDFLAGS) $(LDFLAGS) $(EXTRALDFLAGS)
    mv -f $(REALLIBNAME) "$(TOP)/lib"
    [ "$(DEBUG)" = "Y" ] || $(STRIP) "$(TOP)/lib/$(REALLIBNAME)"
    @[ -z $(SOLIBNAME) ] || ln -sf $(REALLIBNAME) $(SOLIBNAME)
    @[ -z $(SOLIBNAME) ] || mv -f $(SOLIBNAME) "$(TOP)/lib"
    @[ -z $(SIMPLE_LIBNAME) ] || ln -sf $(REALLIBNAME) $(SIMPLE_LIBNAME)
    @[ -z $(SIMPLE_LIBNAME) ] || mv -f $(SIMPLE_LIBNAME) "$(TOP)/lib"
    @echo -e '\e[32m' ========= generate share libray $@ end ========= '\e[0m'

endif
endif
##################################################

##################################################
ifneq ($(EXENAME),)
ifeq ($(EXE2PIE),Y)
EXECFLAGS += -fPIE
EXELDFLAGS += -pie -Wl,-Bsymbolic -Wl,-Bsymbolic-functions
endif
$(shell mkdir -p "$(TOP)/bin")
$(EXENAME): $(CONFIG_H_FILE) $(EXEDEPS) $(EXEOBJS)
    $(CCEXE) -Wl,--allow-shlib-undefined -Wl,--no-as-needed -o $(EXENAME) $(EXEOBJS) $(EXELDFLAGS) $(LDFLAGS) $(EXTRALDFLAGS)
    mv -f $(EXENAME) "$(TOP)/bin/"
    [ "$(DEBUG)" = "Y" ] || $(STRIP) "$(TOP)/bin/$(EXENAME)"
    @echo -e '\e[32m' ========= generate execute $@ end ========= '\e[0m'
endif
##################################################

.PHONY: rules_clean rules_install rules_build_info

#因为后面包含依赖文件会自动在all前面执行.d的规则,所以后面要加上$(CONFIG_H_FILE),
#因为在规则中$<表示第一个依赖文件名
%.d: %.c $(CONFIG_H_FILE)
    @$(CC) -MM $(EXECFLAGS) $(LIBCFLAGS) $(CFLAGS) $(EXTRACFLAGS) $< | sed -e 's,^[0-9a-zA-Z._-]*: \([0-9a-zA-Z._-]*/\),\1&,' -e 's,^\([0-9a-zA-Z.-_/]*\)\.o:,\1.o \1.d \1.lo:,' > $@

%.o: %.c
    $(CC) $(EXECFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c -o $@ $<

%.lo: %.c
    $(CC) $(LIBCFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c -o $@ $<

%.dd: %.cpp $(CONFIG_H_FILE)
    @$(CCP) -MM $(EXECFLAGS) $(LIBCFLAGS) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) $< | sed -e 's,^[0-9a-zA-Z._-]*: \([0-9a-zA-Z._-]*/\),\1&,' -e 's,^\([0-9a-zA-Z.-_/]*\)\.o:,\1.oo \1.dd \1.loo:,' > $@

%.oo: %.cpp
    $(CCP) $(EXECFLAGS) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c -o $@ $<

%.loo: %.cpp
    $(CCP) $(LIBCFLAGS) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c -o $@ $<

rules_clean:
    -rm -f $(CONFIG_H_FILE) $(EXENAME) $(REALLIBNAME) $(EXEOBJS) $(LIBOBJS) $(EXEDEPS) $(LIBDEPS) $(GCOVFILES)
    -[ -z $(EXENAME) ] || rm -f "$(TOP)/bin/$(EXENAME)"
    -[ -z $(LIBNAME) ] || rm -f "$(TOP)/lib/$(LIBNAME)."*
    -rm -f "$(TOP)/build_info.ini"

ifneq ($(INSTALL),)
rules_install: $(LIBNAME) $(EXENAME)
    -mkdir -p $(INSTALL)
    -[ ! -f "$(TOP)/package.ini" ] || cp -af "$(TOP)/*.ini" $(INSTALL)/
    -[ ! -d "$(TOP)/include" ] || cp -af "$(TOP)/include" $(INSTALL)/
    -[ ! -d "$(TOP)/lib" ] || cp -af "$(TOP)/lib" $(INSTALL)/
    -[ ! -d "$(TOP)/bin" ] || cp -af "$(TOP)/bin" $(INSTALL)/
    -[ ! -d "$(TOP)/etc" ] || cp -af "$(TOP)/etc" $(INSTALL)/
    -[ ! -d "$(TOP)/style" ] || cp -af "$(TOP)/style" $(INSTALL)/
    -[ ! -d "$(TOP)/share" ] || cp -af "$(TOP)/share" $(INSTALL)/
    -[ ! -d "$(TOP)/local" ] || cp -af "$(TOP)/local" $(INSTALL)/
    -[ ! -d "$(TOP)/var" ] || cp -af "$(TOP)/var" $(INSTALL)/
    @echo -e '\e[32m' ========= install $(LIBNAME) $(EXENAME) to $(INSTALL) end ========= '\e[0m'
else
rules_install:
    @echo -e '\e[33;1m' you not set INSTALL_TOP, so no install. '\e[0m'
endif

ifneq ($(CONFIG_H_FILE),)
define CONFIG_H_ITEM
if [ "$($(1))" = "Y" ] || [ "$($(1))" = "y" ] ; then echo "#define $(1) 1" >> $(CONFIG_H_FILE) ; else echo "/*no define $(1) */" >> $(CONFIG_H_FILE) ; fi ;
endef
$(CONFIG_H_FILE): $(TOP)/def_config.mk
    @echo "/*this file is auto generated by rules.mk from config.mk*/" > $(CONFIG_H_FILE)
    @echo "#ifndef _$(EXENAME)_$(LIBNAME)_CONFIG_H"  >> $(CONFIG_H_FILE)
    @echo "#define _$(EXENAME)_$(LIBNAME)_CONFIG_H"  >> $(CONFIG_H_FILE)
    @echo ""  >> $(CONFIG_H_FILE)
    @$(foreach ITEM,$(CONFIG_H),$(call CONFIG_H_ITEM,$(ITEM)))
    @echo ""  >> $(CONFIG_H_FILE)
    @echo "#endif"  >> $(CONFIG_H_FILE)
    @echo ""  >> $(CONFIG_H_FILE)
    @echo -e '\e[32m' ========= generate $@ end ========= '\e[0m'
endif

rules_build_info:
    @grep -s -m 1 "version" "$(TOP)/package.ini" > "$(TOP)/build_info.ini" || true
    @echo "time=\"`date '+%Y/%m/%d-%H:%M:%S'`\"" >> "$(TOP)/build_info.ini"
    @cat  "$(TOP)/build_info.ini"
    @echo -e '\e[32m' ========= generate build_info.ini end ======== '\e[0m'

ifneq ($(MAKECMDGOALS),clean)
-include $(EXEDEPS) $(LIBDEPS)
endif

#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
endif

 

# EXENAME 指明生成的可执行文件名
# EXESRCS 指定要编译的源代码文件
# EXECFLAGS 指定编译时的参数
# EXELDFLAGS 指定链接时的参数