[m-rev.] for review: stand-alone interface example

Julien Fischer juliensf at csse.unimelb.edu.au
Tue Feb 13 15:43:34 AEDT 2007


The attached files are an example of how to use the the
new `--generate-standalone-interface' option.  I'm thinking
of adding this to the samples directory.

Julien.
-------------- next part --------------
/*
** vim: ts=4 sw=4 et
*/
#include <stdio.h>

/*
** This header file is part of the stand-alone interface.
** It contains declarations for mercury_init() and mercury_terminate(),
** which are used to respectively start and shutdown the Mercury runtime.
*/
#include "mercury_lib_int.h"

/*
** mercury_lib.mh is generated by the compiler when we build libmercury_lib.
** It contains declarations for procedures exported by pragma foreign_export
** as well as other exported entities, like mutables.
**
*/
#include "mercury_lib.mh"

int
main(int argc, char **argv)
{
    void *stack_bottom;
   
    /* Before calling any Mercury procedures we must first initialise
    ** the Mercury runtime, standard library and any other Mercury libraries
    ** that we will be using.  The function mercury_init() is used to do
    ** this.  In order it does the following:
    **
    ** (1) initialises the runtime
    ** (2) initialises the standard library
    ** (3) calls any predicates specified in `:- initialise' declarations
    **     and assigns any mutables their initial value   
    **
    ** We strongly recommend that calling this function is the first thing
    ** that your program does.
    **
    ** The third argument to mercury_init() is address of the base of the
    ** stack.  In grades that support conservative GC is used tell the
    ** collector where to begin tracing.
    */
    mercury_init(argc, argv, &stack_bottom);

    /*
    ** Here is a call to an exported Mercury procedure that does some I/O.
    */
    write_hello();

    /*
    ** Lookup the current value of the Mercury mutable 'global' and print it
    ** out.  In C code we can refer to `global' by it's "foreign" name, the
    ** name given by mutable's foreign_name attribute.
    **
    ** WARNING: in grades that support multithreading access to Mercury
    ** mutables from C is *not* (currently) thread safe.
    */
    printf("The current value of global is %" MR_INTEGER_LENGTH_MODIFIER "d.\n",
        GLOBAL);

    /*
    ** Change the value of the Mercury mutable `global'.
    */
    GLOBAL = 42;

    /*
    ** Call a Mercury procedure that prints out the current value of
    ** the mutable `global'.
    */
    write_global_value();

    /*
    ** Once we have finished calling Mercury procedures then we shut
    ** down the Mercury runtime by calling the function
    ** mercury_terminate().  The value returned by this function 
    ** is Mercury's exit status (as set by io.set_exit_status/3.)
    **
    ** This function will also invoke any finalisers specified in
    ** `:- finalise' declarations in the set of Mercury libraries that
    ** we are using.
    */
    return mercury_terminate();
}
-------------- next part --------------
mercury_lib: the initialiser has now been invoked.
Hello World
The current value of global is 561.
The new value of global is 42.
mercury_lib: the finaliser has now been invoked.
-------------- next part --------------
# This directory contains an example of how to create and use a stand-alone
# interface.  Stand-alone interfaces allow exported Mercury procedures to be
# called from "foreign" applications, that is applications whose entry point
# is something other than a Mercury main/2 predicate.  (By "exported" Mercury
# procedure we mean one that is the subject of a pragma foreign_export
# declaration.)
#
# A stand-alone interface consists of an object / header file pair.  These
# define a pair of functions whose respective tasks are to initialise and
# shutdown the Mercury runtime plus a given set of Mercury libraries that the
# foreign application may wish to use.  It is important to initialise the
# Mercury runtime before calling any Mercury procedures.  The header file
# created as part of the stand-alone interface is compatible with either C or
# C++.
#
# Stand-alone interfaces are created by invoking the compiler with the
# `--generate-standalone-interface' option.  The Mercury libraries that the
# foreign application may wish to use are specified via the usual mechanisms,
# e.g. the `--ml' and `--mld' options.  The Mercury standard library is always
# included amongst the set of libraries.
#
# In this example there is a small foreign application written in C contained
# in the file c_main.c.  This application calls some Mercury procedures
# defined in the Mercury library `mercury_lib' (which is contained in the file
# mercury_lib.m).  The program also manipulates the value of a mutable defined
# in this library.
#
# To build the application we first compile `mercury_lib'.  For this example
# we don't bother installing it since that would just lead to the command
# lines being unwieldy.  We then build the stand-alone interface, which in
# this example is called mercury_lib_int.  Finally we compile c_main.c and
# link them all together.  Specific details concerning each step in the build
# process are discussed below.  See c_main.c for details of how to invoke the
# stand-alone interface from C or C++ code.
#
# NOTE: the following example is statically linked against the Mercury
# libraries.  This is in order to make the example as portable as possible.
# Shared libraries will also work with stand-alone interfaces on systems
# that support them.

# XXX The grade is currently hardcoded to be hlc.gc because stand-alone
# interfaces in the lowlevel C grades are broken.  (hl.gc would also
# be fine.)
#
GRADE=hlc.gc

all: c_main

# Build the example Mercury library, mercury_lib.
# The dependency on the .init file is merely a convenience.  It's a good
# one to choose since it will always be regenerated if one of the .m files
# in a library is changed.
#
# In order to keep the command lines in this makefile sane we don't
# bother installing it.  Usually we would be working with an installed
# library.
#
mercury_lib.init: mercury_lib.m
	mmc --grade $(GRADE) --make libmercury_lib

# The following rule creates the stand-alone interface to the mercury_lib
# library, Mercury standard library and Mercury runtime.  Since we haven't
# installed mercury_lib all the relevant files will have been built in
# this directory; with an installed library we would need to use the
# `--mld' option to specify its location.
#
mercury_lib_int.o: mercury_lib.init
	mmc --grade $(GRADE) --mercury-linkage static --ml mercury_lib \
		--generate-standalone-interface mercury_lib_int

# We use the mgnuc script here rather than invoking gcc directly since
# c_main.c #includes parts of the Mercury runtime and mgnuc knows where to
# find those header files without us specifying the location.  If we used
# gcc (or some other C compiler) directly then we would need to specify the
# location of the runtime and standard library header files, e.g. by using
# the `-I' option.
#
c_main.o: c_main.c mercury_lib.init mercury_lib_int.o
	mgnuc --grade $(GRADE) -c c_main.c

# For similar reasons we use the ml script rather than invoking ld directly.
#
c_main: c_main.o mercury_lib_int.o mercury_lib.init
	ml --grade $(GRADE) --mercury-libs static -o c_main \
		c_main.o libmercury_lib.a mercury_lib_int.o	

.PHONY: realclean
realclean:
	-mmc --make mercury_lib.realclean
	/bin/rm -f mercury_lib_int.[cho] c_main.o c_main
	/bin/rm -rf Mercury
-------------- next part --------------
%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%

:- module mercury_lib.
:- interface.

:- import_module io.

%-----------------------------------------------------------------------------%

    % Write "Hello World" to the current Mercury text output stream.
    %
:- pred write_hello(io::di, io::uo) is det.

    % Write the current value of the mutable `global' to the current
    % Mercury text output stream.
    %
:- pred write_global_value(io::di, io::uo) is det.

%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%

:- implementation.

:- import_module list.
:- import_module string.

%-----------------------------------------------------------------------------%

:- mutable(global, int, 561, ground, [untrailed,
    foreign_name("C", "GLOBAL"), attach_to_io_state]).

%-----------------------------------------------------------------------------%

:- pragma foreign_export("C", write_hello(di, uo),
    "write_hello").

write_hello(!IO) :-
    io.write_string("Hello World\n", !IO).

:- pragma foreign_export("C", write_global_value(di, uo),
    "write_global_value").

write_global_value(!IO) :-
    get_global(Value, !IO),
    io.format("The new value of global is %d.\n", [i(Value)], !IO).

%-----------------------------------------------------------------------------%
%
% Initialiser for this library
%

:- initialise initialiser/2.

:- pred initialiser(io::di, io::uo) is det.

initialiser(!IO) :-
    io.write_string("mercury_lib: the initialiser has now been invoked.\n",
        !IO).

%-----------------------------------------------------------------------------%
%
% Finaliser for this library
%

:- finalise finaliser/2.

:- pred finaliser(io::di, io::uo) is det.

finaliser(!IO) :-
    io.write_string("mercury_lib: the finaliser has now been invoked.\n",
        !IO).

%-----------------------------------------------------------------------------%
:- end_module mercury_lib.
%-----------------------------------------------------------------------------%


More information about the reviews mailing list