[m-rev.] diff: add stand-alone interface example

Julien Fischer juliensf at csse.unimelb.edu.au
Thu Feb 22 17:39:11 AEDT 2007


Pete has already reviewed this one.

Estimated hours taken: 8
Branches: main

Add an example of how to use a stand-alone interface to the samples.

samples/c_interface/standalone_c/Makefile:
samples/c_interface/standalone_c/c_main.c:
samples/c_interface/standalone_c/c_main.exp:
samples/c_interface/standalone_c/mercury_lib.m:
 	New files.  An annotated example of how to use a standalone interface.

samples/c_interface/README:
 	Mention the new example.

Julien.

Index: README
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/samples/c_interface/README,v
retrieving revision 1.1
diff -u -r1.1 README
--- README	19 Nov 1998 06:18:16 -0000	1.1
+++ README	22 Feb 2007 06:32:11 -0000
@@ -24,3 +24,7 @@
  simpler_cplusplus_calls_mercury A simpler example of C++ code calling
                                  Mercury.

+standalone_c			Another example of C code calling Mercury
+				code this time use the compiler's 
+				`--generate-standalone-interface' option.
+
Index: standalone_c/Makefile
===================================================================
RCS file: standalone_c/Makefile
diff -N standalone_c/Makefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ standalone_c/Makefile	22 Feb 2007 06:32:11 -0000
@@ -0,0 +1,85 @@
+# 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.
+
+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 --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 --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 -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 --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
Index: standalone_c/c_main.c
===================================================================
RCS file: standalone_c/c_main.c
diff -N standalone_c/c_main.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ standalone_c/c_main.c	22 Feb 2007 06:32:11 -0000
@@ -0,0 +1,83 @@
+/*
+** 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();
+}
Index: standalone_c/c_main.exp
===================================================================
RCS file: standalone_c/c_main.exp
diff -N standalone_c/c_main.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ standalone_c/c_main.exp	22 Feb 2007 06:32:11 -0000
@@ -0,0 +1,5 @@
+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.
Index: standalone_c/mercury_lib.m
===================================================================
RCS file: standalone_c/mercury_lib.m
diff -N standalone_c/mercury_lib.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ standalone_c/mercury_lib.m	22 Feb 2007 06:32:11 -0000
@@ -0,0 +1,77 @@
+%-----------------------------------------------------------------------------%
+% 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.
+%-----------------------------------------------------------------------------%
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list