CS248 Menu Buttons

UNIX Programming

"Chapter Eight - Development Tools"

Chapter Outline

Lecture Notes

Development Tools

Now we are going to look at some of the tools available for developing programs on UNIX systems.

Here are some of the tools discussed in this chapter.

The make Command and Makefiles

With small programs, of one or two source files and a header fiel, we just recompile the application after editing. For example:

.

Problems of Multiple Source Files

With larger programs, the time for the editi-compile-test cycle can start to grow.

The problem get even worse if there are multiple header files included in different source files.

We could easily have the situation shown below:

The Concept of make

The make command has a lot of built-in knowledge, that makes use of file we supply makefile) on how to construct the application.

The Syntax of Makefiles

A makefile consists of a set of dependencies and rules.

A dependency has a target (a file to be created) and a set of source files upon which it is dependent.

The rules describe how to create the target from the dependent files.

Options and Parameters to make

The make program itself has several options. The three most commonly used one:

Dependencies

The dependencies specify how each file in the final application relates to the source files.

For example, myapp: main.o 2.o 3.o, mean myapp is dependent on the files main.o 2.o and 3.o.

In a makefile, we write these rules by writing the name of the target, a colon, spaces or tabs and then a space or tab-separated list of files taht are used to create the target file.

If we wish ti make several files, we can use the phony target all.

Rules

Now to look at the rules describing how to create a target. If a file needs rebuilding, what command should be used?

It might be as simple as using gcc -c 2.c

Try It Out - A Simple Makefile

Most rules consist of a simple command that might have been typed on the command line.

For our example above, the makefile including the rules, Makefile1, becomes:

We invoke the make command with the -f option, since our makefile doesn't have either of the usual defualt names of makefile or Makefile.

Let's create our source files and try again. Since we're not actually interested in the result, these can be very simple.

The header files are actually empty, so we can create those with touch:

main.c contains main, which calls function_two and function_three.

It's not much of an appliction, but here are the listings:

LEt's try main again:

This is a successful make.

How It Works

The main command has processed the dependencies section of the makefile and determined the files that need to be created and in which order.

We can now test our makefile to see whether it handles changes to the file b.h correctly:

It does!

Let's check what happens if we delete an object file:

Again, make correctly determines the actions required.

Comments in a Makefile

A comment starts with a # and continues tothe end of the line.

Macros in a Makefile

Makefiles allow us to use macros, so we can write them in a more generalized form.

We define a macro in a makefile by writing MACRONAME=value, then accessing the value of MACRONAME by writing either $(MACRONAME) or {MARCRNAME}.

Normally, macros are defined inside the makefile itself, but they can be specified by calling make with the macro definintion, for example make CC=c89.

Try It Out - A Makefile with Macros

Here's an updated version of our makefile, Makefile2, using macros:

If we delete our old installation and create a new one with this new makefile, we get:

How It Works

The make command replaces the $(CC), $(CFLAGS) and $(INCLUDE) with the appropriate definitions, rather like the C compiler does with #define.

Multiple Targets

It's often useful to be able to make more than a single target file, or to collect several groups of commands into a single place.

We can extend our makefile to do this.

Try it Out - Multiple Targets

Le'ts add a 'clean' option that removes unwanted objects and in 'install' option that moves the applcation to an installed directory.

Here's the next version of the makefile, Makefile3:

You may not have permission as an 'ordinary' user to install new commands in /user/local/bin.

You can either change permissions on this directory or change user (with the su command) to root before invoking make install.

Test It Out

1. we remove myapp and all objects.
2. The make command uses the target all, which causes myapp to be built.
3. We run make again, and since everything is up to date, it does nothing.
4. We delete everything and do a make install.
5. Finally, we run make clean, which deletes the objects.

Built-in Rules and Suffix Rules

make has a large number of built-in rules which can significantly simplify makefiles.

Built-in Rules

Since many rules are always the same, make has a large number of built-in rules. LEt's create a file, foo.c--a traditional 'Hello World' program:

Without specifying a makefile, we'll try and compile it using make:

You can see, make knows how to invoke the compiler. Sometimes, these built-in rules are referred to as inference rules.

The default rules use macros, so by specifying some new values for the macros we can change the default behavior, such as which compiler is called.

We can ask make to print its rules by doing a make -p.

We can simplify our makefile to use the built-in rules and just give the dependencies.

Suffix Rules

The built-in rules work by using suffixes (similar to DOS).

make know to create a .o file from a .c file. It knows a file with .cpp is a C++ and not a C file.

Try It Out - Suffix Rules

Here's a fragment of our makefile with a new general rule for converting .cpp files to .o.

Here is a new file called Makefile5.

Let's try this new rule

How It Works

The special dependency .cc.o: tells make that the rules that follow are for translating from a file with a suffix of .cpp to a file with a suffix of .o.

Here's the list of special macros you may need.

Managing Libraries with make

Library files conventionally has an extension of .a.

The syntax is lib(file.o), which means the object file file.o, as stored in the library lib.a.

The make command has a built-in rule for managing libraries, which is usually something like this:

Try It Out - Managing a Library

Let's change our application so that the files 2.o and 3.o are kept in a library called mylib.a.

Here is our Makefile6:


Notice how we allow the default rules to do most of the work.

Let's test our new version of the makefile:

How It Works

We first delete all the objects and the library and allow make to build myapp, which it does by compiling and creating the library, before main.o with the library to create myapp.

It test dependencies and makes the proper updates and changes.

Advanced Topic: Makefiles and Subdirectories

With large projects, it's sometimes convenient to split some files that comprise a library away from the main files and store thme in a subdirectory.

You can have a second makefile in the subdirectory to compile the files, store them in a library and then copy the library up a level into the main directory.

Or you can use additional macros in a single makefile.

We compile the files in the subdirectory and leave themm there. We then make the library in the current directory with a dependency and rule something like this:

GNU make and gcc

If you're using GNU make and the GNU gcc compiler, there are a couple of interestinng extra options.

The -jN ('jobs') option allows make to execute N commands at the same time.

The -MM option to gcc produces a deoendency list in a form suitable for make.

Try It Out - gcc -MM

Here is the -MM command.

How It Works

The gcc compiler simply outputs the requird dependency lines in a format ready for insertion into a makefile.

Source Code Control

There are two widely used UNIX systems for managing source files: RCS (Revision Control System) and SCCS (source Code Control System).

RCS

The RCS system comprises a number of commands for managing sources files.

It works by tracking a source file as it's changed by maintaining a single file with a list of changes in sufficient detail to recreate any previous versions.

The rcs command

We'll start with an initial version of the file we wish to manage.

We'll use important.c, which starts life as a copy of foo.c with the following comments at the beginning.

The first task is to initialize RCS control over the file, using the rsc command.

The command rcs -i initializes the RCS control file.

After this command, rsc has creted a new read-only file with a ,v extension:

The ci Command

We can now check in our file, using th ci command to store the current version:

If we now look at the directory, we'll see that important.c has been deleted:

The file contents and control information are all stored in the RCS file, important.c,v.

The co Command

To change a file, we must first 'check out' the file. FOr read only, use the co command. For write permission, we must lock the file by using the co -l command.

LEt's lock out a copy of the file,

and look at the directory:

There's is now a file for us to edit, to put in our new changes.

We use the ci command to store the changes.

The output section of important.c is now:

We use ci like this:


We've now stored the revised version of the file.

If we look at the directory, we see the file importand.c has again been removed:

The rlog Command

It is often useful to look at a summary of changes to a file.

We can do this with the rlog command:

If we now decide that we want the first version of the file back, we can ask co for it by specifying the revision we require:


The rcsdiff Command

.If we just want to know what was changed between two revisions, we can use the rcsdiff command:

THis tells us that a single line was inserted after the original line 11.

Identifying Revisions

Two command macros of the RCS system are: $RCSfile$ and $Id$.

$RCSfile$ is expanded to the name of the file. $Id$ expands to a string identifying the revision.

Let's change our file for a third time and add some of these macros:

We edit the file and it now looks like this:

Let's check in this revision and see hiw RCS manages the special strings:

If we look in the directory, we find only the RCS file:

If we check out (with the co command) and examine the current version of the source file, we can see the macros tha thave been expanded:


Try It Out - GNU make with RCS

make already has some built-in rules for managing RCS files.

Let's delete the source file and see how make deals with the missing source file:

How It Works

make has a default rule that to make a file with no extension you can compile a file of the same name, bu twith a .c extension.

A second default rule allows make to crete important.c from important.c,v by using RCS.

The ident Command

We can use the ident command to find the version of a file that contains a $Id$ string.

Try It Out - ident

How It Works

By executing the program we show the string has been incorporated into the executables.

Then we show how the ident command can extract $Id$ strings from an executable file.

SCCS

SCCS offers very similar facilities to RCS.

The advantage of SCCS is that it's specified in X/Open, so all branded versions of UNIX should support it.

Comparing RCS and SCCS

Here is a table comparing RCS and SCCS.

Writing a Manual Page

If you write a new command, you should create a manual page to go with it.

The layout of most pages follows a closely set pattern, which is of the form:

You can leave out seections that aren't relevant.

Manual pages are formatted using nroff or groff.

Here's the source of a simpile manual page for our application:


The groff command commonly produces ASCII text(-Tascii) or PostScript (-Tps) output.

We tell groff its a manual page using the -man option, which causes special manual page macro edfinitions to be loaded.

This gives the output:


Distributing Software

The main problem with program distribution is ensuring that all files are included and are of exactly the right version.

Here is a set of methods for program distribution:

The patch Program

The patch command allows yu to distribute just the 'differences', so someone with version 1 of a file and a difference file for version 1 to version 2 can use the patch command to generate version 2 for themselves.

If we start with version 1 of a file,

and then produce version 2,

we can create a difference listing with the diff command:

The diffs file contains:

This is actually a set of editor commands for changing one file into another.

Suppose we have file1.c and the diffs file. We can update our file using patch:

The patch command has now changed file1.c to be the same as file2.c.

You can unpatch file back to file1.c using the patch -R command.


Other Distribution Utilities

Files are commonly distributed with extensions of .tar.gz or .tgz. These are gzip-ed TAR files.

Let's create a gzip-ed file of our application:

We now have a TAR file:

We can make this smaller using the compression program gzip:

A very impressive reduction in size. This .tar.gz may then be renamed to a simple .tgz extension:

To get our file back, we decompress and extract them from the tar file again:

With GNU's version of tar, things are even easier.

We can create the compressed archive in a single step:

And we can decompress it just as easily, like this:

tar Command Description

As you can see from our examples, the basic tar syntax is:

In this section, we've used combinations of six different options:


Summary

We have looked at a few of the tools for development and distribution of programs.

These include: make, patch, tar, and gzip.


CS 248 - UNIX Programming Web Site Menu
Information | Syllabus | Schedule | Online "Lectures" | Projects | Quizzes | Web Board



Copyright © 2001 by James L. Fuller, all rights reserved.