[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