[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