head 3.1; access; symbols; locks; strict; comment @.\" @; 3.1 date 95.06.27.10.50.24; author grog; state Exp; branches; next 3.0; 3.0 date 95.06.25.14.31.30; author grog; state Exp; branches; next 2.7; 2.7 date 95.06.25.10.58.32; author grog; state Exp; branches; next 2.6; 2.6 date 95.06.09.04.30.25; author grog; state Exp; branches; next 2.5; 2.5 date 95.05.15.17.25.08; author grog; state Exp; branches; next 2.4; 2.4 date 95.02.11.11.24.31; author grog; state Exp; branches; next 2.3; 2.3 date 95.02.04.15.10.36; author grog; state Exp; branches; next 2.2; 2.2 date 95.01.25.17.02.52; author grog; state Exp; branches; next 2.1; 2.1 date 95.01.17.16.50.55; author grog; state Exp; branches; next 2.0; 2.0 date 94.12.17.17.21.38; author grog; state Exp; branches; next ; desc @@ 3.1 log @Minor mods @ text @.\" For emacs, this file is in -*- nroff-fill -*- mode .\" $Id: care-and-feeding.ms,v 3.0 1995年06月25日 14:31:30 grog Exp grog $ .\" $Log: care-and-feeding.ms,v $ .\" Revision 3.0 1995年06月25日 14:31:30 grog .\" Final draft .\" .\" Revision 2.6 1995年06月09日 04:30:25 grog .\" Remove date from page headers .\" Minor mods .\" .\" Revision 2.5 1995年05月15日 17:25:08 grog .\" Major mods after Andy's final draft review .\" .\" Revision 2.4 1995年02月11日 11:24:31 grog .\" Minor mods .\" .\" Revision 2.3 1995年02月04日 15:10:36 grog .\" Minor mods .\" .\" Revision 2.2 1995年01月25日 17:02:52 grog .\" Minor mods .\" .\" Revision 2.1 1995年01月17日 16:50:55 grog .\" Minor mods .\" .\" .so global.ms .Se \*[nchcare] "Care and feeding of source trees" .St "Care and feeding of source trees" .XX "source tree" In \*[chunpack], we saw how to create an initial source tree. It won't stay in this form for long. During a port, the source tree is constantly changing: .Ls B .Li Before you can even start, you may apply \fIpatches\fR to the tree to bring it up to date. .Li After unpacking and possibly patching, you may find that you have to clean out junk left behind from a previous port. .Li In order to get it to compile in your environment, you perform some form of \fIconfiguration\fR, which modifies the tree to some extent. We'll look at package configuration in \*[chconfig]. .Li During compilation, you add many new files to the tree. You may also create new subdirectories. .Li After installation, you remove the unneeded files, for example object files and possibly the final installed files. .Li After cleaning up, you may decide to archive the tree again to save space on disk. .Le Modifying the source tree brings uncertainty with it: what is original, what have I modified, how do I remove the changes I have made and get back to a clean, well-defined starting point? In this chapter we'll look at how to get to a clean starting point. Usually this will be the case after you have extracted the source archive, but frequently you need to add patches or remove junk. We'll also look at how to build a tree with sources on CD-ROM, how to recognize the changes you have made and how to maintain multiple versions of your software. .Ah "Updating old archives" .Pn update-archive You don't always need to get a complete package: another possibility is that you might already have an older version of the package. If it is large--again, for example, the GNU C compiler--you might find it better to get \fIpatches\fR and update the source tree. Strictly speaking, a patch is any kind of modification to a source or object file. In UNIX parlance, it's almost always a \fIdiff\fR, a file that describes how to modify a source file to produce a newer version. Diffs are almost always produced by the \fIdiff\fR program, which we describe in \*[chepilogue], page \*[diff]. In our case study, we have \fIgcc\fR version 2.5.6 and want to update to 2.5.8. We discover the following files on the file server: .Ps ftp> \f(CBls\f(CW 200 PORT command successful. 150 Opening ASCII mode data connection for /bin/ls. -rw-rw-r-- 1 117 1001 10753 Dec 12 19:15 gcc-2.5.6-2.5.7.diff.gz -rw-rw-r-- 1 117 1001 14726 Jan 24 09:02 gcc-2.5.7-2.5.8.diff.gz -rw-rw-r-- 1 117 1001 5955006 Dec 22 14:16 gcc-2.5.7.tar.gz -rw-rw-r-- 1 117 1001 5997896 Jan 24 09:03 gcc-2.5.8.tar.gz 226 Transfer complete. ftp> .Pe .XX "diff, program" .XX "program, diff" In other words, we have the choice of copying the two \fIdiff\fR files \fIgcc-2.5.6-2.5.7.diff.gz\fR and \fIgcc-2.5.7-2.5.8.diff.gz\fR, a total of 25 kB, and applying them to your source tree, or copying the complete 6 MB archive \fIgcc-2.5.8.tar.gz\fR. .Bh "Patch" .XX "patch, program" .XX "program, patch" .Pn patch .XX "patch, running" \fIdiff\fR files are reasonably understandable, and you can apply the patches by hand if you want, but it's obviously easier and safer to use a program to apply the changes. This is the purpose of \fIpatch\fR. \fIpatch\fR takes the output of the program \fIdiff\fR and uses it to update one or more files. To apply the patch, it proceeds as follows: .Ls N .Li First, it looks for a file header. If it finds any junk before the file header, it skips it and prints a message to say that it has done so. It uses the file header to recognize the kind of diff to apply. .Li It renames the old file by appending a string to its name. By default, the string is \fI.orig\fR, so \fIfoo.c\fR would become \fIfoo.c.orig\fR. .XX ".orig, suffix" .XX "suffix, .orig" .Li It then creates a new file with the name of the old file, and copies the old file to the new file, modifying it with the patches as it goes. Each set of changes is called a \fIhunk\fR. .XX "hunk, definition" .XX "diff, hunk" .Le The way \fIpatch\fR applies the patch depends on the format. The most dangerous kind are \fIed\fR style diffs, because there is no way to be sure that the text is being replaced correctly. With context diffs, it can check that the context is correct, and will look a couple of lines in each direction if it doesn't find the old text where it expects it. You can set the number of lines it will look (the \fIfuzz factor\fR) .XX "patch, fuzz factor" .XX "fuzz factor, patch" with the \s10\f(CW-F\fR\s0 flag. It defaults to 2. .LP If the old version of the file does not correspond exactly to the old version used to make the diff, \fIpatch\fR may not be able to find the correct place to insert the patch. Except for \fIed\fR format diffs, it will recognize when this happens, and will print an error message and move the corresponding hunk to a file with the suffix \fI.rej\fR (for reject). .XX ".rej, suffix" .XX "suffix, .rej" .LP .XX "Mui, Linda" .XX "Pearce, Eric" A typical example are the patches for X11R5. You might start with the sources supplied on the companion CD-ROM to \fIX Window System Administrator's Guide\fR by Linda Mui and Eric Pearce. This CD-ROM includes the complete X11R5 sources to patch level 21. At the time of writing, five further patches to X11R5 have been released. To bring the source tree up to patch level 26, you would proceed as follows: .LP First, \fIread the header of the patch file\fR. As we have seen, \fIpatch\fR allows text before the first file header, and the headers frequently contain useful information. Looking at patch 22, we see: .Ps $ \f(CBgunzip < /cd0/x11r5/fix22.gz | more\f(CW X11 R5 Public Patch #22 MIT X Consortium To apply this patch: cd to the top of the source tree (to the directory containing the "mit" and "contrib" subdirectories) and do: patch -p -s < ThisFile Patch works silently unless an error occurs. You are likely to get the following warning messages, which you can ignore: .Pe In this example we have used \fIgunzip\fR to look at the file directly; we could just as well have used GNU \fIzcat\fR. .XX "gunzip, program" .XX "program, gunzip" .XX "zcat, program" .XX "program, zcat" .XX "-s, patch flag" .XX "patch flag, -s" .XX "-p, patch flag" .XX "patch flag, -p" The patch header suggests the flags \f(CW-s\fR and \f(CW-p\fR. The \f(CW-s\fR flag to \fIpatch\fR tells it to perform its work silently--otherwise it prints out lots of information about what it is doing and why. The \f(CW-p\fR flag is one of the most complicated to use: it specifies the \fIpathname strip count\fR, .XX "pathname strip count, patch" .XX "patch, pathname strip count" how to treat the directory part of the file names in the header. We'll look at it in more detail in the section \fICan't find file to patch\fR on page \*[cant-find-file]. .LP This information is important: \fIpatch\fR is rather like a chainsaw without a guard, and if you start it without knowing what you are doing, you can make a real mess of its environment. In this case, we should find that the root of our source tree looks like: .Ps $ \f(CBcd /usr/x11r5\f(CW $ \f(CBls -FC mit\f(CW Imakefile RELNOTES.ms extensions/ rgb/ LABEL bug-report fonts/ server/ Makefile clients/ hardcopy/ util/ Makefile.ini config/ include/ RELNOTES.PS demos/ lib/ RELNOTES.TXT doc/ man/ \fI\&... that looks OK, we're in the right place\fR $ \f(CBgunzip < /cd0/x11r5/fix22.gz | patch -p -s\f(CW .Pe We've taken another liberty in this example: since the patch file was on CD-ROM in compressed form, we would have needed to extract it to disk in order to patch the way the file header suggests. Instead, we just \fIgunzip\fR directly into the \fIpatch\fR program. .LP It's easy to make mistakes when patching. If you try to apply a patch twice, \fIpatch\fR will notice, but you can persuade it to reapply the patch anyway. In this section, we'll look at the havoc that can occur as a result. In addition, we'll disregard some of the advice in the patch header. This is the way I prefer to do it: .Ps $ \f(CBgunzip < /cd0/x11r5/fix23.gz | patch -p &> patch.log\f(CW .Pe This invocation allows \fIpatch\fR to say what it has to say (no \f(CW\s10-s\fR\s0 flag), but copies both the standard output and the error output to the file \fIpatch.log\fR, .XX "patch, logfile" so nothing appears on the screen. You can, of course, pipe the output through the \fItee\fR program, but in practice things happen so fast that any error message will usually run off the screen before you can read it. It certainly would have done so here: \fIpatch.log\fR had a length of 930 lines. It starts with .Ps Hmm... Looks like a new-style context diff to me... The text leading up to this was: -------------------------- | Release 5 Public Patch #23 | MIT X Consortium \fI\&... followed by the complete header\f(CW |Prereq: public-patch-22 .Pe This last line is one safeguard that \fIpatch\fR offers to ensure that you are working with the correct source tree. If \fIpatch\fR finds a \fIPrereq:\fR .XX "patch, Prereq: line" .XX "Prereq: line, patch" line in the file header, it checks that this text appears in the input file. For comparison, here's the header of \fImit/bug-report\fR: .Ps To: xbugs@@expo.lcs.mit.edu Subject: [area]: [synopsis] [replace with actual area and short description] VERSION: R5, public-patch-22 [MIT public patches will edit this line to indicate the patch level] .Pe In this case, \fIpatch\fR finds the text. When it does, it prints out the corresponding message: .Ps | |*** /tmp/,RCSt1006225 Tue Mar 9 14:40:48 1993 |--- mit/bug-report Tue Mar 9 14:37:04 1993 -------------------------- Good. This file appears to be the public-patch-22 version. .Pe This message shows that it has found the text in \fImit/bug-report\fR. The first hunk in any X11 \fIdiff\fR changes this text (in this case to \fIpublic-patch-23\fR), so that it will notice a repeated application of the patch. Continuing, .Ps Patching file mit/bug-report using Plan A... Hunk #1 succeeded at 2. Hmm... The next patch looks like a new-style context diff to me... The text leading up to this was: -------------------------- |*** /tmp/,RCSt1005203 Tue Mar 9 13:45:42 1993 |--- mit/lib/X/Imakefile Tue Mar 9 13:45:45 1993 -------------------------- Patching file mit/lib/X/Imakefile using Plan A... Hunk #1 succeeded at 1. Hunk #2 succeeded at 856. Hunk #3 succeeded at 883. Hunk #4 succeeded at 891. Hunk #5 succeeded at 929. Hunk #6 succeeded at 943. Hunk #7 succeeded at 968. Hunk #8 succeeded at 976. Hmm... The next patch looks like a new-style context diff to me... .Pe This output goes on for hundreds of lines. What happens if you make a mistake and try again? .Ps $ \f(CBgunzip < /cd0/x11r5/fix23.gz | patch -p &> patch.log\f(CW This file doesn't appear to be the public-patch-22 version--patch anyway? [n] \f(CBy\f(CW \f(BIbad choice...\f(CW Reversed (or previously applied) patch detected! Assume -R? [y] \fIRETURN pressed\f(CW Reversed (or previously applied) patch detected! Assume -R? [y] \fIRETURN pressed\f(CW Reversed (or previously applied) patch detected! Assume -R? [y] \f(CB^C\f(CW$ .Pe The first message is printed because \fIpatch\fR didn't find the text \f(CW\s10public-patch-22\fR\s0 in the file (in the previous step, \fIpatch\fR changed it to read \f(CW\s10public-patch-23\fR\s0). This message also appears in \fIpatch.log\fR. Of course, in any normal application you should immediately stop and check what's gone wrong. In this case, I make the incorrect choice and go ahead with the patch. Worse still, I entered \f(CWRETURN\fR to the next two prompts. Finally, I came to my senses and hit \s10\f(CWCTRL-C\fR\s0, the interrupt character on my machine, to stop \fIpatch\fR. .LP The result of this is that \fIpatch\fR removed the patches in the first two files (the \f(CW\s10-R\fR\s0 flag tells \fIpatch\fR to behave as if the files were reversed, which has the same effect as removing already applied patches). I now have the first two files patched to patch level 22, and the others patched to patch level 23. Clearly, I can't leave things like this. .LP Two wrongs don't normally make a right, but in this case they do. We do it again, and what we get this time looks pretty much the same as the time before: .Ps $ gunzip < /cd0/x11r5/fix23.gz | patch -p &> mit/patch.log Reversed (or previously applied) patch detected! Assume -R? [y] ^C$ .Pe In fact, this time things went right, as we can see by looking at \fIpatch.log\fR: .Ps |*** /tmp/,RCSt1006225 Tue Mar 9 14:40:48 1993 |--- mit/bug-report Tue Mar 9 14:37:04 1993 -------------------------- Good. This file appears to be the public-patch-22 version. Patching file mit/bug-report using Plan A... Hunk #1 succeeded at 2. Hmm... The next patch looks like a new-style context diff to me... The text leading up to this was: -------------------------- |*** /tmp/,RCSt1005203 Tue Mar 9 13:45:42 1993 |--- mit/lib/X/Imakefile Tue Mar 9 13:45:45 1993 -------------------------- Patching file mit/lib/X/Imakefile using Plan A... Hunk #1 succeeded at 1. \fI(lots of hunks succeed)\f(CW Hmm... The next patch looks like a new-style context diff to me... The text leading up to this was: -------------------------- |*** /tmp/d03300 Tue Mar 9 09:16:46 1993 |--- mit/lib/X/Ximp/XimpLCUtil.c Tue Mar 9 09:16:41 1993 -------------------------- Patching file mit/lib/X/Ximp/XimpLCUtil.c using Plan A... Reversed (or previously applied) patch detected! Assume -R? [y] .Pe This time the first two files have been patched back to patch level 23, and we stop before doing any further damage. .Ch "Hunk #3 failed" .XX "patch, error message, Hunk #3 failed" Patch makes an implicit assumption that the patch was created from an identical source tree. This is not always the case--you may have changed something in the course of the port. The differences frequently don't cause problems if they are an area unrelated to the patch. In this example, we'll look at how things can go wrong. Let's consider the following situation: during a previous port of X11R5 pl 22,\** .FS The abbreviation \fIpl\fR is frequently used to mean \fIpatch level\fR. .FE you ran into some problems in \fImit/lib/Xt/Selection.c\fR and fixed them. The original text read: .Ps if (XtWindow(widget) == window) XtAddEventHandler(widget, mask, TRUE, proc, closure); else { Widget w = XtWindowToWidget(dpy, window); RequestWindowRec *requestWindowRec; if (w != NULL && w != widget) widget = w; if (selectWindowContext == 0) selectWindowContext = XUniqueContext(); .Pe You had problems with this section, so you commented out a couple of lines: .Ps if (XtWindow(widget) == window) XtAddEventHandler(widget, mask, TRUE, proc, closure); else { /* This doesn't make any sense at all - ignore * Widget w = XtWindowToWidget(dpy, window); */ RequestWindowRec *requestWindowRec; /* if (w != NULL && w != widget) widget = w; */ if (selectWindowContext == 0) selectWindowContext = XUniqueContext(); .Pe Back in the present, you try to apply patch 24 to this file: .Ps $ \f(CBgunzip < /cd0/x11r5/fix24.gz | patch -p &> mit/patch.log\f(CW $ .Pe So far so good. But in \fIpatch.log\fR we find .Ps |*** /tmp/da4854 Mon May 17 18:19:57 1993 |--- mit/lib/Xt/Selection.c Mon May 17 18:19:56 1993 -------------------------- Patching file mit/lib/Xt/Selection.c using Plan A... Hunk #1 succeeded at 1. Hunk #2 succeeded at 70. Hunk #3 failed at 361. Hunk #4 succeeded at 1084. Hunk #5 succeeded at 1199. 1 out of 5 hunks failed--saving rejects to mit/lib/Xt/Selection.c.rej .Pe What does this mean? There's nothing for it but to look at the files concerned. In \fIfix24\fR we find .Ps *** /tmp/da4854 Mon May 17 18:19:57 1993 --- mit/lib/Xt/Selection.c Mon May 17 18:19:56 1993 *************** *** 1,4 **** \fIthis must be hunk 1\f(CW ! /* $\&XConsortium: Selection.c,v 1.74 92/11/13 17:40:46 converse Exp $ */ /*********************************************************** Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, --- 1,4 ---- ! /* $\&XConsortium: Selection.c,v 1.78 93/05/13 11:09:15 converse Exp $ */ /*********************************************************** Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, *************** *** 70,75 **** --- 70,90 ---- \fIthis must be hunk 2\f(CW Widget w; /* unused */ *************** *** 346,359 **** \fIand this must be hunk 3, the one that failed\f(CW { Display *dpy = req->ctx->dpy; Window window = req->requestor; ! Widget widget = req->widget; \fI\&... etc\fR *************** *** 1068,1073 **** --- 1084,1096 ---- \fIhunk 4\f(CW *************** *** 1176,1181 **** --- 1199,1213 ---- \fIand hunk 5--at least the count is correct\f(CW .Pe \fIpatch\fR put the rejects in \fISelection.c.rej\fR. Let's look at it: .Ps *************** *** 346,359 **** { Display *dpy = req->ctx->dpy; Window window = req->requestor; ! Widget widget = req->widget; if (XtWindow(widget) == window) ! XtAddEventHandler(widget, mask, TRUE, proc, closure); else { - Widget w = XtWindowToWidget(dpy, window); RequestWindowRec *requestWindowRec; - if (w != NULL && w != widget) widget = w; if (selectWindowContext == 0) selectWindowContext = XUniqueContext(); if (XFindContext(dpy, window, selectWindowContext, --- 361,375 ---- { Display *dpy = req->ctx->dpy; Window window = req->requestor; ! Widget widget = XtWindowToWidget(dpy, window); + if (widget != NULL) req->widget = widget; + else widget = req->widget; + if (XtWindow(widget) == window) ! XtAddEventHandler(widget, mask, False, proc, closure); else { RequestWindowRec *requestWindowRec; if (selectWindowContext == 0) selectWindowContext = XUniqueContext(); if (XFindContext(dpy, window, selectWindowContext, .Pe The characters \s10\f(CW+\fR\s0 and \s10\f(CW-\fR\s0 at the beginning of the lines in this hunk identify it as a \fIunified context diff\fR. We'll look at them in more detail in \*[chepilogue], page \*[unified-context-diffs]. Not surprisingly, they are the contents of hunk 3. Because of our fix, \fIpatch\fR couldn't find the old text and thus couldn't process this hunk. In this case, the easiest thing to do is to perform the fix by hand. To do so, we need to look at the partially fixed file that \fIpatch\fR created, \fImit/lib/Xt/Selection.c\fR. The line numbers have changed, of course, but since hunk 3 wasn't applied, we find exactly the same text as in \fImit/lib/Xt/Selection.c.orig\fR, only now it starts at line 366. We can effectively replace it by the "after" text in \fISelection.c.rej\fR, remembering of course to remove the indicator characters in column 1. .Ch "Can't find file to patch" .Pn cant-find-file .XX "patch, pathname strip count" .XX "patch, error message, Can't find file" Sometimes you'll see a message like: .Ps $ \f(CBpatch -p patch.log\f(CW Enter name of file to patch: .Pe One of the weaknesses of the combination of \fIdiff\fR and \fIpatch\fR is that it's easy to get the file names out of sync. What has probably happened here is that the file names don't agree with your source tree. There are a number of ways for this to go wrong. The way that \fIpatch\fR treats the file names in diff headers depends on the \s10\f(CW-p\fR\s0 flag, the so-called \fIpathname strip count\fR: .Ls B .Li If you omit the \s10\f(CW-p\fR\s0 flag, \fIpatch\fR strips all directory name information from the file names and leaves just the filename part. Consider the following diff header: .Ps *** config/sunos4.h~ Wed Feb 29 07:13:57 1992 --- config/sunos4.h Mon May 17 18:19:56 1993 .Pe Relative to the top of the source tree, the file is in the directory \fIconfig\fR. If you omit the \s10\f(CW-p\fR\s0 flag, \fIpatch\fR will look for the file \fIsunos4.h\fR, not \fIconfig/sunos4.h\fR, and will not find it. .Li If you specify \s10\f(CW-p\fR\s0, \fIpatch\fR keeps the complete names in the headers. .Li If you specify \s10\f(CW-p\fIn\fR\s0, \fIpatch\fR will remove the first \fIn\fR directory name components in the pathname. This is useful when the diffs contain incorrect base path names. For example, you may find a diff header which looks like: .Ps *** /src/freesoft/gcc-patches/config/sunos4.h~ Wed Feb 29 07:13:57 1992 --- /src/freesoft/gcc-patches/config/sunos4.h Mon May 17 18:19:56 1993 .Pe .IP Unless your source tree also happens to be called \fI/src/freesoft/gcc-patches\fR, \fIpatch\fR won't be able to find the files if you use the \s10\f(CW-p\fR\s0 flag with no argument. Assuming that you are in the root directory of the package (in other words, the parent directory of \fIconfig\fR), you really don't want to know about the \fI/src/freesoft/gcc-patches/\fR component. This pathname consists of four parts: the leading \fI/\fR making the pathname absolute, and the three directory names \fIsrc\fR, \fIfreesoft\fR and \fIgcc-patches\fR. In this case, you can enter .Ps $ \f(CBpatch -p4 patch.log\f(CW .Pe .IP The \f(CW\s10-p4\fR\s0 tells \fIpatch\fR to ignore the first four pathname components, so it would read thes filenames just as \fIconfig/sunos4.h~\fR and \fIconfig/sunos4.h\fR. .Le .Pn apply-bad-patch In addition to the problem of synchronizing the path names, you may run into broken diffs which don't specify pathnames, even though the files belong to different directories. We'll see how easy it is to make this kind of mistake in \*[chepilogue], page \*[how-to-diff]. For example, you may find that the diff headers look like: .Ps *** sunos4.h~ Wed Feb 29 07:13:57 1992 --- sunos4.h Mon May 17 18:19:56 1993 .Pe This kind of diff is a real nuisance: you at least need to search for the file \fIsunos4.h\fR, and if you're unlucky you'll find more than one and have to examine the patches to figure out which one is intended. Then you need to give this name to the prompt, and \fIpatch\fR should perform the patches. Unfortunately, in a large collection of diffs, this can happen dozens of times. .Ch "I can't seem to find a patch in there" .XX "patch, error message, can't find patch" Sometimes you will get what looks like a perfectly good unified context diff, but when you run \fIpatch\fR against it, you get a message: .Ps $ \f(CBpatch \f(CB ln -s $i .\f(CW> \f(CBdone\f(CW $ \f(CBls -l\f(CW \fIsee what we got\f(CW total 16 lrwxrwxrwx COPYING -> /cd0/src/find/COPYING lrwxrwxrwx COPYING.LIB -> /cd0/src/find/COPYING.LIB lrwxrwxrwx ChangeLog -> /cd0/src/find/ChangeLog lrwxrwxrwx INSTALL -> /cd0/src/find/INSTALL lrwxrwxrwx Makefile -> /cd0/src/find/Makefile lrwxrwxrwx Makefile.in -> /cd0/src/find/Makefile.in lrwxrwxrwx NEWS -> /cd0/src/find/NEWS lrwxrwxrwx README -> /cd0/src/find/README lrwxrwxrwx config.status -> /cd0/src/find/config.status lrwxrwxrwx configure -> /cd0/src/find/configure lrwxrwxrwx configure.in -> /cd0/src/find/configure.in lrwxrwxrwx find -> /cd0/src/find/find lrwxrwxrwx lib -> /cd0/src/find/lib lrwxrwxrwx locate -> /cd0/src/find/locate lrwxrwxrwx man -> /cd0/src/find/man lrwxrwxrwx xargs -> /cd0/src/find/xargs .Pe I omitted most of the information that is printed by \fIls -l\fR in order to get the information on the page: what interests us here is that all the files, including the directories, are symbolic links. In some cases, this is what we want: we don't need to create copies of the directories on the hard disk when a single link to a directory on the CD-ROM does it just as well. In this case, unfortunately, that's not the way it is: our sources are in the directory \fIfind\fR, and that's where we will have to write our objects. We need to do the whole thing again for the subdirectory \fIfind\fR: .Ps $ \f(CBcd ~mysource/find\f(CW \fIchange to the source directory on disk\f(CW $ \f(CBrm find \fIget rid of the directory symlink\f(CW $ \f(CBmkdir find \fIand make a directory\f(CW $ \f(CBcd find \fIand change to it\f(CW $ \f(CBfor i in /cd0/src/find/find/*; do\f(CW> \f(CB ln -s $i .\f(CW> \f(CBdone\f(CW $ \f(CBls -l\f(CW total 18 lrwxrwxrwx Makefile -> /cd0/src/find/find/Makefile lrwxrwxrwx Makefile.in -> /cd0/src/find/find/Makefile.in lrwxrwxrwx defs.h -> /cd0/src/find/find/defs.h lrwxrwxrwx find -> /cd0/src/find/find/find lrwxrwxrwx find.c -> /cd0/src/find/find/find.c lrwxrwxrwx fstype.c -> /cd0/src/find/find/fstype.c lrwxrwxrwx parser.c -> /cd0/src/find/find/parser.c lrwxrwxrwx pred.c -> /cd0/src/find/find/pred.c lrwxrwxrwx tree.c -> /cd0/src/find/find/tree.c lrwxrwxrwx util.c -> /cd0/src/find/find/util.c lrwxrwxrwx version.c -> /cd0/src/find/find/version.c .Pe Yes, this tree really does have a directory called \fIfind/find/find\fR, but we don't need to worry about it. Our sources and our \fIMakefile\fR are here. We should now be able to move back to the top-level directory and perform the \fImake\fR: .Ps $ \f(CBcd ..\f(CW $ \f(CBmake\f(CW .Pe This is a relatively simple example, but it shows two important aspects of the technique: .Ls B .Li You don't need to create a symlink for every single file. Although symlinks are relatively small--in this case, less than 100 bytes--they occupy up to 1024 bytes of disk space per link, and you can easily find yourself taking up a megabyte of space just for the links. .Li On the other hand, you \fIdo\fR need to make all the directories where output from the build process is stored. You need to make symlinks to the existing files in these directories. .Le An additional problem with this technique is that many tools don't test whether they have succeeded in creating their output files. If they try to create files on CD-ROM and don't notice that they have failed, you may get some strange and misleading error messages later on. .Bh "Object links on CD-ROM" .XX "object link, on CD-ROM" .XX "CD-ROM, object links on" .Pn cd-obj-links Some CD-ROMs, notably those derived from the Berkeley Net/2 release, have a much better idea: the CD-ROM already contains a symlink to a directory where the object files are stored. For example, the FreeBSD 1.1 CD-ROM version of \fIfind\fR is stored on \fI/cd0/filesys/usr/src/usr.bin/find\fR and contains: .Ps total 106 drwxrwxr-x 2 bin 2048 Oct 28 1993 . drwxrwxr-x 153 bin 18432 Nov 15 23:28 .. -rw-rw-r-- 1 bin 168 Jul 29 1993 Makefile -rw-rw-r-- 1 bin 3157 Jul 29 1993 extern.h -rw-rw-r-- 1 bin 13620 Sep 7 1993 find.1 -rw-rw-r-- 1 bin 5453 Jul 29 1993 find.c -rw-rw-r-- 1 bin 4183 Jul 29 1993 find.h -rw-rw-r-- 1 bin 20736 Sep 7 1993 function.c -rw-rw-r-- 1 bin 3756 Oct 17 1993 ls.c -rw-rw-r-- 1 bin 3555 Jul 29 1993 main.c -rw-rw-r-- 1 bin 3507 Jul 29 1993 misc.c lrwxrwxr-x 1 root 21 Oct 28 1993 obj -> /usr/obj/usr.bin/find -rw-rw-r-- 1 bin 7766 Jul 29 1993 operator.c -rw-rw-r-- 1 bin 4657 Jul 29 1993 option.c -rw-rw-r-- 1 root 2975 Oct 28 1993 tags .Pe All you have to do in this case is to create a directory called \fI/usr/obj/usr.bin/find\fR. The \fIMakefile\fRs are set up to compile into that directory. .Ah "Tracking changes to the tree" .XX "tree, tracking changes" The most obvious modification that you make to a source tree is the process of building: the compiler creates object files\** .FS To be pedantic, usually the assembler creates the object files, not the compiler. .FE and the loader creates executables. Documentation formatters may produce formatted versions of the source documentation, and possibly other files are created as well. Whatever you do with these files, you need to recognize which ones you have created and which ones you have changed. We'll look at these aspects in the following sections. .Bh "Timestamps" .XX "tree, timestamps" .XX "timestamps" It's easy enough to recognize files that have been added to the source tree since its creation: since they are all newer than any file in the original source tree, the simple command \fIls -lt\fR (probably piped into \fImore\fR or \fIless\fR) will display them in the reverse order in which they were created (newest first) and thus separate the new from the old. .LP Every UNIX file and directory has three timestamps. The file system represents timestamps in the \s10\f(CWtime_t\fR\s0 format, the number of seconds elapsed since January 1, 1970 UTC. See \*[chtime], page \*[time_t], for more details. The timestamps are: .Ls B .Li .XX "last modification, timestamp" .XX "timestamp, last modification" The \fIlast modification\fR timestamp, updated every time the file or directory is modified. This is what most users think of as \fIthe\fR file timestamp. You can display it with the \fIls -l\fR command. .XX "ls, -l flag" .XX "-l flag, ls" .Li .XX "timestamp, last access" .XX "last access, timestamp" The \fIlast access\fR timestamp, updated every time a data transfer is made to or from the file. You can display it with the \fIls -lu\fR command. This timestamp can be useful in a number of different places. .XX "ls, -lu flags" .XX " -lu flags, ls" .Li .XX "timestamp, status change" .XX "status change, timestamp" The \fIstatus change\fR timestamp (at least, that's what my header files call it). This is a sort of kludged\** .XX "kludge, defined" .FS A \fIkludge\fR is a programming short cut, usually a nasty, untidy one. The \fINew Hacker's Dictionary\fR goes to a lot of detail to explain the term, including why it should be spelt \fIkluge\fR and not \fIkludge\fR. .FE last modification timestamp for the inode, that part of a file which stores information about the file. The most frequent changes which don't affect the other timestamps are change in the number of links or the permissions, which normally isn't much use to anybody. On the other hand, the inode also contains the other timestamps, so if this rule were enforced rigidly, a change to another timestamp would also change the status change timestamp. This would make it almost completely useless. As a result, most implementations suppress the change to the status change timestamp if only the other timestamps are modified. If you want, you can display the status change timestamp with the \fIls -lc\fR command. .XX "ls, -lc flags" .XX "-lc flags, ls" .Le Whichever timestamp you choose to display with \fIls -l\fR, you can cause \fIls\fR to sort by it with the \f(CW\s10-t\fR\s0 flag. Thus, \fIls -lut\fR displays and sorts by the last access timestamp. .XX "ls, -lut flags" .XX "-lut flags, ls" .LP .Pn last-mod-times Of these three timestamps, the last modification timestamp is by far the most important. There are a number of reasons for this: .Ls B .Li \fImake\fR relies on the last modification timestamp to decide what it needs to compile. If you move the contents of a directory with \fIcp\fR, it changes all the modification timestamps to the time when the copy was performed. If you then type \fImake\fR, you will perform a significant amount of needless compilation. .Li It's frequently important to establish if two files are in fact the same, in other words, if they have identical content. In the next section we'll see some programmatic tools that help us with this, but as a first approximation we can assume that two files with the same name, length and modification timestamp have an identical content, too. The modification timestamp is the most important of these three: you can change the name, but if length and timestamp are the same, there's still a good chance it's the same file. If you change the timestamp, you can't rely on the two files being the same just because they have the same name and length. .Li As we have seen above, the last modification timestamp is useful for sorting when you list directories. If you're looking for a file you made the week before last, it helps if it is dated accordingly. .Le .Ch "Keeping timestamps straight" .XX "timestamps, keeping straight" .XX "tree, keeping timestamps straight" Unfortunately, it's not as easy to keep timestamps straight. Here are some of the things that can go wrong: .Ls B .Li If you copy the file somewhere else, traditional versions of \fIcp\fR always set the modification timestamp to the time of copying. \fIln\fR does not, and neither does \fImv\fR if it doesn't need to make a physical copy, so either of these are preferable. In addition, more modern versions of \fIcp\fR offer the flag \f(CW\s10-p\fR\s0 (preserve), which preserves the modification timestamp and the permissions. .Li When extracting an archive, \fIcpio\fR's default behaviour is to set the modification timestamp to the time of extraction. You can avoid this with the \f(CW\s10-m\fR\s0 flag to \fIcpio\fR. .XX "cpio, program" .XX "program, cpio" .Li Editing the file changes the modification timestamp. This seems obvious, but you frequently find that you make a modification to a file to see if it solves a problem. If it doesn't help, you edit the modification out again, leaving the file exactly as it was, except for the modification timestamp, which points to right now. A better strategy is to save the backup file, if the editor keeps one, or otherwise to rename the original file before making the modifications, then to rename it back again if you decide not to keep the modifications. .Li In a network, it's unusual for times to be exactly the same. UNIX machines are not very good at keeping the exact time, and some gain or lose as much as 5 minutes per day. This can cause problems if you are using NFS. You edit your files on one machine, where the clocks are behind, and compile on another, where the clocks are ahead. The result can be that objects created before the last edit still have a modification timestamp that is more recent, and \fImake\fR is fooled into believing that it doesn't need to recompile. Similar problems can occur when one system is running with an incorrect time zone setting. .Le .Bh "cmp" .XX "cmp, program" .XX "program, cmp" A modification timestamp isn't infallible, of course: even if EOF, timestamp and name are identical, there still can be a lingering doubt as to whether the files really are identical. This doubt becomes more pronounced if you seee something like: .Ps $ \f(CBls -l\f(CW total 503 -rw-rw-rw- 1 grog wheel 1326 May 1 01:00 a29k-pinsn.c -rw-rw-rw- 1 grog wheel 28871 May 1 01:00 a29k-tdep.c -rw-rw-rw- 1 grog wheel 4259 May 1 01:00 a68v-nat.c -rw-rw-rw- 1 grog wheel 4515 May 1 01:00 alpha-nat.c -rw-rw-rw- 1 grog wheel 33690 May 1 01:00 alpha-tdep.c \fI\&... etc .Pe It's a fairly clear bet that somebody has done a \fItouch\fR on all the files, and their modification timestamps have all been set to midnight on May 1.\** The \fIcmp\fR program can give you certainty: .FS Midnight? That looks like 1 a.m. But remember that UNIX timestamps are all in UTC, and that's 1 a.m. in my time zone. This example really \fIwas\fR done with \fItouch\fR. .FE .Ps $ \f(CBcmp foo.c ../orig/foo.c \fIcompare with the original\f(CW $ \f(CBecho $? \fIshow exit status\f(CW 0 \fI0: all OK\f(CW $ \f(CBcmp bar.c ../orig/bar.c bar.c ../orig/bar.c differ: char 1293, line 39 $ \f(CBecho $? \fIshow exit status\f(CW 1 \fI1: they differ\f(CW .Pe Remember you can tell the shell to display the exit status of the previous command with the shell variable \f(CW\s10$?\fR\s0. In the C shell, the corresponding variable is called \s10\f(CW$status\fR\s0. If the contents of the files are identical, \fIcmp\fR says nothing and returns an exit status 0. If they are, it tells you where they differ and returns 1. You can use the exit status in a shell script. For example, the following Bourne shell script (it doesn't work with \fIcsh\fR) compares files that are in both the current tree (which is the current working directory) and the original tree (\fI../orig\fR) and makes a copy of the ones that have changed in the directory \fI../changed\fR. .Ps $ \f(CBfor i in *; do \fIcheck all files in the directory\f(CW> \f(CB if [ -f ../orig/$i ]; then \fIit is present in the orig tree\f(CW> \f(CB cmp $i ../orig/$i 2>&1>/dev/null \fIcompare them\f(CW> \f(CB if [ $? -ne 0 ]; then \fIthey're different\f(CW> \f(CB cp -p $i ../changed \fImake a copy\f(CW> \f(CB fi\f(CW> \f(CB fi\f(CW> \f(CBdone\f(CW .Pe There are a couple of points to note about this example: .Ls B .Li We're not interested in where the files differ, or in even seeing the message. We just want to copy the files. As a result, we copy both \fIstdout\fR and \fIstderr\fR of \fIcmp\fR to \fI/dev/null\fR, the UNIX bit bucket. .Li When copying, we use \f(CW\s10-p\fR\s0 to ensure that the timestamps don't get changed again. .Le .Ah "An example--updating an existing tree" Chances are that before long you will have an old version of \fIgcc\fR on your system, but that you will want to install a newer version. As we saw on page \*[update-archive], the gzipped archive for \fIgcc\fR is around 6 MB in size, whereas the patches run to 10 KB or 15 KB, so we opt to get \fIdiffs\fR from \s10\f(CWprep.ai.mit.edu\fR\s0 to update version 2.6.1 to 2.6.3. That's pretty straightforward if you have enough disk space: we can duplicate the complete source tree and patch it. Before doing so, we should check the disk space: the \fIgcc\fR source tree with all objects takes up 110 MB of disk space. .Ps $ \f(CBcd /porting/src\fI move to the parent directory\f(CW $ \f(CBmkdir gcc-2.6.3\f(CW \fI\&make a directory for the new tree\f(CW $ \f(CBcd gcc-2.6.1\fI move to the old directory\f(CW $ \f(CBtar cf - . | (cd ../gcc-2.6.3;tar xf -)\f(CW \fI\&and copy all files\**\f(CW .FS When moving directories with \fItar\fR, it may not seem to be important whether you say \f(CWtar c .\fR or \f(CWtar c *\fR--but it is. If you say \f(CW*\fR, you will miss out any file names starting with \f(CW.\fR (period). .FE $ \f(CBcd ../gcc-2.6.3\f(CW \fI\&move to new directory\f(CW $ \f(CBmake clean\f(CW \fI\&and start off with a clean slate\f(CW $ \f(CBgunzip < /C/incoming/gcc-2.6.1-2.6.2.tar.gz | patch -p | tee patch.log\f(CW Hmm... Looks like a new-style context diff to me... The text leading up to this was: -------------------------- |Changes for GCC version 2.6.2 from version 2.6.1: | |Before applying these diffs, go to the directory gcc-2.6.1. Remove all |files that are not part of the distribution with the command | | make distclean | |Then use the command | | patch -p1 | |feeding it the following diffs as input. Then rename the directory to |gcc-2.6.2, re-run the configure script, and rebuild the compiler. | |diff -rc2P -x c-parse.y -x c-parse.c -x c-parse.h -x c-gperf.h -x cexp.c -x bi-parser.c -x objc-parse.y -x objc-parse.c |-x TAGS -x gcc.?? -x gcc.??s -x gcc.aux -x gcc.info* -x cpp.?? -x cpp.??s -x cpp.aux -x cpp.info* -x cp/parse.c -x cp/pa |rse.h gcc-2.6.1/ChangeLog gcc-2.6.2/ChangeLog |*** gcc-2.6.1/ChangeLog Tue Nov 1 21:32:40 1994 |--- gcc-2.6.2/ChangeLog Sat Nov 12 06:36:04 1994 -------------------------- File to patch: .Pe Oops, these patches contain the directory name as well. As the diff header indicates, we can solve this problem by supplying the \s10\f(CW-p1\fR\s0 flag to \fIpatch\fR. We can also solve the problem by moving up one level in the directory hierarchy, since we have stuck to the same directory names. This message also reminds us that \fIpatch\fR is very verbose, so this time we enter: .Ps $ \f(CBgunzip < /C/incoming/gcc-2.6.1-2.6.2.tar.gz | patch -p1 -s | tee patch.log\f(CW 1 out of 6 hunks failed--saving rejects to cccp.c.rej $ .Pe What went wrong here? Let's take a look at \fIcccp.c.rej\fR and \fIcccp.c.orig\fR. According to the hunk, line 3281 should be .Ps if (ip->macro != 0) .Pe The hunk wants to change it to .Ps if (output_marks) .Pe However, line 3281 of \fIcccp.orig\fR is .Ps if (output_marks) .Pe In other words, we had already applied this change, probably from a message posted in \s10\f(CWgnu.gcc.bugs\fR\s0. Although the patch failed, we don't need to worry: all the patches had been applied. .LP Now we have a \fIgcc-2.6.2\fR source tree in our directory. To upgrade to 2.6.3, we need to apply the next patch: .Ps $ gunzip < /C/incoming/gcc-2.6.2-2.6.3.diff.gz | patch -p1 -s | tee -a patch.log .Pe We use the \s10\f(CW-a\fR\s0 option to patch here to keep both logs--possibly overkill in this case. This time there are no errors. .LP After patching, there will be a lot of original files in the directory, along with the one \fI.rej\fR file. We need to decide when to delete the \fI.orig\fR files: if something goes wrong compiling one of the patched files, it's nice to have the original around to compare. In our case, though, we have a complete source tree of version 2.6.2 on the same disk, and it contains \fIall\fR the original files, so we can remove the \fI.orig\fR files: .Ps $ \f(CBfind . -name "*.orig" -print | xargs rm\f(CW .Pe We use \fIxargs\fR instead of \s10\f(CW-exec rm {} \e;\fR\s0 because it's faster: \s10\f(CW-exec rm\fR\s0 starts a \fIrm\fR process for every file, whereas \fIxargs\fR will put as many file names onto the \fIrm\fR command line as possible. After cleaning up the tree, we \fIback it up\fR. It's taken us a while to create the tree, and if anything goes wrong, we'd like to be able to restore it to its initial condition as soon as possible. @ 3.0 log @Final draft @ text @d2 1 a2 1 .\" $Id: care-and-feeding.ms,v 2.6 1995/06/09 04:30:25 grog Exp grog $ d4 3 a818 8 .Ls B .Li .Li They may represent modified versions of an existing file. Various programs enable you to compare the contents of files and create summary information about how they differ. .Le We'll look at these topics in the following sections. @ 2.7 log @Final draft, second cut @ text @a1108 13 .\" .Ah "Summary" .\" We've seen a number of rather scattered points in this chapter: .\" .Ls B .\" .Li .\" The source tree is the most important part of the package. A little extra care .\" helps ensure that ports go smoothly. .\" .Li .\" \fIpatch\fR is a useful tool for updating source trees, but it can easily get .\" out of control. .\" .Li .\" Be religious about timestamps. They're one of the best indications you have .\" about what has been going on in the source tree. .\" .Le @ 2.6 log @Remove date from page headers Minor mods @ text @d2 1 a2 1 .\" $Id: care-and-feeding.ms,v 2.5 1995/05/15 17:25:08 grog Exp grog $ d4 4 a194 1 $ d859 1 a859 1 .XX "klduge, defined" d1109 13 a1121 13 .Ah "Summary" We've seen a number of rather scattered points in this chapter: .Ls B .Li The source tree is the most important part of the package. A little extra care helps ensure that ports go smoothly. .Li \fIpatch\fR is a useful tool for updating source trees, but it can easily get out of control. .Li Be religious about timestamps. They're one of the best indications you have about what has been going on in the source tree. .Le @ 2.5 log @Major mods after Andy's final draft review @ text @d2 1 a2 1 .\" $Id: care-and-feeding.ms,v 2.4 1995/02/11 11:24:31 grog Exp grog $ d4 3 d22 1 a22 1 .St "Care and feeding of source trees ($Date: 1995/02/11 11:24:31 $)" a54 1 .Le @ 2.4 log @Minor mods @ text @d2 1 a2 1 .\" $Id: care-and-feeding.ms,v 2.3 1995/02/04 15:10:36 grog Exp grog $ d4 3 d19 1 a19 1 .St "Care and feeding of source trees ($Date: 1995/02/04 15:10:36 $)" d46 6 a51 12 clean, well-defined starting point? In this chapter we'll look at: .Ls B .Li How to get to a clean starting point. Usually this will be the case after you have extracted the source archive, but frequently you need to add patches or remove junk. .Li How to build a tree with sources on CD-ROM. .Li How to recognize the changes you have made. .Li How to maintain multiple versions of your software. d92 1 a92 1 .Ls B d104 4 a107 1 file to the new file, modifying it with the patches as it goes. a126 2 A typical example are the patches for X11R5. You might start with the sources supplied on the companion CD-ROM to [Mui&Pearce 1993]. d129 6 a134 3 This CD-ROM includes the complete X11R5 sources to patch level 21. At the time of writing, five further patches to X11R5 have been released. To bring the source tree up to patch level 26, you would proceed as follows: d245 4 a248 4 This message shows that it has found the text in \fImit/bug-report\fR. One of the changes in any X11 \fIdiff\fR is to change the first things \fIpatch\fR does is to change this text (to \fIpublic-patch-23\fR), so that it will notice a repeated application of the patch. Continuing, d331 11 a341 7 Patch makes an implicit assumption that the patch was created based on another identical source tree. This is not always the case--you may have changed something in the course of the port. The differences frequently don't cause problems if they are an area unrelated to the patch. In this example, we'll look at how things can go wrong. Let's consider the following situation: during a previous port of X11R5 pl 22, you ran into some problems in \fImit/lib/Xt/Selection.c\fR and fixed them. The original text read: d457 7 a463 4 Not surprisingly, these is the contents of hunk 3. Because of our fix, \fIpatch\fR couldn't find the old text and thus couldn't process this hunk. In this case, the easiest thing to do is to perform the fix by hand. To do so, we need to look at the partially fixed file that \fIpatch\fR created, d500 4 a503 4 If you specify (for example) \s10\f(CW-p4\fR\s0, \fIpatch\fR will remove the first 4 directory name components in the pathname. This is useful when the diffs contain incorrect base path names. For example, you may find a diff header which looks like: d538 2 a539 2 examine the patches to figure out which one is intended. Then you just need to give this name to the prompt, and \fIpatch\fR should perform the patches. d551 3 a553 3 versions are prepared to skip anything they don't understand, this could be the result. The only thing for it is to get a newer version of \fIpatch\fR--see \*[appcdrom], for details. d573 2 a574 2 don't like the message, which makes you wonder why \fIdiff\fR prints it. In any case, the solution is simple: edit the \fIdiff\fR and remove the offending line. d577 1 a577 3 At the end of a session, \fIpatch\fR leaves behind a number of files: .Ls B .Li d586 1 a586 2 .Li If any patches failed, you will have files called \fIfilename.rej\fR a587 5 (for "rejected"). These contain the hunks that \fIpatch\fR could not apply. Another common suffix for rejects is \f(CW\s10#\fR\s0. Again, you can change the suffix, this time with the \f(CW\s10-r\fR\s0 flag. .Le If you have any \fI.rej\fR a589 2 files, you need to look at them and find out what went wrong. It's a good idea to keep the \fI.orig\fR d592 7 a598 1 files until you're sure that the patches have all worked as indicated. d611 1 a611 1 which don't really have much to do with \fIemacs\fR d658 2 a659 2 course, but Murphy's law will ensure that if you don't save it, you \fIcan\fR be sure that you will need it again. d664 4 a667 4 can be sure that you don't accidentally change anything. You can, unfortunately, also be sure that you can't deliberately change anything. Normal \fIMakefiles\fR expect to put their objects in the source tree, so this complicates the build process significantly. d669 2 a670 2 In the next two sections, we'll look at a couple of techniques have evolved to address this problem. Both use symbolic links. d678 2 a679 2 the same directory. For example, assume you have a directory \fI/cd0/src/find\fR with the sources to \fIfind\fR: d689 1 a689 1 a link tree with the following input: a690 1 $ \f(CBdir=/cd0/src/find\f(CW d692 1 a692 1 $ \f(CBfor i in $dir/*; do\f(CW d723 1 a723 1 $ \f(CBdir=/cd0/src/find/find\f(CW d727 1 a727 1 $ \f(CBfor i in $dir/*; do\f(CW d800 2 a801 2 The most obvious modification that you make to a source tree is that the process of building puts new files into it: the compiler creates object files\** d808 3 a810 1 created as well. You may want to do a number of things with these files: a812 23 Remove them again: they take up space and can demonstrably be rebuilt (well, at least it has already worked once). Traditionally, you do this with \fImake clean\fR. We'll look at this in \*[chmake], on page \*[make-clean]. .Li Install them where the general user population can use them. You typically do this with \fImake install\fR. We'll look at this in \*[chinstall]. .Li Make an installable package out of them. This is an idea that has not yet caught on properly, though packaging tools such as those supplied with System V.4 make the idea more appealing. .IP Installable packages are an interesting concept: traditionally, UNIX software has always been supplied in source form--after all, that's what this book is all about--but it's usually possible to distribute software for a specific architecture in binary form. Such a distribution has many advantages. In particular, it makes it possible for non-technical users to install software without having to wade through a book like this. We'll look at software packaging tools in \*[chinstall]. .Le Whatever you do with these files, the first thing you want to do is to be able to recognize them. There are a number of ways of recognizing files that have been created or changed in the course of building the package: .Ls B a813 2 They will have been modified more recently than anything in the distribution. .Li d822 5 a826 7 There can be many reasons why you want to identify the files that have been created since installation of the source tree. Fortunately, this is simple: since they have been created since the creation of the source tree, they are all newer than any file in the original source tree. With the simple command \fIls -lt\fR (probably piped into \fImore\fR or \fIless\fR), you can display them in the reverse order in which they were created (newest first) and thus separate the new from the old. d836 3 a838 3 The \fIlast modification\fR timestamp is updated every time the file or directory is modified. This is what most users think of as \fIthe\fR file timestamp. You can display it with the \fIls -l\fR command. d844 3 a846 3 The \fIlast access\fR timestamp is updated every time a data transfer is made to or from the file. You can display it with the \fIls -lu\fR command. This timestamp can be useful in a number of different places. d900 3 a902 3 As we have seen above, the last modification timestamp is useful as a sort criterion when you list directories. If you're looking for a file you made the week before last, it helps if it is dated accordingly. d935 1 a935 1 files on one machine, where the clocks are behing, and compile on another, where d988 1 a988 1> \f(CB cmp $i ../orig/$i &>/dev/null \fIcompare them\f(CW d1013 1 a1013 3 \fIgcc\fR source tree with all objects takes up 110 MB of disk space, and even after a \fImake clean\fR it still has 33 MB. In this case, we do have enough space, and we don't want to remove the objects from the 2.6.1 tree, so we enter: d1075 1 a1075 1 if (ip->macro != 0) d1105 1 a1105 1 We've seen a number of only marginally related points in this chapter: @ 2.3 log @Minor mods @ text @d2 1 a2 1 .\" $Id: care-and-feeding.ms,v 2.2 1995年01月25日 17:02:52 grog Exp grog $ d4 3 d16 1 a16 1 .St "Care and feeding of source trees ($Date: 1995年01月25日 17:02:52 $)" d18 1 a18 1 In \*[chunpack] we saw how to create an initial source tree. It won't stay in d545 1 a545 1 \*[appcdrom] for details. d810 1 a810 1 clean\fR. We'll look at this in \*[chmake] on page \*[make-clean]. d852 1 a852 1 since January 1, 1970 UTC. See \*[chtime], page \*[time_t] for more details. @ 2.2 log @Minor mods @ text @d2 1 a2 1 .\" $Id: care-and-feeding.ms,v 2.1 1995年01月17日 16:50:55 grog Exp grog $ d4 3 d13 1 a13 1 .St "Care and feeding of source trees ($Date: 1995年01月17日 16:50:55 $)" d541 2 a542 2 result. The only thing for it is to get a newer version of \fIpatch\fR, for example in the directory \fIutil/patch-2.1\fR on the companion CD-ROM. d1024 5 a1028 4 .Ah "Cleaning up the case study source trees" In \*[chunpack], we extracted three of our case study trees (\fIuucp\fR, C news and \fIelm\fR) directly from source archives, so there isn't anything further to do. In the case of \fIgcc\fR, however, we opted to get \fIdiffs\fR from d1030 1 a1030 1 straightforward if you have enough disk space. We can duplicate the complete @ 2.1 log @Minor mods @ text @d2 1 a2 1 .\" $Id: care-and-feeding.ms,v 2.0 1994年12月17日 17:21:38 grog Exp grog $ d4 2 d7 1 d10 1 a10 1 .St "Care and feeding of source trees ($Date: 1994年12月17日 17:21:38 $)" d869 17 a885 10 it). This is a sort of kludged last modification timestamp for the inode, that part of a file which stores information about the file. The most frequent changes which don't affect the other timestamps are change in the number of links or the permissions, which normally isn't much use to anybody. On the other hand, the inode also contains the other timestamps, so if this rule were enforced rigidly, a change to another timestamp would also change the status change timestamp. This would make it almost completely useless. As a result, most implementations suppress the change to the status change timestamp if only the other timestamps are modified. If you want, you can display the status change timestamp with the \fIls -lc\fR command. @ 2.0 log @checked in with -k by grog at 1995年01月09日 13:22:41 @ text @d2 1 a2 1 .\" $Id: care-and-feeding.ms,v 1.31 1994年12月17日 17:21:38 grog Exp grog $ a3 2 .\" Revision 1.31 1994年12月17日 17:21:38 grog .\" Minor mods for bignuts macros a4 66 .\" Revision 1.30 1994年12月16日 13:29:53 grog .\" Minor mods .\" .\" Revision 1.29 1994年12月08日 15:14:36 grog .\" Minor mods .\" .\" Revision 1.28 1994年12月08日 14:40:05 grog .\" Finished major changes .\" .\" Revision 1.27 1994年12月08日 10:31:57 grog .\" Nearly finished rewrite. .\" .\" Revision 1.26 1994年12月07日 13:53:10 grog .\" Major restructure, nearly finished .\" .\" Revision 1.25 1994年12月01日 16:29:02 grog .\" Minor mods .\" .\" Revision 1.24 1994年11月15日 12:14:42 grog .\" Minor mods .\" .\" Revision 1.23 1994年10月29日 13:17:56 grog .\" Minor mods .\" .\" Revision 1.22 1994年09月30日 17:58:33 grog .\" Snapshot 30 September 94 .\" .\" Revision 1.21 1994年09月04日 17:28:11 grog .\" Minor mods .\" .\" Revision 1.20 1994年08月25日 17:07:30 grog .\" Change all names from .roff to .ps, set uniform version number 1.20, minor mods .\" .\" Revision 1.11 1994年08月07日 12:00:30 grog .\" Change global.defs to global.roff .\" .\" Revision 1.10 1994年07月12日 19:47:32 grog .\" Minor mods, page number references .\" .\" Revision 1.9 1994年06月09日 13:33:19 grog .\" Get globals right .\" .\" Revision 1.8 1994年06月07日 15:59:39 grog .\" Change global file to global.defs .\" .\" Revision 1.7 1994年05月27日 08:41:12 grog .\" Mods as suggested by Mike Loukides .\" .\" Revision 1.6 1994年05月16日 16:25:19 grog .\" Half-finished version with some loose ends round CVS .\" .\" Revision 1.5 1994年05月13日 15:38:05 grog .\" Many mods, add stuff on CD-ROM source trees .\" .\" Revision 1.4 1994年05月13日 12:05:57 grog .\" More fun with Id and Log .\" .\" Revision 1.3 1994年05月13日 12:03:14 grog .\" Try to fix the Id stuff .\" .\" Revision 1.2 1994年05月13日 11:57:09 grog .\" Add stuff about CD-ROM directory trees .\" .\" Revision 1.1 1994年05月11日 17:20:31 grog .\" Initial revision .\" a7 1 We use the term \fIsource tree\fR d9 2 a10 7 to refer to the directory or hierarchy of directories in which the package is stored. For most purposes, the source tree \fIis\fR the package: it is involved in nearly everything you do when porting. In this chapter, we'll look at the way the source tree changes in the course of a port, and what you can do to keep it in good shape. .LP During a typical port, the source tree is constantly changing: d13 5 a17 13 Initially, you create the tree and read the source archive into it. We looked at this in \*[chunpack]. Alternatively, you may have a source tree on CD-ROM. You can't modify CD-ROMs, but you may want to leave the sources on the CD and just put the modified files on to disk. .Li After unpacking, you may find that you have to clean out junk left behind from a previous port. .Li You may apply \fIpatches\fR .XX "patches" to the source tree to bring it up to date. For example, you might start with an out-of-date archive from a CD-ROM, and add some patches to bring it up to the current version. We'll look at patching on page \*[patch]. d37 3 a39 2 How to get to a clean starting point. This may be as simple as reading in the archive, but frequently you need to add patches or remove junk. d47 23 a69 14 .Ah "Getting off to a clean start" .XX "tree, tidying up" At the beginning of a port, it's a good idea to make sure you have a well-defined starting point to which you can revert if things go catastrophically wrong. This is normally the case after unpacking the archive, but on occasion you will have to do more work: the tree could be out of date and require patching, or it could contain junk left behind from a previous port. In this section, we'll look at these topics. .LP In \*[chgetting], on page \*[get-patches], we saw that it's frequently better to update an old version of a package rather than to copy the complete new archive. Typically, this is done with \fIpatches\fR. Strictly speaking, a patch is any kind of modification to a source or object file. In UNIX parlance, it's almost always a \fIdiff\fR, d72 4 a75 3 a file that describes how to modify a source file to produce a newer version. Diffs are almost always produced by the \fIdiff\fR program, which we describe in \*[chepilogue], page \*[diff]. d81 5 a85 6 The output if \fIdiff\fR is reasonably understandable, and you can apply the patches by hand if you want, but it's obviously easier and safer to use a program to apply the changes. This is the purpose of \fIpatch\fR. .XX "patch" \fIpatch\fR takes the output of the program \fIdiff\fR and uses it to update one or more files. To apply the patch, it proceeds as follows: d88 2 a89 2 First, find a file header. If it finds any junk before the file header, it skips it and prints a message to say that it has done so. It uses the file d93 1 a93 1 string is \fI.orig\fR, a95 1 so \fIfoo.c\fR would become \fIfoo.c.orig\fR. d321 7 a327 8 One of the biggest dangers in patching source trees is the implicit assumption that the patch was created based on another identical source tree. This is not always the case--you may have changed something in the course of the port. The differences frequently don't cause problems if they are an area unrelated to the patch. In this example, we'll look at how things can go wrong. Let's consider the following situation: during a previous port of X11R5 pl 22, you ran into some problems in \fImit/lib/Xt/Selection.c\fR and fixed them. The original text read: d925 2 a926 3 modification timestamp to the time of extraction (see \*[chunpack], page \*[cpio-mod-times]). You can avoid this with the \f(CW\s10-m\fR\s0 flag to \fIcpio\fR. d968 3 a970 3 Midnight? That looks like 1 a.m. Remember that UNIX timestamps are all in UTC, and that's 1 a.m. in my time zone. This example really \fIwas\fR done with \fItouch\fR. d1011 15 a1025 95 .Ah "Version control" .XX "version control" .XX "revision control" Let's consider the matter of source updates in a more general fashion. There are a number of reasons why sources get updated: .Ls B .Li The original author adds new features or fixes bugs. At some point, he will release a new version that will usually be identified by a new version number. .Li You add new features or fix bugs. At some point, you will let the original author know about them. .Li You make experimental modifications to sources in order to figure out how to get around some problem you are having. In many cases, you don't really expect these modifications to work, but they may give you more insight into the problem. As a result, you will usually want to remove them from the source tree when you have your results. This removal is frequently called backing the changes out. .Le So far, the tools we have seen relate to individual files. We have tools to compare the ages of files, tools to compare the contents of files, and tools to automatically update files. This still doesn't do anything to address the questions of keeping a directory tree consistent. What we would like is a tool that can keep track of the changes to the tree as a whole. In particular, .Ls B .Li It should enable us, if we want, to go back to a previous, known state of the complete tree without us having to perform possibly hundreds of comparisons and patches. .Li It should help merge our modifications into a new version of the software when it comes along. .Le These two requirements conflict to a certain extent. The source tree is developing in two different directions: the author of the software is making additions, and so are you. In addition, there is no one generally accepted way to handle version numbers. .Bh "Version numbers" .XX "version numbers" .XX "FCS" .XX "First Customer Shipment" The current trend in version numbering is to have a major and a minor version number. The major number usually starts at 1 for the first general release (frequently called \fIFCS\fR for First Customer Shipment), and gets incremented when the author considers that sufficient new functionality has been incorporated, or when the Marketing Department considers it opportune. The minor number starts at 0 and gets incremented each time a new version is shipped. The complete number is usually shown as the two numbers separated by a period. Thus, the initial shipment of \fIfoo++\fR might be version 1.0, and it may then go through 1.1, 1.2 and 1.3 before being bumped to 2.0. .LP This does not address internal versions, which may end up being not so internal after all. Between scheduled releases, bug fixes may be issued, and experimental versions may be created. These may be numbered by a third digit, so that the second bug fix to version 1.2 of \fIfoo++\fR might have the version number 1.2.2, or possibly 1.2pl2 (\fIpl\fR stands for patch level). As we saw in \*[chunpack], on page \*[filename-structure], the resultant source tree might be called \fIfoo++-1.2.2\fR. .LP With this numbering scheme, we can envisage a number of operations, starting with \fIfoo++\fR version 1.2.2: .Ls B .Li We make our own private experimental changes, and call the resultant version 1.2.2.1. .Li We make further changes to 1.2.2.1, and call them 1.2.2.2. .Li We back version 1.2.2.2 out and revert to 1.2.2.1. .Li We get version 1.3 from the author and install it in the same version tree. .Li We merge our changes from 1.2.2.1 into 1.3, and call the resultant version 1.3.0.1. We need to be careful here: it's likely that the author will release a version 1.3.1 in the not-too-distant future, so we can't use that number. .Le In practice, keeping track of different versions is at least as complicated as this description looks, and one of the biggest causes of software bugs in large projects is the uncertainty of the exact version of a given file. This is the purpose of version control systems. .LP A version control system is a package that stores a number of versions of source files and can retrieve any version relatively quickly. They are strictly source-based, so they don't help much with binary files (though they offer some features that help). The most generally available version control system is RCS (Revision Control System), and it is included on the companion CD-ROM, so we'll look at that first. .Bh "RCS" .XS "RCS" .XX "version control, RCS" .XX "revision control system" .Pn RCS RCS stores source files in a form related to the latest version\** of d1027 3 a1029 3 .XX "version" RCS talks about \fIrevisions\fR, not versions. I prefer the term \fIversion\fR, and most people use it, so we'll stick with it in this book. d1031 42 a1072 65 .XX ",v, suffix" .XX "suffix, v," the file, but it includes a header with information about how the versions differ. The files for a given directory are normally stored in a subdirectory called \fIRCS\fR, and to avoid confusion, RCS adds the suffix \fI,v\fR to the file names. These files are private to RCS and you shouldn't access them directly. In many cases, the file security is set in such a manner that you can't. .LP RCS provides a number of straightforward programs to manipulate these files: .Ls B .Li You store a file with the \fIci\fR .XX "ci, RCS command" .XX "RCS, ci command" command. \fIci\fR takes a normal source file and stores it in the RCS directory. .Li .XX "co, RCS command" .XX "RCS, co command" You get a copy of the file for reading with the \fIco\fR command. This gives you a version (the latest version, unless you ask for another one) of the file in the current directory. .Li .XX "co, -l flag" .XX "-l flag, co" You can get a copy of the file for updating with the \fIco -l\fR command. If you intend to check a new version in, you should use the \f(CW\s10-l\fR\s0 flag when checking out--otherwise RCS refuses to perform the update. .Li You can perform various sundry operations on the file with the program \fIrcs\fR. .XX "rcs, program" .XX "program, rcs" We'll see some examples of their use further down. .Li You can automate the generation of \fIdiffs\fR with the program \fIrcsdiff\fR. .XX "rcsdiff, program" .XX "program, rcsdiff" .Li You can ease the pain of merging two sets of modifications into a new file with \fIrcsmerge\fR. .XX "rcsmerge, program" .XX "program, rcsmerge" .Le The complete RCS system, including hardcopy documentation, is on the companion CD-ROM in the directory \fIgnu/rcs-5.6.0.1\fR. .Ch "File checkin" .XX "RCS, file checkin" .XX "file checkin, RCS" .XX "checkin, RCS" Initially to set RCS up, you should create a directory \fIRCS\fR, in which RCS stores its files.\** .FS RCS doesn't complain if you don't create the \fIRCS\fR directory--it just stores its files in the current directory instead. It's tidier to use the subdirectory, though, since it helps to distinguish RCS files from other things. .FE Then you decide which files you want to check in. RCS offers some additional documentation facilities that we will examine on page \*[rcs-doc]. It's best to use these tools before initial checkin, but since they're optional, we'll defer the discussion until later. .LP In a typical source tree, you might check in all sources, header files and the \fIMakefile\fR: d1074 1 a1074 37 $ \f(CBmkdir RCS\f(CW $ \f(CBci *.c *.h Makefile\f(CW RCS/knlist.c,v <-- knlist.c enter description, terminated with single '.' or end of file: NOTE: This is NOT the log message!>> \f(CBProgram to extract kernel namelist\f(CW>> \f(CB^D\f(CW initial revision: 1.1 done RCS/lineno.c,v <-- lineno.c enter description, terminated with single '.' or end of file: NOTE: This is NOT the log message!>> \f(CBProgram to intern symbols in lowbug\f(CW>> \f(CB^D\f(CW initial revision: 1.1 done \fI\&... etc.\fR .Pe The first time RCS checks a file in, it asks for a brief description, which describes the purpose of the file. This does not change from one version of the file to the next, so you input it only once. Additionally, for each change, \fIci\fR asks for a log message--we'll see what that is on page \*[Log-message]. At the end of the description, I entered the end-of-file character (CTRL-D on my machine), and RCS entered the file into the RCS directory, printing the revision number as it went. At the same time, it removed the file from the current directory. .Ch "File checkout" .XX "RCS, file checkout" .XX "file checkout, RCS" .XX "checkout, RCS" At some later time you will want to access the files again. This is even more straightforward: if you want to look at, say, \fIlineno.c\fR, you enter .Ps $ \f(CBco lineno.c\f(CW RCS/lineno.c,v --> lineno.c revision 1.1 done d1076 1 a1076 4 This makes a copy of version 1.1 of \fIlineno.c\fR in the current directory. .LP Let's assume that you now want to update \fIlineno.c\fR. You make a couple of minor changes, and then check it back in again: d1078 3 a1080 32 $ \f(CBci lineno.c\f(CW RCS/lineno.c,v <-- lineno.c ci error: no lock set by grog .Pe The problem here is that you have checked the file out for reading only. In order to update it, you need to tell RCS that you intend to update it when you check it out. In RCS parlance, you request RCS to \fIlock\fR .XX "RCS, locking" .XX "locking, RCS" it: while you're working on it, nobody else can check it out to lock it, otherwise somebody's work could get lost. In this case, \fIassuming somebody else hasn't updated it in the meantime\fR, you can lock it with the \fIrcs\fR program \f(CW-u\fR flag: .Ps $ \f(CBrcs -u lineno.c\f(CW RCS file: RCS/lineno.c,v 1.1 unlocked done .Pe Then you check the file in again: .Ps $ \f(CBci lineno.c\f(CW RCS/lineno.c,v <-- lineno.c new revision: 1.2; previous revision: 1.1 enter log message, terminated with single '.' or end of file:>> \f(CBChanged buffer size from 256 to 1024, added #define BUFSIZE\f(CW>> \f(CB^D\f(CW done .Pe This \fIis\fR the log message: every time you update a module, RCS expects you to supply a mesasge to say what you have changed. You can omit the log message, but then RCS puts a default message in the log: d1082 1 a1082 1 *** empty log message *** d1084 3 a1086 108 This always makes me feel like I've been caught trying to cut corners, so I always put \fIsomething\fR in the log message. .LP You can tell whether somebody has updated it or not by the version number. If somebody else has changed the file in the meantime, RCS doesn't notify you: you need to compare the version number with what you have already. .Ch "RCS version numbers" .XX "RCS, version numbers" .XX "version numbers, RCS" The key to RCS' version management is the \fIversion number\fR, which RCS calls a \fIrevision number\fR. Unless told otherwise, when RCS checks in a file for the first time, it gives it the version number 1.1, not 1.0 as you might expect. If you want, you can tell \fIci\fR to insert version 1.0 with the \f(CW\s10-r\fR\s0 flag: .Ps $ \f(CBci -r1.0 file\f(CW .Pe From then on, each time you check a new version of the file in, \fIci\fR increments the second number, so the versions will then have the numbers 1.1, 1.2 and so on. When at some later date you decide to change the version number to 2.0, you state this explicitly with the \f(CW\s10-r\fR\s0 flag. .LP RCS' idea of version numbers is rather restrictive: two-part version numbers, like 1.1, 1.2, and so on, are the standard numbers for revisions on the \fItrunk\fR, .XX "RCS, trunk" .XX "trunk, RCS" the main part of the tree. At any point on the trunk, the tree may grow a \fIbranch\fR, .XX "RCS, branch" .XX "branch, RCS" an additional version based on the version from which it grows. These branches have three-part numbers: for example, if you update version 1.3 and don't specify any special options, the new version will be version 1.4. To get to version 2.0, you specify it explicitly with the \s10\f(CW-r\fR\s0 flag: .Ps $ \f(CBci -r2.0 foo.c\f(CW .Pe If you make another update to version 1.3, this will create a branch with the number 1.3.1. This branch is not a version: it can have multiple versions which will be numbered 1.3.1.1, 1.3.1.2, and so on: .Fs 0i .PS 4i .ps -2 box "1.1" arrow R12: box "1.2" arrow R13: box "1.3" arrow R21: box "1.4" arrow R22: box "2.0" arrow dashed box invis "Trunk" line invis down from R21.s RB1: box "1.3.1.1" arrow from R13.s to RB1.w line invis down from R22.s RB2: box "1.3.1.2" arrow from RB1.e to RB2.w arrow dashed right from RB2.e move .3i box invis "Branch 1.3.1" .ps +2 .PE This strategy does not always match well with existing software: for example, files from \fIgcc\fR version 2.6.2 cannot be given version number 2.6.2, because this is a branch number, not a version number. See [Tichy 1991] .XX "Tichy, Walter" on the companion CD-ROM for more confusing details. .LP .Pn RCS-version-numbers Version numbers are allocated on a per-file basis. In the course of a port, you normally update some source files frequently and others not at all. This can result in a wide divergence of version numbers amongst the files of a single source tree. .Ch "Correlating sources and objects" .XX "RCS, correlating sources and objects" .Pn rcs-doc One of the limitations of RCS is that it manages source files only. To get the corresponding object files, you use \f(CW\s10make\fR\s0. That may be well and good, but frequently you have an object program that is giving you problems, and you want to know which version of what source was used to make it. RCS has documentation facilities which help here: to each \fI.c\fR file, near the top, add .Ps static char rcs_id [] = "$\&Id$"; /* $\&Log$ */ .Pe The \fI$\fR signs are part of the keyword. When RCS checks out a file with such keywords, it replaces them with version information from the RCS file. In our \fIlineno.c\fR from the previous example, we would find after checkout: .Ps static char rcs_id [] = "$\&Id: lineno.c,v 1.2 1994年05月11日 11:00:50 grog Exp grog $"; /* $\&Log: lineno.c,v $ * Revision 1.2 1994年05月11日 11:00:50 grog * Changed buffer size from 256 to 1024, added #define BUFSIZE * * Revision 1.1 1994年05月11日 08:59:16 grog * Initial revision * */ .Pe The \fI$\&Log$\fR entry is fairly straightforward: it has been replaced by a revision history of the source file, taken from the log entries typed in when checking the file in. d1088 2 a1089 72 The keyword \fI$\&Id$\fR is replaced by an identification line which at first seems only partially intelligible. The individual components are: .Ls B .Li \fIlineno.c,v\fR is the name of the RCS file, not of the source file you use. .Li \fI1.2\fR is the current version. .Li \fI1994/05/11 11:00:50\fR is the creation timestamp of this version. As in all RCS timestamps, it is specified in UTC. .Li \fIgrog\fR is the name of the user who created the update. .Li \fIExp\fR is the file \fIstate\fR. The documentation suggests \fIExp\fR for files in experimental state, \fIStab\fR for files that are stable, and \fIRel\fR for files that are released. In practice, you almost never see anything except \fIExp\fR--even the RCS sources are \fIExp\fR! Possibly this is a comment on the state of the art. .Li \fIgrog\fR (again) is the user ID of the locker. This field is only present if the file is locked. .Le In this example, the identification is used to initialize a static character array called \f(CW\s10rcs_id\fR\s0. You don't refer to the array, so the name is not important (and also because you don't refer to the array, most compilers warn you about the lack of reference). The array is included in the object file and finds its way to the final executable. The RCS program \fIident\fR .XX "ident" uses this string to identify the source files that participated in the program: .Ps $\& \f(CBident fu\f(CW fu: $\&Id: strrchr.s,v 1.2 1993年11月18日 20:21:55 donn Exp $ $\&Id: strcat.s,v 1.1 1993年11月12日 10:27:35 donn Exp $ $\&Id: strncpy.s,v 1.1 1993年11月12日 10:29:49 donn Exp $ \fI\&... more library $\&\&Id$s\f(CW $\&Id: fu.cc,v 2.2 1994年05月10日 15:41:35 grog Exp $ $\&Id: rows.cc,v 2.2 1994年05月10日 15:41:35 grog Exp $ $\&Id: columns.cc,v 2.2 1994年05月10日 15:38:19 grog Exp $ $\&Id: physio.cc,v 2.2 1994年05月10日 15:29:14 grog Exp $ $\&Id: cache.cc,v 2.2 1994年05月10日 15:38:19 grog Exp $ $\&Id: audit.cc,v 2.2 1994年05月10日 15:38:19 grog Exp $ \fI\&... more program $\&Id$s .Pe This example shows that the C library in use (from BSD/OS) also uses RCS,\** .FS .XX "Seeley, Donn" \s8\f(CWdonn\fR\s0 is Donn Seeley of BSDI. .FE and gives an accurate indication of the files that went to make up the program. .Ch "Accessing other versions" .XX "RCS, accessing other versions" Unless you tell them to do anything else, the \fIco\fR and \fIci\fR commands always operate on the most recent revision of the main branch of the revision tree. If you want anything else, you must ask for it, again with the \f(CW\s10-r\fR\s0 flag: .Ps $ \f(CBco -r2.1.1.3 fragmented.c\f(CW .Pe .Ch "Identifying a release" .XX "release, identifying" .XX "RCS, identifying release" After a number of changes, the version numbers of each file in a package will be markedly different: some might still be at version 1.1, others could have had hundreds of updates. This doesn't make it easy to identify the files that belong to a software release. There are a couple of things you can do to make things easier: .Ls B .Li Before a release, bring all version up to a uniform version number. For example, if the highest version number is 1.82, you might bump the version numbers of all files to 1.100. You can do this with: d1091 1 a1091 2 $ \f(CBco -M -l RCS/*\f(CW \fI\&check out all RCS files\f(CW $ \f(CBci -f1.100 -d -\f(CW \fI\&and check in again with version number 1.100\f(CW d1093 9 a1101 11 .IP In this example, we have used the \s10\f(CW-M\fR\s0 flag on checkout and the \s10\f(CW-d\fR\s0 flag on checkin in order not to change the modification timestamps. The \s10\f(CW-f\fR\s0 flag to \fIci\fR forces a checkin even if the file hasn't changed. .Li Assign a \fIversion name\fR .XX "RCS, version name" .XX "version name, RCS" to the files. This is a symbolic name (for example \fIRelease-2\fR) which will be assigned to all the files. For example, you could write: d1103 1 a1103 1 $ \f(CBrcs -n"Release-2" RCS/*\f(CW d1105 6 a1110 116 .IP This will assign the symbolic name \fIRelease-2\fR to the current version of all files, regardless of their version number. Many people swear by this method, but it has a number of disadvantages: in particular, this symbolic name does not occur in the \fI$\&Log$\fR or \fI$\&Id$\fR messages, and it's difficult to correlate the version numbers with the release string. In addition, you can't use any old string for the name: a number of characters, including blanks and periods, are not permitted, so you can't use this method to force a version number like \s10\f(CW2.6.2\fR\s0. .Le .Ch "Programs that know about RCS" .XX "RCS, programs that know about" In some cases, checking out RCS files can be a real nuisance: for example, when you run \fImake\fR, you could find yourself checking out every single file. There is an easier way: some flavours of \fImake\fR, including GNU \fImake\fR, know about RCS and automatically check out RCS files if they don't find what they are looking for in the current directory. On completion of the build, they then remove the RCS files from the current directory again. .LP In addition, \fIemacs\fR knows about RCS. In particular, if you try to edit a file that is maintained by RCS, \fIemacs\fR automatically checks it out for you, and also checks it in for you with the \fIvc-toggle-read-only\fR command, which is usually bound to the key sequence \fICTRL-x CTRL-q\fR. .Ch "Gotchas with RCS" .XX "RCS, gotchas" .XX "gotchas, RCS" Although RCS is relatively easy to use, many programmers don't like it. They tend to see it as something that stands between them and getting the job done. In fact, RCS imposes relatively few restrictions, but there are a couple of things that can give you headaches: .Ls B .Li The keywords have been chosen to be relatively uncommon, but if they occur in normal programs, RCS still changes the text. The first time I put the text of this chapter into RCS, it messed up all my examples with \fI$\&Id$\fR and friends.\** .FN If you find yourself in a similar predicament, and you're using \fItroff\fR, you can prevent this from happening by writing \fI$\e&Id$\fR etc. .FE .Li Frequently, when porting a package, you add new source files which weren't present in the original. RCS doesn't support this concept: if you want a new file in a branch, you need a version of the same file in the trunk, even if it doesn't belong there. .Li .Pn Log-message RCS log messages are inserted after the keyword \fI$\&Log$\fR. Depending on the kind of source file, different comments are required to ensure that the log messages don't get interpreted by whatever program processes the file. RCS knows about files with the suffices \fI.c\fR and \fI.h\fR, and will use \f(CW\s10//\fR\s0 for C++ files, even if they're in the middle of a \fI/* \&... */\fR style of comment, but for just about anything else it uses \fI#\fR, which is not always appropriate. You can modify the comment string with the command \f(CW\s10rcs -c'\fIcomment\f(CW'\fR\s0. .Li .Pn RCS-changes-timestamps By default, RCS sets timestamps to the current time both on checkin and checkout. You can get RCS to check files in with their last modification timestamp by using \s10\f(CWci -d\fR\s0, and on checkout you can use \s10\f(CWco -M\fR\s0 to restore the last modification timestamp. RCS documentation states: \fIUse this option with care; it can confuse make(1)\fR. This is misleading, since there are many ways to confuse \fImake\fR: if you run \fImake\fR, check the files in and then out again, and then re-run \fImake\fR, it will re-make everything, because the timestamps have changed. On the other hand, if you revert to an older version of a source, and restore the last modification timestamp of the old version, \fImake\fR will see that everything is "up to date" and do nothing. Clearly, it depends on what you are doing whether you want to restore the old timestamps or not. I prefer to restore the last modification timestamps at all times. .Le A general rule of thumb is: .IP \fIUse RCS if your package is set up for RCS, or if you plan to perform extensive modifications to the package. Otherwise, don't bother.\fR .LP .XE "RCS" .Bh "SCCS" .XX "SCCS" .XX "version control, SCCS" .XX "source code control system" Another common version control system is \fISCCS\fR, the Source Code Control System. This is a proprietary product supplied with most versions of System V and Xenix. If you have SCCS, you'll also have ample documentation for it, so we'll just look at it briefly here. .LP SCCS can in fact be considered a predecessor of RCS, as you can see in [Tichy 1991] .XX "Tichy, Walter" (on the companion CD-ROM). The main differences are: .Ls B .Li SCCS uses substantially the same version numbering scheme as RCS. .Li The source is stored in a different manner. This is a performance issue that shouldn't be of much practical significance (RCS claims to be much faster than SCCS). .Li .XX "s., filename prefix" .XX "prefix, s." .XX "filename prefix, s." SCCS files have the prefix \fIs.\fR instead of the file name suffix \fI,v\fR. SCCS may also create a number of other files with other prefixes. .Li The SCCS equivalents of \fIco\fR and \fIci\fR are \fIget\fR and \fIdelta\fR (in some versions, \fIsccs get\fR and \fIsccs delta\fR) respectively. You must specify the file names in the SCCS form (with the prefixed \fIs.\fR). .XX "get, SCCS program" .XX "SCCS, get program" .XX "delta, SCCS program" .XX "SCCS, delta program" .XX "sccs get, program" .XX "program, sccs get" .XX "sccs delta, program" .XX "program, sccs delta" .Le d1123 1 a1123 5 .Li RCS is a useful tool for software development, but using it when porting can require significant modifications, which aren't worthwhile for a straightforward port. .Le@

AltStyle によって変換されたページ (->オリジナル) /