[mercury-users] SegV on ROTD2006-04-26.sun.sparc.solaris2.8 on pointer passing with cc

Julien Fischer juliensf at cs.mu.OZ.AU
Thu Jun 22 02:09:24 AEST 2006



On Tue, 20 Jun 2006 doug.auclair at logicaltypes.com wrote:

> Dear Julien, you wrote:
>
> >Has the runtime been initialised?
>
> No, it hasn't.  I also don't see in the manuals (user's, lib, & lang)
> how to do that ... would you kindly let me know what I need to do ...
> where do I scrutinize to obtain this information? I missed
> it in the two passes I took of the manuals after I read your
> response.

It's not in any of the documentation because it's not something we recommend
doing.  The reason your code was seg faulting was that the runtime hadn't been
initialised - calling small predicates that do integer arithmetic just happens
to work because they don't rely on any runtime services, however things like
I/O operations do.

Currently, if you want to call Mercury code from a C program what we recommend
is that you have main/2 in Mercury call the C program's main() (although it
will obviously need a different name) function and then make calls back to
exported Mercury predicates as necessary.  This ensures that the Mercury runtime
is initialised correctly  (See the various examples in samples/c_interface.)

IIRC, what you are trying to do is have a library of Mercury code that is
called from C a program where main is defined in C (i.e. there is no Mercury
main/2 anywhere in your code)?

Short answer:

We don't really currently provide any user-level support for that (and what
support we do provide isn't really documented).

Longer answer:

The longer answer depends on the details of what happens when Mercury programs
are executed, in particular how the runtime environment is initialised.  The
following description is specific to the C backends (the Java and IL backends
handle some of the details a little differently).

For every executable foo that it creates the Mercury compiler also creates
an initialisation file, typically called foo_init.c (if main/2 resided in
foo.m for example).  This file contains a number of C functions that are used
for interacting with the runtime.  It also contains the function main(), which
looks likes this:

	int
	main(int argc, char **argv)
	{
	   return mercury_main(argc, argv);
	}

The function mercury_main() is also from the _init.c file.  It looks like
this:

	int
	mercury_main(int argc, char **argv)
	{
	   void *dummy;
	   mercury_init(argc, argv, &dummy);
	   mercury_call_main();
	   return mercury_terminate();
	}

The call to mercury_init() is responsible for initialising the runtime (more
on which shortly).  mercury_call_main() does what its name suggests and calls
the main/2 predicate and mercury_terminate() makes sure that the runtime is
shutdown correctly.

The function mercury_init() is where our program first interacts with the
runtime.  The Mercury runtime exports a number of global variables that it
expects the code in the _init.c file to set to appropriate values.  The main
thing that mercury_init() does is set the values of those globals.  Having
done that it then calls the function mercury_runtime_init() (defined in
runtime/mercury_wrapper.c) to finish initialising the runtime.  Here's a
cut-down version of the mercury_init() function generated for samples/hello.

	void
	mercury_init(int argc, char **argv, void *stackbottom)
	{

	   MR_address_of_mercury_init_io = mercury_init_io;
	   MR_address_of_init_modules = init_modules;
	   MR_address_of_init_modules_type_tables = init_modules_type_tables;
	   MR_address_of_init_modules_debugger = init_modules_debugger;

	   MR_address_of_init_modules_required = init_modules_required;
	   MR_address_of_final_modules_required = final_modules_required;

           ...

	   MR_program_entry_point = main_2_p_0;

	   MR_runtime_flags = "";

	   mercury_runtime_init(argc, argv);

	   return;
	}

The function mercury_runtime_init() is responsible for things like:

	* initialising the garbage collector (if we are in a grade that
	  uses garbage collection)
	* processing command line arguments
	* processing environment variables, e.g. the MERCURY_OPTIONS
	  variable
	* initialising the standard library, e.g. setting up standard file
	  streams etc.
	* calling any user-defined initialisation predicates

(In debugging or profiling grades it also does a bit of other stuff related to
those things as well.)

Once mercury_init() has done its job we're about ready to start running
Mercury code.  The function mercury_call_main() just calls the function
mercury_runtime_main() (also defined in runtime/mercury_wrapper.c) which runs
the Mercury predicate that the global MR_program_entry_point is pointing to.
(The exact mechanisms depend on whether we are using the high-level or
low-level backends but that distinction isn't important here.)

Once main/2 has finished we call mercury_terminate() which in turn calls
mercury_runtime_terminate() (also defined in runtime/mercury_wrapper.c) which
shuts the runtime down in an orderly fashion, e.g. runs user-defined
finalisers, closes file streams etc.

In the situation where you want to call Mercury code from an application
written in C (or possibly something else) you need to make sure that the above
runtime initialisation takes places.  There are a few ways you can ensure
this:

(1) As mentioned above have the Mercury main/2 predicate call the "real" main
    function in the manner of the examples in the samples directory.

If you want to define your own main() function in C then that won't work.

(2) Use the compiler's `--no-main' option.  This causes it to omit the
    main() function from the _init.c file.  You can then call the various
    functions from the _init.c file from your own main function.

There isn't really any documentation for the above approach but there is a
rather prominent example, the compiler itself.  The Mercury compiler together
with top_level_init.c is built as a library and then linked with the main
function defined in the file main.c (in the top-level of the Mercury source
tree.)  (The comments in main.c and compiler/Mmakefile are about the best
documentation we can provide here.)

[The reason we have this is for the GCC backend where we need to build the
compiler as a library and then link it against gcc].

A possible problem with this approach is that if your Mercury code doesn't
define main/2 then you will probably need to edit the _init.c file by hand
(the value of MR_program_entry_point will refer to something doesn't exist).

Also, if you have built your code as a Mercury library there will be an
additional problem in that the compiler will not have generated the _init.c
file at all.  (I guess you try and use mkinit to construct it by hand,
although that's potentially quite error prone.)

While writing this I've thought up an alternative method for doing this would
allow you to specify a group of Mercury libraries and have the compiler
generate a small library that would initialise the runtime sufficiently to
call any exported predicates in those libraries.  While I won't claim that
this alternative is truly marvellous, this mailing list is to narrow to
contain it ;-) (I'll post the details to mercury-developers sometime in the
next couple of days.)

Julien.
--------------------------------------------------------------------------
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-users-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the users mailing list