[ This document consists of the text of Appendix B of Software
Portability with imake, by Paul DuBois. Copyright (c) 1996
O'Reilly and Associates, Inc. All rights reserved. Permission
is granted to copy this document for personal use only. This copyright
notice must be retained in all copies. ]
This appendix describes how to build and install imake
and related configuration software if you do not already have
it on your machine. The software (referred to here as "the
distribution") is available as itools.tar.gz or itools.tar.Z
from the archive sites listed in Appendix A, Obtaining Configuration
Software.
The essential programs you will need for working your way through
this book are:
Some of these may be new to you, particularly if you are looking
at this appendix without reading the rest of the book first. imake,
of course, is discussed throughout the book. xmkmf, makedepend,
and mkdirhier are discussed in Chapter 2, A Tour of
imake. imboot is discussed in Chapter 10, Coordinating
Sets of Configuration Files, and Chapter 15, Designing
Extensible Configuration Files.
The distribution also includes the X11 configuration files and
some miscellaneous programs like msub and imdent.
Most of the distribution is based on the current release of X11
(X11R6.1, public patch 1 at the time of writing), but some programs
are not part of the standard X11 distribution, e.g., imboot,
msub, and imdent.
% cd itoolsThe distribution root directory contains an include subdirectory in which some header files needed to compile imake and makedepend are located. The itools directory also contains a config subdirectory under which the rest of the configuration software is located. config is divided into the following subdirectories:
To find programs, use the which command. It will tell you
either where a program is located, or, if it couldn't find it,
which directories it looked in (usually the directories named
in your PATH variable). In the following example, which
tells you that imake is installed in /usr/local/bin:
% which imake /usr/local/bin/imakeOn the other hand, if which can't find imake, you'll get a result like this:
% which imake no imake in . /usr/local/bin /usr/bin/X11 /usr/ucb /bin /usr/binIf you don't have which, you can use either of the scripts which.sh or which.csh supplied in the util directory. If which doesn't find imake, try looking in /usr/local/bin, /usr/bin, /usr/bin/X11, or in any /usr/X11Rn/bin directory you may have. You can also look in /var/X11Rn/bin, /opt/X11Rn/bin, or /local/X11Rn/bin. If you have OpenWindows, look for /usr/ openwin/bin.
In many instances, if you discover that a program included in
the distribution is already installed, you don't need to install
it. However, you should make exceptions when you have out-of-date
or broken versions of programs:
| /usr/X11R6.1/bin | Location of programs |
| /usr/X11R6.1/lib/X11/config | Location of the X11 configuration files |
| /usr/local/lib/config | Location of the imboot configuration root directory |
Suppose you want to install programs in /usr/local/bin
and the X11 configuration files in /var/X11R6.1/lib/X11/config,
and that you want to use /var/lib/config for the imboot
configuration root. Make the changes as follows:
#ifndef BinDir #define BinDir /usr/local/bin #endif
#ifndef ConfigDir #define ConfigDir /var/X11R6.1/lib/X11/config #endif
CONFIGROOTDIR = /usr/local/lib/configChange it to this:
CONFIGROOTDIR = /var/lib/config
| /u/you/bin | Location of programs |
| /u/you/lib/config/X11R6.1 | Location of the X11 configuration files |
| /u/you/lib/config | Location of the imboot configuration root directory |
Change into the config/cf directory and look around; you'll
see the configuration files listed below:
% cd config/cf % ls Amoeba.cf Server.tmpl hp.cf necLib.rules site.def DGUX.cf Threads.tmpl hpLib.rules necLib.tmpl site.sample FreeBSD.cf Win32.cf hpLib.tmpl noop.rules sony.cf Imake.cf Win32.rules ibm.cf oldlib.rules sun.cf Imake.rules WinLib.tmpl ibmLib.rules osf1.cf sunLib.rules Imake.tmpl apollo.cf ibmLib.tmpl osfLib.rules sunLib.tmpl Imakefile bsd.cf linux.cf osfLib.tmpl sv4Lib.rules Library.tmpl bsdLib.rules lnxLib.rules pegasus.cf sv4Lib.tmpl Makefile bsdLib.tmpl lnxLib.tmpl sco.cf svr4.cf Mips.cf bsdi.cf luna.cf scoLib.rules ultrix.cf NetBSD.cf convex.cf macII.cf sequent.cf usl.cf Oki.cf cray.cf moto.cf sgi.cf x386.cf Project.tmpl fujitsu.cf ncr.cf sgiLib.rules xf86.rules README generic.cf nec.cf sgiLib.tmpl xfree86.cfFind a vendor-specific configuration file that applies to your machine. This will be one of the files named with a .cf suffix. For Sun machines, use sun.cf, for Silicon Graphics machines, use sgi.cf, etc. If you find no vendor file for your system, you may need to write one using the detailed instructions. (First look in the config/misc directory, though. It contains instructions for some systems that aren't supported in the standard X11 distribution.)
Find the definitions of OSMajorVersion, OSMinorVersion,
and OSTeenyVersion in your vendor file. They represent
the major, minor, and subminor release numbers for your operating
system. Check that they are correct, and change them if they are
not. Suppose linux.cf specifies Linux 1.2.11:
#ifndef OSMajorVersion #define OSMajorVersion 1 #endif #ifndef OSMinorVersion #define OSMinorVersion 2 #endif #ifndef OSTeenyVersion #define OSTeenyVersion 11 #endifIf you're running Linux 1.2.8, the major and minor numbers are correct, but you must change the subminor number to 8:
#ifndef OSTeenyVersion #define OSTeenyVersion 8 #endifIf your OS release is defined only by major and minor numbers, your vendor file may not contain any definition for OSTeenyVersion.
Look over site.def to see whether you want to change anything.
In particular, to use gcc (version 2.x.x) as your C compiler,
define HasGcc2 as YES by uncommenting the #define
that is already there.
The distribution should build on many systems at this point. In
the distribution root (the itools directory) execute the
following command:
% make World >& world.logThe command just shown uses csh redirection. If you are using a shell from the Bourne shell family (sh, ksh, bash), use this command instead:
$ make World > world.log 2>&1For Windows NT, use this command:
nmake World.Win32 > world.logWhen the command terminates, look through world.log to see whether or not the World operation completed without error. If everything looks okay, go to the next section, "Installing the Software." Otherwise you may need to specify BOOTSTRAPCFLAGS. Look in Table B-1 and find the bootstrap flags for your system. If the value is varies, several values are possible and you must examine the vendor file and figure out which value is appropriate for your machine. If your system is not listed, the distribution hasn't been ported to it and you need to use the detailed instructions.
| Vendor File | Bootstrap Flags | Remark |
| Amoeba.cf | -DAMOEBA -DCROSS_i80386 -DCROSS_COMPILE | For i80386 architecture |
| -DAMOEBA -DCROSS_mc68000 -DCROSS_COMPILE | For Sun 3 architecture | |
| -DAMOEBA -DCROSS_sparc -DCROSS_COMPILE | For SPARC architecture | |
| DGUX.cf | -DDGUX | |
| FreeBSD.cf | -D__FreeBSD__ | |
| Mips.cf | -DMips | |
| NetBSD.cf | -D__NetBSD__ | |
| Oki.cf | -DOki | |
| Win32.cf | -DWIN32 | |
| apollo.cf | -Dapollo | |
| bsd.cf | -DNOSTDHDRS | |
| bsdi.cf | -D__bsdi__ | |
| convex.cf | -D__convex__ -tm c1 | |
| cray.cf | -DCRAY | possibly -D_CRAY? |
| fujitsu.cf | -D__uxp__ | For SPARC architecture |
| -D__sxg__ | For mc68000 architecture | |
| hp.cf | -Dhpux | |
| ibm.cf | varies | Will include -Dibm |
| linux.cf | -Dlinux | |
| luna.cf | -Dluna | |
| macII.cf | -DmacII | |
| moto.cf | -DMOTOROLA -DSVR4 | If SVR4 conformant |
| -DMOTOROLA -DSYSV | If not SVR4 conformant | |
| ncr.cf | -DNCR | |
| nec.cf | -DNEC | |
| osf1.cf | -D__osf__ | |
| pegasus.cf | -DM4310 -DUTEK | |
| sco.cf | none | |
| sequent.cf | -Dsequent | For Dynix 3 |
| -D_SEQUENT_ | For Dynix Ptx | |
| sgi.cf | -DSYSV | For IRIX 3.x, 4.x |
| -DSVR4 | For IRIX 5.x and up | |
| sony.cf | -Dsony | |
| sun.cf | -Dsun -DNOSTDHDRS | For SunOS before 4.1 |
| -Dsun | For SunOS 4.1 up to 5.0 | |
| -Dsun -DSVR4 | For SunOS 5.0 and up | |
| svr4.cf | -DSVR4 -Di386 | For i386 architecture |
| -DSVR4 | For non-i386 architecture | |
| ultrix.cf | -Dultrix | |
| usl.cf | -DUSL | |
| x386.cf | varies | Will include -DSYSV386 |
In the distribution root, execute the following command, replacing
flags with the appropriate bootstrap flags for
your system:
% make World BOOTSTRAPCFLAGS="flags" >& world.logExamples:
% make World BOOTSTRAPCFLAGS="-Dsun -DSVR4" >& world.log % make World BOOTSTRAPCFLAGS="-Dhpux" >& world.logWhen the command terminates, look through world.log to see whether or not the World operation completed without error. If it failed, use the detailed instructions. Otherwise, go ahead and install the software.
% make installOtherwise, change into individual directories under the config directory and install only those files in which you are interested. The instructions below show how to do this; leave out the parts for the files you don't want to install.
% make install.cffiles
% make install.imakeDo not install ccimake; it is only needed for compiling imake.
% make install.makedependIf you did not build the compiled version, the script version will be installed from the util directory.
% make install.xmkmf % make install.mkdirhierIf you have a System V version of install instead of a BSD-compatible one, the distribution contains two scripts bsdinst and install.sh that you can use instead. Some systems use one, others use the other. You can tell which one to install by watching what commands make has been executing as you've been installing the software above:
% make install.bsdinst (or) % make install.install.shIf you built the script version of makedepend, install it:
% make install.makedepend
% make install.imboot % make install.msub % make install.imdent
If you're porting imake to a system on which it's not currently
supported, use one of the following locators to see if there's
any information for your type of system:
http://www.primate.wisc.edu/software/imake-stuff/OS ftp://ftp.primate.wisc.edu/software/imake-stuff/OSIf you're not running UNIX, you should also read Chapter 18, Using imake on Non-UNIX Systems.
When imake runs, it invokes cpp to process the configuration
files. Default values for most configuration parameters are defined
in Imake.tmpl, Project.tmpl, etc. Also included
among the configuration files are many vendor files, each of which
contains parameter values that override any defaults that are
inappropriate for a particular vendor's systems. Since there are
several different vendor files from which to choose, cpp
has to figure out which is the right one for the machine you are
actually using. cpp does this by checking various symbols
known to identify different types of systems. The one that is
defined determines the current system type.
The symbol that identifies your system can come from a couple
of sources. Some vendors ship a cpp that predefines a symbol
unique to that vendor's systems. For instance, on Ultrix, cpp
predefines ultrix, which makes it easy to ascertain the
system type:
#ifdef ultrix
/* it's Ultrix, all right... */
#endif
Unfortunately, some vendor-supplied symbols aren't useful for
system identification because they are ambiguous (or have become
so). For instance, at one time (in the days of X11R3) the mips
symbol unambiguously indicated a true Mips Computers, Inc. machine,
but the symbol later became ambiguous when several other OS's
written to run on Mips processors also defined mips (Ultrix,
NEWS OS, IRIX, etc.). In the absence of a unique predefined vendor
symbol, it is necessary to make up an identifier symbol and to
tell imake to define it when starting up cpp. Thus,
to signify true Mips machines, the "artificial" symbol
Mips is now used.
It might even be that your preprocessor predefines no useful system-indicating
symbols at all. ANSI C takes a dim view of most predefined symbols,
so ANSI cpps tend to provide few symbols that can be used
to determine the system type. Here, too, you invent an identifier
symbol and make sure imake defines it so cpp can
determine which vendor file to use.
Thus, to port imake to your machine, you must satisfy three
requirements:
#ifdef linux # define MacroIncludeFile <linux.cf> # define MacroFile linux.cf # undef linux # define LinuxArchitecture # define i386Architecture # undef i386 #endif /* linux */The SunOS block is more complex:
#ifdef sun # define MacroIncludeFile <sun.cf> # define MacroFile sun.cf # ifdef SVR4 # undef SVR4 # define SVR4Architecture # endif # ifdef sparc # undef sparc # define SparcArchitecture # endif # ifdef mc68000 # undef mc68000 # define Sun3Architecture # endif # ifdef i386 # undef i386 # define i386Architecture # endif # undef sun # define SunArchitecture #endif /* sun */The first line of each block tests the trigger symbol. If it is undefined, the block is skipped. Otherwise, the block does three things:
#ifdef brandxyz # define MacroIncludeFile <brandxyz.cf> # define MacroFile brandxyz.cf # undef brandxyz # define BrandXYZArchitecture #endifAfter you write the vendor block, document the trigger symbol that identifies your system type by putting a definition for BootstrapCFlags in your vendor file. The following line goes in brandxyz.cf:
#define BootstrapCFlags -Dbrandxyz
There are a few symbols you must define in the vendor file:
#ifndef OSMajorVersion #define OSMajorVersion 3 #endif #ifndef OSMinorVersion #define OSMinorVersion 4 #endif #ifndef OSTeenyVersion #define OSTeenyVersion 1 #endifThe OS numbers are used when you need to select parameter values that vary for different releases of the system. Define them even if you don't use them anywhere else in the vendor file, because Imakefile writers sometimes need to know the release numbers.
#define SystemV YESIf your system is based on System V Release 4, define SystemV4:
#define SystemV4 YESIf your system isn't based on System V, don't define either symbol.
To some extent, you find out which defaults to override by trial
and error: write a minimal vendor file containing only the symbols
described above, then try to build the distribution. If the build
fails because a parameter value is incorrect, put the correct
value in the vendor file and try again. However, you can minimize
trial and error by taking advantage of the experience of those
who've gone before you. Existing vendor files serve as a guide
to help you figure out what should go in your own vendor file
by giving you some idea of the parameters most likely to need
special treatment. If any existing files are for operating systems
that are similar to yours, your vendor file is likely to be similar
to those files.
You now have the vendor block and the vendor file written; all
you need is imake.
Makefile.ini builds imake in two steps because some
systems require special flags to ensure proper compilation of
all but the most trivial programs. imake isn't especially
complex, but it isn't trivial, either, so a small helper program
ccimake is compiled first. ccimake is designed to
be simple enough to compile with no special treatment, and it
figures out any extra flags needed to get imake to compile
without error on your platform. Those flags are added to the imake-building
command.
To build ccimake and imake, you'll run the following
make command (but don't run it yet; we won't be ready for
a few pages):
% make -f Makefile.ini BOOTSTRAPCFLAGS="flags" cc -o ccimake -O -I../../include ccimake.c cc -c -O -I../../include './ccimake' imake.c cc -o imake imake.oThe trigger is specified in the value of BOOTSTRAPCFLAGS. For existing ports, determine flags from Table B-1. For new ports, use -Dtrigger (e.g., -Dbrandxyz for Brand XYZ systems).* [[footnote: If your cpp predefines the trigger, BOOTSTRAPCFLAGS can be empty:
% make -f Makefile.ini BOOTSTRAPCFLAGS=""However, it doesn't hurt to specify the trigger explicitly. ]]
Makefile.ini incorporates the value of BOOTSTRAPCFLAGS
into CFLAGS and generates the three commands just shown.
The first compiles ccimake. The second invokes ccimake
and includes the result in the arguments passed to the command
that compiles imake.o. The third produces the imake
executable.
The trigger symbol passed in through BOOTSTRAPCFLAGS
is used to determine the platform type, but in different ways
for each program. The key to understanding trigger use is imakemdep.h
in the config/imake directory. This header file is included
by the source for ccimake and imake and has one
part for each. (It is also used by makedepend and has a
third part for that program; we'll get to that shortly.)
The contents of imakemdep.h are organized like this:
#ifdef CCIMAKE
/* part 1 (for ccimake) */
#else
# ifndef MAKEDEPEND
/* part 2 (for imake) */
# else
/* part 3 (for makedepend) */
# endif
#endif
The source for ccimake defines CCIMAKE before
including imakemdep.h, so that part 1 is processed. makedepend
source defines MAKEDEPEND, so that part 3 is processed.
imake source doesn't define either symbol, so part 2 is
processed.
For a new port of imake, you must add the proper information
for your system to each part of imakemdep.h. For existing
ports you need to verify that the information already there is
correct, and fix it if it isn't. The following discussion shows
how to set up each part of imakemdep.h.
imakemdep.h--Part 1 (for ccimake)
The first part of imakemdep.h consists of a bunch of #ifdef/#endif
blocks. Each of them defines imake_ccflags as a string
containing the flags needed to get imake to compile on
a particular platform. The proper definition is selected according
to the trigger symbol that is defined when ccimake is compiled.
Some flags commonly specified in the definition of imake_ccflags
are -DSYSV (System V Release 2 or 3), -DSVR4
(System V Release 4), or -DUSG to indicate USG systems.
For instance, if Brand XYZ systems are based on System V Release
4, specify the following:
#ifdef brandxyz #define imake_ccflags "-DSVR4" #endifYou might need more than one flag (see the hpux block for a particularly unpleasant example). Note that all flags are specified in a single string.
If no special flags are necessary to compile imake, there
need not be any block for your system, and imake_ccflags
is given a default definition (currently -O).
If you don't know whether or not ccimake needs to produce
any special flags, experiment by trying to compile imake
by hand. Once you figure out how to do it, make your knowledge
explicit by defining imake_ccflags appropriately in imakemdep.h.
imakemdep.h--Part 2 (for imake)
The second part of imakemdep.h contains four sections.
Each of them poses a question:
#ifdef trigger
"-Dtrigger",
#endif
If trigger is defined when imake is compiled,
it causes a definition of itself to be passed to cpp when
imake executes. (If your cpp predefines the trigger,
you may not see an instance of this construction for your system,
but there is no harm in adding one explicitly.)
For Brand XYZ systems, add the following entry to cpp_argv[]:
#ifdef brandxyz
"-Dbrandxyz",
#endif
This causes imake to pass -Dbrandxyz to cpp,
allowing cpp to select the Brand XYZ vendor block as it
processes the configuration files.
If you need to pass more than one argument to cpp, add
the definitions for each argument as separate strings:
#ifdef brandxyz
"-Dbrandxyz",
"-DSVR4",
#endif
imakemdep.h--Part 3 (for makedepend)
The third part of imakemdep.h applies to the compiled version
of makedepend. (This has nothing to do with compiling imake,
but since we're talking about imakemdep.h, we might as
well cover it here.)
This part of imakemdep.h puts entries in the predefs[]
string array based on which of various system- and compiler-related
definitions are predefined by cpp. makedepend uses
this information to be smart about which header files to pay attention
to when it generates header file dependencies. Consider the following
C program fragment:
#ifdef ultrix #include "headera.h" #else #include "headerb.h" #endifmakedepend knows to generate a dependency for headera.h and not headerb.h if ultrix is defined, and the other way around if it is undefined; a dumb dependency generator has to assume dependencies on both files in either case.
For existing ports, you can leave this part of imakemdep.h
alone. For a new port, add symbols appropriate for your system
if they are not already listed among the predefs[] initializers.
First, find the lines that end the predefs[] initialization:
/* add any additional symbols before this line */
{NULL, NULL}
Then add new entries before those lines for any symbols predefined
by your cpp:
#ifdef sym1
{"sym1", "1"},
#endif
#ifdef sym2
{"sym2", "1"},
#endif
/* add any additional symbols before this line */
{NULL, NULL}
% make -f Makefile.ini clean rm -f ccimake imake.o imake rm -f *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a tags TAGS make.log \#*Then build ccimake and imake, substituting the bootstrap flags for your system into the following command:
% make -f Makefile.ini BOOTSTRAPCFLAGS="flags"For Brand XYZ, the command looks like this:
% make -f Makefile.ini BOOTSTRAPCFLAGS="-Dbrandxyz" making imake with BOOTSTRAPCFLAGS=-Dbrandxyz cc -o ccimake -Dbrandxyz -O -I../../include ccimake.c cc -c -Dbrandxyz -O -I../../include './ccimake' imake.c cc -o imake imake.oAfter you build imake, test whether it is configured correctly, using imake's -v option to tell it to echo the cpp command it executes. The normal input and output files are of no interest here, so we use -T/dev/null and -f/dev/null to provide an empty input template and target description file, and -s/dev/null to throw away the output:
% imake -v -T/dev/null -f/dev/null -s/dev/null cpp -I. -Uunix -Dbrandxyz Imakefile.cIf you see a definition for your trigger symbol in the cpp command echoed by imake (-Dbrandxyz in the example above), imake is properly configured. If you don't see the definition, imake should still be okay if cpp predefines the trigger. Use the following command to check whether that is so (assuming the preprocessor imake uses is /lib/cpp):
% echo "trigger" | /lib/cppIf the trigger doesn't appear in the output or turns into "1", cpp predefines it. If you see the trigger string literally in the output, cpp doesn't predefine it, and you need to reconfigure imake to pass -Dtrigger to cpp explicitly.
% make World BOOTSTRAPCFLAGS="flags" >& world.logThis will rebuild imake and also build the rest of the distribution. After it finishes, see the section "Installing the Software" for installation instructions.
If you can build imake but make World still
fails, try building the distribution in stages to get an idea
of where the problem lies. First, build the Makefiles from the
distribution root:
% ./config/imake/imake -I./config/cf % make MakefilesIf that works, try the following:
% make clean % make depend % makeIf make depend fails while trying to compile makedepend, skip it and try the step following it. You can go back later and try to figure out why makedepend doesn't build.
If you can't get any of this to work, read misc/Porting
to see if it contains any helpful advice.