📄 ch55.htm
字号:
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
<SCRIPT>
<!--
function displayWindow(url, width, height) {
var Win = window.open(url,"displayWindow",'width=' + width +
',height=' + height + ',resizable=1,scrollbars=yes');
}
//-->
</SCRIPT>
</HEAD>
-->
<font face="Arial,Helvetica" size="-1" color="#006666">
<b>Linux</b></font><p>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<UL>
<LI><A HREF="#Heading1">- 55 -</A>
<UL>
<LI><A HREF="#Heading2">Source Code Control</A>
<UL>
<LI><A HREF="#Heading3">make</A>
<LI><A HREF="#Heading4">NOTE</A>
<UL>
<LI><A HREF="#Heading5">A Sample makefile</A>
<LI><A HREF="#Heading6">Basic makefile Format</A>
</UL>
<LI><A HREF="#Heading7">TIP</A>
<UL>
<LI><A HREF="#Heading8">Building Different Versions of Programs</A>
<LI><A HREF="#Heading9">Forcing Recompiles</A>
</UL>
<LI><A HREF="#Heading10">TIP</A>
<UL>
<LI><A HREF="#Heading11">Macros</A>
<LI><A HREF="#Heading12">Suffix Rules</A>
</UL>
<LI><A HREF="#Heading13">RCS</A>
<UL>
<LI><A HREF="#Heading14">Deltas</A>
</UL>
<LI><A HREF="#Heading15">TIP</A>
<LI><A HREF="#Heading16">NOTE</A>
<UL>
<LI><A HREF="#Heading17">Creating an RCS file</A>
<LI><A HREF="#Heading18">Retrieving an RCS File</A>
<LI><A HREF="#Heading19">Using Keywords</A>
</UL>
<LI><A HREF="#Heading20">Retrieving Version Information from an RCS File</A>
<LI><A HREF="#Heading21">Administering Access</A>
<LI><A HREF="#Heading22">Comparing and Merging Revisions</A>
<LI><A HREF="#Heading23">NOTE</A>
<LI><A HREF="#Heading24">Tying It All Together: Working with make and RCS</A>
<LI><A HREF="#Heading25">Summary</A>
</UL>
</UL>
</UL>
<P>
<HR SIZE="4">
<H2 ALIGN="CENTER"><A NAME="Heading1<FONT COLOR="#000077">- 55 -</FONT></H2>
<H2 ALIGN="CENTER"><A NAME="Heading2<FONT COLOR="#000077">Source Code Control</FONT></H2>
<P><I>by Peter MacKinnon</I></P>
<P>IN THIS CHAPTER</P>
<UL>
<LI>make
<P>
<LI>RCS
<P>
<LI>Retrieving Version Information from an RCS File
<P>
<LI>Administering Access
<P>
<LI>Comparing and Merging Revisions
<P>
<LI>Tying It All Together: Working with make and RCS
</UL>
<P>A large-scale software project involving numerous files and programmers can present
logistical nightmares if you happen to be the poor soul responsible for managing
it:</P>
<P>"How do I know whether this file of input/output routines that Sue has been
working on is the most current one?"</P>
<P>"Oh, no--I have to recompile my application, but I can't remember which of
these 50 files I changed since the last compile!"</P>
<P>Even small applications typically use more than one source code file. When compiling
and linking C applications, you usually must deal with not only source code, but
also header files and library files. Fortunately, Linux features a software development
environment that, for the most part, can greatly simplify these concerns.</P>
<P>In this chapter, we will look at the following software development utilities
for Linux:
<UL>
<LI><TT>make</TT>
<P>
<LI><BR>
RCS (Revision Control System)
</UL>
<H3 ALIGN="CENTER"><A NAME="Heading3<FONT COLOR="#000077">make</FONT></H3>
<P>Perhaps the most important of all the software development utilities for Linux,
<TT>make</TT> is a program that keeps a record of dependencies between files and
only updates those files that have been changed since the last update. The term update
usually refers to a compile or link operation, but it may also involve the removal
of temporary files. This updating process can sometimes be repeated dozens of times
in the course of a software project. Instead of managing these tasks manually, <TT>make</TT>
can be your automatic dependency manager, giving you more time to do other important
things such as coding or watching TV.</P>
<P><TT>make</TT> generates commands using a description file known as a <TT>makefile</TT>.
These commands are then executed by the shell. The <TT>makefile</TT> is basically
a set of rules for <TT>make</TT> to follow whenever performing an update of your
program. These rules usually relate to the definition of the dependencies between
files. In the case of creating a Linux executable of C code, this usually means compiling
source code into object files, and linking those object files together, perhaps with
additional library files. <TT>make</TT> also can figure some things out for itself,
such as the fact that the modification times (or timestamps) for certain files may
have changed.
<DL>
<DT></DT>
</DL>
<DL>
<DD>
<HR>
<A NAME="Heading4<FONT COLOR="#000077"><B>NOTE: </B></FONT><TT>makefile</TT>
or <TT>Makefile</TT> is literally the name that the <TT>make</TT> program expects
to find in the current directory.
<HR>
</DL>
<P><TT>make</TT> is certainly best suited for C programming, but it can be used with
other types of language compilers for Linux, such as assembler or FORTRAN.
<H4 ALIGN="CENTER"><A NAME="Heading5<FONT COLOR="#000077">A Sample makefile</FONT></H4>
<P>Let's look at a simple application of <TT>make</TT>. The command<FONT COLOR="#0066FF"></FONT>
<PRE><FONT COLOR="#0066FF">$ make someonehappy
</FONT></PRE>
<P>tells Linux that you want to create a new version of <TT>someonehappy</TT>. In
this case, <TT>someonehappy</TT> is an executable program; thus, there will be compiling
and linking of files. <TT>someonehappy</TT> is referred to as the target of this
<TT>make</TT> operation. The object files that are linked together to create the
executable are known as <TT>someonehappy</TT>'s dependents. The source code files
that are compiled to create these object files are also indirect dependents of <TT>someonehappy</TT>.</P>
<P>The files that are used to build <TT>someonehappy</TT> are the following (the
contents of these files are unimportant to the example): Two C source code files:
<TT>main.c</TT>, <TT>dothis.c</TT></P>
<P>Three header files: <TT>yes.h</TT>, <TT>no.h</TT>, <TT>maybe.h</TT></P>
<P>One library file: <TT>/usr/happy/lib/likeatree.a</TT>
<BLOCKQUOTE>
<P>An assembly language file: <TT>itquick.s</TT>
</BLOCKQUOTE>
<P>It appears that this is a small project, so you could choose to manually compile
and link these files to build your executable. Instead, create a <TT>makefile</TT>
for your <TT>someonehappy</TT> project to help automate these tedious tasks.</P>
<P>In your favorite editor, write the following:<FONT COLOR="#0066FF"></FONT>
<PRE><FONT COLOR="#0066FF">someonehappy: main.o dothis.o itquick.o /usr/happy/lib/likeatree.a
cc -o someonehappy main.o dothis.o itquick.o /usr/happy/lib/likeatree.a
main.o: main.c
cc -c main.c
dothis.o: dothis.c
cc -c dothis.c
itquick.o: itquick.s
as -o itquick.o itquick.s
fresh:
rm *.o
maybe.h: yes.h no.h
cp yes.h no.h /users/sue/
</FONT></PRE>
<H4 ALIGN="CENTER"><A NAME="Heading6<FONT COLOR="#000077">Basic makefile Format</FONT></H4>
<P>So, assuming that these files are in the same directory as the <TT>makefile</TT>,
what do you have? The format of a <TT>makefile</TT> such as the one you have made
is a series of entries. Your <TT>makefile</TT> has six entries: the first line of
an entry is the dependency line, which lists the dependencies of the target denoted
at the left of the colon; the second line is one or more command lines, which tells
<TT>make</TT> what to do if the target is newer than its dependent (or dependents).
An entry basically looks like this:<FONT COLOR="#0066FF"></FONT>
<PRE><FONT COLOR="#0066FF">target: dependents
(TAB) command list
</FONT></PRE>
<P>The space to the left of the <TT>command list</TT> is actually a tab. This is
part of the <TT>makefile</TT> syntax: Each command line must be indented using a
tab. A dependency line can have a series of commands associated with it. <TT>make</TT>
executes each command line as if the command had its own shell. Thus, the command<FONT
COLOR="#0066FF"></FONT>
<PRE><FONT COLOR="#0066FF">cd somewhere
mv *.c anotherwhere
</FONT></PRE>
<P>will not behave the way you may have intended. To remedy this kind of situation,
you must use the following syntax whenever you need to specify more than one command:<FONT
COLOR="#0066FF"></FONT>
<PRE><FONT COLOR="#0066FF">dependency line
command1;command2;command3;...
</FONT></PRE>
<P>or<FONT COLOR="#0066FF"></FONT>
<PRE><FONT COLOR="#0066FF">dependency line
command1; \
command2; \
command3;
</FONT></PRE>
<P>and so on. If you use a backslash to continue a line, it must be the last character
before the end-of-line character.
<DL>
<DT></DT>
</DL>
<DL>
<DD>
<HR>
<A NAME="Heading7<FONT COLOR="#000077"><B>TIP:</B> </FONT>You can specify different
kinds of dependencies for a target by placing the same target name on different dependency
lines.
<HR>
</DL>
<P>The first entry in our <TT>makefile</TT> is the key one for building our executable.
It states that <TT>someonehappy</TT> is to be built if all the dependent object files
and library files are present, and if any are newer than the last version of <TT>someonehappy</TT>.
Of course, if the executable is not present at all, <TT>make</TT> merrily performs
the compile command listed, but not right away. First, <TT>make</TT> checks to see
which object files need to be recompiled in order to recompile <TT>someonehappy</TT>.
This is a recursive operation as <TT>make</TT> examines the dependencies of each
target in the hierarchy, as defined in the <TT>makefile</TT>.</P>
<P>The last entry is a little goofy. It copies the header files <TT>yes.h</TT> and
<TT>no.h</TT> (somehow related to <TT>maybe.h</TT>) to the home directories of the
user named <TT>sue</TT> if they have been modified. This is somewhat conceivable
if Sue was working on related programs that used these header files and needed the
most recent copies at all times. More importantly, it illustrates that <TT>make</TT>
can be used to do more than compiling and linking, and that <TT>make</TT> can execute
several commands based on one dependency.</P>
<P>The <TT>fresh</TT> target is another example of a target being used to do more
than just compiling. This target lacks any dependents, which is perfectly acceptable
to the <TT>make</TT> program. As long as there are no files in the current directory
named <TT>fresh</TT>, <TT>make</TT> executes the supplied command to remove all object
files. This works because <TT>make</TT> treats any such entry as a target that must
be updated.</P>
<P>So, if you enter the command<FONT COLOR="#0066FF"></FONT>
<PRE><FONT COLOR="#0066FF">$ make someonehappy
</FONT></PRE>
<P><TT>make</TT> starts issuing the commands it finds in the <TT>makefile</TT> for
each target that must be updated to achieve the final target. <TT>make</TT> echoes
these commands to the user as it processes them. Simply entering<FONT COLOR="#0066FF"></FONT>
<PRE><FONT COLOR="#0066FF">$ make
</FONT></PRE>
<P>would also work in this case, because <TT>make</TT> always processes the first
entry it finds in the <TT>makefile</TT>. These commands are echoed to the screen,
and the <TT>make</TT> process halts if the compiler finds an error in the code.</P>
<P>If all of <TT>someonehappy</TT>'s dependencies are up-to-date, <TT>make</TT> does
nothing except inform you of the following:<FONT COLOR="#0066FF"></FONT>
<PRE><FONT COLOR="#0066FF">`someonehappy' is up to date
</FONT></PRE>
<P>You can actually supply the name (or names) of any valid target in your <TT>makefile</TT>
on the command line for <TT>make</TT>. It performs updates in the order that they
appear on the command line, but still applies the dependency rules found in the <TT>makefile</TT>.
If you supply the name of a fictional target (one that doesn't appear in your <TT>makefile</TT>
and is not the name of a file in the current directory), <TT>make</TT> will complain
something like this:<FONT COLOR="#0066FF"></FONT>
<PRE><FONT COLOR="#0066FF">$ make fiction
make: ***No rule to make target 'fiction' . Stop.
</FONT></PRE>
<H4 ALIGN="CENTER"><A NAME="Heading8<FONT COLOR="#000077">Building Different
Versions of Programs</FONT></H4>
<P>Suppose that you want to have different versions of your <TT>someonehappy</TT>
program that use most of the same code, but require slightly different interface
routines. These routines are located in different C files (<TT>dothis.c</TT> and
<TT>dothat.c</TT>), and they both use the code found in <TT>main.c</TT>. Instead
of having separate <TT>makefile</TT>s for each version, you can simply add targets
that do different compiles. Your <TT>makefile</TT> would look like the following
one. Note the first line that has been added. It is a comment about the <TT>makefile</TT>,
and is denoted by a <TT>#</TT> character followed by the comment text.<FONT COLOR="#0066FF"></FONT>
<PRE><FONT COLOR="#0066FF"># A makefile that creates two versions of the someonehappy program
someonehappy1: main.o dothis.o itquick.o /usr/happy/lib/likeatree.a
cc -o someonehappy main.o dothis.o itquick.o /usr/happy/lib/likeatree.a
someonehappy2: main.o dothat.o itquick.o /usr/happy/lib/likeatree.a
cc -o someonehappy main.o dothat.o itquick.o /usr/happy/lib/likeatree.a
main.o: main.c
cc -c main.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -