[mercury-users] Can Mercury be used to build an API?

Fergus Henderson fjh at cs.mu.oz.au
Thu Apr 3 13:38:04 AEST 1997


Peter Ludemann, you wrote:
> 
> I'm casting about for a higher-level language for producing a library
> ... it needs to be C/C++-callable.  I looked through the Mercury
> manuals and found hints about calling Mercury from C but couldn't
> figure out the details.

This aspect is not very well documented yet (sorry).
There are however some examples of how to do this in
the samples/c_interface/c_calls_mercury directory in
the source and binary distributions.

> So, can I easily create a C-callable API with Mercury?

It is reasonably easy.

We've made some improvements in the C interface since the latest public
release, 0.6.  From the draft NEWS file for Mercury 0.7:

 |   The C interface now handles Mercury functions properly --
 |   previously it only handled predicates, not functions. 
 |   Also, exporting semidet predicates or functions to C now works
 |   (see `samples/c_interface/c_calls_mercury.m' for some examples).
 |   We've included some examples of how to use the C interface
 |   to interface with C++.

In 0.6 `main' must be in Mercury, to ensure that the Mercury runtime
system gets properly initialized, but it need to nothing more
than call a C function `c_main' that does all the work.
In 0.7 `main' can be in C or C++; you just need to call a function to
initialize the Mercury runtime system before calling any other Mercury
predicates or functions.

> It wouldn't be acceptable to do
>        start_mercury();  call();  call();  stop_mercury();
> but it would be OK to do
>        obj = create_my_api_object();
>          call(obj, ...);
>          call(obj, ...);
>        destroy_my_api_object(obj);

I don't understand the difference here; why is the former unacceptable?

In Mercury 0.6, it would like roughly like this:

	c_main() {
		create_my_api_object(&obj);
		foo(obj, ...);
		bar(obj, ...);
		...
		create_my_api_object(&anotherobj);
		foo(anotherobj, ...);
		bar(anotherobj, ...);
	}

Then on the Mercury side you need

	main -->
		c_main.

In Mercury 0.7, it can be a bit simpler:

	main() {
		mercury_main(...);	/* like your `start_mercury()' */
		...
		obj = create_my_api_object();
		foo(obj, ...);
		bar(obj, ...);
		...
		anotherobj = create_my_api_object();
		foo(anotherobj, ...);
		bar(anotherobj, ...);
	}

In both 0.6 & 0.7, there's usually no need to call destroy_my_api_object(),
because the conservative garbage collector will recover the storage
automatically.

> [Assuming that create_my_api_object can create the Mercury
> environment; and assuming that I could have multiple Mercury
> environments if necessary, and that they would have fairly small
> "footprints".]

The way the current implementation works, there is only one Mercury
environment.  But you can have multiple Mercury API objects.
The Mercury engine is reentrant in the sense that you can have
Mercury calls C calls Mercury calls C calls...
It's not multithreaded, though; you can't have multiple threads running
Mercury code simultaneously. 

We're working on a multithreaded version.  In the multithreaded
version, there is still a single Mercury engine, but you can have
multiple "contexts" (different Mercury threads share a single heap, but
they each have their own stacks).  However, the multithreaded version
is not yet ready for prime-time.

So, does that answer your queries?
Is Mercury suitable for your requirements?

Cheers,
	Fergus.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3         |     -- the last words of T. S. Garp.



More information about the users mailing list