[m-rev.] for review: fix library intialisers / finalisers

Julien Fischer juliensf at cs.mu.OZ.AU
Tue May 16 16:51:43 AEST 2006


For review by Zoltan.

Estimated hours taken: 7
Branches: main, release

Fix the bug with initialisers/finalisers in libraries not being called (and as
a consequence also fixes the bugs with mutables not being given their correct
initial values.  The problem was that the directives necessary to call them
were not being included in the libraries' .init file.

The fix is to add a new mode of operation to mkinit that given a list of .c
files that make up some Mercury library, constructs the .init file for that
library.  In particular, it now constructs the .init file so that it contains
any REQUIRED_{INIT,FINAL} directives needed by the library.  The new mode of
operation is invoked when mkinit is given the `-k' option.

Modify the build systems (i.e. mmake and mmc --make) to conform to the above
change.

util/mkinit.c:
	Add a new mode of operation, `-k'.  When invoked with this
	option mkinit will read a list of .c files and emit a sequence of
	INIT, REQUIRED_INIT and REQUIRED_FINAL directives to stdout,
	corresponding to INIT, REQUIRED_INIT and REQUIRED_FINAL comments
	in the .c files.

compiler/modules.m:
	Change the rule mmake uses to build .init files so that it calls
	mkinit -k on all the .c files generated for the library.

scripts/Mmake.vars.in:
	Add a new mmake variable MKLIBINIT.  This is the program used to
	create .init files.  (It will nearly always be mkinit.)

compiler/compile_target_code.m:
	Change how .init files are built.  We now have to call mkinit -k to
	scan all of the .c files to write out the correct set of INIT,
	REQUIRED_INIT and REQUIRED_FINAL directives.  The code here is
	that used by mmc --make for creating the .init files.

compiler/make.program_target.m:
	Build the .init file after building the .c files, since building
	it before will no longer work.

Julien.

Index: compiler/compile_target_code.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/compile_target_code.m,v
retrieving revision 1.86
diff -u -r1.86 compile_target_code.m
--- compiler/compile_target_code.m	12 May 2006 04:32:03 -0000	1.86
+++ compiler/compile_target_code.m	16 May 2006 03:51:35 -0000
@@ -866,18 +866,39 @@
     io.open_output(TmpInitFileName, InitFileRes, !IO),
     (
         InitFileRes = ok(InitFileStream),
-        list.foldl(make_init_file(InitFileStream), AllModules, !IO),
-        globals.io_lookup_maybe_string_option(extra_init_command,
-            MaybeInitFileCommand, !IO),
-        (
-            MaybeInitFileCommand = yes(InitFileCommand),
-            make_all_module_command(InitFileCommand, MainModuleName,
-                AllModules, CommandString, !IO),
-            invoke_system_command(InitFileStream, verbose_commands,
-                CommandString, Succeeded0, !IO)
+        ModuleNameToCFileName =
+            (pred(ThisModule::in, CFileName::out, !.IO::di, !:IO::uo) is det :-
+                module_name_to_file_name(ThisModule, ".c", no, CFileName, !IO)
+        ),
+        list.map_foldl(ModuleNameToCFileName, AllModules, AllCFilesList, !IO),
+        join_quoted_string_list(AllCFilesList, "", "", " ", CFileNames),
+
+        globals.io_lookup_string_option(mkinit_command, MkInit, !IO),
+        MkInitCmd = string.append_list(
+            [   MkInit,
+                " -k ",
+                " ", CFileNames
+            ]),
+        invoke_system_command(InitFileStream, verbose, MkInitCmd, MkInitOK,
+            !IO),
+
+        (
+            MkInitOK =  yes,
+            globals.io_lookup_maybe_string_option(extra_init_command,
+                MaybeInitFileCommand, !IO),
+            (
+                MaybeInitFileCommand = yes(InitFileCommand),
+                make_all_module_command(InitFileCommand, MainModuleName,
+                    AllModules, CommandString, !IO),
+                invoke_system_command(InitFileStream, verbose_commands,
+                    CommandString, Succeeded0, !IO)
+            ;
+                MaybeInitFileCommand = no,
+                Succeeded0 = yes
+            )
         ;
-            MaybeInitFileCommand = no,
-            Succeeded0 = yes
+            MkInitOK   = no,
+            Succeeded0 = no
         ),

         io.close_output(InitFileStream, !IO),
@@ -898,16 +919,6 @@
         Succeeded = no
     ).

-:- pred make_init_file(io.output_stream::in, module_name::in,
-    io::di, io::uo) is det.
-
-make_init_file(InitFileStream, ModuleName, !IO) :-
-    InitFuncName0 = make_init_name(ModuleName),
-    InitFuncName = InitFuncName0 ++ "init",
-    io.write_string(InitFileStream, "INIT ", !IO),
-    io.write_string(InitFileStream, InitFuncName, !IO),
-    io.nl(InitFileStream, !IO).
-
 %-----------------------------------------------------------------------------%

 link_module_list(Modules, FactTableObjFiles, Succeeded, !IO) :-
Index: compiler/make.program_target.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make.program_target.m,v
retrieving revision 1.47
diff -u -r1.47 make.program_target.m
--- compiler/make.program_target.m	17 Mar 2006 01:40:25 -0000	1.47
+++ compiler/make.program_target.m	16 May 2006 03:39:18 -0000
@@ -5,12 +5,13 @@
 % This file may only be copied under the terms of the GNU General
 % Public License - see the file COPYING in the Mercury distribution.
 %-----------------------------------------------------------------------------%
-
+%
 % File: make.program_target.m.
 % Main author: stayl.
-
+%
 % Build targets which relate to whole programs or libraries.
-
+%
+%-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%

 :- module make.program_target.
@@ -560,32 +561,33 @@
             IntSucceeded, !Info, !IO),
         (
             IntSucceeded = yes,
-            % Errors while making the `.init' file should be very rare.
-            io.output_stream(ErrorStream, !IO),
-            compile_target_code.make_init_file(ErrorStream, MainModuleName,
-                AllModules, InitSucceeded, !IO),
+            make_linked_target(MainModuleName - static_library,
+                StaticSucceeded, !Info, !IO),
+            shared_libraries_supported(SharedLibsSupported, !IO),
             (
-                InitSucceeded = yes,
-                make_linked_target(MainModuleName - static_library,
-                    StaticSucceeded, !Info, !IO),
-                compile_target_code.shared_libraries_supported(
-                    SharedLibsSupported, !IO),
+                StaticSucceeded = yes,
+                (
+                    SharedLibsSupported = yes,
+                    make_linked_target(MainModuleName - shared_library,
+                        SharedLibsSucceeded, !Info, !IO)
+                ;
+                    SharedLibsSupported = no,
+                    SharedLibsSucceeded = yes
+                ),
+                % We can only build the .init file if we have succesfully
+                % built the .c files.
                 (
-                    StaticSucceeded = yes,
-                    (
-                        SharedLibsSupported = yes,
-                        make_linked_target(MainModuleName - shared_library,
-                            Succeeded, !Info, !IO)
-                    ;
-                        SharedLibsSupported = no,
-                        Succeeded = yes
-                    )
+                    SharedLibsSucceeded = yes,
+                    % Errors while making the .init file should be very rare.
+                    io.output_stream(ErrorStream, !IO),
+                    make_init_file(ErrorStream, MainModuleName,
+                        AllModules, Succeeded, !IO)
                 ;
-                    StaticSucceeded = no,
-                    Succeeded = no
+                    SharedLibsSucceeded = no,
+                    Succeeded = no
                 )
             ;
-                InitSucceeded = no,
+                StaticSucceeded = no,
                 Succeeded = no
             )
         ;
Index: compiler/modules.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.390
diff -u -r1.390 modules.m
--- compiler/modules.m	2 May 2006 05:57:07 -0000	1.390
+++ compiler/modules.m	16 May 2006 06:40:22 -0000
@@ -5048,9 +5048,6 @@
     io.write_string(DepStream, Version, !IO),
     io.write_string(DepStream, ".\n\n", !IO),

-    map.keys(DepsMap, Modules0),
-    select_ok_modules(Modules0, DepsMap, Modules),
-
     module_name_to_make_var_name(ModuleName, MakeVarName),

     module_name_to_file_name(ModuleName, ".init", yes, InitFileName, !IO),
@@ -5270,12 +5267,16 @@

     module_name_to_file_name(ModuleName, ".dep", no, DepFileName, !IO),
     module_name_to_file_name(ModuleName, ".dv", no, DvFileName, !IO),
+
     io.write_strings(DepStream, [
         InitFileName, " : ", DepFileName, "\n",
         "\techo > ", InitFileName, "\n"
     ], !IO),
-    list.foldl(append_to_init_list(DepStream, InitFileName), Modules, !IO),
-
+    io.write_strings(DepStream, [
+        "\t$(MKLIBINIT) -k ", "$(", MakeVarName, ".cs)", " >> ",
+        InitFileName, "\n"
+    ], !IO),
+
     % $(EXTRA_INIT_COMMAND) should expand to a command to
     % generate extra entries in the `.init' file for a library.
     % It may expand to the empty string.
Index: scripts/Mmake.vars.in
===================================================================
RCS file: /home/mercury1/repository/mercury/scripts/Mmake.vars.in,v
retrieving revision 1.102
diff -u -r1.102 Mmake.vars.in
--- scripts/Mmake.vars.in	24 Feb 2006 07:11:21 -0000	1.102
+++ scripts/Mmake.vars.in	16 May 2006 06:17:39 -0000
@@ -358,6 +358,10 @@
 EXTRA_MLLIBS	=
 LIB_MLLIBS	= $(patsubst %,-l%,$(ALL_EXTRA_LIBRARIES))

+# Program used to create the .init file for a library.
+# This is usually just mkinit invoked with the `-k' option.
+MKLIBINIT	= mkinit
+
 # These only have an effect with `mmc --make'.
 LINKAGE = shared
 MERCURY_LINKAGE = @DEFAULT_LINKAGE@
Index: util/mkinit.c
===================================================================
RCS file: /home/mercury1/repository/mercury/util/mkinit.c,v
retrieving revision 1.109
diff -u -r1.109 mkinit.c
--- util/mkinit.c	5 May 2006 07:49:29 -0000	1.109
+++ util/mkinit.c	15 May 2006 06:42:43 -0000
@@ -15,6 +15,11 @@
 ** produces the initialization file (usually called *_init.c) on stdout.
 ** The initialization file is a small C program that calls the initialization
 ** functions for all the modules in a Mercury program.
+**
+** Alternatively, if invoked with the -k option, this program produces a
+** list of intialization directives on stdout.  This mode of operation is
+** is used when building .init files for libraries.
+**
 */

 /*---------------------------------------------------------------------------*/
@@ -256,6 +261,7 @@
 static MR_bool      output_main_func = MR_TRUE;
 static MR_bool      need_initialization_code = MR_FALSE;
 static MR_bool      need_tracing = MR_FALSE;
+static MR_bool      output_lib_init = MR_FALSE;
 static const char   *experimental_complexity = NULL;

 static int          num_experimental_complexity_procs = 0;
@@ -510,6 +516,8 @@
                     const char **func_names, int num_func_names);
 static  void    output_main_init_function(Purpose purpose, int num_bunches);
 static  void    output_main(void);
+static  void    output_lib_init_file(void);
+static  void    output_init_program(void);
 static  void    process_file(const char *filename);
 static  void    process_init_file(const char *filename);
 static  void    output_init_function(const char *func_name,
@@ -558,9 +566,6 @@
 int
 main(int argc, char **argv)
 {
-    int filenum;
-    int num_bunches;
-    int i;

     MR_progname = argv[0];

@@ -573,17 +578,78 @@

     set_output_file();

-    do_path_search();
-    output_headers();
+    if (output_lib_init == MR_TRUE) {
+        output_lib_init_file();         /* Output a .init file. */
+    } else {
+        output_init_program();          /* Output a _init.c file. */
+    }

-    if (need_initialization_code) {
-        printf("#define MR_MAY_NEED_INITIALIZATION\n\n");
+    if (num_errors > 0) {
+        fputs("/* Force syntax error, since there were */\n", stdout);
+        fputs("/* errors in the generation of this file */\n", stdout);
+        fputs("#error \"You need to remake this file\"\n", stdout);
+        if (output_file_name != NULL) {
+            (void) fclose(stdout);
+            (void) remove(output_file_name);
+        }
+        return EXIT_FAILURE;
+    }
+
+    return EXIT_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+** Output the initialisation file for a Mercury library, the .init file.
+*/
+static void
+output_lib_init_file(void)
+{
+    int filenum;
+    int i;
+
+    for (filenum = 0; filenum < num_files; filenum++) {
+            process_file(files[filenum]);
+    }
+
+    for (i = 0; i < std_module_next; i++) {
+        printf("INIT %s%s\n", std_modules[i], module_suffix[PURPOSE_INIT]);
     }

+    for (i = 0; i < req_init_module_next; i++) {
+        printf("REQUIRED_INIT %s\n", req_init_modules[i]);
+    }
+
+    for (i = 0; i < req_final_module_next; i++) {
+        printf("REQUIRED_FINAL %s\n", req_final_modules[i]);
+    }
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+** Output the initialisation program for a Mercury executable, the *_init.c
+** file.
+*/
+static void
+output_init_program(void)
+{
+    int filenum;
+    int num_bunches;
+    int i;
+
+    do_path_search();
+    output_headers();
+
     for (filenum = 0; filenum < num_files; filenum++) {
         process_file(files[filenum]);
     }

+    if (need_initialization_code) {
+        printf("#define MR_MAY_NEED_INITIALIZATION\n\n");
+    }
+
     std_and_special_modules = MR_NEW_ARRAY(const char *,
         std_module_next + special_module_next);

@@ -624,19 +690,6 @@
     output_main_init_function(PURPOSE_REQ_FINAL, num_bunches);

     output_main();
-
-    if (num_errors > 0) {
-        fputs("/* Force syntax error, since there were */\n", stdout);
-        fputs("/* errors in the generation of this file */\n", stdout);
-        fputs("#error \"You need to remake this file\"\n", stdout);
-        if (output_file_name != NULL) {
-            (void) fclose(stdout);
-            (void) remove(output_file_name);
-        }
-        return EXIT_FAILURE;
-    }
-
-    return EXIT_SUCCESS;
 }

 /*---------------------------------------------------------------------------*/
@@ -648,7 +701,7 @@
     int         i;
     String_List *tmp_slist;

-    while ((c = getopt(argc, argv, "A:c:g:iI:lo:r:tw:xX:")) != EOF) {
+    while ((c = getopt(argc, argv, "A:c:g:iI:lo:r:tw:xX:k")) != EOF) {
         switch (c) {
         case 'A':
             /*
@@ -738,6 +791,10 @@
             experimental_complexity = optarg;
             break;

+        case 'k':
+            output_lib_init = MR_TRUE;
+            break;
+
         default:
             usage();
         }
@@ -763,8 +820,9 @@
     fputs("  -o file:\toutput to the named file\n", stderr);
     fputs("  -r word:\tadd word to the flags for the runtime\n", stderr);
     fputs("  -t:\t\tenable execution tracing\n", stderr);
-    fputs("  -w entry:\tset the entry point to the egiven label\n", stderr);
+    fputs("  -w entry:\tset the entry point to the given label\n", stderr);
     fputs("  -I dir:\tadd dir to the search path for init files\n", stderr);
+    fputs("  -k:\t\tgenerate the .init for a library\n", stderr);
     exit(EXIT_FAILURE);
 }


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



More information about the reviews mailing list