If you use Mmake or ‘mmc --make’, then you do not need to understand the details of how the Mercury implementation goes about building programs. Thus you may wish to skip this chapter.
To compile a source file to object code via C without creating an executable, use the command
mmc -c filename.m
Since targeting C is the default, this tells ‘mmc’ to generate C code, and then invoke the configured C compiler to translate that to object code. ‘mmc’ puts the generated C code into a file called module.c and the generated object code into a file called module.o, where module is the name of the Mercury module defined in filename.m. If the source file contains nested modules, then each submodule will get compiled to separate C and object files.
Before you can compile a module, you must make the interface files for the modules that it imports (directly or indirectly). You can create the interface files for one or more source files using the following commands:
mmc --make-short-int filename1.m filename2.m … mmc --make-priv-int filename1.m filename2.m … mmc --make-int filename1.m filename2.m …
The first command builds (or rebuilds) the ‘.int3’ file of each module contained in the named source files. The second command builds (or rebuilds) the ‘.int0’ file of each module contained in the named source files. (Note that only modules that have submodules need ‘.int0’ files.) The third command builds (or rebuilds) both the ‘.int’ and ‘.int2’ file of each module contained in the named source files.
If you are going to compile with ‘--intermodule-optimization’ enabled, then you also need to create the optimization interface files.
mmc --make-opt-int filename1.m filename2.m …
If you are going to compile with ‘--transitive-intermodule-optimization’ enabled, then you also need to create the transitive optimization files.
mmc --make-trans-opt filename1.m filename2.m …
After you have made all the interface files, one way to create an executable for a multi-module program is to compile all the modules at the same time using the command
mmc filename1.m filename2.m …
This will by default put the resulting executable in filename1, though you can use the ‘-o filename’ option to specify a different name for the output file, if you so desire.
The other way to create an executable for a multi-module program is to compile each module separately using ‘mmc -c’, and then link the resulting object files together. The linking is a two stage process.
First, you must create and compile an initialization file, which is a C source file containing calls to automatically generated initialization functions contained in the C code of the modules of the program:
c2init module1.c module2.c … > main-module_init.c, mgnuc -c main-module_init.c
The ‘c2init’ command line must contain the name of the C file of every module in the program. The order of the arguments is not important. The ‘mgnuc’ command is the Mercury GNU C compiler; it is a shell script that invokes the configured C compiler with the options appropriate for compiling the C programs generated by Mercury. (In the early days of the Mercury project, the configured C compiler was almost always GCC, which is why the name of the script is what it is, but the script itself will work with clang or MSVC as well.)
You then link the object code of each module with the object code of the initialization file to yield the executable:
ml -o main-module module1.o module2.o … main_module_init.o
‘ml’, the Mercury linker, is another shell script that invokes a C compiler with options appropriate for Mercury, this time for linking. ‘ml’ also pipes any error messages from the linker through ‘mdemangle’, the Mercury symbol demangler, so that any error messages refer to predicate and function names from the Mercury source code rather than to the names used in the intermediate C code.
The above command puts the executable in the file main-module. The same command line without the ‘-o’ option would put the executable into the file a.out.
‘mmc’ and ‘ml’ both accept a ‘-v’ (verbose) option. You can use that option to see what is actually going on. For the full set of options of ‘mmc’, see Invocation.
Once you have created an executable for a Mercury program,
you can go ahead and execute it.
You may however wish to specify certain options to the Mercury runtime system.
The Mercury runtime accepts
options via the MERCURY_OPTIONS
environment variable.
The most useful of these are the options that set the size of the stacks.
(For the full list of available options, see Environment.)
When targeting Java or C#, and when targeting high level C (‘mmc --high-level-code’), stack management is the responsibility of the target language’s compiler. When targeting low level C (‘mmc’ without –high-level code), stack management is the responsibility of ‘mmc’ and of the C runtime system. This backend uses two stacks, the det stack and the nondet stack. With ‘mmc --stack-segments’, both of these stacks will grow and shrink automatically as needed. Without ‘--stack-segments’, their size is fixed at program start-up. The default size is 4096k times the word size (in bytes) for the det stack and 64k times the word size (in bytes) for the nondet stack, but these can be overridden with the ‘--detstack-size’ and ‘--nondetstack-size’ options, whose arguments are the desired sizes of the det and nondet stacks respectively, in units of kilobytes. On operating systems that provide the appropriate support, the Mercury runtime will ensure that stack overflow is trapped by the virtual memory system.
With conservative garbage collection (the default), the heap will start out with a zero size, and will be dynamically expanded as needed, When not using conservative garbage collection, the heap has a fixed size like the stacks. The default size is 8Mb times the word size (in bytes), but this can be overridden with the ‘--heap-size’ option.