[Chapter 52] 52.8 Building Programs from Source Code
Author: Jerry Peek, Tim O'Reilly & Mike Loukides
Date: 1998-08-04T21:58:49Z

#

| Chapter 52 What's on the Disc |

## 52.8 Building Programs from Source Code

The programs on the disc are supplied in binary form for the most popular UNIX platforms, as listed in article 52.3. But we also supply C source code for those of you who are on unsupported platforms.

Now, don't run away. You don't have to be a C programmer to compile these sources. I've never written a C program in my life, and I compile public domain software all the time. The CD-ROM provides build scripts for each of the packages, so many of you can just run the script and have everything installed automatically.

If the build scripts don't work, the CD-ROM also has a script to copy the sources to your local hard disk. Although we can't promise that you'll be able to build the sources on your own without a hitch, this article includes some explanation of how to build sources without needing to learn how to program in C.

### 52.8.1 Running the Build Scripts

Before you do anything, try out the build scripts. You might be able to get away without knowing anything at all about the build process.

To build programs from source code, first mount the CD-ROM as described in article 52.5.

Each package on the CD-ROM that has source code can be compiled with the "build" script. The build script will copy the files off the CD into your current directory, compile, and install them.

As the CD-ROM is read-only, you must use a directory on some other disk for the build. For example, if you wanted to build the "compress" package, a directory called compress will be created in the current directory when the build script is run. The build script has default settings for the directory to which the source code will be copied, the directory in which the package will be installed, the directory in which the "shareable" portion of the package will be installed, and a "prefix" for the shareable directories. These settings can be overridden by the following environment variables (6.1):

SOURCEDIR

  This is where the source code for the package resides on the CD-ROM. The build script tries to determine this automatically, so you should not have set SOURCEDIR unless you are using the build script somewhere other than the CD-ROM.

INSTALLDIR

  This is the directory where the package will be installed. It is set to /usr/local by default. For example, to change INSTALLDIR to /opt:

  >     % setenv INSTALLDIR /opt   csh
  >     $ INSTALLDIR=/opt ; export INSTALLDIR   sh

INSTALLSHAREDIR

  This is the directory where "shareable" portions of the package will be installed (/usr/local/share by default). You can set it to the same value as INSTALLDIR if you want them in the same location.

SHAREPREFIX

  This "prefix" will be prepended to the directory names for lib, include, spool, and bin. There is no default setting, but you could use s if you wanted to conform to the same scheme used by the "install" program to name shareable directories slib, sinclude, sspool, and sbin.

By default, the files generated by the build process will not be removed. If you set the RM variable before running the build, the entire build directory will be removed once the build finishes:

>     % setenv RM true   csh
>     $ RM=true ; export RM   sh

For a list of the available packages, run the build.pt script in the CD-ROM mount directory. The actual name of the script depends on your operating system (as described in article 52.5), but assuming that the CD-ROM is mounted on /cdrom, it is likely to be one of the following commands:

>     % /cdrom/BUILD.PT\;1
>     % /cdrom/BUILD.PT
>     % /cdrom/build.pt\;1
>     % /cdrom/build.pt

The command will print a list similar to the following:

>     bash         bsdtar       bsplit       calen        cpmod        cvtbase
>     delete       diff         ediff        emacs        fgrep        fileutils
>     find         gawk         getopt       glimpse      grabchars    grep
>        ...

To build one of these packages, run the same command followed by the package name. For example:

>     % /cdrom/build.pt bash

The build script will copy the package to the current directory, compile, and install the package according to the values of the environment variables. For this example, the shareable and non-shareable portions of the package are combined.

>     % /archive/cdrom/BUILD.PT jot
>     BUILD script provided by Ready-to-Run Software, Inc.
>     Copyright 1997 Ready-to-Run Software, Inc. All Rights Reserved.
>     Assuming CDROM   is mounted at /archive/cdrom
>     Assuming MACHINE is ALPHA
>     Assuming SOURCEDIR is /archive/cdrom/SOURCES
>     Ignore any errors about directories already existing
>     tools/
>     tools/BUGS
>     tools/Makefile
>     tools/jot.c
>     tools/lam.c
>     tools/rs.c
>     cc -O -o jot jot.c

#### 52.8.1.1 Missing Programs

Some of the build scripts expect non-standard programs to be installed. Some of these come on the CD-ROM:

patch

  Several packages depend on the patch (33.9) program to apply "patches" or "diffs" to source code. This is the primary method of updating source code without replacing the entire file.

perl

  Perl (37.1) is a scripting language used by several packages, including the install and build scripts.

unshar

  The unshar program is needed to unpack shell archive files (19.3).

uncompress

  The uncompress program is needed to unpack files that have been compressed with the compress (24.7) command.

Some other utilities are not included:

gcc

  The GNU (52.9) C compiler was used to compile most of the packages. You can try your system's default C compiler, but it may not work for every package.

GNU make

  GNU make (28.13) was used to compile most of the packages. If you don't have it, try using your system's version.

#### 52.8.1.2 Problems

Any number of things can go wrong with your build. You might not have the right libraries or include files installed. Your compiler may not work the way the program expects it to. You might not have the right permissions. You might run out of disk space.

These problems are so varied that there's no way we can list any generalized solutions. Try asking an administrator or programmer on your site, or try calling Ready-to-Run Software's CD support line (52.9). But we have a few tips that might help:

- bsdtar | If your system has problems with filenames longer than 14 characters, you may have to install bsdtar to be able to "untar" the source code. bsdtar creates unique 14-character filenames as it unpacks an archive.

- If your system lacks the -p option (4.8) to the mkdir command, you may need to install a new version from the GNU fileutils package. The -p option is used by the installation and build scripts.

And if all else fails, you can try to delve into the source code itself. That brings us to our next section ...

### 52.8.2 Compiling Source Code

Compiling programs from source doesn't require you to be a C programmer, just that you understand the general procedure and that you have some common sense and luck.

Almost all UNIX binary programs are written in the C language. These programs are written in text files - the text files are referred to as the source code-and then converted to binary files using a compiler. The typical compiler on a UNIX system is called cc.

Although most people call cc a "compiler," it's really a front-end program. Unless you tell it not to, cc first runs a preprocessor. Next it runs the compiler. Then it runs the linker/loader to make the actual executable file. We'll gloss over that in this article and just say that "cc does it."

On top of cc, there's usually another front-end: almost all programs are designed to be compiled using the make program.

Although we can't prepare you for everything you might need to know to compile programs from the CD-ROM for your platform, this section should at least give you an idea of how it's supposed to work.

#### 52.8.2.1 Copying the Sources

Before you can actually compile the sources, you need to copy the sources to your local hard disk. You can't just compile the sources directly from the CD-ROM because the CD-ROM is read-only.

The first thing you need to do is to decide where you want to install the sources, and then cd to that directory. For example, I like to build sources in a subdirectory of my home directory. Let's suppose I want to install the pcal program. I create the new directory and then cd there:

    ~
    % mkdir ~/pcal_src
    % cd ~/pcal_src

For installing the sources onto your local hard disk, the CD-ROM has a script called source.pt. Assuming that the CD-ROM is mounted on /cdrom, the script can be called using one of the following commands:

>     % /cdrom/SOURCE.PT\;1 package-name
>     % /cdrom/SOURCE.PT package-name
>     % /cdrom/source.pt\;1 package-name
>     % /cdrom/source.pt package-name

Where package-name is the name of the package that you want to install sources for. To get a listing of the files, call source.pt without any arguments:

>     % source.pt
>     SOURCE script provided by Ready-to-Run Software, Inc.
>     Copyright 1997 Ready-to-Run Software, Inc. All Rights Reserved.

>     Assuming CDROM is mounted at /archive/cdrom/
>     Usage: /archive/cdrom/SOURCE.PT <package
>     Available packages are:

>          !              80cols         Clear          _emacs_ml      _enter_csh
>          _enter_sh      _exit_csh      _exit_sh       addup          age_files
>          ascii          awf            bash           behead         bkedit
>          bsdtar         bsplit         cal_today      calen          catsaway
>          center         cgrep          cgrep_sed      checksed       chmod_edit
>          chunksort      cleanup        cleanup_sed    cls            cols
>          count_it       count_types    cpmod          crontab        crush
>          csh_init       csh_logout     cvtbase        date-month     del
>          delete         diff           dir_path       dirtop         doublespace
>          ediff          elookfor       emacs          exrc           fgrep
>          fileutils      find           findcmd        findtext       flip
>          fmt_sh         formprog       ftpfile        gawk           getmac
>          getopt         glimpse        grabchars      grep           groff
>          gzip           head           hey            hgrep          index
>          ipl            ispell         jot            lensort        less
>          lf             lndir          logerrs        longlines      look
>          lookfor        ls_today       make_print     manindex       motd_diff
>          namesort       netpbm         nextday        no_run         nom
>          offset         oldlinks       opttest        paircheck      patch
>          pcal           perl5          phone          pipegrep       pstext
>          psutils        pushin         qcsh           qsubst         qterm
>          rcs            rcsegrep_fast  rcsgrep        rcsrevs        recomment
>          redo           relink         ren            rename         rot
>          runsed         runtime        sc             screen         screensize
>          script_tidy    search_el      sedman         sh_init        sh_logout
>          sharutils      shellutils     showmatch      sl             sls
>          smiley         squoze         stat           stree          stripper
>          su             tar            tcap           tcsh           termtest
>          textutils      tgrep          tknew          tm             tpipe
>          tputinit       triplespace    twin           vgrep          vis
>          vtree          watchq         whereiz        which          wordfreq
>          xgrep          xtail          zap            zloop          zmore
>          zvi

(Note that all the packages on the CD-ROM are listed here, shell scripts as well as C sources.)

In my case, I want to install pcal, so I run the following command:

>     % /cdrom/source.pt pcal
>     SOURCE script provided by Ready-to-Run Software, Inc.
>     Copyright 1993 Ready-to-Run Software, Inc. All Rights Reserved.

>     Copied /POWER_TOOLS/SOURCES/PCAL/PCAL_43.Z to pcal-4.3.tar.Z
>     Copied /POWER_TOOLS/SOURCES/PCAL/RS6000/PCAL to RS6000patch.pcal
>     Copied /POWER_TOOLS/SOURCES/PCAL/RTR/PCAL to rtrpatch.pcal
>     3 files copied successfully.

The source.pt script copies all the relevant files into your current directory.

#### 52.8.2.2 Uncompressing the Sources

If you now list the directory, you'll find the files that were just copied there.

>     % ls
>     RS6000patch.pcal        pcal-4.3.tar.Z          rtrpatch.pcal

The file called pcal-4.3.tar.Z is the pcal source package, in a tarred and compressed form. The .Z suffix tells you that the file was compressed using the compress (24.7) command. You need to run uncompress first:

>     % uncompress pcal-4.3.tar.Z

If you don't have the uncompress command, use gunzip.

#### 52.8.2.3 Untarring the Sources

After you have uncompressed the file, you'll see the file without the .Z suffix.

>     % ls
>     RS6000patch.pcal        pcal-4.3.tar            rtrpatch.pcal

The .tar suffix to the pcal-4.3.tar file means that the file was packed using the tar command (19.5). Again, if you don't have tar, it's on the CD-ROM.

To unpack the file, use tar with the -x option for "extract" and the -f option to specify a filename. (I also like to use -v for verbose output.) My command line might read:

>     % tar xvf pcal-4.3.tar
>     x pcal-4.3/ReadMe, 7673 bytes, 15 tape blocks
>     x pcal-4.3/Descrip.mms, 3713 bytes, 8 tape blocks
>     x pcal-4.3/Make_Pcal.com, 3090 bytes, 7 tape blocks
>     x pcal-4.3/Makefile, 1159 bytes, 3 tape blocks
>     x pcal-4.3/Makefile.Amiga, 1010 bytes, 2 tape blocks
>     x pcal-4.3/Makefile.DOS, 1023 bytes, 2 tape blocks
>     x pcal-4.3/Makefile.VMS, 2505 bytes, 5 tape blocks
>     x pcal-4.3/Orig.ReadMe, 984 bytes, 2 tape blocks
>     x pcal-4.3/Pcal.TEX, 28199 bytes, 56 tape blocks
>     x pcal-4.3/Pcal.hlp, 29099 bytes, 57 tape blocks
>     x pcal-4.3/SetUp.com, 670 bytes, 2 tape blocks
>     x pcal-4.3/VaxCrtl.opt, 31 bytes, 1 tape blocks
>     x pcal-4.3/calendar, 12101 bytes, 24 tape blocks
>     x pcal-4.3/exprpars.c, 8538 bytes, 17 tape blocks
>     x pcal-4.3/moon91, 2828 bytes, 6 tape blocks
>     x pcal-4.3/moon92, 2887 bytes, 6 tape blocks
>     x pcal-4.3/pcal.c, 46440 bytes, 91 tape blocks
>     x pcal-4.3/noprotos.h, 2530 bytes, 5 tape blocks
>     x pcal-4.3/pcalglob.h, 4551 bytes, 9 tape blocks
>     x pcal-4.3/pcalinit.c, 4071 bytes, 8 tape blocks
>     x pcal-4.3/protos.h, 4341 bytes, 9 tape blocks
>     x pcal-4.3/moonphas.c, 17817 bytes, 35 tape blocks
>     x pcal-4.3/troffman.sty, 4894 bytes, 10 tape blocks
>     x pcal-4.3/writefil.c, 24597 bytes, 49 tape blocks
>     x pcal-4.3/pcal.man, 25296 bytes, 50 tape blocks
>     x pcal-4.3/pcaldefs.h, 17643 bytes, 35 tape blocks
>     x pcal-4.3/pcalinit.ps, 14297 bytes, 28 tape blocks
>     x pcal-4.3/pcalutil.c, 21238 bytes, 42 tape blocks
>     x pcal-4.3/pcallang.h, 35465 bytes, 70 tape blocks
>     x pcal-4.3/readfile.c, 32888 bytes, 65 tape blocks

tar creates a subdirectory called pcal-4.3. cd to this directory to continue your build.

>     % cd pcal-4.3

Note that if you have the zcat command, you might have combined the steps for uncompressing and untarring the files into a single command line, as shown in article 19.7:

>     % zcat pcal-4.3.tar.Z | tar xvf -

If you are on a System V-based system, you may have to use tar with the -o option (19.7) to make sure that you get ownership of the files.

#### 52.8.2.4 Unsharring the Sources

Before we go on, let's back up a bit. Some packages aren't stored as tar archives, but as shar archives (19.2). shar archives are generally distributed in multiple files, under names such as part01.Z, part02.Z, etc. The qterm source package is an example of a package that is distributed as shar files.

>     % mkdir ~/qterm_src
>     % cd ~/qterm_src
>     % /cdrom/source.pt qterm
>     % /archive/cdrom/SOURCE.PT qterm
>     SOURCE script provided by Ready-to-Run Software, Inc.
>     Copyright 1997 Ready-to-Run Software, Inc. All Rights Reserved.

>     Assuming CDROM is mounted at /archive/cdrom/
>     Copied /archive/cdrom//SOURCES/QTERM/PART01.Z to part01.Z
>     Copied /archive/cdrom//SOURCES/QTERM/PART02.Z to part02.Z
>     Copied /archive/cdrom//SOURCES/QTERM/RS6000/QTERM to RS6000patch.qterm
>     Copied /archive/cdrom//SOURCES/QTERM/I386/QTERM to i386patch.qterm
>     Copied /archive/cdrom//SOURCES/QTERM/SUN4C/QTERM to sun4cpatch.qterm
>     Copied /archive/cdrom//SOURCES/QTERM/HP700/QTERM to hp700patch.qterm
>     Copied /archive/cdrom//SOURCES/QTERM/LINUX/QTERM to linuxpatch.qterm
>     Copied /archive/cdrom//SOURCES/QTERM/SSOL2/QTERM to SSol2patch.qterm
>     Copied /archive/cdrom//SOURCES/QTERM/RTR/QTERM to rtrpatch.qterm
>     9 file(s) copied successfully.

To extract the qterm sources, uncompress the "part" files and then use the unshar program to unpack them.

    ?
    % uncompress part0?.Z
    % unshar part0?
    unshar:  Sending header to part01.hdr.
    unshar:  Doing part01:
    If this archive is complete, you will see the following message:
              "shar: End of archive 1 (of 2)."
    shar: Extracting "README" (2200 characters)
    shar: Extracting "options.3" (7383 characters)
    shar: Extracting "options.c" (10901 characters)
    shar: Extracting "options.h" (2592 characters)
    shar: Extracting "qterm.c" (24777 characters)
    shar: End of archive 1 (of 2).

    You still must unpack the following archives:
             2
    unshar:  Sending header to part02.hdr.
    unshar:  Doing part02:
    If this archive is complete, you will see the following message:
              "shar: End of archive 2 (of 2)."
    shar: Extracting "Makefile" (1908 characters)
    shar: Extracting "qterm.1" (5805 characters)
    shar: Extracting "qterm.h" (3281 characters)
    shar: Extracting "qtermtab" (3311 characters)
    shar: End of archive 2 (of 2).
    You have unpacked both archives.

If you don't have shar and unshar, it's on the CD-ROM; but the true beauty of shar archives is that you can always remove any headers and footers from the file and use the Bourne shell (sh) to unpack the files.

To edit out the header, remove any lines at the top of the file that don't resemble Bourne shell syntax. Since many shar archives are distributed in email or in newsgroups, the files might include the header of a mail message or news posting. The author might also precede the actual shar archive with some explanation of what the program does. A good bet is to look for a line reading `#!/bin/sh` and remove all lines preceding it. Even better, most shell archives contain directions right in the file:

>     (text .... )

>     #! /bin/sh
>     # This is a shell archive.  Remove anything before this line,
>     # then feed it into a shell via "sh file" or similar.
>     # To overwrite existing files, type "sh file -c".

To remove the footer, look for anything resembling a user's mail signature. (shar archives usually have an exit message at the end, so editing out the footer isn't always needed ... but it doesn't hurt.)

After editing out the header and footer, just run the files through sh individually:

>     % vi part0?
>        edit out headers
>     % sh part01; sh part02
>        ...

Note that it's especially important to install and unpack shar archives in discrete, well-named directories (such as qterm_src, in this case). Since shar files are almost always given generic names of part01, part02, etc., it's easy to overwrite files or to get confused if you accidentally unpack more than one package in the same directory.

#### 52.8.2.5 Applying Patches

When I copied the pcal sources using the source.pt shell script, I also got two patch files (33.9): rtrpatch.pcal and RS6000patch.pcal. These are patches prepared by Ready-to-Run Software for compiling the pcal package.

The RS6000patch.pcal file is a patch for compilng on IBM's RS6000 platform. If you aren't on a RS6000, then you probably don't need this file. When building other packages, you might see other platform-specific patch files, with prefixes like i386, xenix, hp700, sun3, sun4, etc. Naturally, you shouldn't use these packages if you aren't on one of these platforms.

The rtrpatch.pcal file is a general-purpose patch for all platforms. You should apply this patch for all platforms.

Before you apply any of Ready-to-Run's patches, you should first make sure that there aren't any patch files in the untarred source directory. If the sources did come with patch files, they would have to be applied before Ready-to-Run's. In the pcal-4.3 directory, list the directory contents:

>     % ls -aF
>     ./              Makefile.VMS    calendar        pcal.man        protos.h
>     ../             Orig.ReadMe     exprpars.c      pcaldefs.h      readfile.c
>     Descrip.mms     Pcal.TEX        moon91          pcalglob.h      troffman.sty
>     Make_Pcal.com   Pcal.hlp        moon92          pcalinit.c      writefil.c
>     Makefile        ReadMe          moonphas.c      pcalinit.ps
>     Makefile.Amiga  SetUp.com       noprotos.h      pcallang.h
>     Makefile.DOS    VaxCrtl.opt     pcal.c          pcalutil.c

A patch file generally has the string patch or pch in it. There are no patch files in this directory. Now that I'm sure that there aren't any other patches, I run the patch command. (Naturally, if you don't already have patch, you can get its sources off the CD-ROM.) To run patch, make sure you're in the source directory (in this case, the pcal-4.3 subdirectory created when I ran tar). Then run patch, taking input from the patch file in the parent directory:

    < ../
    % patch < ../rtrpatch.pcal
    Hmm...  Looks like a new-style context diff to me...
    The text leading up to this was:
    --------------------------------
    |*** Makefile.orig      Tue Dec 17 05:34:19 1991
    |-- Makefile   Mon Nov 23 05:59:49 1992
    --------------------------------
    Patching file Makefile using Plan A...
    Hunk #1 succeeded at 5.
    Hunk #2 succeeded at 46.
    done

The patch is now applied.

#### 52.8.2.6 An Easy Build

Up to now, all we've been doing is just getting the source tree together. Now we're up to the part where we actually build the package.

First of all, if there's any universal rule about compiling sources, it's:

> If there's a file called README, read it!

README files often contain esoteric details about the history of the program and what improvements could be made, etc. But they might also contain details about how to build the package. Reading a README can save you hours of frustration trying to figure out what to tweak to make the program build on your platform.

Another file to look for is one called Configure. Configure is a shell script that tries to figure out what sort of platform you're on and how to build the package for you, and it's remarkably effective. The sources for perl and patch both come with Configure scripts.

pcal doesn't come with a README or with a Configure script. But it does come with a file called Makefile. (Actually, it comes with several Makefiles, for different platforms - but the default Makefile is the one for UNIX systems, which is what you want.) The Makefile is used by the make program (28.13). There have been entire books written about make, but if you're lucky, all you need to know about it is that if you see a Makefile, then all you need to compile a program is to type make.

First, though, scan through the Makefile to see if there are any comments there. You might have to make some changes in the Makefile to configure it for your system. For example, the qterm Makefile has the following very helpful lines:

>     #
>     # Add "-DUSG5" to DEFS below, if your system is UNIX System V.
>     # Add "-DHAS_VARARGS" if your system supports varargs.
>     # Add "-DOPT_COMPAT" to support old command line options.
>     #
>     DEFS    = -DTABFILE=\"$(TABFILE)\" -DOPT_COMPAT

You probably know whether your system is System V-based or not. If you never used this program before, you probably don't care about old command line options. And if you don't know what varargs are or whether your system supports it ... try seeing if there's a manpage (50.1) for it. (You might even find out what it is!)

>     % man varargs

>     VARARGS(3)             C LIBRARY FUNCTIONS             VARARGS(3)

>     NAME
>          varargs - handle variable argument list

>     SYNOPSIS
>          #include <varargs.h>
>        ...

What do you know, I have varargs. So I add the `-DHAS_VARARGS` command-line option to the `DEFS=` line:

>     DEFS    = -DTABFILE=\"$(TABFILE)\" -DOPT_COMPAT -DHAS_VARARGS

The pcal Makefile, on the other hand, only includes a single line of instruction towards the top:

>     # Set the configuration variables below to taste.

This isn't particularly helpful, but scan the Makefile anyway for anything obviously wrong. When you're satisfied, just cross your fingers and run make:

>     % make
>     /bin/cc   -c pcal.c
>     /bin/cc   -c exprpars.c
>     /bin/cc   -c moonphas.c
>     /bin/cc   -c pcalutil.c
>     /bin/cc   -c readfile.c
>     /bin/cc    -o pcalinit pcalinit.c
>     pcalinit pcalinit.ps pcalinit.h
>     /bin/cc   -c writefil.c
>     /bin/cc  -o pcal pcal.o exprpars.o moonphas.o pcalutil.o readfile.o
>     writefil.o -lm

There were no error or warning messages, so you're fine. Errors mean that the program package probably didn't build completely; you'll have to find the cause and fix them. If there were warnings, the programs may not work right or have a subtle flaw. For a program like a spreadsheet, where hidden flaws can be a disaster, you'd better find out what the warnings mean and fix them. Otherwise, just cross your fingers some more and see if the program works.

When you list the pcal source directory now, you should see several new files with a .o suffix, but the most important thing is that the pcal executable is now built and ready to be installed on your system.

>     % ls -aF
>     ./              Orig.ReadMe     moon91          pcaldefs.h      protos.h
>     ../             Pcal.TEX        moon92          pcalglob.h      readfile.c
>     Descrip.mms     Pcal.hlp        moonphas.c      pcalinit*       readfile.o
>     Make_Pcal.com   ReadMe          moonphas.o      pcalinit.c      troffman.sty
>     Makefile        SetUp.com       noprotos.h      pcalinit.h      writefil.c
>     Makefile.Amiga  VaxCrtl.opt     pcal*           pcalinit.ps     writefil.o
>     Makefile.DOS    calendar        pcal.c          pcallang.h
>     Makefile.VMS    exprpars.c      pcal.man        pcalutil.c
>     Makefile.orig   exprpars.o      pcal.o          pcalutil.o

You can now try out the program, and once you're sure it works, install it. To install the program, many Makefiles provide an install target.

>     % make install

On many machines, you'll need to be logged in as root to be able to install the binary and manpage system-wide. If so, it might be a good idea to run make with the -n option first. The -n option says to just show what commands would be executed without actually executing them.

>     % make -n install

Or if you prefer to just install the program by hand, just move the executable and the manpage to the right directories (be sure to rename the manpage as appropriate):

>     % mv pcal /usr/local/bin
>     % mv pcal.man /usr/local/man/man1/pcal.1

Note, however, that some programs may have extra steps in installing the executable. If all this worked as advertised, you can bail out now. Otherwise, you might need to know more about what goes on behind the scenes before you can figure out what went wrong.

#### 52.8.2.7 Functions, Libraries, and Header Files

To understand the compilation process, it helps to understand a little about libraries and header files.

C programs are written almost entirely using functions. Article 15.3 shows an example of a function defined in the Bourne shell programming language. C language functions are basically the same idea: group together a series of commands, give them a name, and then you can execute those commands using that name whenever you want and as many times as you want. Functions are also sometimes referred to as subroutines, library functions, or just routines.

Now, you can define C functions in the same source file. But the operating system also provides a vast collection of function definitions - which is very nice, because otherwise you'd be building every program from scratch. The function definitions are kept in libraries, which are generally installed on your system in /usr/lib/ with a lib prefix and a .a suffix (for example, /usr/lib/libc.a).

Functions also have to be declared in the program. Function declarations are kept in header or include files, which are generally installed on your system in /usr/include/ with .h suffixes (for example, /usr/include/stdio.h).

If you use functions that are defined in libraries (and you most definitely will), you need to make sure that when the program is compiled, it is linked to the libraries it needs. You also have to make sure that the proper header files are read by your program, since the program won't compile unless all functions have been declared.

For example, if you need to take the square root of a number in your program, you need to use the sqrt() function. This function resides in the Math library. This means that you need to link the program with libm.a and you need to read in the math.h header file (which declares sqrt()). So in the program, you need to have the following line near the top of the source file:

>     #include <math.h>

and when you compile the program, you need to use the -l (lowercase L) command-line option to link with libm:

>     % cc -o file file.c -lm

Note the following facts:

- Unless you name the executable file with `-o` `file`, cc will name it a.out.

- The source filename must end with a .c suffix.

- Since math.h lives in /usr/include, you don't need to give its absolute pathname on the `#include` line, just put the name of the header file between angle brackets as shown. Relative pathnames (14.2) starting at /usr/include can be used in angle brackets. For instance, `<sys/foo.h>` means /usr/include/sys/foo.h.

  By default, cc looks for header files in /usr/include, and you can have it look automatically in other directories by specifying them with the -I command-line option. If you want to use a header file in directory that isn't searched by default, supply its absolute or relative pathname in double quotes instead.

- When linking with a library on the command line, you should put the -l options at the end. If you use more than one library, you'll need more than one -l option. The order of the -l options is important; check the documentation or look for a comment in the source code.

- The compiler found libm.a because it was in /usr/lib, which it searches by default. If you want it to use a library in another directory, you may need to supply the directory using the -L command-line option.

As you can imagine, there's much more to know. But that's the general idea of compiling C programs on UNIX systems, and it's about as much as we can tell you without starting to teach you C.

#### 52.8.2.8 The make Program

When you're writing a simple C program, you can simply compile the program using cc:

>     % cc test.c

But more complicated programs (like many of the programs on the CD-ROM) require a bit more work. More complicated programs are easier to handle if you write them in modules. So, for example, the pcal source tree on the CD-ROM contains several .c files: exprpars.c, moonphas.c, pcalinit.c, pcalutil.c, readfile.c, writefil.c, and, of course, pcal.c. Each of these source files needs to be compiled separately into object files (with .o suffixes). If you give the -c option, cc will compile ".c files" into ".o files" and stop without making the finished executable. When you run cc again - but give it the .o filenames (exprpars.o, moonphas.o, and so on) it will link all those object files with the libraries and make the executable file.

This makes compilation a bit harder to keep track of. There are a lot more steps. Furthermore, it means that whenever a file is changed, you have to remember not only to recompile it but also to relink the entire program.

This is a job for the make program. We showed uses for make in articles 21.9 and 28.13, but this is what it was really meant for. The pcal source tree comes with a file called Makefile. (Actually, it comes with several different Makefiles for different platforms, but that's another issue.) The Makefile keeps track of each of the programs and each of their dependencies. It also keeps track of any command-line options you might want passed to cc, including libraries to link to. The result is that when you want to make the pcal program, all you need to do is type:

>     % make pcal

Or, even better, just:

>     % make

This is a lot easier than trying to keep track of all the modules and command-line options yourself.

So if you can't compile a program because the header file it needs is installed in a non-standard place, you'd specify that in the Makefile. You could add the appropriate -I option to the `COPTS` declaration line:

>     COPTS    = -I/usr/include/sys

Or if you want to use a different compiler than cc, you could redefine that variable:

>     CC       = /usr/local/bin/gcc

Again, this is only the tip of the iceberg. But a basic understanding of libraries, header files, and make has helped me build many programs that wouldn't compile the first time. For help with make, see O'Reilly & Associates' Managing Projects with make by Andrew Oram and Steve Talbott.

- LM, EP

52.7 Other Ways to Get the Software |  | 52.9 Software Support from RTR