4.3.6 Conditional Compilation

A pair of directives

     :- if(:Goal).
     ...
     :- endif.

will evaluate Goal and, if the goal succeeds, the sentences between the if/1 directive and the matching endif/0 directive will be processed as usual.

If the evaluation of Goal does not succeed, i.e. fails or raises an exception, the sentences between the if/1 directive and the endif/0 directive are completely ignored, except that any conditional directives must be properly nested. In particular, term expansion will not be performed on such ignored sentences and the goals of any nested conditional directives will not be evaluated.

The full form of conditional compilation directives include optional else/0 and elif/1 and are used as follows

     :- if(:Goal1).
     ...
     :- else.
     ...
     :- endif.

If the goal of the if/1 directive succeeds, the sentences up to the matching else/0 directive are processed as usual. Otherwise, if the goal fails or raises an exception, the sentences between the else/0 directive and the matching endif/0 directive are processed as usual.

Finally, elif/1 is available as a shorthand for nested uses of if/1 and else/0

     :- if(:Goal1).
     ...
     :- elif(:Goal2).
     ...
     :- elif(:Goal3).
     ...
     :- else.
     ...
     :- endif.

will evaluate the goals in turn, until one of them succeeds in which case the following sentences will be processed as usual up to the corresponding else/0, endif/0 or elif/1.

A valid sequence of conditional compilation directives must contain exactly one if/1 directive followed by zero or more elif/1 directives followed by at most one else/0 directive followed by exactly one endif/0 directive. Valid sequences of conditional directives can be nested.

All directives that make up a sequence of conditional compilation directives must be in the same file. For instance, you cannot have a if/1 directive in one file and then have the corresponding endif/0 directive in a file included with an include/1 directive. Nested conditional compilation sequences can of course be located in included files.

Conditional compilation directives are handled very early in the processing of an input file. In particular, term expansion hooks will never see if/1, else/0, elif/1 or endif/0 directives. Also, neither of if/1, else/0, elif/1 or endif/0 are defined as predicates.

If evaluation of a goal for if/1 directive or an elif/1 directive raises an exception, an error message will be written and the goal will be treated as if it failed.

4.3.6.1 Conditional Compilation Examples

Conditional compilation is useful for writing portable Prolog code since it makes it possible to adapt to peculiarities of various implementations. The Prolog flag dialect, used by several Prolog implementations, is especially useful here.

     :- if(current_prolog_flag(dialect, sicstus).
     %% We are being compiled in SICStus
     %% Only SICStus has this library
     :- use_module(library(process), [process_create/2]).
     
     :- elif(current_prolog_flag(dialect, othervendor)).
     
     %% We are being compiled in Other Vendor, we need to provide our own
     %% compatibility layer
     
     :- use_module(...).
     process_create(A,B) :- ...
     
     :- else.
     %% We are being compiled in some unknown Prolog, give up.
     
     process_create(_,_) :- throw(not_implemented).
     
     :- endif.

Another possible usage is for disabling, perhaps costly, debugging code when building an optimized version of the code.

     %% Only need environ/2 at compile-time for conditional compilation
     :- load_files(library(system), [when(compile_time), imports([environ/2])]).
     
     :- if(\+ environ(optimize, true)).
     
     %% This clause does some expensive sanity checks. Disabled when building
     %% an optimized version.
     foo(X) :-
        \+ valid_x(X),
        throw(invalid_x(X)).
     
     :- endif.
     
     %% This clause is always present.
     foo(X) :-
        do_x_things(X).

Invoking the SICStus development system with an option -Doptimize=true, to set the system property optimize, and then compiling the above code will ensure that the first, sanity checking, clause is not part of the foo/1 predicate. Invoking the development system without such an option will ensure that the sanity checking clause is part of the foo/1 predicate.


Send feedback on this subject.