Shell, Makefiles, and Tarballs

In this tutorial, we will first demonstrate how to compile source code using shell scripts and makefiles. Then we will demonstrate how to create tarballs (.tar.gz or .tgz files).

  1. Contents
  2. 1. Interacting with the Shell
  3. 1.1. Shell Concepts
  4. 1.2. Shell Scripts
  5. 2. Makefiles
  6. 2.1. The UNIX Make Utility
  7. 2.2. Makefile Structure
  8. 2.2.1. Explicit Rules
  9. 2.2.2. Dependency Lines
  10. 2.2.3. Shell Lines
  11. 2.2.4. Macros
  12. 2.2.5. Inference Rules
  13. 3. Tarballs
  14. 3.1. Tape Archives
  15. 3.2. GNU Compression

Interacting with the Shell

Shell Concepts

A shell is a command language interpreter that executes commands read from the standard input device or from a file. A shell passes the commands to the system kernel, which executes the commands.

Even though GUIs are the most common method to interact with kernels in modern operating systems, shells provide certain advantages over GUIs, and as such, they are still widely used today.


Shell Scripts

A shell script is a text file that contains a sequence of commands. It performs tasks such as file manipulation, program execution, and text displaying. There are many types of shells, and at UHUNIX, /bin/csh is the default shell.

Here is simple an example that demonstrates how to build a java file using a cshell script.

#!/bin/csh # Define variables for the source and class files. set SRCFILE="Example.java" set CLASSFILE="Example.class" if ( -e $SRCFILE ) then if ( -e $CLASSFILE ) then rm $CLASSFILE echo "Cleaned old class file." endif javac -classpath .:External.jar $SRCFILE echo "Done." else echo "The install script could not locate the required source file." endif

Different shells have slightly different syntaxes. For example, the script above, executed using /bin/bash, is shown below.

#!/bin/bash # Define variables for the source and class files. SRCFILE="Example.java" CLASSFILE="Example.class" if [ -e $SRCFILE ] ; then if [ -e $CLASSFILE ] ; then rm $CLASSFILE echo "Cleaned old class file." fi javac -classpath .:External.jar $SRCFILE echo "Done." else echo "The install script could not locate the required source file." fi

The first line of a shell script indicates the path to the shell that the system should use to execute the script.

Typically, we give shell scripts permissions to execute. The following command allows the owner to read, write, and execute the file; it allows other users only to read and execute the file.

$ chmod 755 myscript.sh

With these access bits assigned, we can execute the script by entering the path to the script into the shell interpreter.

$ ./myscript.sh

Makefiles

The UNIX make utility was designed to provide a simple way to organize code compilation and avoid redundant recompilation. It automatically builds executable programs and libraries from source code by reading makefiles.


The UNIX Make Utility

The make program looks for a file named “makefile” or “Makefile” in the current working directory. It then parses this file to build target output, clean intermediate files, or even install programs on the file system. Arguments to the program generally indicate which action to perform. For example,

$ make clean
$ make all
$ make install

The -f option may be used if more than one makefiles exists in the current directory, the makefile is located elsewhere in a different directory, or the makefile is named something other than “makefile” or “Makefile”. For example,

$ make -f path/to/the/makefile

There are many other options to the make utility, and to learn more about these options, refer to the man page.


Makefile Structure

Here is an example of a makefile that builds a simple Java project. An explanation of how this file works is given below.

all: Homework.jar External.jar Homework.jar: One.class Two.class jar cvf Homework.jar One.class Two.class One.class: One.java Two.java External.jar javac -classpath .:External.jar One.java Two.java Two.class: clean: rm -f *.class Homework.jar

Explicit Rules

A makefile consists of a series of rules that specify when and how to build a target. In the following example, the target is Homework.jar, it depends on One.class and Two.class, and the shell statement to build the target is indented below.

Homework.jar: One.class Two.class jar cvf Homework.jar One.class Two.class

Dependency Lines

The first line of a rule is called a dependency line. It tells the make utility when to rebuild a target. For example:

Homework.jar: One.class Two.class

To the left of the colon is the target of the dependency. To the right of the colon are the sources needed to make the target. Basically, the dependency lines tell the make utility which targets depend on which sources.

make rebuilds the target only when the target’s timestamp shows an earlier time than the any of the timestamps of it sources. This process is recursive throughout the procedure of building makefiles.


Shell Lines

The indented lines that follow each dependency line are called shell lines. Shell lines tell the make utility how to build a target. It’s important to note that these lines must be indented using a TAB ('\t') character. For example:

jar cvf Homework.jar One.class Two.class

A target can have more than one shell line. For example, if we would like to see progress messages during the build process, we could write a message to standard output like the following:

Homework.jar: One.class Two.class @echo "Archiving..." jar cvf Homework.jar One.class Two.class

Macros

To improve the maintainability of our makefiles, we can define macros. For example:

JCC = javac JFLAGS = -classpath .:External.jar all: Homework.jar External.jar Homework.jar: One.class Two.class jar cvf Homework.jar One.class Two.class One.class: One.java Two.java External.jar $(JCC) $(JFLAGS) One.java Two.java Two.class: clean: rm -f *.class Homework.jar

Macros can also be defined on the command line. Command line macros have higher precedence than the same name macros defined in the makefile. For example:

$ make "JFLAGS=-Xlint:all -classpath .:External.jar"

We can also define run-time macros with values set dynamically. These macros return information about the current target being built. For example:

Example.class: Example.java javac $<

$< is a predifined macro that indicates the first of the explicit sources. Here $< is substituted with Example.java.


Inference Rules

Inference rules generalize the build process so we don’t have to define explicit rules for each target.

Inference rules are rules distinguished by the use of the character “%” in the dependency line. The “%” (rule character) is a wild card, matching zero or more characters. For example:

%.class:%.java javac $<

Tarballs

Tarballs provide an easy way to backup, restore, and transfer a directory structure.


Tape Archives

“tar” is both a program and a file format. The tar program was originally designed to backup and restore files to and from reels of tape. In modern times, the utility is primarly used to backup a directory structure, including subdirectories, into a single file and to restore that directory structure at a later time.

For example, the following command creates a file named myarchive.tar using the files and directories located in mydirectory:

$ tar -cvf myarchive.tar mydirectory
a mydirectory/ 0K
a mydirectory/file1.txt 4K
a mydirectory/file2.txt 8K
a mydirectory/subdir/ 0K
a mydirectory/subdir/file3.txt 40K

Then, to rebuild this directory structure using the myarchive.tar file, we would execute the following command:

$ tar -xvf myarchive.tar
x mydirectory, 0 bytes, 0 tape blocks
x mydirectory/file1.txt, 4081 bytes, 8 tape blocks
x mydirectory/file2.txt, 8162 bytes, 16 tape blocks
x mydirectory/subdir, 0 bytes, 0 tape blocks
x mydirectory/subdir/file3.txt, 40810 bytes, 80 tape blocks

GNU Compression

The UNIX gzip utility compresses single files, and it is commonly used to compress .tar files. For example, the following command compresses myarchive.tar.

$ gzip myarchive.tar

After executing this command, the file myarchive.tar is replaced with a much smaller file myarchive.tar.gz. To decompress this file into the original, we would execute the following:

$ gzip -d myarchive.tar.gz

The gunzip utility is usually distributed with gzip, and it accomplishes the same thing.

$ gunzip myarchive.tar.gz

In either case, after executing this command, the file myarchive.tar.gz is replaced with a larger file myarchive.tar, the same file we compressed earlier.

It is so common to use tar and gzip together that people often use the extension .tgz to indicate a tar-gzipped file, which is often called a tarball.

Valid HTML 4.01 Valid CSS