[m-rev.] for review: auto detection of library grades

Julien Fischer jfischer at opturion.com
Wed Aug 28 17:47:00 AEST 2013


For review by anyone.

This change has also revealed a bug in the existing library grade check in
mmc --make; I will fix that separately since that fix also needs to go on
to the 13.05 branch.

--------------------


Auto detection of standard library grades.

Currently, the set of installed standard library grades is hardcoded in
Mercury's configuration file (and some other spots, but they are not relevant
here).  This change modifies the compiler so it can scan the standard library
directory at runtime in order to determine what library grades are installed.
This removes the need for the set of library grades to be specified in the
configuration file at all.  Adding or removing grades from an existing
installation should now not require changes to any configuration files
(provided you don't use mmake -- see below).

In the case where the library grades are specified in the Mercury.config file
and auto detection is also enabled, the auto detected grades will override any
--libgrade settings from the Mercury.config file.

Automatic detection of library grades is not supported with mmake and I don't
have any plans to support it.  mmake will just use the set of grades with
which the installation was configured.

compiler/options.m:
 	Add a new option `--auto-detect-libgrades' that can be used to control
 	the new feature.  For now, this is a developer-only option and is
 	disabled by default -- I will document it properly when it is enabled
 	by default.

compiler/mercury_compile.m:
 	Scan the standard library directory to see what grades are installed
 	and set the options necessary to make the set of library grades those
 	that were detected.

compiler/options_file.m:
 	Add a predicate for looking up the value of the MERCURY_STDLIB_DIR
 	variable.

Julien.

diff --git a/compiler/mercury_compile.m b/compiler/mercury_compile.m
index 9e690bb..8623595 100644
--- a/compiler/mercury_compile.m
+++ b/compiler/mercury_compile.m
@@ -89,6 +89,7 @@
  :- import_module assoc_list.
  :- import_module bool.
  :- import_module cord.
+:- import_module dir.
  :- import_module gc.
  :- import_module getopt_io.
  :- import_module list.
@@ -235,6 +236,7 @@ real_main_after_expansion(CmdLineArgs, !IO) :-
              OptionArgs = [],
              NonOptionArgs = []
          ),
+        AutoDetectedGradeFlags = [],
          Variables = options_variables_init,
          MaybeMCFlags = yes([])
      ;
@@ -258,6 +260,7 @@ real_main_after_expansion(CmdLineArgs, !IO) :-
                  (
                      FlagsErrors = [_ | _],
                      usage_errors(FlagsErrors, !IO),
+                    AutoDetectedGradeFlags = [],
                      Variables = options_variables_init,
                      MaybeMCFlags = no
                  ;
@@ -271,14 +274,20 @@ real_main_after_expansion(CmdLineArgs, !IO) :-
                          (
                              MaybeVariables = yes(Variables),
                              lookup_mmc_options(FlagsArgsGlobals, Variables,
-                                MaybeMCFlags, !IO)
+                                MaybeMCFlags, !IO),
+                            lookup_mercury_stdlib_dir(FlagsArgsGlobals, Variables,
+                                MaybeMerStdLibDir, !IO),
+                            auto_detect_libgrades(FlagsArgsGlobals, MaybeMerStdLibDir,
+                                AutoDetectedGradeFlags, !IO)
                          ;
                              MaybeVariables = no,
                              MaybeMCFlags = no,
+                            AutoDetectedGradeFlags = [],
                              Variables = options_variables_init
                          )
                      ;
                          MaybeConfigFile = no,
+                        AutoDetectedGradeFlags = [],
                          Variables = options_variables_init,
                          lookup_mmc_options(FlagsArgsGlobals, Variables,
                              MaybeMCFlags, !IO)
@@ -287,18 +296,20 @@ real_main_after_expansion(CmdLineArgs, !IO) :-
              ;
                  MaybeMCFlags0 = no,
                  Variables = options_variables_init,
+                AutoDetectedGradeFlags = [],
                  MaybeMCFlags = no
              )
          ;
              MaybeVariables0 = no,
              Variables = options_variables_init,
+            AutoDetectedGradeFlags = [],
              MaybeMCFlags = no
          )
      ),
      (
          MaybeMCFlags = yes(MCFlags),
-        handle_given_options(MCFlags ++ OptionArgs, _, _, _,
-            Errors, ActualGlobals, !IO),
+        AllFlags = MCFlags ++ AutoDetectedGradeFlags ++ OptionArgs,
+        handle_given_options(AllFlags, _, _, _, Errors, ActualGlobals, !IO),

          % When computing the option arguments to pass to `--make', only include
          % the command-line arguments, not the contents of DEFAULT_MCFLAGS.
@@ -2025,6 +2036,107 @@ maybe_output_prof_call_graph(Verbose, Stats, !HLDS, !IO) :-
      ).

  %-----------------------------------------------------------------------------%
+%
+% Library grade detection.
+%
+
+:- pred auto_detect_libgrades(globals::in, maybe(list(string))::in,
+    list(string)::out, io::di, io::uo) is det.
+
+auto_detect_libgrades(Globals, MaybeConfigMerStdLibDir, GradeOpts, !IO) :-
+    globals.lookup_bool_option(Globals, auto_detect_libgrades, AutoDetect),
+    (
+        AutoDetect = yes,
+        ( if
+            % Was the standard library directory set on the command line?
+            % 
+            globals.lookup_maybe_string_option(Globals,
+                mercury_standard_library_directory, MaybeStdLibDir),
+            MaybeStdLibDir = yes(MerStdLibDir)
+        then
+            do_auto_detect_libgrades(MerStdLibDir, GradeOpts, !IO)
+        else if
+            % Was the standard library directory set using the
+            % MERCURY_STDLIB_DIR variable?
+            MaybeConfigMerStdLibDir = yes([MerStdLibDir])
+        then
+            do_auto_detect_libgrades(MerStdLibDir, GradeOpts, !IO)
+        else
+            GradeOpts = [] 
+        )
+    ;
+        AutoDetect = no,
+        GradeOpts = []
+    ).
+
+:- pred do_auto_detect_libgrades(string::in, list(string)::out,
+    io::di, io::uo) is det.
+
+do_auto_detect_libgrades(StdLibDir, GradeOpts, !IO) :-
+    ModulesDir = StdLibDir / "modules",
+    dir.foldl2(do_auto_detect_libgrade, ModulesDir, [], MaybeGradeOpts, !IO),
+    (
+        MaybeGradeOpts = ok(GradeOpts0),
+        (
+            GradeOpts0 = [],
+            GradeOpts = GradeOpts0
+        ;
+            GradeOpts0 = [_ | _],
+            % Override any --libgrades settings from Mercury.config.
+            GradeOpts = ["--no-libgrade" | GradeOpts0]
+        )
+    ;
+        MaybeGradeOpts = error(_, _),
+        GradeOpts = []
+    ).
+
+:- pred do_auto_detect_libgrade(string::in, string::in, io.file_type::in,
+    bool::out, list(string)::in, list(string)::out, io::di, io::uo) is det.
+
+do_auto_detect_libgrade(DirName, FileName, FileType, Continue, !GradeOpts, !IO) :-
+    (
+        FileType = directory,
+        (
+            % We do not generate .init files for the non-C grades so just check
+            % for directories in StdLibDir / "modules" containing the name of
+            % their base grade.
+            %
+            ( string.prefix(FileName, "csharp")
+            ; string.prefix(FileName, "erlang")
+            ; string.prefix(FileName, "java")
+            )
+        ->
+            !:GradeOpts = ["--libgrade", FileName | !.GradeOpts]
+        ;
+            % For C grades, we check for the presence of the .init file for
+            % mer_std to test whether the grade is present or not.
+            %
+            InitFile = DirName / FileName / "mer_std.init",
+            io.check_file_accessibility(InitFile, [read], Result, !IO),
+            (
+                Result = ok,
+                !:GradeOpts = ["--libgrade", FileName | !.GradeOpts]
+            ;
+                Result = error(_)
+            )
+        ),
+        Continue = yes
+    ;
+        ( FileType = regular_file
+        ; FileType = symbolic_link
+        ; FileType = named_pipe
+        ; FileType = socket
+        ; FileType = character_device
+        ; FileType = block_device
+        ; FileType = message_queue
+        ; FileType = semaphore
+        ; FileType = shared_memory
+        ; FileType = unknown
+        ),
+        Continue = yes
+    ).
+
+%-----------------------------------------------------------------------------%

  :- pred gc_init(io::di, io::uo) is det.

diff --git a/compiler/options.m b/compiler/options.m
index 40121d8..755a994 100644
--- a/compiler/options.m
+++ b/compiler/options.m
@@ -980,6 +980,7 @@
      ;       mercury_configuration_directory_special
      ;       install_command
      ;       install_command_dir_option
+    ;       auto_detect_libgrades
      ;       libgrades
      ;       libgrades_include_components
      ;       libgrades_exclude_components
@@ -1893,6 +1894,7 @@ option_defaults_2(build_system_option, [
      mercury_configuration_directory     -   maybe_string(no),
      install_command                     -   string("cp"),
      install_command_dir_option          -   string("-r"),
+    auto_detect_libgrades               -   bool(no),
      libgrades                           -   accumulating([]),
      libgrades_include_components        -   accumulating([]),
      libgrades_exclude_components        -   accumulating([]),
@@ -2864,6 +2866,7 @@ long_option("install-command",      install_command).
  long_option("install-command-dir-option", install_command_dir_option).
  long_option("use-symlinks",         use_symlinks).
  long_option("library-grade",        libgrades).
+long_option("auto-detect-libgrades", auto_detect_libgrades).
  long_option("libgrade",             libgrades).
  long_option("libgrades-include-component", libgrades_include_components).
  long_option("libgrades-include",           libgrades_include_components).
@@ -5786,6 +5789,11 @@ options_help_build_system -->
          "\ta directory. The given command will be invoked as",
          "\t`<command> <option> <source> <target>'",
          "\tto install each directory. The default option is `-r'.",
+
+        % `--auto-detect-libgrades' is a developer-only that controls
+        % whether the compiler should scan the installation directory
+        % to determine what standard library grades are available.
+
          "--libgrade <grade>",
          "\tAdd <grade> to the list of compilation grades in",
          "\twhich a library to be installed should be built.",
diff --git a/compiler/options_file.m b/compiler/options_file.m
index b7e19e7..6ad9a27 100644
--- a/compiler/options_file.m
+++ b/compiler/options_file.m
@@ -73,6 +73,11 @@
  :- pred lookup_main_target(globals::in, options_variables::in,
      maybe(list(string))::out, io::di, io::uo) is det.

+    % Look up $(MERCURY_STDLIB_DIR).
+    %
+:- pred lookup_mercury_stdlib_dir(globals::in, options_variables::in,
+    maybe(list(string))::out, io::di, io::uo) is det.
+
  %-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%

@@ -835,6 +840,24 @@ lookup_main_target(Globals, Vars, MaybeMainTarget, !IO) :-
          MaybeMainTarget = no
      ).

+%-----------------------------------------------------------------------------%
+
+lookup_mercury_stdlib_dir(Globals, Vars, MaybeMerStdlibDir, !IO) :-
+    lookup_variable_words_report_error(Globals, Vars, "MERCURY_STDLIB_DIR",
+        MerStdlibDirResult, !IO),
+    (
+        MerStdlibDirResult = var_result_set(MerStdlibDir),
+        MaybeMerStdlibDir = yes(MerStdlibDir)
+    ;
+        MerStdlibDirResult = var_result_unset,
+        MaybeMerStdlibDir = yes([])
+    ;
+        MerStdlibDirResult = var_result_error(_),
+        MaybeMerStdlibDir = no
+    ).
+
+%-----------------------------------------------------------------------------%
+
  lookup_default_options(Globals, Vars, Result, !IO) :-
      lookup_mmc_maybe_module_options(Globals, Vars, default, Result, !IO).




More information about the reviews mailing list