}
由于参数student表示的是一个对constStudent型对象的引用,所以student不能调用非const成员函数如set_student()。
如果get_name()和get_score()成员函数也变成非const型,那么上面的student.get_name()和student.get_score()的使用就是非法的,这样就会给我们处理问题造成困难。
因此,我们没有理由反对使用const,该加const时就应该加上const,这样使成员函数除了非const的对象之外,const对象也能够调用它。
c/C++通用Makefile
GenericMakefileforC/C++Program
==================================================
Keywords:
Makefile,make,Generic,C/C++
Author:
whyglinux(whyglinuxAThotmailDOTcom)
Date:
2006-03-04
==================================================
本文提供了一个用于对C/C++程序进行编译和连接以产生可执行程序的通用Makefile。
在使用Makefile之前,只需对它进行一些简单的设置即可;而且一经设置,即使以后对源程序文件有所增减一般也不再需要改动Makefile。
因此,即便是一个没有学习过Makefile书写规则的人,也可以为自己的C/C++程序快速建立一个可工作的Makefile。
这个Makefile可以在GNUMake和GCC编译器下正常工作。
但是不能保证对于其它版本的Make和编译器也能正常工作。
如果你发现了本文中的错误,或者对本文有什么感想或建议,可通过whyglinuxAThotmailDOTcom邮箱和作者联系。
此Makefile的使用方法如下:
1.程序目录的组织
尽量将自己的源程序集中在一个目录中,并且把Makefile和源程序放在一起,这样用起来比较方便。
当然,也可以将源程序分类存放在不同的目录中。
在程序目录中创建一个名为Makefile的文本文件,将后面列出的Makefile的内容复制到这个文件中。
(注意:
在复制的过程中,Makfile中各命令前面的Tab字符有可能被转换成若干个空格。
这种情况下需要把Makefile命令前面的这些空格替换为一个Tab。
)
将当前工作目录切换到Makefile所在的目录。
目前,这个Makefile只支持在当前目录中的调用,不支持当前目录和Makefile所在的路径不是同一目录的情况。
2.指定可执行文件
程序编译和连接成功后产生的可执行文件在Makefile中的PROGRAM变量中设定。
这一项不能为空。
为自己程序的可执行文件起一个有意义的名子吧。
3.指定源程序
要编译的源程序由其所在的路径和文件的扩展名两项来确定。
由于头文件是通过包含来使用的,所以在这里说的源程序不应包含头文件。
程序所在的路径在SRCDIRS中设定。
如果源程序分布在不同的目录中,那么需要在SRCDIRS中一一指定,并且路径名之间用空格分隔。
在SRCEXTS中指定程序中使用的文件类型。
C/C++程序的扩展名一般有比较固定的几种形式:
.c、.C、.cc、.cpp、.CPP、.c++、.cp、或者.cxx(参见mangcc)。
扩展名决定了程序是C还是C++程序:
.c是C程序,其它扩展名表示C++程序。
一般固定使用其中的一种扩展名即可。
但是也有可能需要使用多种扩展名,这可以在SOURCE_EXT中一一指定,各个扩展名之间用空格分隔。
虽然并不常用,但是C程序也可以被作为C++程序编译。
这可以通过在Makefile中设置CC=$(CXX)和CFLAGS=$(CXXFLAGS)两项即可实现。
这个Makefile支持C、C++以及C/C++混合三种编译方式:
o如果只指定.c扩展名,那么这是一个C程序,用$(CC)表示的编译命令进行编译和连接。
o如果指定的是除.c之外的其它扩展名(如.cc、.cpp、.cxx等),那么这是一个C++程序,用$(CXX)进行编译和连接。
o如果既指定了.c,又指定了其它C++扩展名,那么这是C/C++混合程序,将用$(CC)编译其中的C程序,用$(CXX)编译其中的C++程序,最后再用$(CXX)连接程序。
这些工作都是make根据在Makefile中提供的程序文件类型(扩展名)自动判断进行的,不需要用户干预。
4.指定编译选项
编译选项由三部分组成:
预处理选项、编译选项以及连接选项,分别由CPPFLAGS、CFLAGS与CXXFLAGS、LDFLAGS指定。
CPPFLAGS选项可参考C预处理命令cpp的说明,但是注意不能包含-M以及和-M有关的选项。
如果是C/C++混合编程,也可以在这里设置C/C++的一些共同的编译选项。
CFLAGS和CXXFLAGS两个变量通常用来指定编译选项。
前者仅仅用于指定C程序的编译选项,后者仅仅用于指定C++程序的编译选项。
其实也可以在两个变量中指定一些预处理选项(即一些本来应该放在CPPFLAGS中的选项),和CPPFLAGS并没有明确的界限。
连接选项在LDFLAGS中指定。
如果只使用C/C++标准库,一般没有必要设置。
如果使用了非标准库,应该在这里指定连接需要的选项,如库所在的路径、库名以及其它联接选项。
现在的库一般都提供了一个相应的.pc文件来记录使用库所需要的预编译选项、编译选项和连接选项等信息,通过pkg-config可以动态提取这些选项。
与由用户显式指定各个选项相比,使用pkg-config来访问库提供的选项更方便、更具通用性。
在后面可以看到一个GTK+程序的例子,其编译和连接选项的指定就是用pkg-config实现的。
5.编译和连接
上面的各项设置好之后保存Makefile文件。
执行make命令,程序就开始编译了。
命令make会根据Makefile中设置好的路径和文件类型搜索源程序文件,然后根据文件的类型调用相应的编译命令、使用相应的编译选项对程序进行编译。
编译成功之后程序的连接会自动进行。
如果没有错误的话最终会产生程序的可执行文件。
注意:
在对程序编译之后,会产生和源程序文件一一对应的.d文件。
这是表示依赖关系的文件,通过它们make决定在源程序文件变动之后要进行哪些更新。
为每一个源程序文件建立相应的.d文件这也是GNUMake推荐的方式。
6.Makefile目标(Targets)
下面是关于这个Makefile提供的目标以及它所完成的功能:
omake
编译和连接程序。
相当于makeall。
omakeobjs
仅仅编译程序产生.o目标文件,不进行连接(一般很少单独使用)。
omakeclean
删除编译产生的目标文件和依赖文件。
omakecleanall
删除目标文件、依赖文件以及可执行文件。
omakerebuild
重新编译和连接程序。
相当于makeclean&&makeall。
关于这个Makefile的实现原理不准备详细解释了。
如果有兴趣的话,可参考文末列出的“参考资料”。
Makefile的内容如下:
代码:
###############################################################################
#
#GenericMakefileforC/C++Program
#
#Author:
whyglinux(whyglinuxAThotmailDOTcom)
#Date:
2006/03/04
#Description:
#Themakefilesearchesindirectoriesforthesourcefiles
#withextensionsspecifiedin,thencompilesthesources
#andfinallyproducesthe,theexecutablefile,bylinking
#theobjectives.
#Usage:
# $make compileandlinktheprogram.
# $makeobjs compileonly(nolinking.Rarelyused).
# $makeclean cleantheobjectivesanddependencies.
# $makecleanall cleantheobjectives,dependenciesandexecutable.
# $makerebuild rebuildtheprogram.Thesameasmakeclean&&makeall.
#==============================================================================
##CustomizingSection:
adjustthefollowingifnecessary.
##=============================================================================
#Theexecutablefilename.
#Itmustbespecified.
#PROGRAM :
=a.out #theexecutablename
PROGRAM :
=
#Thedirectoriesinwhichsourcefilesreside.
#Atleastonepathshouldbespecified.
#SRCDIRS :
=. #currentdirectory
SRCDIRS :
=
#Thesourcefiletypes(headersexcluded).
#Atleastonetypeshouldbespecified.
#Thevalidsuffixesareamongof.c,.C,.cc,.cpp,.CPP,.c++,.cp,or.cxx.
#SRCEXTS :
=.c #Cprogram
#SRCEXTS :
=.cpp #C++program
#SRCEXTS :
=.c.cpp#C/C++program
SRCEXTS :
=
#Theflagsusedbythecpp(mancppformore).
#CPPFLAGS :
=-Wall-Werror#showallwarningsandtakethemaserrors
CPPFLAGS :
=
#ThecompilingflagsusedonlyforC.
#IfitisaC++program,noneedtosettheseflags.
#IfitisaCandC++mergingprogram,settheseflagsfortheCparts.
CFLAGS :
=
CFLAGS +=
#ThecompilingflagsusedonlyforC++.
#IfitisaCprogram,noneedtosettheseflags.
#IfitisaCandC++mergingprogram,settheseflagsfortheC++parts.
CXXFLAGS :
=
CXXFLAGS +=
#Thelibraryandthelinkoptions(CandC++common).
LDFLAGS :
=
LDFLAGS +=
##ImplictSection:
changethefollowingonlywhennecessary.
##=============================================================================
#TheCprogramcompiler.Uncommentittospecifyyoursexplicitly.
#CC =gcc
#TheC++programcompiler.Uncommentittospecifyyoursexplicitly.
#CXX =g++
#Uncommentthe2linestocompileCprogramsasC++ones.
#CC =$(CXX)
#CFLAGS =$(CXXFLAGS)
#Thecommandusedtodeletefile.
#RM =rm-f
##StableSection:
usuallynoneedtobechanged.Butyoucanaddmore.
##=============================================================================
SHELL =/bin/sh
SOURCES=$(foreachd,$(SRCDIRS),$(wildcard$(addprefix$(d)/*,$(SRCEXTS))))
OBJS =$(foreachx,$(SRCEXTS),\
$(patsubst%$(x),%.o,$(filter%$(x),$(SOURCES))))
DEPS =$(patsubst%.o,%.d,$(OBJS))
.PHONY:
allobjscleancleanallrebuild
all:
$(PROGRAM)
#Rulesforcreatingthedependencyfiles(.d).
#---------------------------------------------------
%.d:
%.c
@$(CC)-MM-MD$(CFLAGS)$<
%.d:
%.C
@$(CC)-MM-MD$(CXXFLAGS)$<
%.d:
%.cc
@$(CC)-MM-MD$(CXXFLAGS)$<
%.d:
%.cpp
@$(CC)-MM-MD$(CXXFLAGS)$<
%.d:
%.CPP
@$(CC)-MM-MD$(CXXFLAGS)$<
%.d:
%.c++
@$(CC)-MM-MD$(CXXFLAGS)$<
%.d:
%.cp
@$(CC)-MM-MD$(CXXFLAGS)$<
%.d:
%.cxx
@$(CC)-MM-MD$(CXXFLAGS)$<
#Rulesforproducingtheobjects.
#---------------------------------------------------
objs:
$(OBJS)
%.o:
%.c
$(CC)-c$(CPPFLAGS)$(CFLAGS)$<
%.o:
%.C
$(CXX)-c$(CPPFLAGS)$(CXXFLAGS)$<
%.o:
%.cc
$(CXX)-c$(CPPFLAGS)$(CXXFLAGS)$<
%.o:
%.cpp
$(CXX)-c$(CPPFLAGS)$(CXXFLAGS)$<
%.o:
%.CPP
$(CXX)-c$(CPPFLAGS)$(CXXFLAGS)$<
%.o:
%.c++
$(CXX-c$(CPPFLAGS)$(CXXFLAGS)$<
%.o:
%.cp
$(CXX)-c$(CPPFLAGS)$(CXXFLAGS)$<
%.o:
%.cxx
$(CXX)-c$(CPPFLAGS)$(CXXFLAGS)$<
#Rulesforproducingtheexecutable.
#----------------------------------------------
$(PROGRAM):
$(OBJS)
ifeq($(strip$(SRCEXTS)),.c) #Cfile
$(CC)-o$(PROGRAM)$(OBJS)$(LDFLAGS)
else #C++file
$(CXX)-o$(PROGRAM)$(OBJS)$(LDFLAGS)
endif
-include$(DEPS)
rebuild:
cle