Makefile隐含规则使用的变量
在隐含规则中的命令中,基本上都是使用了一些预先设置的变量。你可以在你的makefile中改变这些变量的值,或是在make的命令行中传入这些值,或是在你的环境变量中设置这些值,无论怎么样,只要设置了这些特定的变量,那么其就会对隐含规则起作用。当然,你也可以利用make的“-R”或“--no–builtin-variables”参数来取消你所定义的变量对隐含规则的作用。
例如,第一条隐含规则——编译C程序的隐含规则的命令是“$(CC)–c $(CFLAGS)$(CPPFLAGS)”。Make默认的编译命令是“cc”,如果你把变量“$(CC)”重定义成“gcc”,把变量“$(CFLAGS)”重定义成“-g”,那么,隐含规则中的命令全部会以“gcc –c -g $(CPPFLAGS)”的样子来执行了。
我们可以把隐含规则中使用的变量分成两种:一种是命令相关的,如“CC”;一种是参数相的关,如“CFLAGS”。下面是所有隐含规则中会用到的变量:
1、关于命令的变量。
AR
函数库打包程序。默认命令是“ar”。
AS
汇编语言编译程序。默认命令是“as”。
CC
C语言编译程序。默认命令是“cc”。
CXX
C++语言编译程序。默认命令是“g++”。
CO
从 RCS文件中扩展文件程序。默认命令是“co”。
CPP
C程序的预处理器(输出是标准输出设备)。默认命令是“$(CC) –E”。
FC
Fortran 和 Ratfor 的编译器和预处理程序。默认命令是“f77”。
GET
从SCCS文件中扩展文件的程序。默认命令是“get”。
LEX
Lex方法分析器程序(针对于C或Ratfor)。默认命令是“lex”。
PC
Pascal语言编译程序。默认命令是“pc”。
YACC
Yacc文法分析器(针对于C程序)。默认命令是“yacc”。
YACCR
Yacc文法分析器(针对于Ratfor程序)。默认命令是“yacc –r”。
MAKEINFO
转换Texinfo源文件(.texi)到Info文件程序。默认命令是“makeinfo”。
TEX
从TeX源文件创建TeX DVI文件的程序。默认命令是“tex”。
TEXI2DVI
从Texinfo源文件创建军TeX DVI 文件的程序。默认命令是“texi2dvi”。
WEAVE
转换Web到TeX的程序。默认命令是“weave”。
CWEAVE
转换C Web 到 TeX的程序。默认命令是“cweave”。
TANGLE
转换Web到Pascal语言的程序。默认命令是“tangle”。
CTANGLE
转换C Web 到 C。默认命令是“ctangle”。
RM
删除文件命令。默认命令是“rm –f”。
2、关于命令参数的变量
下面的这些变量都是相关上面的命令的参数。如果没有指明其默认值,那么其默认值都是空。
ARFLAGS
函数库打包程序AR命令的参数。默认值是“rv”。
ASFLAGS
汇编语言编译器参数。(当明显地调用“.s”或“.S”文件时)。
CFLAGS
C语言编译器参数。
CXXFLAGS
C++语言编译器参数。
COFLAGS
RCS命令参数。
CPPFLAGS
C预处理器参数。( C 和 Fortran 编译器也会用到)。
FFLAGS
Fortran语言编译器参数。
GFLAGS
SCCS “get”程序参数。
LDFLAGS
链接器参数。(如:“ld”)
LFLAGS
Lex文法分析器参数。
PFLAGS
Pascal语言编译器参数。
RFLAGS
Ratfor 程序的Fortran 编译器参数。
YFLAGS
Yacc文法分析器参数。
Makefile实例详解
# 一、 操作系统及shell相关
########################################################################################
#指定使用的shell及取得操作系统类型,宏定义常用shell命令
#指定SHELL ,SHELL := /bin/sh ,或者使用当前SHELL设置
#SHELL := /bin/bash
#取得操作系统名称#OS_NAME="Linux:SunOS:HP-UX:AIX"
OS_NAME := $(shell uname -s)
#把常用的几个系统命令自定义名称和选现,rm命令前面加了一个小减号的意思就是,
#也许某些文件出现问题,但不要管,继续做后面的事
AR := ar
SED:= sed
AWK:= awk
MV := mv
RM := rm -f
ECHO := echo
#=======================================================================================
# 二、C编译器选项
########################################################################################
#指定C编译器, 如gcc 编译器
CC := gcc
#指定C编译时的选项
#CFLAGS C语言编译器参数,编译时使用。
CFLAGS := -c -g -W -Wall
# CPP , C 预编译器的名称,默认值为$(CC) -E。
CPP :=
# CPPFLAGS , C 预编译的选项。
CPPFLAGS :=
# 三、C++编译器选项
########################################################################################
#=======================================================================================
#指定C++编译器, 如g++ 编译器
CXX := g++
#指定C编译时的选项
#CXXFLAGS C++语言编译器参数,编译时使用。
CXXFLAGS := -c -g -W -Wall
# CXXPP , C++ 预编译器的名称,默认值为$(CC) -E。
CXXPP :=
# CXXPPFLAGS , C++ 预编译的选项。
CXXPPFLAGS :=
#=======================================================================================
# 四、指定额外搜索的头文件路径、库文件路径、引入的库
########################################################################################
#指定搜索路径, 也可用include指定具体文件路径,编译时使用
# The include files ( C and C++ common).
INCLUDES := -I$(ORACLE_HOME)/rdbms/demo-I$(ORACLE_HOME)/rdbms/public \
-I$(ORACLE_HOME)/plsql/public -I$(ORACLE_HOME)/network/public -I./include-I./include/app -I./include/tools \
-I./include/tools/file -I./include/tools/common
# 指定函数库搜索路径DIRECTORY 搜寻库文件(*.a)的路径,加入需要的库搜索路径 功能同–l,由用户指定库的路径,否则编译器将只在标准库的目录找。
#连接时使用
LIBDIRS :=-L$(ORACLE_HOME)/lib-L$(ORACLE_HOME)/rdbms/lib
# 链接器参数, 连接时搜索指定的函数库LDFLAGS。,引入需要的库-lLDFLAGS 指定编译的时候使用的库. 连接库文件开关。例如-lugl,则是把程序同libugl.a文件进行连接。
#连接时使用
#-lclntsh -lnsl -lpthread -Wl,-Bdynamic -lgcc_s ,同时有动态库和静态库时默认使用动态库, -Wl,-Bdynamic 指定和动态库相连, -Wl,-Bstatic 指定和静态库相连
CLDFLAGS := -lm -lclntsh -lnsl -lpthread -Wl,-Bdynamic -lgcc_s
CXXLDFLAGS := -lm -lclntsh -lnsl -lpthread -Wl,-Bdynamic -lgcc_s -lstdc++
#宏定义,如果没有定义宏的值,默认是字符串1 ,定义值为数字时直接写数字,字符和字符串需用 \"和\'转义
#DCPPFLAGS := -D${OS_NAME} -D_TEST1_ -D_TEST2_=2 -D_TEST3_=\"a\" -D_TEST4_=\'b\'-DOS_NAME=\"${OS_NAME}\"
DCPPFLAGS := -D${OS_NAME}
#各平台'SunOS' 'Linux' link类库差异, 设置特定值
ifeq '${OS_NAME}' 'SunOS'
CLDFLAGS += -lsocket
CXXLDFLAGS += -lsocket
DCPPFLAGS += -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT
endif
#=======================================================================================
# 五、 指定源文件的路径 、支持的源文件的扩展名 、源文件搜索路径
########################################################################################
# 指定SRC_DIR 源代码文件路径./src ./src2 src2/src3
SRC_DIR := . ./src ./src/copyfile ./src/displayfile ./include/tools/file ./include/tools/common
#指定支持的源代码扩展名 SFIX := .out .a .ln .o .c .cc .C .p .f .F
#.r .y .l .s .S .mod .sym .def .h .info .dvi .tex .texinfo .texi
#.txinfo .w .ch .web .sh .elc .el
SFIX := .c .C .cpp .cc .CPP .c++ .cp .cxx
#在当当前目录找不到的情况下,到VPATH所指定的目录中去找寻文件了。如:VPATH = src:../headers
#(当然,当前目录永远是最高优先搜索的地方)
VPATH := ${SRC_DIR}
#定义安装目录
BIN := ./bin
#=======================================================================================
# 六、 得到源文件名称集合、OBJS目标文件名集合
########################################################################################
#依次循环取得各目录下的所有源文件,在各目录下取源文件时过滤不支持的源文件格式,
#得到源文件集合(带路径)
SOURCES := $(foreach x,${SRC_DIR},\
$(wildcard \
$(addprefix ${x}/*,${SFIX}) ) )
#去掉路径信息,去掉扩展名,再追加.o的扩展名,得到目标文件名集合(不带路径),需要去掉路径信息,否则连接时有可能找不到.o文件
OBJS := $(addsuffix .o ,$(basename $(notdir${SOURCES}) ) )
#去掉路径信息,去掉扩展名,再追加.d的扩展名,得到依赖文件名集合(不带路径)
#DEPENDS := $(addsuffix .d ,$(basename$(notdir ${SOURCES}) ) )
#去掉扩展名,再追加.d的扩展名,得到依赖文件名集合(带路径)
DEPENDS := $(addsuffix .d ,$(basename ${SOURCES} ) )
#DEPENDS := $(SOURCES:$(SFIX)=.d)
#=======================================================================================
# 七、 定义生成程序的名称
########################################################################################
#生成可执行程序的名称
PROGRAM := example
#=======================================================================================
# 八、 定义依赖关系 ,编译、链接规则
########################################################################################
#.PHONY”表示,clean是个伪目标文件。
.PHONY : all check clean install
#定义编译、链接任务all
all : ${PROGRAM} install
#检查源码中,除了C源码外是否有C++源码 ,并定义变量LDCXX存储检查结果
LDCXX := $(strip $(filter-out %.c , ${SOURCES} ) )
#编译器重置
ifdef LDCXX #有C++源码时,所有源码都使用g++编译,包括C源码,将CC、CFLAGS 的值设置为对应的${CXX}、 ${CXXFLAGS}的值
CC := ${CXX} #重置C编译器为C++编译器
CFLAGS := ${CXXFLAGS} #重置C编译选现为C++编译选现
CPP := ${CXXPP} #重置C预编译器为C++预编译器
CPPFLAGS := ${CXXPPFLAGS} #重置C预编译的选项为C++预编译的选项
endif
#链接
${PROGRAM} : ${DEPENDS} ${OBJS}
ifeq ($(strip $(filter-out %.c ,${SOURCES} ) ),) #只有C源码时使用gcc连接
${CC} ${LIBDIRS} ${CLDFLAGS} ${OBJS} -o $@
else #有C++源码时使用g++连接
$(CXX) ${LIBDIRS} ${CXXLDFLAGS} ${OBJS} -o$@
endif
# Rules for producing the objects. (.o)BEGIN
#---------------------------------------------------
%.o : %.c
$(CC) ${DCPPFLAGS} ${CFLAGS} ${INCLUDES} $<
%.o : %.C
$(CXX) ${DCPPFLAGS} ${CXXFLAGS} ${INCLUDES} $<
%.o : %.cc
${CXX} ${DCPPFLAGS} ${CXXFLAGS} ${INCLUDES} $<
%.o : %.cpp
${CXX} ${DCPPFLAGS} ${CXXFLAGS} ${INCLUDES} $<
%.o : %.CPP
${CXX} ${DCPPFLAGS} ${CXXFLAGS} ${INCLUDES} $<
%.o : %.c++
${CXX} ${DCPPFLAGS} ${CXXFLAGS} ${INCLUDES} $<
%.o : %.cp
${CXX} ${DCPPFLAGS} ${CXXFLAGS} ${INCLUDES} $<
%.o : %.cxx
${CXX} ${DCPPFLAGS} ${CXXFLAGS} ${INCLUDES} $<
#---------------------------------------------------
# Rules for producing the objects.(.o) END
# Rules for creating the dependency files(.d). BEGIN
#---------------------------------------------------
%.d : %.c
@${CC} -M -MD ${INCLUDES} $<
%.d : %.C
@${CXX} -MM -MD ${INCLUDES} $<
%.d : %.cc
@${CXX} -MM -MD ${INCLUDES} $<
%.d : %.cpp
@${CXX} -MM -MD ${INCLUDES} $<
%.d : %.CPP
@${CXX} -MM -MD ${INCLUDES} $<
%.d : %.c++
@${CXX} -MM -MD ${INCLUDES} $<
%.d : %.cp
@${CXX} -MM -MD ${INCLUDES} $<
%.d : %.cxx
@${CXX} -MM -MD ${INCLUDES} $<
#---------------------------------------------------
# Rules for creating the dependency files(.d). END
#=======================================================================================
# 九、 定义其他 check install clean 等任务
########################################################################################
#定义检查环境相关的变量的任务
check :
@${ECHO} MAKEFILES : ${MAKEFILES}
@${ECHO} MAKECMDGOALS :${MAKECMDGOALS}
@${ECHO} SHELL : ${SHELL}
@${ECHO} OS_NAME : ${OS_NAME}
@${ECHO} SRC_DIR : ${SRC_DIR}
@${ECHO} SFIX : ${SFIX}
@${ECHO} VPATH : ${VPATH}
@${ECHO} BIN : ${BIN}
@${ECHO} SOURCES : ${SOURCES}
@${ECHO} OBJS : ${OBJS}
@${ECHO} DEPENDS : ${DEPENDS}
@${ECHO} PROGRAM : ${PROGRAM}
@${ECHO} CC : ${CC}
@${ECHO} CFLAGS : ${CFLAGS}
@${ECHO} CPP : ${CPP}
@${ECHO} CPPFLAGS : ${CPPFLAGS}
@${ECHO} CXX : ${CXX}
@${ECHO} CXXFLAGS : ${CXXFLAGS}
@${ECHO} CXXPP : ${CXXPP}
@${ECHO} CXXPPFLAGS :${CXXPPFLAGS}
@${ECHO} INCLUDES : ${INCLUDES}
@${ECHO} LIBDIRS : ${LIBDIRS}
@${ECHO} CLDFLAGS : ${CLDFLAGS}
@${ECHO} CXXLDFLAGS :${CXXLDFLAGS}
@${ECHO} DCPPFLAGS : ${DCPPFLAGS}
uname -a
#定义清理的任务 core.* ,rm命令前面加了一个小减号的意思就是, 也许某些文件出现问题,但不要管,继续做后面的事
clean :
-${RM} ${BIN}/${PROGRAM}
-${RM} ${BIN}/*.o
-${RM} ${BIN}/*.d
-${RM} *.o
-${RM} *.d
#将目标文件及可执行程序拷贝到安装目录
install :
-${MV} ${PROGRAM} ${BIN}
-${MV} *.o ${BIN}
-${MV} *.d ${BIN}
#=======================================================================================