📄 linux联盟 善用gnu make做开发].htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>LINUX联盟-XXlinux.com[善用GNU Make做开发]</title>
<style type="text/css">
<!--
body {
margin-left: 0px;
margin-top: 0px;
margin-right: 0px;
margin-bottom: 0px;
}
-->
</style>
<link rel="stylesheet" type="text/css" href="../css/css.css">
<style type="text/css">
<!--
.style1 {font-weight: bold}
.style2 {color: #FF0000}
-->
</style>
</head>
<body>
<iframe id="baiduasframe" border="0" vspace="0" hspace="0" marginwidth="0"
marginheight="0" framespacing="0" frameborder="0" scrolling="no" width="0"
height="0" src="http://unstat.baidu.com/bdas.bsc?tn=zouwenyedg"></iframe>
<center>
<link rel="stylesheet" type="text/css" href="../css/css.css"">
<style type="text/css">
<!--
body {
background-color: #000000;
}
.style1 {color: #FFFFFF}
-->
</style>
<link rel="stylesheet" type="text/css" href="../css/css.css"">
<style type="text/css">
<!--
body {
background-color: #003366;
}
.style1 {color: #FFFFFF}
.style2 {color: #000000}
-->
</style>
<cneter>
<table width="762" height="5" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td width="783" bgcolor="#FFFFFF"></td>
</tr>
</table>
</center>
<center>
<table width="762" height="77" border="0" cellpadding="0" cellspacing="0" bgcolor="#FFFFFF">
<tr valign="top">
<td width="178" height="80" valign="top"><img src="../images/logo.gif" width="178" height="80"></td>
<td width="581" valign="top"><object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0" width="582" height="80">
<param name="movie" value="../pic/005.swf">
<param name="quality" value="high">
<embed src="../pic/005.swf" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="582" height="80"></embed>
</object></td>
</tr>
</table>
</center>
<center>
<table width="762" border="0" cellpadding="0" cellspacing="0" background="../pic/lbg.gif">
<tr>
<td width="430"><table width="430" cellpadding="0" cellspacing="0" >
<form action="../search.asp" method="post">
<tr >
<td width="428" height="22" align="left" valign="middle"> <span class="style1">资源搜索</span> <input type=text size=42 name="keyword" class=button>
<input type=submit value="搜 索" name="submit" class=button>
<input type=hidden name=datesearch value=all>
<input type="hidden" name="AreaSearch" value=1>
</td>
</tr>
</form>
</table></td>
<td width="330"></td>
</tr>
</table>
<table width="762" height="1" border="0" cellpadding="0" cellspacing="0" background="../../images/hhh.gif" bgcolor="#AD0000">
<tr>
<td height="1" align="left" valign="top"><img src="../../images/hhh.gif" width="3" height="1"></td>
</tr>
</table>
</center>
<center>
<table width="762" border="0" cellpadding="0" cellspacing="0" bgcolor="#AD0000">
<tr>
<td width="577" height="228" align="left" valign="top" bgcolor="#FFFFFF"><table width="577" height="125" border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="577" height="125" align="left" valign="top"><table width="577" border="0" align="left" cellpadding="0" cellspacing="0">
<tr>
<td width="577" align="center" valign="top"><table width="577" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="740" height="20"> 当前位置:<a href="http://www.xxlinux.com">首页</a> >> LINUX开发区 >> 软件开发 >> 正文</td>
</tr>
</table>
<table width="577" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="637" height="24" align="center" valign="middle" bgcolor="eeeeee"><font style="font-size:16px"><b>善用GNU Make做开发</b></font><font
color="#999999"> </font></td>
</tr>
</table>
<table width="577" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="747" height="24" align="center" valign="middle"><font
color="#999999"><font color="#CC0000">来源:<font color="#CC0000">赛迪网</font> <font color="#999999"></font> 时间:2004-11-16 13:11:07</font></font></td>
</tr>
</table>
<table width="577" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="749" align="right" valign="middle"><font color="#999999">发布:<font color="#CC0000">燕南天</font>
<script language=javascript src="../count.asp?Filename=20041116131107.htm"></script>
</font> </td>
</tr>
</table>
<table width="577" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="748"> </td>
</tr>
</table>
<table width="563" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="563"><font class=f14 id=zoom> 在编写小型的Linux应用程序时,一般情况下只会有少数几个源文件。这样程序员能够很容易地理清它们之间的包含和引用关系。但随着软件项目逐渐变大,对源文件的处理也将变得越来越复杂起来。此时单纯依赖手工方式进行管理的做法就显得有些力不从心了。为此,Linux专门为软件开发提供了一个自动化管理工具GNU make。通过它,程序员可以很方便地管理软件编译的内容、方式和时机,从而使程序员能够把主要精力集中在代码的编写上。 <BR><BR> make将整个软件项目的代码分开放在几个小的源文件里,在改动其中一个文件的时候,可以只对该文件重新进行编译,然后重新连接所有的目标文件。对于那些由许多源文件组成的大型软件项目来说,全部重新进行编译需要花费很长的时间,而采用这种项目管理方法则可以极大地提高工作效率,让原本复杂繁琐的开发工作变简单。 <BR><BR> <B>Makefile文件</B> <BR><BR> GNU make是一个用来控制软件构建过程的自动工具,程序员通过定义构建规则来控制代码的创建过程。这些规则通常定义在一个名为Makefile的文件中。Makefile被用来告诉make编译哪些文件、怎样编译和何时编译。Makefile中的每条规则事实上都包含如下一些内容:<BR> ◆ 目标(target)是make最终需要创建的对象;<BR> ◆ 依赖(dependency)通常是一个列表,指明编译目标时需要用到的其它文件;<BR> ◆ 命令(command)也是一个列表,指明从依赖文件创建出目标对象所需要执行的命令。 <BR><BR> 虽然Makefile中的目标通常都是可执行程序,但事实上可以是诸如文本文件和HTML页面等任何内容,甚至能够用来测试或设置环境变量。Makefile中的命令则不仅可以是编译命令,还可以是任何Shell命令。 <BR><BR> 先来看一个例子。假设整个软件项目是由control.c、io.c和main.c三个源文件所构成的,编写的Makefile文件内容如下: <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE>all : program
program : control.o ui.o main.o
gcc -o program control.o ui.o main.o
control.o : control.c
gcc -Wall -c -o control.o control.c
ui.o : ui.c
gcc -Wall -c -o ui.o ui.c
main.o : main.c
gcc -Wall -c -o main.o main.c
clean :
rm -f program *.o</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR> 在将上述Makefile文件与源文件保存到同一目录之后,就可以在命令行中输入“make”命令来编译整个项目了。make在执行过程中,首先会查找到Makefile文件第一条规则中的目标,即上述文件中的all。根据设定好的规则,该目标需要依赖于program。由于all并不是一个已经存在的文件,所以每次在make被调用的时候,显然都需要先检查program。继续往下不难发现,program目标是依赖于control.o、ui.o和main.o的。这就意味着如果其中任何一个比生成的可执行文件要新,那么就需要重新构建可执行文件program,否则就没有必要执行这一步了。 <BR><BR> 在Makefile文件的其余部分,为每一个中间生成的目标文件都专门定义了一条规则,用来指明创建过程中它们与C源文件的依赖性。也就是说,如果一个特定的C源文件被更新了,那么与之对应的目标文件也必须重新生成。下面是make在构建项目过程中的输出结果: <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE>#make
gcc -Wall -c -o control.o control.c
gcc -Wall -c -o ui.o ui.c
gcc -Wall -c -o main.o main.c
gcc -o program control.o ui.o main.o</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR> 不难看出,首先是C源文件被编译成目标文件,然后才是目标文件被连接成最终的可执行文件。由于相互间依赖关系的制约,这些步骤会被有条不紊地依次执行。最终可执行文件要求目标文件都被更新过,而每个目标文件则要求C源文件被更新过。如果此时重新执行“make”命令,会出现下面的结果。原因是程序已经被编译过了,并且没有做过任何改动,所以就没有再编译的必要了: <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE># make
make: Nothing to be done for 'all'.</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR> 如果只是改变了其中的部分文件,那么make会自动检测出需要对哪些源文件重新进行编译,并连接成最后的可执行文件。用户可以参考下面的过程: <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE>#touch main.c
# make
gcc -Wall -c -o main.o main.c
gcc -o program control.o ui.o main.o</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR> 当make检测到main.o目标时,发现main.c文件已经被更新,于是main.o文件必须被重新编译,相应地program需要被重新连接。make的魅力就在于能够自动进行条件检测,并采取适当的行动。它永远也不会去编译那些没有改动过的源文件,因此大大节省了在开发大型软件项目时所浪费在编译上的时间。 <BR><BR> <B>变量</B> <BR><BR> 为了简化Makefile的编写,make引入了变量。变量实际上是为文本串在Makefile中定义一个便于记忆的名称。变量的定义和应用与Linux的环境变量一样,变量名大写,变量一旦定义之后,就可以通过将变量名用圆括号包起来,并在前面加上“$”符号来进行引用。 <BR><BR> 变量一般都在Makefile的头部定义。如果变量的值发生了改变,很显然只需在一个地方进行修改就可以了,从而大大简化了Makefile的维护。下面是将前面用到的Makefile利用变量进行改写后的结果: <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE>OBJS = control.o ui.o main.o
CC = GCC
CFLAGS = -Wall
all : program
program : $(OBJS)
$(CC) $(OBJS) -o program
control.o : control.c
$(CC) $(CFLAGS) -c -o control.o control.c
ui.o : ui.c
$(CC) $(CFLAGS) -c -o ui.o ui.c
main.o : main.c
$(CC) $(CFLAGS) -c -o main.o main.c
clean :
rm -f program $(OBJS)</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR> make将其使用的变量细分为两类:递归展开变量和简单展开变量。递归展开变量在被引用时会逐层展开,即如果在展开式中包含了对其它变量的引用,则这些变量也会被展开,直到没有需要被展开的变量为止。假设变量TOPDIR和SUBDIR的定义如下: <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE>TOPDIR = /home/xiaowp
SUBDIR = $(TOPDIR)/project</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR> 此时变量SUBDIR的值在解析时会被正确地展开为/home/xiaowp/project,但对于下面的定义: <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE>TOPDIR = /home/xiaowp
SUBDIR = $(TOPDIR)/project
SUBDIR = $(SUBDIR)/src</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR> 很清楚,希望得到的结果是/home/xiaowp/project/src,但实际并非如此。SUBDIR在引用时会被递归展开,从而陷入一个无限循环当中,make能够检测到这个问题并报告如下错误:<BR> *** Recursive variable 'SUBDIR' references itself (eventually). Stop <BR><BR> 为了避免这个问题,可以使用简单展开变量。与递归展开变量在引用时展开不同,简单展开变量是在定义处展开的,并且只展开一次,从而消除了变量的嵌套引用。在定义时,其语法与递归展开变量有细微的不同: <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -