[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