用途说明
make命令是一个常用的编译命令,尤其是在开发C/C++程序时,它通过Makefile文件中描述的源程序之间的依赖关系来自动进行编译。Makefile文件是按照规定的格式编写的,文件中需要说明如何编译各个源文件并连接生成可执行文件,并要求定义源文件之间的依赖关系。在首次执行 make时,会将所有相关的文件都进行编译,而在以后make时,通常是进行增量编译,即只对修改过的源代码进行编译。许多Tarball格式的开源软 件,在解压之后,一般先执行./configure,然后执行make,再执行make install进行安装。在进行Java编译时,我们常用的是ant,这个ant工具的发明乃是由于James被makefile的特殊格式弄烦了,采用 XML格式来描述任务之间的关系,但是ant工具借鉴了make工具的做法这是肯定的。
man make 写道
The purpose of themake utility is to determine automatically which pieces of a large program needto be recom-
piled, and issue thecommands to recompile them. The manual describes the GNU implementation ofmake, which
was written byRichard Stallman and Roland McGrath, and is currently maintained by Paul Smith.Our examples
show C programs,since they are most common, but you can use make with any programming languagewhose compiler
can be run with ashell command. In fact, make is not limited to programs. You can use it todescribe any
task where somefiles must be updated automatically from others whenever the others change.
To prepare to usemake, you must write a file called the makefile that describes therelationships among files
in your program, andthe states the commands for updating each file. In a program, typically theexecutable
file is updated fromobject files, which are in turn made by compiling source files.
Once a suitablemakefile exists, each time you change some source files, this simple shellcommand:
make
suffices to performall necessary recompilations. The make program uses the makefile data base andthe last-
modification timesof the files to decide which of the files need to be updated. For each of thosefiles, it
issues the commandsrecorded in the data base.
make executescommands in the makefile to update one or more target names, where name istypically a program.
If no -f option ispresent, make will look for the makefiles GNUmakefile, makefile, and Makefile,in that
order.
Normally you shouldcall your makefile either makefile or Makefile. (We recommend Makefile becauseit appears
prominently near thebeginning of a directory listing, right near other important files such asREADME.) The
first name checked,GNUmakefile, is not recommended for most makefiles. You should use this name ifyou have a
makefile that isspecific to GNU make, and will not be understood by other versions of make. Ifmakefile is
‘-’, the standardinput is read.
make updates atarget if it depends on prerequisite files that have been modified since thetarget was last
modified, or if thetarget does not exist.
使用make进行编译的关键点就是掌握makefile的编写规则,make的手册页中说道,makefile文件可以是GNUmakefile,makefile或者Makefile,但是推荐使用Makefile,因为在列出某个目录的文件时,使用Makefile作为文件名时将被排在前面。 makefile文件也像C/C++代码一样支持include方式,即把一些基本的依赖规则写在一个公共的文件中,然后其他makefile文件包含此 文件。我所使用的公共makefile文件名为common.mk,是多年以前从一个高人那儿拷贝而来的,现在贡献给大家。里面有些晦涩难懂的 makefile指令,但是对于使用者来说可以不必关注。思路就是将makefile所在目录的源程序找出来,然后按照依赖关系进行编译。
common.mk 写道
#This is the commonpart for makefile
SOURCE := $(wildcard*.c) $(wildcard *.cc) $(wildcard *.cpp)
OBJS := $(patsubst%.c,%.o,$(patsubst %.cc,%.o,$(patsubst %.cpp,%.o,$(SOURCE))))
DEPS := $(patsubst%.o,%.d,$(OBJS))
MISSING_DEPS :=$(filter-out $(wildcard $(DEPS)),$(DEPS))
CPPFLAGS += -MD
.PHONY : everythingobjs clean veryclean vc rebuild ct rl
everything :$(TARGETS)
objs : $(OBJS)
clean :
@$(RM) *.o
@$(RM) *.d
veryclean: clean
@$(RM) $(TARGETS)
@$(RM) cscope.out
@$(RM) core*
vc: veryclean
ct:
@$(RM) $(TARGETS)
rl: ct everything
rebuild: verycleaneverything
ifneq($(MISSING_DEPS),)
$(MISSING_DEPS) :
@$(RM) $(patsubst%.d,%.o,$@)
endif
-include $(DEPS)
怎么来使用这个common.mk来帮助我们编写makefile文件呢,首先我们来看一下编译成静态库的情况。见下面文件,其中的libhyfcd.a就是目标静态库文件的名称,INCS定义了依赖的包含文件路径。
makefile 写道
TARGETS = $(BIN1)
BIN1 = libhyfcd.a
BIN1_OBJS = $(OBJS)
BIN1_LIBS =
BIN1_LFLAGS =
INCS = -I..-I../../hycu2 -I/usr/include/mysql
#CC := g++
CC := gcc
CXX := gcc
CFLAGS := -g $(INCS)-Wall -D_REENTRANT -D__DECLSPEC_SUPPORTED -DOPENSSL_NO_KRB5 #-DNDEBUG
CXXFLAGS :=$(CFLAGS)
include common.mk
# $(BIN1) :$(BIN1_OBJS)
# $(CC) -g -o $@$(BIN1_LFLAGS) $^ $(addprefix -l,$(BIN1_LIBS))
$(BIN1):$(BIN1_OBJS)
ar rcs $@ $^
再来看一下编译成可执行文件的情况。见下面文件,其中msgc就是目标执行文件,BIN1_LIBS是依赖的库。
写道
TARGETS = $(BIN1)
BIN1 = msgc
BIN1_OBJS = $(OBJS)
BIN1_LIBS = cursespthread
BIN1_LFLAGS =#-L../hyfc/lib
INCS = #-I../hyfc
CC := g++
CFLAGS := -g $(INCS)-Wall
#CFLAGS := -g$(INCS) -Wall -DLOG_CHECK
#CFLAGS := -g$(INCS) -Wall #-DNDEBUG
CXXFLAGS :=$(CFLAGS)
include/usr/include/hyfc/common.mk
$(BIN1) :$(BIN1_OBJS)
$(CC) -g -o $@$(BIN1_LFLAGS) $^ $(addprefix -l,$(BIN1_LIBS))
补充(2011.08.07):列位看官,如果你关注的是Makefile的语法结构,那么不妨看参考资料【5】《GNUmake中文手册》。
常用参数
格式:make
使用默认的makefile文件进行编译,按照GNUmakefile,makefile和Makefile的顺序进行查找。编译目标all。
格式:make -fmakefile.debug
使用指定的makefile进行编译,此处就是makefile.debug。编译目标all。
格式:make install
编译目标install。通常用于安装软件。
格式:make clean
编译目标clean。通常用于清除目标文件.o。
格式:make veryclean
编译目标clean。通常用于清除目标文件.o以及执行文件等,意思是干净的清除掉除makefile和源程序之外的文件。
格式:make rl
编译目标rl。rl是relink的缩写,即重新链接,常用于某个依赖的库文件发生变化时强制重新链接生成执行文件。
使用示例
示例一 编译安装mysql++2.3.2的过程
[root@jfht setup]# ls mysql++-2.3.2.tar.gz
mysql++-2.3.2.tar.gz
[root@jfht setup]# tar zxf mysql++-2.3.2.tar.gz
[root@jfht setup]# cd mysql++-2.3.2
[root@jfhtmysql++-2.3.2]# ./configure --prefix=/usr
checking buildsystem type... i686-pc-linux-gnu
checking host systemtype... i686-pc-linux-gnu
checking targetsystem type... i686-pc-linux-gnu
checking for gcc...gcc
checking for Ccompiler default output file name... a.out
checking whether theC compiler works... yes
checking whether weare cross compiling... no
checking for suffixof executables...
checking for suffixof object files... o
checking whether weare using the GNU C compiler... yes
checking whether gccaccepts -g... yes
checking for gccoption to accept ANSI C... none needed
checking forranlib... ranlib
checking for aBSD-compatible install... /usr/bin/install -c
checking whether ln-s works... yes
checking whethermake sets $(MAKE)... yes
checking for ar...ar
checking forstrip... strip
checking for nm...nm
checking if make isGNU make... yes
checking fordependency tracking method... gcc
checking for gcc...(cached) gcc
checking whether weare using the GNU C compiler... (cached) yes
checking whether gccaccepts -g... (cached) yes
checking for gccoption to accept ANSI C... (cached) none needed
checking how to runthe C preprocessor... gcc -E
checking foregrep... grep -E
checking for ANSI Cheader files... yes
checking forsys/types.h... yes
checking forsys/stat.h... yes
checking forstdlib.h... yes
checking forstring.h... yes
checking formemory.h... yes
checking forstrings.h... yes
checking forinttypes.h... yes
checking forstdint.h... yes
checking forunistd.h... yes
checking zlib.husability... yes
checking zlib.hpresence... yes
checking forzlib.h... yes
checking for gzreadin -lz... yes
checking whether -lmis needed to use C math functions... no
checking whether-lsocket is needed... no
checking whether-lnsl is needed... no
checking for MySQLlibrary directory... /usr/lib
checking for MySQLinclude directory... /usr/include/mysql
checking formysql_store_result in -lmysqlclient... yes
checking formysql_ssl_set in -lmysqlclient... yes
checking forlocaltime_r()... yes
checking for main in-lintl... no
checking for g++...g++
checking whether weare using the GNU C++ compiler... yes
checking whether g++accepts -g... yes
checking for STLslist extension... <ext/slist>, namespace __gnu_cxx
configure: creating./config.status
config.status:creating Makefile
config.status:creating mysql++.spec
config.status:creating lib/Doxyfile
config.status:creating lib/mysql++.h
config.status:creating config.h
[root@jfhtmysql++-2.3.2]# make && make install
此处省略较多输出。
/usr/bin/install -c-d /usr/lib
/usr/bin/install -c-m 644 libmysqlpp.so /usr/lib
/usr/bin/install -clibmysqlpp.so.2.3.2 /usr/lib
(cd /usr/lib ; rm -flibmysqlpp.so libmysqlpp.so.2; ln -s libmysqlpp.so.2.3.2 libmysqlpp.so.2; ln -slibmysqlpp.so.2 libmysqlpp.so)
/usr/bin/install -c-d /usr/include/mysql++
(cd . ;/usr/bin/install -c -m 644 lib/*.h /usr/include/mysql++)
[root@jfhtmysql++-2.3.2]#
示例二 使用common.mk进行编译的例子
[root@jfht src]# make
make: Nothing to bedone for `everything'.
[root@jfht src]# make clean
[root@jfht src]# make
g++ -g -Wall -MD -c -o compiler.o compiler.cpp
g++ -g -Wall -MD -c -o file_updater.o file_updater.cpp
g++ -g -Wall -MD -c -o file_util.o file_util.cpp
g++ -g -Wall -MD -c -o gen_async.o gen_async.cpp
g++ -g -Wall -MD -c -o gen_c.o gen_c.cpp
g++ -g -Wall -MD -c -o gen_cpp.o gen_cpp.cpp
g++ -g -Wall -MD -c -o gen_fmdo2.o gen_fmdo2.cpp
g++ -g -Wall -MD -c -o gen_fmdo.o gen_fmdo.cpp
g++ -g -Wall -MD -c -o gen_hyfc.o gen_hyfc.cpp
g++ -g -Wall -MD -c -o gen_hyfcw.o gen_hyfcw.cpp
g++ -g -Wall -MD -c -o gen_java.o gen_java.cpp
g++ -g -Wall -MD -c -o gen_jdom.o gen_jdom.cpp
g++ -g -Wall -MD -c -o gen_jt.o gen_jt.cpp
g++ -g -Wall -MD -c -o gen_jxh.o gen_jxh.cpp
g++ -g -Wall -MD -c -o gen_pas.o gen_pas.cpp
g++ -g -Wall -MD -c -o gen_php.o gen_php.cpp
g++ -g -Wall -MD -c -o gen_struts.o gen_struts.cpp
g++ -g -Wall -MD -c -o gen_tag.o gen_tag.cpp
g++ -g -Wall -MD -c -o gen_udpsw.o gen_udpsw.cpp
g++ -g -Wall -MD -c -o gen_wsdl.o gen_wsdl.cpp
g++ -g -Wall -MD -c -o gen_xml.o gen_xml.cpp
g++ -g -Wall -MD -c -o msgc.o msgc.cpp
g++ -g -Wall -MD -c -o string_util.o string_util.cpp
g++ -g -o msgc compiler.o file_updater.o file_util.o gen_async.o gen_c.o gen_cpp.o gen_fmdo2.ogen_fmdo.o gen_hyfc.o gen_hyfcw.o gen_java.o gen_jdom.o gen_jt.o gen_jxh.ogen_pas.o gen_php.o gen_struts.o gen_tag.o gen_udpsw.o gen_wsdl.o gen_xml.o msgc.ostring_util.o -lcurses -lpthread
cp -af msgc /usr/bin
cp -af msgcmsgc.`uname -r`
[root@jfht src]# make rl
g++ -g -o msgc compiler.o file_updater.o file_util.o gen_async.o gen_c.o gen_cpp.o gen_fmdo2.ogen_fmdo.o gen_hyfc.o gen_hyfcw.o gen_java.o gen_jdom.o gen_jt.o gen_jxh.ogen_pas.o gen_php.o gen_struts.o gen_tag.o gen_udpsw.o gen_wsdl.o gen_xml.o msgc.ostring_util.o -lcurses -lpthread
cp -af msgc /usr/bin
cp -af msgcmsgc.`uname -r`
[root@jfht src]#