%************************************************************************ %* * \section[separate-compilation]{Separate compilation} \index{separate compilation} \index{recompilation checker} \index{make and recompilation} %* * %************************************************************************ This section describes how GHC supports separate compilation. \subsection[hi-files]{Interface files} When GHC compiles a source module @A@, it generates an object @A.o@, {\em and} a companion {\em interface file} @A.hi@. The interface file contains information needed by the compiler when it compiles any module @B@ that imports @A@, whether directly or indirectly. When compiling @B@, GHC will read @A.hi@ to find the details that it needs to know about things defined in @A@. Furthermore, when compiling module @C@ which imports @B@, GHC may decide that it needs to know something about @A@ --- for example, @B@ might export a function that involves a type defined in @A@. In this case, GHC will go and read @A.hi@ even though @C@ does not explicitly import @A@ at all. The interface file may contain all sorts of things that aren't explicitly exported from @A@ by the programmer. For example, even though a data type is exported abstractly, @A.hi@ will contain the full data type definition. For small function definitions, @A.hi@ will contain the complete definition of the function. For bigger functions, @A.hi@ will contain strictness information about the function. And so on. GHC puts much more information into @.hi@ files when you use @-O@. Without @-O@ it puts in just the minimum; with @-O@ it lobs in a whole pile of stuff. @A.hi@ should really be thought of as a compiler-readable version of @A.o@. If you use a @.hi@ file that wasn't generated by the same compilation run that generates the @.o@ file the compiler may assume all sorts of incorrect things about @A@, resulting in core dumps and other unpleasant happenings. In the olden days, GHC compared the newly-generated @.hi@ file with the previous version; if they were identical, it left the old one alone and didn't change its modification date. In consequence, importers of a module with an unchanged output @.hi@ file were not recompiled. This doesn't work any more. In our earlier example, module @C@ does not import module @A@ directly, yet changes to @A.hi@ should force a recompilation of @C@. And some changes to @A@ (changing the definition of a function that appears in an inlining of a function exported by @B@, say) may conceivably not change @B.hi@ one jot. So now \subsection[recomp]{The recompilation checker} GHC keeps a version number on each interface file, and on each type signature within the interface file. It also keeps in every interface file a list of the version numbers of everything it used when it last compiled the file. If the source file's modification date is earlier than the @.o@ file's date (i.e. the source hasn't changed since the file was last compiled), and you give GHC the @-recomp@ flag, then GHC will be clever. It compares the version numbers on the things it needs this time with the version numbers on the things it needed last time (gleaned from the interface file of the module being compiled); if they are all the same it stops compiling rather early in the process saying ``Recompilation not required''. What a beautiful sight! It's still an experimental feature (that's why @-recomp@ is off by default), so tell us if you think it doesn't work. Patrick Sansom has a workshop paper about how all this is done. Ask him (email: \tr{sansom}) if you want a copy. \subsection{Using @make@} It is reasonably straightforward to set up a \tr{Makefile} to use with GHC, assuming you name your source files the same as your modules. Thus: \begin{verbatim} HC = ghc HC_OPTS = -cpp $(EXTRA_HC_OPTS) SRCS = Main.lhs Foo.lhs Bar.lhs OBJS = Main.o Foo.o Bar.o .SUFFIXES : .o .hi .lhs .hc .s cool_pgm : $(OBJS) $(RM) $@ $(HC) -o $@ $(HC_OPTS) $(OBJS) # Standard suffix rules .o.hi: @: .lhs.o: $(RM) $@ $(HC) -c $< $(HC_OPTS) .hs.o: $(RM) $@ $(HC) -c $< $(HC_OPTS) # Optional .hc.o: $(RM) $@ $(HC) -c $< $(HC_OPTS) # Optional .s.o: $(RM) $@ $(HC) -c $< $(HC_OPTS) # Inter-module dependencies Foo.o Foo.hc Foo.s : Baz.hi # Foo imports Baz Main.o Main.hc Main.s : Foo.hi Baz.hi # Main imports Foo and Baz \end{verbatim} (Sophisticated \tr{make} variants may achieve some of the above more elegantly. Notably, @gmake@'s pattern rules let you write the more comprehensible: \begin{verbatim} %.o : %.lhs $(RM) $@ $(HC) -c $< $(HC_OPTS) \end{verbatim} What we've shown should work with any \tr{make}.) Note the cheesy \tr{.o.hi} rule: It records the dependency of the interface (\tr{.hi}) file on the source. The rule says a \tr{.hi} file can be made from a \tr{.o} file by doing... nothing. Which is true. Note the inter-module dependencies at the end of the Makefile, which take the form \begin{verbatim} Foo.o Foo.hc Foo.s : Baz.hi # Foo imports Baz \end{verbatim} They tell @make@ that if any of @Foo.o@, @Foo.hc@ or @Foo.s@ have an earlier modification date than @Baz.hi@, then the out-of-date file must be brought up to date. To bring it up to date, @make@ looks for a rule to do so; one of the preceding suffix rules does the job nicely. Putting inter-dependencies of the form \tr{Foo.o : Bar.hi} into your \tr{Makefile} by hand is rather error-prone. Don't worry---never fear, \tr{mkdependHS} is here! (and is distributed as part of GHC) Add the following to your \tr{Makefile}: \begin{verbatim} depend : mkdependHS -- $(HC_OPTS) -- $(SRCS) \end{verbatim} Now, before you start compiling, and any time you change the \tr{imports} in your program, do \tr{make depend} before you do \tr{make cool_pgm}. \tr{mkdependHS} will append the needed dependencies to your \tr{Makefile}. @mkdependHS@ is fully describe in \Sectionref{mkdependHS}. A few caveats about this simple scheme: (a)~You may need to compile some modules explicitly to create their interfaces in the first place (e.g., \tr{make Bar.o} to create \tr{Bar.hi}). (b)~You may have to type \tr{make} more than once for the dependencies to have full effect. However, a \tr{make} run that does nothing {\em does} mean ``everything's up-to-date.'' (c) This scheme will work with mutually-recursive modules but, again, it may take multiple iterations to ``settle.''