% Document type: LaTeX % % $Header: imake.tex,v 1.1 89/02/25 03:25:37 moraes Exp $ % % Copyright 1986, Mark Moraes % May be freely used for non-commercial purposes provided acknowledgement % to the source is given. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\documentstyle[fullpage,notes]{article} \documentstyle[fullpage]{article} %\documentstyle[dvidoc]{article} \title{An {\em Imake} tutorial} \author{Mark Moraes, Computer Systems Research Institute,\\ University of Toronto\\ moraes@csri.toronto.edu} \date {Revised \today} \begin{document} \maketitle {\em {\tt \$(TOP)} in the document refers to the top level directory of the X Windows source tree.} \section{Introduction} {\em Imake} is a tool for generating Makefiles \footnote{Familiarity with the {\em make} program and C preprocessor syntax is assumed in this document. Those unfamiliar with these are advised to read their system manuals for {\em make} and {\em cpp} and experiment with them} for large software distributions. {\em Imake} uses the C preprocessor on macro-makefiles (called {\em Imakefiles}) to generate Makefiles. It uses a predefined template file for default values and macros. The {\em imake} program is part of, and used by the X Windows System software distribution. (The following description uses fragments from the X Windows distribution as examples --- you might want to look at the files in {\tt \$(TOP)/config} for more detailed information. The source code for {\tt imake} is in {\tt \$(TOP)/util/imake}, and includes a {\tt sample.rules} file as well as a manual page) This document attempts to provide a working introduction to {\em imake}. In particular, it provides an annotated tour of some of the relevant files, and through some example {em Imakefiles}. For a more precise description of {\em imake}'s workings, see the manual page. \section{Why {\em Imake}} Makefiles have some limitations for large software distributions, distributed over multiple directories, viz. \begin{itemize} \item A single makefile doesn't handle multiple directories well, which means that each directory needs a makefile. At that point, to change a default value, for example the directory where the binaries are to be installed, you have to change all the makefiles. \item Typically, makefiles are used to achieve a limited set of actions, like create a binary from a set of object files, or generate a library from some object files, etc. These can be encapsulated in rules that are slightly more complex that the ones {\em make} supports (which are only suffix based) \item A production makefile which supports all the actions necessary for a development environment, can get fairly long --- typically, you want a {\em clean} target, an {\em install} target, a {\em depend} target, and an {\em all} target. \item For a system that is ported to many different systems, there are bound to be differences in the requirements of the systems, that cannot be dealt with solely at the C source level. For instance, some System V Unix \footnote{Unix is a trademark of AT\&T} machines provide a BSD compatibility library which must be linked in with {\tt -lbsd}, and BSD includes that must the C compiler must be told about with a {\tt -I/usr/include/bsd option}. Vanilla {\em make} allows no facilities for changes like this, and you end up having multiple makefiles, with suffixes to indicate the type of system being used. \end{itemize} \section{A simple example} For example, for a simple program, {\tt xcalc}, the Imakefile looks something like: \begin{quote} \begin{verbatim} LOCAL_LIBRARIES = $(XLIB) SYS_LIBRARIES = -lm #ifdef MacIIArchitecture DEFINES = -DIEEE #endif /* MacIIArchitecture */ SRCS = xcalc.c sr.c OBJS = xcalc.o sr.o ComplexProgramTarget(xcalc) \end{verbatim} \end{quote} This will generate a Makefile which will contain an {\tt all} target, and an {\tt xcalc} target, both of which will result in the program {\tt xcalc} being compiled and linked. The Makefile will also contain an {\tt install} target, which will install the binaries in specified destination directories, an {\tt install.man} target, which will install the manual pages for the program, a {\tt clean} target, which will remove all compiler generated files, editor backup files, etc., and a {\tt depend} target which will invoke the {\em makedepend} program to generate Makefile depenencies. It will also contain a {\tt Makefile} target, so you only need to type {\tt make Makefile} to regenerate the Makefile should the Imakefile change. The real work lies in {\tt ComplexProgramTarget}, which is defined in the template as a {\tt \#define} macro, which expands out to the make rules needed to generate program {\em xcalc}, from the variables {\tt SRCS} and {\tt OBJS}. Let's take a look at that particular rule. \begin{quote} \begin{verbatim} /* * This target is the general interface for building a single program */ #define ComplexProgramTarget(program) @@\ PROGRAM = program @@\ @@\ AllTarget(program) @@\ @@\ program: $(OBJS) $(LOCAL_LIBRARIES) @@\ $(RM) $@ @@\ $(CC) -o $@ $(OBJS) $(LOCAL_LIBRARIES) $(LDFLAGS) $(SYSLAST_LIBRARIES) @@\ @@\ relink:: @@\ $(RM) $(PROGRAM) @@\ $(MAKE) $(MFLAGS) $(PROGRAM) @@\ @@\ InstallProgram(program,$(BINDIR)) @@\ InstallManPage(program,$(MANDIR)) @@\ DependTarget() @@\ clean:: @@\ $(RM) $(PROGRAM) \end{verbatim} \end{quote} Ignoring {\tt AllTarget()} for now, we see that {\tt program} is defined to depend on the {\tt OBJS}, and {\tt LOCAL\_LIBRARIES}, and to make it, the old version is removed (a precaution to save disk space, among other things), and then, {\tt program} is linked from {\tt OBJS}, {\tt LOCAL\_LIBRARIES}, and {\tt SYSLAST\_LIBRARIES}. ({\tt LDFLAGS} are link flags) An additional target {\tt relink::} is also generated, which can be used if libraries change. {\tt InstallProgram} generates the the {\tt install::} target, which puts the program in {\tt BINDIR}, {\tt InstallManPage} installs the manual page, {\tt DependTarget} generates the target for {\em make depend} which invokes a {\em makedepend} program to follow all {\tt \#includes} in the source. These macros are listed below --- they aren't very complex. \begin{quote} \begin{verbatim} /* * Install a man page. */ #define InstallManPage(file,dest) @@\ InstallManPageLong(file,dest,file) /* * Install a program */ #define InstallProgram(program,dest) @@\ install:: program @@\ $(INSTALL) -c $(INSTALLFLAGS) program dest /* * This makes the depend target given OBJS. */ #define DependTarget() @@\ depend:: $(DEPEND) @@\ @@\ depend:: @@\ $(DEPEND) -s "# DO NOT DELETE" -- $(CFLAGS) -- $(SRCS) @@\ @@\ $(DEPEND): @@\ @echo "making $@"; \ @@\ cd $(DEPENDSRC); $(MAKE) @@\ #define AllTarget(depends) @@\ all:: depends \end{verbatim} \end{quote} Note the use of make variables like {\tt \$(INSTALL)} to describe programs that are used - this makes it possible to define these in the templates, and thus enhances portability. Also, note that the make targets use a conditional dependency branch with double colons (::) rather than the more common single colon (:). This allows multiple make targets. Based on all this, the Imakefile expands to the following Makefile: \begin{quote} \begin{verbatim} LOCAL_LIBRARIES = $(XLIB) SYS_LIBRARIES = -lm SRCS = xcalc.c sr.c OBJS = xcalc.o sr.o PROGRAM = xcalc all:: xcalc xcalc: $(OBJS) $(LOCAL_LIBRARIES) $(RM) $@ $(CC) -o $@ $(OBJS) $(LOCAL_LIBRARIES) $(LDFLAGS) $(SYSLAST_LIBRARIES) relink:: $(RM) $(PROGRAM) $(MAKE) $(MFLAGS) $(PROGRAM) install:: xcalc $(INSTALL) -c $(INSTALLFLAGS) xcalc $(BINDIR) install.man:: xcalc.man $(INSTALL) -c $(INSTMANFLAGS) xcalc.man $(MANDIR)/xcalc.n depend:: $(DEPEND) depend:: $(DEPEND) -s "# DO NOT DELETE" -- $(CFLAGS) -- $(SRCS) $(DEPEND): @echo "making $@"; \ cd $(DEPENDSRC); $(MAKE) clean:: $(RM) $(PROGRAM) \end{verbatim} \end{quote} We've omitted a few standard definitions for {\tt CFLAGS, CC, DEPEND, INSTALL, RM, LDFLAGS} etc. These are installation and system dependent, and form part of the Imake template. They will precede the above text. \section{Generating the Makefile for the first time} Invoking {\em Imake} for the first time is a little complex because you have to tell it where to find the template, as well as define the top level directory. The simplest way to do it is to use the {\tt ximake} script that should have been installed along with the rest of {\tt X} and {\tt imake}. The invocation is simply \begin{quote} {\tt ximake} \end{quote} \section{The {\em Imake} template} For a more portable setup, it is possible to split the template file into the following components: \begin{itemize} \item the rules \item the system-dependent macros, which vary depending on the specific architecture/operating-system combination, things like the compiler name, flags. \item the site dependent variables --- where to install the binaries, libraries etc. \end{itemize} For example the X distribution has an {\tt Imake.rules} file, which defines various rules like {\tt ComplexProgramTarget()}, system dependent files of the form {\em machinetype}{\tt .cf}, eg. {\tt sun.cf, ultrix.cf}, ..., and a site dependent variables file called {\tt site.def}. The template looks something like the following: (This is abbreviated to keep the flavour but omit much detail, deemed unnecessary for the purposes of this tutorial --- annotations in C style comments) \begin{quote} \begin{verbatim} #ifdef sun #define MacroIncludeFile "sun.cf" #define MacroFile sun.cf #undef sun #define SunArchitecture #endif /* sun */ /* * The macrofile sun.cf contains definitions specific to Sun * machines --- examples from it are after this file */ /**/########################################################################### /**/# platform-specific configuration parameters - edit MacroFile to change #include MacroIncludeFile /**/########################################################################### /**/# site-specific configuration parameters - edit site.def to change #include "site.def" /***************************************************************************** * * * DEFAULT DEFINITONS * * * * The following section contains defaults for things that can be overridden * * in the various .macros files and site.def. DO NOT EDIT! * * * ****************************************************************************/ #ifndef SystemV #define SystemV NO /* need system 5 style */ #endif #ifndef BuildServer #define BuildServer YES /* go ahead and build server */ #endif #ifndef UnalignedReferencesAllowed #define UnalignedReferencesAllowed NO /* if arbitrary deref is okay */ #endif #ifndef BourneShell /* to force shell in makefile */ #define BourneShell /bin/sh #endif /* * Lots and lots more variables that can be overridden in the site.def * including: */ #ifndef DestDir #define DestDir /* as nothing */ #endif #ifndef UsrLibDir #define UsrLibDir $(DESTDIR)/usr/lib #endif #ifndef BinDir #define BinDir $(DESTDIR)/usr/bin/X11 #endif #ifndef IncDir #define IncDir $(DESTDIR)/usr/include/X11 #endif #ifndef IncRoot #define IncRoot $(DESTDIR)/usr/include #endif #ifndef AdmDir #define AdmDir $(DESTDIR)/usr/adm #endif #ifndef LibDir #define LibDir $(USRLIBDIR)/X11 #endif #ifndef LintlibDir #define LintlibDir $(USRLIBDIR)/lint #endif #ifndef FontDir #define FontDir $(LIBDIR)/fonts #endif /* * This is followed by the actual definitions that will appear in the * Makefile, again, the list is partial. */ /* * This list must be reflected in the DIRS_TO_BUILD list in the top-level * Makefile. */ DESTDIR = DestDir /* root of install */ USRLIBDIR = UsrLibDir /* libraries */ BINDIR = BinDir /* programs */ INCDIR = IncDir /* header files */ INCROOT = IncRoot /* base for header files */ ADMDIR = AdmDir /* server log files */ LIBDIR = LibDir /* rgb, XErrorDB, etc. */ LINTLIBDIR = LintlibDir /* lint libraries */ FONTDIR = FontDir /* font directories */ CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(STD_DEFINES) $(DEFINES) LINTFLAGS = $(LINTOPTS) $(INCLUDES) $(STD_DEFINES) $(DEFINES) -DLINT LDFLAGS = $(CDEBUGFLAGS) $(SYS_LIBRARIES) $(SYSAUX_LIBRARIES) TOP = TOPDIR #ifdef CompileWithInstalled EXTENSIONLIB = $(USRLIBDIR)/lib/libXext.a XLIB = $(USRLIBDIR)/libX11.a XMULIB = $(USRLIBDIR)/libXmu.a OLDXLIB = $(USRLIBDIR)/liboldX.a XTOOLLIB = $(USRLIBDIR)/libXt.a XAWLIB = $(USRLIBDIR)/libXaw.a INCLUDES = -I$(INCDIR) -I$(INCROOT) #else /* ! CompileWithInstalled */ EXTENSIONLIB = $(EXTENSIONSRC)/lib/libXext.a XLIB = $(XLIBSRC)/libX11.a XMULIB = $(XMUSRC)/libXmu.a OLDXLIB = $(OLDXLIBSRC)/liboldX.a XTOOLLIB = $(TOOLKITSRC)/libXt.a XAWLIB = $(AWIDGETSRC)/libXaw.a INCLUDES = -I$(TOP) #endif /* CompileWithInstalled */ /* * The above fragment illustrates how different makefiles can be * generated for the distribution, presumably, once with * CompileWithInstalled not defined in site.def, so that the * distribution can be bootstrapped and built for the first time, then * with CompileWithInstalled defined in site.def so that it uses the * already installed libraries instead of requiring the compiled * objects remain forever in src directories */ MACROFILE = MacroFile ICONFIGFILES = $(IRULESRC)/Imake.tmpl \ $(IRULESRC)/$(MACROFILE) $(IRULESRC)/site.def IMAKE_DEFINES = /* leave blank, for command line use only */ IMAKE_CMD = $(NEWTOP)$(IMAKE) -TImake.tmpl -I$(NEWTOP)$(IRULESRC) \ -s Makefile $(IMAKE_DEFINES) /* * Now include the actual rules file --- this contains the definitions * of macros like ComplexProgramTarget, as described earlier */ #include "Imake.rules" /* * INCLUDE_IMAKEFILE is defined by the imake program to be the name of * the Imakefile you are processing, usually just Imakefile. It * gets included here. */ /**/########################################################################### /**/# start of Imakefile #include INCLUDE_IMAKEFILE /* * Followed by some basic rules for all Makefiles, especially useful * for Imakefiles where all you want to do is make the subdirectories. */ /**/########################################################################### /**/# Imake.tmpl common rules for all Makefiles - do not edit /* * These need to be here so that rules in Imakefile occur first; the blank * all is to make sure that an empty Imakefile doesn't default to make clean. */ emptyrule:: CleanTarget() MakefileTarget() TagsTarget() #ifdef IHaveSubdirs /**/########################################################################### /**/# rules for building in SUBDIRS - do not edit InstallSubdirs($(SUBDIRS)) InstallManSubdirs($(SUBDIRS)) CleanSubdirs($(SUBDIRS)) TagSubdirs($(SUBDIRS)) MakefileSubdirs($(SUBDIRS)) #else /**/########################################################################### /**/# empty rules for directories that do not have SUBDIRS - do not edit install:: @echo "install done" install.man:: @echo "install.man done" Makefiles:: #endif /* if subdirectory rules are needed */ /**/########################################################################### /**/# dependencies generated by makedepend \end{verbatim} \end{quote} The {\tt Sun.macros} file looks something \begin{quote} \begin{verbatim} #define SunOSPlatform YES /* set to NO if not running SunOS */ #define OSName SunOS 3.5 #define OSMajorVersion 3 #define OSMinorVersion 5 /**/# platform: $XConsortium: Sun.macros,v 1.52 88/10/23 11:00:55 jim Exp $ /**/# operating system: OSName #if SunOSPlatform && OSMajorVersion == 3 && OSMinorVersion <= 2 #define OptimizedCDebugFlags /* as nothing */ #endif BOOTSTRAPCFLAGS = AS = as CC = cc CPP = /lib/cpp LD = ld LINT = lint INSTALL = install TAGS = ctags RM = rm -f MV = mv LN = ln -s RANLIB = ranlib RANLIBINSTFLAGS = -t AR = ar clq LS = ls LINTOPTS = -axz LINTLIBFLAG = -C MAKE = make STD_CPP_DEFINES = STD_DEFINES = /* This defines the server you want */ #define XsunServer Xsun \end{verbatim} \end{quote} There's more in the macros file but the rest of the definitions are X dependent. Most of the definitions shown here can be overridden in the {\tt site.def} file, so a system administrator can completely reconfigure the setup, if necessary. \section{Simple Imakefiles} We end with a few simple examples to illustrate the rules in the X Imake.rules. \subsection{A single program, one source file} The first is for a simple program that has only one source file {\tt xstring.c} and a corrsponding manual page {\tt xstring.man} It requires the libraries {\tt XAWLIB, XTOOLLIB, and XLIB} (the X Athena widgets, the X Toolkit, and the C library interface to X). \begin{quote} \begin{verbatim} LOCAL_LIBRARIES = $(XAWLIB) $(XTOOLLIB) $(XLIB) SimpleProgramTarget(xstring) \end{verbatim} \end{quote} \subsection{A single program, multiple source files} A slightly more complex Imakefile is the one for {\tt xcalc}, the example described earlier. \begin{quote} \begin{verbatim} LOCAL_LIBRARIES = $(XLIB) SYS_LIBRARIES = -lm #ifdef MacIIArchitecture DEFINES = -DIEEE #endif /* MacIIArchitecture */ SRCS = xcalc.c sr.c OBJS = xcalc.o sr.o ComplexProgramTarget(xcalc) \end{verbatim} \end{quote} \subsection{Multiple programs} An Imakefile for a directory with multiple programs is a little more complicated. {\tt ComplexProgramTarget\_1} is similar to {\tt ComplexProgramTarget} but it uses {\tt OBJS1} to link the program instead of {\tt OBJS}. The first argument is the program name, the second is the list of {\tt LOCAL\_LIBRARIES}, and the third is the list of {\tt SYSLAST\_LIBRARIES}. It is possible to have more complex programs defined (the X Imake rules allow for 3 such targets) called {\tt ComplexProgramTarget\_1, ComplexProgramTarget\_2,} and {\tt ComplexProgramTarget\_3} which link {\tt OBJS1, OBJS2} and {\tt OBJS3} respectively. {\tt SingleProgramTarget} is a variant that allows multiple programs to be built - it differs from a {\tt ComplexProgramTarget\_}n in that it does not generate targets to install the program or the manual page, so it can be used for internal programs as well --- i.e. programs that are compiled to generate files or preprocess data for the installable targets. {\tt CFLAGS}, {\tt LINTFLAGS} and {\tt LDFLAGS} is defined as follows: \begin{quote} \begin{verbatim} CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(STD_DEFINES) $(DEFINES) LINTFLAGS = $(LINTOPTS) $(INCLUDES) $(STD_DEFINES) $(DEFINES) -DLINT LDFLAGS = $(CDEBUGFLAGS) $(SYS_LIBRARIES) $(SYSAUX_LIBRARIES) \end{verbatim} \end{quote} An Imakefile can redefine some of the right hand side variables - typically, \begin{itemize} \item {\tt CDEBUGFLAGS} can be {\tt -g} or {\tt -O}, or if you're using the GNU C compiler, {\tt -g -O}, \item{\tt INCLUDES} is usually {\tt -I\$\{TOP\}} by default, \item {\tt DEFINES} is left for user defined {\tt-D} flags. ({\tt STD\_DEFINES} is defined by the system macros file and should be left alone) \item {\tt SYS\_LIBRARIES} or {\tt SYSAUX\_LIBRARIES} can be used for {\tt -l} options to link in system libraries. ({\tt SYSLAST\_LIBRARIES} is defined by the system macros, typically for portability or emulation. \end{itemize} \begin{quote} \begin{verbatim} XWSRC=$(CONTRIBSRC)/widgets/Xhp XPICLIBDIR=$(LIBDIR)/xpic # The documents go in $(DOCDIR)/xpic - see the install target. DOCDIR=/local/doc/X11 ############################################################# # -DXPIC is used by the filename completion code. # -DMAGIC will include code that puts a '#! $(BINDIR)/xpic' # header on the saved xpic files, and make them executable, so # you can just execute the saved xpic file and it starts up # xpic. # -DDEBUG turns on debugging output - do you really want that?! # -DDRAWBBOX is also for debugging - it draws the bounding box # of all gels. # -DGRAB should be defined if XtAddGrab and XtRemoveGrab can be # made to work in Minibuf.c and input.c - I can't seem to get them # to work. # -DTYPEOUT includes the typeout code - this is still not used by # xpic - not much point defining it. DEFINES = -DXPIC -DMAGIC ############################################################# CDEBUGFLAGS = -g INCLUDES = -I$(XWSRC) -Ibitmaps ############################################################# # Note - You need the HP widgets (Xw) for the X11 Toolkit # These should be defined in an Imake.tmpl - except that the # normal Imake.tmpl insists on these being compiled in the # X directory tree. # For X11R3, the HP widgets use the R2 Intrinsics, which are # provided in with the HP src. XWLIB=$(XWSRC)/lib/libXw.a XTOOLLIB=$(XWSRC)/lib/libXt.a # Sigh - we use sin(), cos(), atan2() for arrow. MATHLIB=-lm OBJS1 = main.o windows.o xpic.o handlers.o input.o \ event.o grid.o error.o spline.o arrow.o newfonts.o \ util.o gels.o null.o obj_line.o obj_spline.o obj_text.o \ obj_box.o obj_circ.o obj_ell.o obj_block.o obj_elem.o \ updown.o text.o isqrt.o ask.o xtypeout.o Minibuf.o Window.o SRCS1 = main.c windows.c xpic.c handlers.c input.c \ event.c grid.c error.c spline.c arrow.c newfonts.c \ util.c gels.c null.c obj_line.c obj_spline.c obj_text.c \ obj_box.c obj_circ.c obj_ell.c obj_block.c obj_elem.c \ updown.c text.c isqrt.c ask.c xtypeout.c Minibuf.c Window.c ############################################################# OBJS2 = x2pic.o hash.o SRCS2 = x2pic.c hash.c ############################################################# OBJS3 = x2ps.o hash.o SRCS3 = x2ps.c hash.c PROGRAMS = xpic x2ps x2pic /* * ComplexProgramTarget(program, local libraries, system libraries) * * The difference between local libraries and system libraries is that * the program will depend on the local libraries, so they must be * filenames, while the system libraries are not dependencies, so * you can use -l */ ComplexProgramTarget_1(xpic,$(XWLIB) $(XTOOLLIB) $(XLIB),$(MATHLIB)) /* * SingleProgramTarget(program, objects, local libraries, system libraries) * * Note that this does not generate install: targets so we do that * explicitly */ SingleProgramTarget(x2pic,$(OBJS2) $(MALLOC),,) InstallProgram(x2ps, $(BINDIR)) InstallManPage(x2ps, $(MANDIR)) SingleProgramTarget(x2ps,$(OBJS3) $(MALLOC),,$(MATHLIB)) InstallProgram(x2pic, $(BINDIR)) InstallManPage(x2pic, $(MANDIR)) /* * This will install the script x2tex.script as $(BINDIR)/x2tex */ InstallScript(x2tex, $(BINDIR)) InstallManPage(x2tex, $(MANDIR)) /* * Some additional files we want to install. This is ordinary Make * stuff, but we use Imake defined variables like $(INSTALL). * $(INSTALLAPPFLAGS) is meant for normal text files. */ install:: -mkdir $(XPICLIBDIR) $(INSTALL) $(INSTAPPFLAGS) x2ps.pro $(XPICLIBDIR) $(INSTALL) $(INSTAPPFLAGS) x2ps.tra $(XPICLIBDIR) -mkdir $(XPICLIBDIR)/fontdesc $(INSTALL) $(INSTAPPFLAGS) fontdesc/xpic $(XPICLIBDIR)/fontdesc $(INSTALL) $(INSTAPPFLAGS) fontdesc/x2pic $(XPICLIBDIR)/fontdesc $(INSTALL) $(INSTAPPFLAGS) fontdesc/x2tpic $(XPICLIBDIR)/fontdesc $(INSTALL) $(INSTAPPFLAGS) fontdesc/x2ps $(XPICLIBDIR)/fontdesc /* * This is a trick that generates a .h file from the Makefile * variables. We compare the newly generated file tune.h.new with * the old one tune.h, and replace the old one with the new one only * if it is different. This will prevent unnecessary compiles, and * avoids the need to have .c files depend on the Makefile because * you want them recompiled if a -D define changes */ tune.h: Makefile echo \#define LIBDIR \"$(XPICLIBDIR)\" > tune.h.new echo \#define PROGRAMNAME \"$(BINDIR)/xpic\" >> tune.h.new echo \#define DUMPDIR \"$(DUMPDIR)\" >> tune.h.new -cmp -s tune.h.new tune.h || cp tune.h.new tune.h \end{verbatim} \end{quote} \subsection{A library archive of object files} An Imakefile for a library looks something like: \begin{quote} \begin{verbatim} # # This library contains miscellaneous utility routines and is not part # of the Xlib standard. # STD_DEFINES = LibraryDefines CDEBUGFLAGS = LibraryCDebugFlags INCLUDES = -I. -I$(TOP) -I$(TOP)/X11 INSTALLFLAGS = $(INSTINCFLAGS) LINTLIBS = $(LINTXLIB) #ifdef OsNameDefines OS_NAME_DEFINES = OsNameDefines #endif HEADERS = \ Xmu.h SRCS = Atoms.c CrPixFBit.c CvtStdSel.c DefErrMsg.c DrRndRect.c FToCback.c \ Lookup.c Lower.c RdBitF.c StrToBS.c StrToBmap.c StrToCurs.c \ StrToJust.c StrToOrnt.c StrToWidg.c OBJS = Atoms.o CrPixFBit.o CvtStdSel.o DefErrMsg.o DrRndRect.o FToCback.o \ Lookup.o Lower.o RdBitF.o StrToBS.o StrToBmap.o StrToCurs.o \ StrToJust.o StrToOrnt.o StrToWidg.o all:: NormalLibraryTarget(Xmu,$(OBJS)) LintLibraryTarget(Xmu,$(SRCS)) InstallLibrary(Xmu,$(USRLIBDIR)) InstallLintLibrary(Xmu,$(LINTLIBDIR)) InstallMultiple($(HEADERS),$(INCDIR)) DependTarget() NormalLintTarget($(SRCS)) \end{verbatim} \end{quote} Sometimes, it is nice to be able to generate libraries compiled with debugging on, and libraries compiled with profiling on, so that these can be used by developers. Something like the following, added before the {\tt NormalLibraryTarget} \begin{quote} \begin{verbatim} #if DebugLibXmu && ProfileLibXmu DebuggedAndProfiledLibraryObjectRule() #else # if DebugLibXmu DebuggedLibraryObjectRule() # else # if ProfileLibXmu ProfiledLibraryObjectRule() # else NormalLibraryObjectRule() # endif # endif #endif \end{verbatim} \end{quote} and something like the following added before the {\tt InstallMultiple} would do the trick quite nicely. \begin{quote} \begin{verbatim} #if ProfileLibXmu ProfiledLibraryTarget(Xmu,$(OBJS)) InstallLibrary(Xmu_p,$(USRLIBDIR)) #endif #if DebugLibXmu DebuggedLibraryTarget(Xmu,$(OBJS)) #endif \end{verbatim} \end{quote} If we wanted a debugging library, we'd define the symbol {\tt DebugLibXmu} in the {\tt site.def} file, and the DebuggedLibraryRule would ensure it generated a library target for {\tt lib}name{\tt \_d.a}, while if we defined the {\tt ProfileLibXmu} symbol, we would get a profiled library target for {\tt lib}name{\tt \_p.a}, in addition to the usual {\tt lib}name{\tt .a}. This sort of configurability is very hard to get from a vanilla makefile. \subsection{Subdirectories} The following Imakefile is for a directory that only contains subdirectories, and we want to make each of the subdirectories: \begin{quote} \begin{verbatim} #define IHaveSubdirs #define PassCDebugFlags 'CDEBUGFLAGS=$(CDEBUGFLAGS)' SUBDIRS = X \ oldX \ Xt \ Xmu \ Xaw MakeSubdirs($(SUBDIRS)) DependSubdirs($(SUBDIRS)) MakeLintLibSubdirs($(SUBDIRS)) MakeLintSubdirs($(SUBDIRS),install.ln,install.ln) \end{verbatim} \end{quote} This will have the {\tt Makefiles} target defined as well as {\tt Makefile} and using the {\tt make Makefiles} command will cause it to regenerate the Makefiles in the subdirectories. It does this by prepending a ``../'' in front of the {\tt TOP} variable, which means that {\tt TOP} should be a relative path. (This is the only reason for {\tt TOP} to be a relative path - if there are no subdirectories, {\tt TOP} can easily be an absolute path. \section{Miscellaneous} {\em Imake} puts null comments of the form {\tt \/\*\*\/} in front of normal {\em make} style comments i.e. the {\tt \#} to protect them from the C preprocessor. They survive unscathed in the resulting Makefile, while C style comments vanish. This provides a good way to distinguish betwen Imakefile comments and comments that you want to appear in the Makefile. However, it does not protect comments in the files that are included {\tt (site.def, Imake.rules, machine.macros)} so if you want to use {\tt \#} style comments in those files, you must protect them yourself with {\tt \/\*\*\/} in front of them. \section{History} {\em Imake} was originally written by Todd Brunhoff (toddb@tekcrl.crl) for X Windows Version 11 Release 1. The configurations for X Windows Version 11 Releases 2, 3 and 4 were reworked considerably by Jim Fulton (jim@expo.lcs.mit.edu) to isolate the rules, machine dependent information, and site dependent information into separate files. \end{document}