# 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