Next: , Up: Compiling multi-module programs   [Contents][Index]


2.3.1 Managing connections between modules

A Mercury module’s source file contains both the interface and the implementation sections of that module. Given a module A which imports module B, when compiling module A, the compiler needs to know what entities (types, predicates, functions etc) module B exports. It could do that by reading module B’s source file and extracting its interface part. However, given that the interface of a module tends to be much more stable than its implementation, that would be incredibly wasteful: it would compute B’s interface, many, many times, getting the same result between each pair of changes to B’s interface. It is far more efficient to store B’s interface in a file, which only ever needs to be updated when B’s source module changes, and does so in way that affects its interface.

In C and in some programming languages based on it, hand-written header files (.h files) usually store the interface of the source file (.c file) with the same base name. Mercury programming uses a similar file, the .int file, with the difference being that a module’s .int file is not hand-written, but is derived from the module’s source file by the Mercury compiler.

In fact, due to Mercury’s module system being substantially more expressive than C’s (not hard when C does not actually have an explicit module system), each module module has three or four interface files, not just one.

As you may guess from that description, managing Mercury interface files is not trivial. It is not hard either, as shown by ZZZ but it is even simpler to leave their management to automatic build tools. These build tools also take care of another issue: separate compilation.

When C programmers update a header file, they must also recompile all the C source files that depend on that header file. Manually keeping track of which source files these are is possible in theory, but very tedious, and extremely error-prone. This is even more true for Mercury. Yet the one simple but guaranteed-to-work method, recompiling everything, can slow down the think-edit-compile-test cycle to an unreasonable degree. Unlike humans, automatic build tools can be trusted to recompile only the modules that need recompilation, reusing the results of previous compilations whereever possible.

The Mercury implementation supports two automatic build tools: mmake, and mmc --make. As their names imply, both are intended to work like the traditional Unix build tool make. The next two sections describe them in turn. They each have strengths and weaknesses (for example, mmake supports only compilation to C, not to Java or C#), and they support different subsets of the available functionality, though the overlap (the set of features they both support) is large. We recommend that projects using Mercury pick one, and use it consistently.

If you can, you should pick mmc --make, because this is the build tool that is likely to receive more development in the future.

You can also use both tools, each for different parts of the same project, such as using mmc --make for the Mercury parts and mmake for typing those parts to the non-Mercury parts, but in general, you should do this only if you have to.


Next: , Up: Compiling multi-module programs   [Contents][Index]