rhl51.htm
来自「linux的初学电子书」· HTM 代码 · 共 1,526 行 · 第 1/3 页
HTM
1,526 行
cp yes.h no.h /users/sue/</FONT></PRE>
<P>Thus, your makefile is now equipped to build two variations of the same program. Issue the command
<BR>
<BR>
<PRE>
<FONT COLOR="#000080">$ make someonehappy1</FONT></PRE>
<P>to build the version using the interface routines found in dothis.c. Build your other program that uses the dothat.c interface routines with the following command:
<BR>
<BR>
<PRE>
<FONT COLOR="#000080">$ make someonehappy2</FONT></PRE>
<BR>
<A NAME="E69E521"></A>
<H4 ALIGN=CENTER>
<CENTER>
<FONT SIZE=4 COLOR="#FF0000"><B>Forcing Recompiles</B></FONT></CENTER></H4>
<BR>
<P>It is possible to trick make into doing (or not doing) recompiles. An example of a situation in which you may not want make to recompile is when you have copied files from another directory. This operation updates the modification times of the files,
though they may not need to be recompiled. You can use the touch utility or make with the -t option to update the modification times of all target files defined in the makefile.
<BR>
<BLOCKQUOTE>
<BLOCKQUOTE>
<HR ALIGN=CENTER>
<BR>
<NOTE>Do you want to test your makefile? Use make with the -n option. It will echo the commands to you without actually executing them.</NOTE>
<BR>
<HR ALIGN=CENTER>
</BLOCKQUOTE></BLOCKQUOTE>
<BR>
<A NAME="E69E522"></A>
<H4 ALIGN=CENTER>
<CENTER>
<FONT SIZE=4 COLOR="#FF0000"><B>Macros</B></FONT></CENTER></H4>
<BR>
<P>make lets you define macros within your makefile, which are expanded by make before the program executes the commands found in your makefile. Macros have the following format:
<BR>
<BR>
<PRE>
<FONT COLOR="#000080">macro identifier = text</FONT></PRE>
<P>The text portion can be the name of a file, a directory, a program to execute, or just about anything. Text can also be a list of files, or a literal text string enclosed by double quotes. The following is an example of macros that you might use in your
someonehappy makefile:
<BR>
<PRE>
<FONT COLOR="#000080">LIBFILES=/usr/happy/lib/likeatree.a
objects = main.o dothis.o
CC = /usr/bin/cc
1version="This is one version of someonehappy"
OPTIONS =</FONT></PRE>
<P>As a matter of convention, macros are usually in uppercase, but they can be typed in lowercase as in the previous example. Notice that the OPTIONS macro defined in the list has no text after the equal sign. This means that you have assigned the OPTIONS
macro to a null string. Whenever this macro is found in a command list, make will generate the command as if there were no OPTIONS macro at all. By the same token, if you try to refer to an undefined macro, make will ignore it during command generation.
<BR>
<P>Macros can also include other macros, as in the following example:
<BR>
<PRE>
<FONT COLOR="#000080">BOOK_DIR = /users/book/
MY_CHAPTERS = ${BOOK_DIR}/pete/book</FONT></PRE>
<P>Macros must be defined before they are used on a dependency line, although they can refer to each other in any order.
<BR>
<P>make has internal macros that it recognizes for commonly used commands. The C compiler is defined by the CC macro, and the flags that the C compiler uses are stored in the CFLAGS macro.
<BR>
<P>Macros are referred to in the makefile by enclosing the macro name in curly brackets and preceding the first bracket with a $. If you use macros in the first someonehappy makefile, it might look like this:
<BR>
<PRE>
<FONT COLOR="#000080"># Time to exercise some macros
CC = /usr/bin/cc
AS = /usr/bin/as
OBJS = main.o dothis.o itquick.o
YN = yes.h no.h
# We could do the following if this part of the path might be used elsewhere
LIB_DIR = /usr/happy/lib
LIB_FILES = ${LIB_DIR}/likeatree.a
someonehappy: ${OBJS} ${LIB_FILES}
${CC} -o someonehappy ${OBJS} ${LIB_FILES}
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: ${YN}
cp yes.h no.h /users/sue/</FONT></PRE>
<P>make also recognizes shell variables as macros if they are set in the same shell in which make was invoked. For example, if a C shell variable named BACKUP is defined by
<BR>
<BR>
<PRE>
<FONT COLOR="#000080">$ setenv BACKUP /usr/happy/backup</FONT></PRE>
<P>you can use it as a macro in your makefile. The macro definition
<BR>
<BR>
<PRE>
<FONT COLOR="#000080">OTHER_BACKUP = ${BACKUP}/last_week</FONT></PRE>
<P>would be expanded by make to be
<BR>
<BR>
<PRE>
<FONT COLOR="#000080">/usr/happy/backup/last_week</FONT></PRE>
<P>You can reduce the size of your makefile even further. For starters, you don't have to specify the executables for the C and assembler compilers because these are known to make. You can also use two other internal macros, referred to by the symbols $@
and $?. The $@ macro always denotes the current target; the $? macro refers to all the dependents that are newer than the current target. Both of these macros can only be used within command lines. Thus, the makefile command
<BR>
<PRE>
<FONT COLOR="#000080">someonehappy: ${OBJS} ${LIB_FILES}
${CC} -o $@ ${OBJS} ${LIB_FILES}</FONT></PRE>
<P>will generate
<BR>
<BR>
<PRE>
<FONT COLOR="#000080">/usr/bin/cc -o someonehappy main.o dothis.o itquick.o /usr/happy/lib/likeatree.a</FONT></PRE>
<P>when using the following:
<BR>
<BR>
<PRE>
<FONT COLOR="#000080">$ make someonehappy</FONT></PRE>
<P>The $? macro is a little trickier to use, but quite powerful. Use it to copy the yes.h and no.h header files to Sue's home directory whenever they are updated. The makefile command
<BR>
<PRE>
<FONT COLOR="#000080">maybe.h: ${YN}
cp $? /users/sue/</FONT></PRE>
<P>evaluates to
<BR>
<BR>
<PRE>
<FONT COLOR="#000080">cp no.h /users/sue/</FONT></PRE>
<P>if only the no.h header file has been modified. It also evaluates to
<BR>
<BR>
<PRE>
<FONT COLOR="#000080">cp yes.h no.h /users/sue/</FONT></PRE>
<P>if both header files have been updated since the last make of someonehappy.
<BR>
<P>So, with a little imagination, you can make use of some well-placed macros to shrink your makefile further, and arrive at the following:
<BR>
<PRE>
<FONT COLOR="#000080"># Papa's got a brand new makefile
OBJS = main.o dothis.o itquick.o
YN = yes.h no.h
LIB_DIR = /usr/happy/lib
LIB_FILES = ${LIB_DIR}/likeatree.a
someonehappy: ${OBJS} ${LIB_FILES}
${CC} -o $@ ${OBJS} ${LIB_FILES}
main.o: main.c
cc -c $?
dothis.o: dothis.c
cc -c $?
itquick.o: itquick.s
${AS} -o $@ $?
fresh:
rm *.o
maybe.h: ${YN}
cp $? /users/sue/</FONT></PRE>
<BR>
<A NAME="E69E523"></A>
<H4 ALIGN=CENTER>
<CENTER>
<FONT SIZE=4 COLOR="#FF0000"><B>Suffix Rules</B></FONT></CENTER></H4>
<BR>
<P>As mentioned earlier in the "Macros" section, make does not necessarily require everything to be spelled out for it in the makefile. Because make was designed to enhance software development in Linux, it has knowledge about how the compilers
work, especially for C. For example, make knows that the C compiler expects to compile source code files having a .c suffix, and that it generates object files having an .o suffix. This knowledge is encapsulated in a suffix rule: make examines the suffix
of a target or dependent to determine what it should do next.
<BR>
<P>There are many suffix rules that are internal to make, most of which deal with the compilation of source and linking of object files. The default suffix rules that are applicable in your makefile are as follows:
<BR>
<PRE>
<FONT COLOR="#000080">.SUFFIXES: .o .c .s
.c.o:
${CC} ${CFLAGS} -c $<
.s.o:
${AS} ${ASFLAGS} -o $@ $<</FONT></PRE>
<P>The first line is a dependency line stating the suffixes that make should try to find rules for if none are explicitly written in the makefile. The second dependency line is terse: Essentially, it tells make to execute the associated C compile on any
file with a .c suffix whose corresponding object file (.o) is out of date. The third line is a similar directive for assembler files. The new macro $< has a similar role to that of the $? directive, but can only be used in a suffix rule. It represents
the dependency that the rule is currently being applied to.
<BR>
<P>These default suffix rules are powerful in that all you really have to list in your makefile are any relevant object files. make does the rest: If main.o is out of date, make automatically searches for a main.c file to compile. This also works for the
itquick.o object file. After the object files are updated, the compile of someonehappy can execute.
<BR>
<P>You can also specify your own suffix rules in order to have make perform other operations. Say, for instance, that you want to copy object files to another directory after they are compiled. You could explicitly write the appropriate suffix rule in the
following way:
<BR>
<PRE>
<FONT COLOR="#000080">.c.o:
${CC} ${CFLAGS} -c $<
cp $@ backup</FONT></PRE>
<P>The $@ macro, as you know, refers to the current target. Thus, on the dependency line shown, the target is a .o file, and the dependency is the corresponding .c file.
<BR>
<P>Now that you know how to exploit the suffix rule feature of make, you can rewrite your someonehappy makefile for the last time (I'll bet you're glad to hear that news).
<BR>
<PRE>
<FONT COLOR="#000080"># The final kick at the can
OBJS = main.o dothis.o itquick.o
YN = yes.h no.h
LIB_FILES = /usr/happy/lib/likeatree.a
someonehappy: ${OBJS} ${LIB_FILES}
${CC} -o $@ ${OBJS} ${LIB_FILES}
fresh:
rm *.o
maybe.h: ${YN}
cp $? /users/sue/</FONT></PRE>
<P>This makefile works as your first one did, and you can compile the entire program using the following:
<BR>
<BR>
<PRE>
<FONT COLOR="#000080">$ make somonehappy</FONT></PRE>
<P>Or, just compile one component of it as follows:
<BR>
<BR>
<PRE>
<FONT COLOR="#000080">$ make itquick.o</FONT></PRE>
<P>This discussion only scratches the surface of make. You should refer to the man page for make to further explore its many capabilities.
<BR>
<BR>
<A NAME="E68E395"></A>
<H3 ALIGN=CENTER>
<CENTER>
<FONT SIZE=5 COLOR="#FF0000"><B>RCS</B></FONT></CENTER></H3>
<BR>
<P>One of the other important factors involved in software development is the management of source code files as they evolve. On any type of software project, you might continuously release newer versions of a program as features are added or bugs are
fixed. Larger projects usually involve several programmers, which can complicate versioning and concurrency issues even further. In the absence of a system to manage the versioning of source code on your behalf, it would be very easy to lose track of the
versions of files. This could lead to situations in which modifications are inadvertently wiped out or redundantly coded by different programmers. Fortunately, Linux provides just such a versioning system, called RCS (Revision Control System).
<BR>
<P>RCS can administer the versioning of files by controlling access to them. For anyone to update a particular file, the person must record in RCS who she is and why she is making the changes. RCS can then record this information along with the updates in
an RCS file separate from the original version. Because the updates are kept independent from the original file, you can easily return to any previous version if necessary. This can also have the benefit of conserving disk space because you don't have to
keep copies of the entire file around. This is certainly true for situations in which versions differ only by a few lines; it is less useful if there are only a few versions, each of which is largely different from the next.
<BR>
<BR>
<A NAME="E69E524"></A>
<H4 ALIGN=CENTER>
<CENTER>
<FONT SIZE=4 COLOR="#FF0000"><B>Deltas</B></FONT></CENTER></H4>
<BR>
<P>The set of changes that RCS records for an RCS file is referred to as a delta. The version number has two forms. The first form contains a release number and a level number. The release number is normally used to reflect a significant change to the code
in the file. When you first create an RCS file, it is given a default release of 1 and level of 1 (1.1). RCS automatically assigns incrementally higher integers for the level number within a release (for example, 1.1, 1.2, 1.3, and so on). RCS enables you
to override this automatic incrementing whenever you want to upgrade the version to a new release.
<BR>
<P>The second form of the version number also has the release and level components, but adds a branch number followed by a sequence number. You might use this form if you were developing a program for a client that required bug fixes, but you don't want to
place these fixes in the next "official" version. Although the next version may include these fixes anyway, you may be in the process of adding features that would delay its release. For this reason, you would add a branch to your RCS file for
this other development stream, which would then progress with sequence increments. For example, imagine that you have a planned development stream of 3.1, 3.2, 3.3, 3.4, and so on. You realize that you need to introduce a bug fix stream at 3.3, which will
not include the functionality proposed for 3.4. This bug fix stream would have a numbering sequence of 3.3.1.1, 3.3.1.2, 3.3.1.3, and so on.
<BR>
<BLOCKQUOTE>
<BLOCKQUOTE>
<HR ALIGN=CENTER>
<BR>
<NOTE>As a matter of good development practice, each level or sequence should represent a complete set of changes. That implies that the code in each version is tested to be free of any obvious bugs.</NOTE>
<BR>
<HR ALIGN=CENTER>
</BLOCKQUOTE></BLOCKQUOTE>
<BLOCKQUOTE>
<BLOCKQUOTE>
<HR ALIGN=CENTER>
<BR>
<NOTE>Is any code completely bug-free? This certainly isn't the case for complex programs in which bugs might become apparent only when code is integrated from different developers. Your aim is to at least make your own part of the world bug-free.</NOTE>
<BR>
<HR ALIGN=CENTER>
</BLOCKQUOTE></BLOCKQUOTE>
<BR>
<A NAME="E69E525"></A>
<H4 ALIGN=CENTER>
<CENTER>
<FONT SIZE=4 COLOR="#FF0000"><B>Creating an RCS File</B></FONT></CENTER></H4>
<BR>
<P>Let's assume that you have the following file of C code, called finest.c:
<BR>
<PRE>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?