[m-rev.] for review: standalone interfaces
Peter Ross
pro at missioncriticalit.com
Thu Feb 8 01:12:10 AEDT 2007
On Mon, Feb 05, 2007 at 05:41:21PM +1100, Julien Fischer wrote:
>
> There is no documentation for the following yet, however Peter Ross has been
> requesting this (and presumably he can work out how to use it for himself.)
>
> Also, while working on this one of the problems I ran into is that the
> compiler
> sets the standard output stream to be different things at different points.
> This is quite confusing and extremely annoying to debug if it goes wrong.
> I would like to (a) change the compiler so that all streams are explicit
> arguments and (b) change the coding standards to say that implicit streams
> shouldn't be used. (It's quite large change but it should be fairly
> trivial.)
> Objections?
>
> For review by anyone.
>
> Estimated hours taken: 20
> Branches: main
>
> Improve support for calling procedures in Mercury libraries from
> applications written in foreign languages, i.e where the program entry point
> is not the Mercury predicate main/2. The main trick is to ensure that the
> necessary runtime initialisation is done before any Mercury procedures are
> called (or at least to provide the mechanism to do such initialisation,
> ensuring that it is done is the programmer's responsibility.)
>
> We currently support this sort of thing via the compiler's `--no-main'
> option. This diff adds a more user friendly mechanism (at least on the
> Mercury side.) In particular, we no longer require that one of the Mercury
> libraries define a main/2 predicate. (Note: the existing behaviour of
> --no-main is unchanged.)
>
> For the set of Mercury libraries that we wish to use from a foreign
> application we create a standalone interface. A standalone interface is a
> cut-down version of the _init.c file that would be created for a Mercury
> executable that uses the same set of libraries. (Which libraries to include
> in the interface can be specified via the usual mechanisms, e.g. the --ml
> option.)
>
> The standalone interface has two parts: an object file that contains the
> cut-down version of the _init.c file, and a header file that contains the
> declarations for the functions that initialise and shut down the Mercury
> runtime. This header file is compatible with both C and C++.
>
> compiler/options.m:
> Add a new option `--generate-standalone-interface' that causes the
> compiler to generate a header/object pair that can be used to
> intialise/shut down the Mercury runtime from a foreign application.
> The basename of the header/object pair is given as an argument to
> this
> option.
>
> compiler/mercury_compile.m:
> Create the standalone interface if invoked with
> `--generate-standalone-interface'.
>
> Emit an error message if `--generate-standalone-interface' is
> specified with `--target java' or `--target il'. We don't
> currently support that.
>
> compiler/compile_target_code.m:
> Add code to implement the `--generate-standalone-interface' option.
>
> Fix a typo: s/Serarator/Separator/.
>
> Fix an overlong line.
>
> compiler/handle_options.m:
> Emit an error message if `--generate-standalone-interface' and
> `--extra-inits' are specified together.
>
> util/mkinit.c:
> Add a new mode of operation that generates standalone interfaces.
> The principle differences between a standalone interface and a
> _init.c file are that the former sets the program entry point to
> MR_dummy_main and does not create a main function.
>
> The new `-s' option tells mkinit to create a standalone interface.
> (Note that `-s' implies `-l'.)
>
> Add a comment pointing to various places that may need to updated if
> mkinit.c is changed.
>
> runtime/mercury_wrapper.{h,c}:
> Add a new procedure MR_dummy_main for use with standalone
> interfaces. Any attempt to call main/2 through the usual entry
> point when operating in standalone mode will cause a runtime abort.
>
> Julien.
>
> Index: compiler/compile_target_code.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/compiler/compile_target_code.m,v
> retrieving revision 1.103
> diff -u -r1.103 compile_target_code.m
> --- compiler/compile_target_code.m 8 Jan 2007 03:03:08 -0000 1.103
> +++ compiler/compile_target_code.m 5 Feb 2007 06:22:33 -0000
> @@ -167,6 +167,14 @@
> is det.
>
> %-----------------------------------------------------------------------------%
> +
> + % make_standalone_interface(Basename, !IO):
> + %
> + % Create a standalone interface in the current directory.
> + %
> +:- pred make_standalone_interface(string::in, io::di, io::uo) is det.
> +
More description of what a stand-alone interface is needed (eg what you
have in the log message).
> @@ -1985,6 +1994,150 @@
> maybe_pic_object_file_extension(Globals, PIC, ObjExt).
>
> %-----------------------------------------------------------------------------%
> +%
> +% Standalone interfaces
> +%
> +
> +% NOTE: the following code is similar to that of make_init_obj/7. Any
> +% changes here may need to be reflected there.
> +
> +make_standalone_interface(Basename, !IO) :-
> + make_standalone_int_header(Basename, HdrSucceeded, !IO),
> + (
> + HdrSucceeded = yes,
> + make_standalone_int_body(Basename, !IO)
> + ;
> + HdrSucceeded = no
> + ).
> +
> +:- pred make_standalone_int_header(string::in, bool::out,
> + io::di, io::uo) is det.
> +
> +make_standalone_int_header(Basename, Succeeded, !IO) :-
> + HdrFileName = Basename ++ ".h",
> + io.open_output(HdrFileName, OpenResult, !IO),
> + (
> + OpenResult = ok(HdrFileStream),
> + io.write_strings(HdrFileStream, [
> + "#ifndef ", to_upper(Basename), "_H\n",
> + "#define ", to_upper(Basename), "_H\n",
> + "\n",
> + "#ifdef __cplusplus\n",
> + "extern \"C\" {\n",
> + "#endif\n",
> + "\n",
> + "extern void\n",
> + "mercury_init(int argc, char **argv, void *stackbottom);\n",
> + "\n",
> + "extern int\n",
> + "mercury_terminate(void);\n",
> + "\n",
> + "#ifdef __cplusplus\n",
> + "}\n",
> + "#endif\n",
> + "\n",
> + "#endif /* ", to_upper(Basename), "_H */\n"],
> + !IO),
> + io.close_output(HdrFileStream, !IO),
> + Succeeded = yes
> + ;
> + OpenResult = error(Error),
> + unable_to_open_file(HdrFileName, Error, !IO),
> + Succeeded = no
> + ).
> +
> +:- pred make_standalone_int_body(string::in, io::di, io::uo) is det.
> +
> +make_standalone_int_body(Basename, !IO) :-
> + globals.io_get_globals(Globals, !IO),
> + globals.lookup_accumulating_option(Globals, init_files, InitFiles0),
> + globals.lookup_accumulating_option(Globals, trace_init_files,
> + TraceInitFiles0),
> + globals.lookup_maybe_string_option(Globals,
> + mercury_standard_library_directory, MaybeStdLibDir),
> + grade_directory_component(Globals, GradeDir),
> + (
> + MaybeStdLibDir = yes(StdLibDir),
> + InitFiles1 = [
> + StdLibDir / "modules" / GradeDir / "mer_rt.init",
> + StdLibDir / "modules" / GradeDir / "mer_std.init" |
> + InitFiles0
> + ],
> + TraceInitFiles = [
> + StdLibDir / "modules" / GradeDir / "mer_browser.init",
> + StdLibDir / "modules" / GradeDir / "mer_mdbcomp.init" |
> + TraceInitFiles0
> + ]
> + ;
> + % Supporting `--no-mercury-standard-library-directory' is necessary
> + % in order to use `--generate-standalone-interface' with the
> + % the lmc script.
> + MaybeStdLibDir = no,
> + InitFiles1 = InitFiles0,
> + TraceInitFiles = TraceInitFiles0
> + ),
> + globals.get_trace_level(Globals, TraceLevel),
> + ( given_trace_level_is_none(TraceLevel) = no ->
> + TraceOpt = "-t",
> + InitFiles = InitFiles1 ++ TraceInitFiles
> + ;
> + TraceOpt = "",
> + InitFiles = InitFiles1
> + ),
> + join_string_list(InitFiles, "", "", " ", InitFilesList),
> + globals.lookup_accumulating_option(Globals, runtime_flags,
> + RuntimeFlagsList),
> + join_quoted_string_list(RuntimeFlagsList, "-r ", "", " ",
> RuntimeFlags),
> + globals.lookup_string_option(Globals, experimental_complexity,
> + ExperimentalComplexity),
> + ( ExperimentalComplexity = "" ->
> + ExperimentalComplexityOpt = ""
> + ;
> + ExperimentalComplexityOpt = "-X " ++ ExperimentalComplexity
> + ),
> + compute_grade(Globals, Grade),
> + globals.lookup_string_option(Globals, mkinit_command, MkInit),
> + CFileName = Basename ++ ".c",
> + io.output_stream(ErrorStream, !IO),
> + MkInitCmd = string.append_list(
> + [ MkInit,
> + " -g ", Grade,
> + " ", TraceOpt,
> + " ", ExperimentalComplexityOpt,
> + " ", RuntimeFlags,
> + " -o ", quote_arg(CFileName),
> + " -s ", InitFilesList
> + ]),
> + invoke_system_command(ErrorStream, cmd_verbose, MkInitCmd, MkInitCmdOk,
> + !IO),
> + (
> + MkInitCmdOk = yes,
> + get_object_code_type(executable, PIC, !IO),
> + maybe_pic_object_file_extension(PIC, ObjExt, !IO),
> + ObjFileName = Basename ++ ObjExt,
> + compile_c_file(ErrorStream, PIC, CFileName, ObjFileName,
> + CompileOk, !IO),
> + (
> + CompileOk = yes
> + ;
> + CompileOk = no,
> + io.set_exit_status(1, !IO),
> + io.write_string("mercury_compile: error while compiling ",
> !IO),
> + io.write_string("standalone interface in `", !IO),
> + io.write_string(CFileName, !IO),
> + io.write_string("'\n", !IO)
> + )
> + ;
> + MkInitCmdOk = no,
> + io.set_exit_status(1, !IO),
> + io.write_string("mercury_compile: error while creating ", !IO),
> + io.write_string("standalone interface in `", !IO),
> + io.write_string(CFileName, !IO),
> + io.write_string("'\n", !IO)
> + ).
> +
Is it possible to factor out the code which is common to make_init_obj?
I imagine a lot of it is exactly the same.
Otherwise this looks fine.
--------------------------------------------------------------------------
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