Building Projects With Imake

Here's an explanation of how Imake works and how you can use it to build your executables—an article for programmers with C and Unix programming skills.
The Files

There are various files involved in the Imake build system; most reside in the Imake configuration directory. Though only one file, Imakefile, is really important to simple uses of Imake, these descriptions are included as a sort of a road map to more in-depth understanding of how Imake works.

  • Imakefile is the file used to generate a Makefile. This file contains your project specific information.

  • Makefile is the final output file. There are many references to help you understand the contents of the Makefile. The easiest to obtain is probably the GNU Info pages on GNU make, which come with the GNU make distribution. See the References section for specifics on information available about make.

  • Imake.tmpl is a generic template used to fill in information not provided by the Imakefile. Most template files are created for large projects that need to customize Imake beyond what is possible through the Imakefile. (The FVWM source as an example.)

  • Imake.rules and other .rules files hold the C preprocessor “defines” that make up the bulk of the Imake rules. Things like SimpleProgramTarget() and DependTarget() are defined in this file.

  • .cf files contain system specific configuration information. is the file that “chooses” the proper platform-specific .cf file.

Putting Imake to Work

Once you've written a basic Imakefile, it's time to put Imake to work. Fortunately, the difficult part is over. Just type the following two commands:

xmkmf -a

If you've written your Imakefile properly, your project will build with no problems.

xmkmf is a Bourne shell script that wraps up the imake command. It calls imake with convenient default arguments and does some cleanup, such as copying the old Makefile to Makefile.bak. This program generates the Makefile from your Imakefile.

imake is a program that you almost never need to run by hand. It's the program that handles the brunt of running the C preprocessor, as well as some minor tweaking (i.e., XCOMM comments) for compatibility with make.

Without any arguments, xmkmf just saves the old Makefile and runs imake to generate a new Makefile from the Imakefile. If you give xmkmf the -a switch, it runs the following commands in the given order:

make Makefile
make includes
make depend

See the xmkmf(1) man pages for more details on xmkmf capabilities.

The Targets

Below is a list of the common make targets contained in an Imake generated Makefile. Precisely which targets end up in your Makefile depend on which rules you used in your Imakefile, of course. A given target always does the same thing regardless of the project. (That is, it will if the Imakefile has been written properly.) In fact, these targets are standard beyond Imake. For example, the GNU Coding Standards specify much the same targets.

  • all: Build the whole project. Usually the default target. This is the target to which the AllTarget() rule adds a dependency.

  • clean: Remove buildable files and backup files. Includes all object files, executables, backup Makefiles and files commonly used by editors as backup files (*~).

  • Makefiles: regenerates all the Makefiles using Imake.

  • depend: generates the dependences between source (*.c) and header (*.h) files and ensures that all object files that need recompiling are rebuilt.

  • tags: builds the tags database used by vi and Emacs. The tags database is simply a list of C-language symbols and their location in the source. It allows for quickly and automatically locating function definitions and other such objects. See the man pages for etags(1), ctags(1), vi(1) and the Info documentation that comes with Emacs.

  • install: installs the final binaries into the main file system. Defaults to a directory under /usr/X11R6/ depending on each type of component. For example, executables go in /bin; man pages go into the proper section directory under /man.

  • lint: This target isn't particularly useful on Linux systems, since there isn't a commonly used lint program. lint is a program that checks C code for common style problems and other non-syntactic mistakes. The GNU compiler has moved much of the functionality of lint into the compiler, compile your code with the -Wall flag set and you'll have most of lint's functionality. With a lint program installed on the system, you can use this make target to run lint on all the source files of the project.