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 指定链接时的参数