6.10 Compiling and loading object code
Traditionally when an ECLiPSe file is compiled, it is loaded immediately
into the system. Sometime it is useful to generate `object code' which can
then be loaded later, perhaps even in a different session of ECLiPSe,
maybe on a different platform. This functionality is provided by the
In order to use this facility, the fcompile library should be loaded first:
fcompile(+File) can then be used to generate an object file from an
ECLiPSe source file. The object file has the same base name as the source
file File, but with the suffix .eco attached.
fcompile generates an object file by compiling an ECLiPSe source
file normally, and then disassembling the compiled code into an object
form, which is written to the object file. This object form is platform
independent and can be loaded into ECLiPSe running on a different
platform from the one that generated it (see section 6.10.1 for
The object file is generated in the current working directory.
Options can be specified for fcompile by using fcompile/2.
fcompile is designed mainly for generating an object file for a whole
The include directive allows multiple source files to be compiled
into one object file. When fcompile encounters an include directive
in the source file:
it will generate the object code for the file(s) in File in place of
the directive. The effect is as if the actual source code for file(s) was
written at the point of the include directive. Note that this can
have a different semantics from recursively compiling files using the compile directive, because any new module in a recursively compiled file
ends with the end of that file. With include, any new modules defined
in that file will not end with the file. Thus, a compile
directive should not be changed to an include directive if the
target file contains definitions for a separate module.
The object code file (with .eco suffix) will be loaded in preference
to the Prolog source file by use_module/1 and lib/1,2 if both
files are present. On the other hand, the compile predicates expect a
source file and will normally not load an object code file.
The compiler generates different object code depending on the settings of
various pragmas. It is the settings of the pragmas at the time the object
code is generated that determines what codes are generated, rather than at
load time. The load time pragma settings have no effect on the object code
that is loaded in, so for example, if the code was generated while the
debug pragma is on, but loaded while the nodebug pragma is on, the loaded
code is still the debuggable, non-optimised code.
Note that in addition to generating the object code for predicates found in
the source file, fcompile also generates the object code of any
auxiliary predicates that are called in the source file.
These are the
predicates that are generated by the compiler (such as the do/2
iterator). A warning is
generated if a file contains more than one module. These warnings often
indicates that files have been incorrectly omitted or included in the
fcompile/1,2 can be used to
generate non-source versions of programs for delivery.
Currently, the compiler generates the auxiliary predicates for the do
iterator using a global counter to name the predicates. Unfortunately this
means that if an object file with auxiliary predicates is loaded into a
module that already has existing code that contains auxiliary predicates,
naming conflict can occur and the old auxiliaries may be replaced. It is
thus strongly recommended that object files should not be loaded into an
existing module. This will only be a problem if the file does not contain
any module declarations that redefines the module (i.e. module/1),
as these redefinition will erase the old copy of
The predicate generates the object code by first compiling the program and
then outputting the object code. Directives, which are executed in a normal
compilation process, will not be executed during the output of the object
code (but the directives themselves will be added to the object code so
that they will be executed when the code is loaded). This can lead to
differences between loading the object code and compiling the program if
the directive affects the compiled code during the compilation
(e.g. determining which files to load by a conditional in a
If macro transformation is defined (via macro/3
declarations) in the module that is fcompiled, then
the “protecting functor” no_macro_expansion
section 12.2) should be used to prevent the macro definition
itself from being transformed when the definition is generated by
fcompile. For example:
the no_macro_transformation/1 wrapper prevents this instance of foo/1 from being transformed when the directive is generated by fcompile.
Note that this is only needed if all terms are transformed, and not for
goals or clause transformation.
:- local macro(no_marco_transformation(foo/1), trans_foo/2, ).
Object file portability
One restriction does apply between platforms of different
word sizes: integers which fit in the word size of one platform
but not the other are represented differently internally in ECLiPSe.
Specifically, integers which takes between 32 and 64
bits to represent are treated as normal integers on a 64 bit machine,
but as bignums (see section 8.2.1) on 32 bit machines. This
difference is normally invisible, but if
such numbers occur as constants in the program code (i.e. their values appear
textually), they can lead to different low-level compiled abstract code on
the different platforms. Avoid using such constants if you want
the object code to be portable across different word sizes (they can always
be computed at run-time, e.g. writing
2^34 instead of 17179869184).