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).
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.
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.
Different shells have slightly different syntaxes. For example, the script above, executed using /bin/bash
, is shown below.
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
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 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.
Here is an example of a makefile that builds a simple Java project. An explanation of how this file works is given below.
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.
The first line of a rule is called a dependency line. It tells the make
utility when to rebuild a target. For example:
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.
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:
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:
To improve the maintainability of our makefiles, we can define macros. For example:
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:
$<
is a predifined macro that indicates the first of the explicit sources. Here $<
is substituted with Example.java
.
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:
Tarballs provide an easy way to backup, restore, and transfer a directory structure.
“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
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.