[m-rev.] for post-commit review: make mdb interactive queries work on OS X

Julien Fischer jfischer at opturion.com
Fri Aug 21 22:13:23 AEST 2015


For post-commit review by anyone.

Make mdb interactive queries work on OS X.

browser/interactive_query.m:
     Use '.dylib' as the extension for the shared library we generate for
     interactive queries when on OS X.  (While '.so' would work in principle,
     its use is unusual on OS X and the Mercury compiler will always use
     '.dylib' anyway.)

     Replace some sequences of I/O operations with single calls to io.format
     so that message components are not spread over multiple lines.

     Add an XXX comment about object file extensions.

     Update comments that refer to 'libquery' rather than 'libmdb_query'.

README.MacOS:
     Delete interactive queries from the list of unsupported features.

tests/debugger/interactive.exp:
     Update this expected output.  The changes are due to earlier
     changes to the formatting and presentation of error messages.

Julien.

diff --git a/README.MacOS b/README.MacOS
index cbfd05b..22e4dfb 100644
--- a/README.MacOS
+++ b/README.MacOS
@@ -182,9 +182,6 @@ to your Mercury.options or Mmakefile.
  Known bugs and unsupported features
  -----------------------------------

-The following feature is not supported on Mac OS X:
-	- interactive queries in mdb
-
  The 'asm_fast' grades will not work on *-apple-darwin machines, primarily
  because of a (long-standing) bug in gcc (GCC bug #10901).  By default,
  the configure script will choose either 'reg' or 'none' as the default base
diff --git a/browser/interactive_query.m b/browser/interactive_query.m
index 0344a3e..f54d8c3 100644
--- a/browser/interactive_query.m
+++ b/browser/interactive_query.m
@@ -12,11 +12,11 @@
  % A module to invoke interactive queries using dynamic linking.
  %
  % This module reads in a query, writes out Mercury code for it to the file
-% `mdb_query.m', invokes the Mercury compiler mmc to compile that file
-% to `libmdb_query.so', dynamically loads in the object code for the module
-% `mdb_query' from the file `libmdb_query.so', looks up the address of the
-% procedure query/2 in that module, calls that procedure, and then
-% cleans up the generated files.
+% `mdb_query.m', invokes the Mercury compiler mmc to compile that file to
+% `libmdb_query.{so,dylib}', dynamically loads in the object code for the
+% module `mdb_query' from the file `libmdb_query.{so,dylib}', looks up the
+% address of the procedure query/2 in that module, calls that procedure, and
+% then cleans up the generated files.
  %
  %-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%
@@ -116,9 +116,8 @@ query_2(QueryType, Imports, Options, MDB_Stdin, MDB_Stdout, ReadTerm, !IO) :-
              Term = term.functor(term.atom("options"),
                  [term.functor(term.string(NewOptions), [], _)], _)
          then
-            io.write_string(MDB_Stdout, "Compilation options: ", !IO),
-            io.write_string(MDB_Stdout, NewOptions, !IO),
-            io.nl(MDB_Stdout, !IO),
+            io.format(MDB_Stdout, "Compilation options: %s\n",
+                [s(NewOptions)], !IO),
              query(QueryType, Imports, NewOptions, MDB_Stdin, MDB_Stdout, !IO)
          else if
              term_to_list(Term, ModuleList)
@@ -500,9 +499,10 @@ cleanup_query(_Options) -->
      io.remove_file("Mercury/cs/" ++ query_module_name ++ ".c", _),
      io.remove_file(query_module_name ++ ".c_date", _),
      io.remove_file("Mercury/c_dates/" ++ query_module_name ++ ".c_date", _),
+    % XXX on some systems the object file extension won't be .o.
      io.remove_file(query_module_name ++ ".o", _),
      io.remove_file("Mercury/os/" ++ query_module_name ++ ".o", _),
-    io.remove_file("lib" ++ query_module_name ++ ".so", _).
+    io.remove_file("lib" ++ query_module_name ++ shlib_extension, _).

      % `grade_option' returns MR_GRADE_OPT, which is defined in
      % runtime/mercury_grade.h. This is a string containing the grade
@@ -533,9 +533,7 @@ verbose = no.

  invoke_system_command(Command, Succeeded, !IO) :-
      ( if verbose = yes then
-        io.write_string("% Invoking system command `", !IO),
-        io.write_string(Command, !IO),
-        io.write_string("'...\n", !IO),
+        io.format("%% Invoking system command `%s'...\n", [s(Command)], !IO),
          io.flush_output(!IO)
      else
          true
@@ -572,14 +570,12 @@ query_module_name = "mdb_query".

  dynamically_load_and_run(!IO) :-
      % Load in the object code for the module `query' from
-    % the file `libquery.so'.
-    dl.open("./lib" ++ query_module_name ++ ".so", lazy, local, MaybeHandle,
-        !IO),
+    % the file `libmdb_query.{so,dylib}'.
+    dl.open("./lib" ++ query_module_name ++ shlib_extension, lazy, local,
+        MaybeHandle, !IO),
      (
          MaybeHandle = dl_error(Msg),
-        io.write_string("dlopen failed: ", !IO),
-        io.write_string(Msg, !IO),
-        io.nl(!IO)
+        io.format("dlopen failed: %s\n", [s(Msg)], !IO)
      ;
          MaybeHandle = dl_ok(Handle),
          % Look up the address of the first mode (mode number 0)
@@ -589,9 +585,7 @@ dynamically_load_and_run(!IO) :-
          dl.mercury_sym(Handle, QueryProc, MaybeQuery, !IO),
          (
              MaybeQuery = dl_error(Msg),
-            io.write_string("dlsym failed: ", !IO),
-            io.write_string(Msg, !IO),
-            io.nl(!IO)
+            io.format("dlsym failed: %s\n", [s(Msg)], !IO)
          ;
              MaybeQuery = dl_ok(QueryPred0),
              % Cast the higher-order term that we obtained to the correct
@@ -602,13 +596,11 @@ dynamically_load_and_run(!IO) :-
              QueryPred(!IO)
          ),

-        % Unload the object code in the libquery.so file.
+        % Unload the object code in the libmdb_query.{so,dylib} file.
          dl.close(Handle, Result, !IO),
          (
              Result = dl_error(CloseMsg),
-            io.write_string("dlclose failed: ", !IO),
-            io.write_string(CloseMsg, !IO),
-            io.nl(!IO)
+            io.format("dlclose failed: %s\n", [s(CloseMsg)], !IO)
          ;
              Result = dl_ok
          )
@@ -638,3 +630,22 @@ inst_cast(_) = _ :-
      private_builtin.sorry("inst_cast").

  %-----------------------------------------------------------------------------%
+
+:- func shlib_extension = string.
+
+shlib_extension =
+   ( if system_is_darwin then ".dylib" else ".so" ).
+
+:- pred system_is_darwin is semidet.
+:- pragma foreign_proc("C",
+    system_is_darwin,
+    [promise_pure, will_not_call_mercury, thread_safe],
+"
+#if defined(MR_MAC_OSX)
+    SUCCESS_INDICATOR = MR_TRUE;
+#else
+    SUCCESS_INDICATOR = MR_FALSE;
+#endif
+").
+
+%-----------------------------------------------------------------------------%
diff --git a/tests/debugger/interactive.exp b/tests/debugger/interactive.exp
index 0ac5405..b93f41e 100644
--- a/tests/debugger/interactive.exp
+++ b/tests/debugger/interactive.exp
@@ -1,10 +1,10 @@
-       1:      1  1 CALL pred interactive.main/2-0 (cc_multi) interactive.m:18
+       1:      1  1 CALL pred interactive.main/2-0 (cc_multi) interactive.m:23
  mdb> echo on
  Command echo enabled.
  mdb> query interactive list
  ?- append(X, Y, ['a', 'b', 'c']).
-<stdin>:026: Inferred :- pred query((list.list(character)),
-<stdin>:026:   (list.list(character))).
+<stdin>:026: Inferred :- pred query(list.list(character),
+<stdin>:026:   list.list(character)).
  <stdin>:026: Inferred :- mode query(out, out) is multi.
  X = [], Y = ['a', 'b', 'c'], true ;
  X = ['a'], Y = ['b', 'c'], true ;
@@ -13,7 +13,7 @@ X = ['a', 'b', 'c'], Y = [], true ;
  fail.
  No (more) solutions.
  ?- qperm([1,2,3], List).
-<stdin>:026: Inferred :- pred query((list.list(int))).
+<stdin>:026: Inferred :- pred query(list.list(int)).
  <stdin>:026: Inferred :- mode query(out) is nondet.
  List = [1, 2, 3], true ;
  List = [1, 3, 2], true ;
@@ -26,15 +26,15 @@ No (more) solutions.
  ?- qperm([1,2,3], List), List = [2 | _].
  <stdin>:001: In clause for predicate `mdb_query.query'/2:
  <stdin>:001:   warning: variable `_2' occurs more than once in this scope.
-<stdin>:012: In clause for predicate `mdb_query.run'/2:
-<stdin>:012:   warning: variable `_2' occurs more than once in this scope.
+<stdin>:013: In clause for predicate `mdb_query.run'/2:
+<stdin>:013:   warning: variable `_2' occurs more than once in this scope.
  <stdin>:014: In clause for predicate `mdb_query.run'/2:
  <stdin>:014:   warning: variable `_2' occurs more than once in this scope.
  <stdin>:015: In clause for predicate `mdb_query.run'/2:
  <stdin>:015:   warning: variable `_2' occurs more than once in this scope.
  <stdin>:026: In clause for predicate `mdb_query.query'/2:
  <stdin>:026:   warning: variable `_2' occurs more than once in this scope.
-<stdin>:026: Inferred :- pred query((list.list(int)), (list.list(int))).
+<stdin>:026: Inferred :- pred query(list.list(int), list.list(int)).
  <stdin>:026: Inferred :- mode query(out, out) is nondet.
  List = [2, 1, 3], _2 = [1, 3], true ;
  List = [2, 3, 1], _2 = [3, 1], true ;
@@ -43,15 +43,15 @@ No (more) solutions.
  ?- qperm([1,2,3], List), List = [4 | _].
  <stdin>:001: In clause for predicate `mdb_query.query'/2:
  <stdin>:001:   warning: variable `_2' occurs more than once in this scope.
-<stdin>:012: In clause for predicate `mdb_query.run'/2:
-<stdin>:012:   warning: variable `_2' occurs more than once in this scope.
+<stdin>:013: In clause for predicate `mdb_query.run'/2:
+<stdin>:013:   warning: variable `_2' occurs more than once in this scope.
  <stdin>:014: In clause for predicate `mdb_query.run'/2:
  <stdin>:014:   warning: variable `_2' occurs more than once in this scope.
  <stdin>:015: In clause for predicate `mdb_query.run'/2:
  <stdin>:015:   warning: variable `_2' occurs more than once in this scope.
  <stdin>:026: In clause for predicate `mdb_query.query'/2:
  <stdin>:026:   warning: variable `_2' occurs more than once in this scope.
-<stdin>:026: Inferred :- pred query((list.list(int)), (list.list(int))).
+<stdin>:026: Inferred :- pred query(list.list(int), list.list(int)).
  <stdin>:026: Inferred :- mode query(out, out) is nondet.
  fail.
  No (more) solutions.
@@ -66,10 +66,9 @@ No (more) solutions.
  For more information, recompile with `-E'.
  Compilation error(s) occurred.
  ?- qperm(List, [1]).
-<stdin>:026: Inferred :- pred query((list.list(int))).
  <stdin>:014: In clause for `run(di, uo)':
  <stdin>:014:   in call to predicate `mdb_query.query'/1:
-<stdin>:014:   mode error: arguments `List' have the following insts:
+<stdin>:014:   mode error: argument `List' has the following inst:
  <stdin>:014:     free
  <stdin>:014:   which does not match any of the valid modes for the callee,
  <stdin>:014:   because of the following error.
@@ -77,18 +76,19 @@ Compilation error(s) occurred.
  <stdin>:026:   in argument 1 of call to predicate `interactive.qperm'/2:
  <stdin>:026:   mode error: variable `HeadVar__2' has instantiatedness `free',
  <stdin>:026:   expected instantiatedness was `ground'.
+<stdin>:026: Inferred :- pred query(list.list(int)).
  For more information, recompile with `-E'.
  Compilation error(s) occurred.
  ?- quit.

  mdb> cc_query interactive list
  ?- append(X, Y, ['a', 'b', 'c']).
-<stdin>:017: Inferred :- pred query((list.list(character)),
-<stdin>:017:   (list.list(character))).
+<stdin>:017: Inferred :- pred query(list.list(character),
+<stdin>:017:   list.list(character)).
  <stdin>:017: Inferred :- mode query(out, out) is multi.
  X = [], Y = ['a', 'b', 'c'], true.
  ?- qperm([1,2,3], List).
-<stdin>:017: Inferred :- pred query((list.list(int))).
+<stdin>:017: Inferred :- pred query(list.list(int)).
  <stdin>:017: Inferred :- mode query(out) is nondet.
  List = [1, 2, 3], true.
  ?- qperm([1,2,3], List), List = [2 | _].
@@ -100,7 +100,7 @@ List = [1, 2, 3], true.
  <stdin>:012:   warning: variable `_2' occurs more than once in this scope.
  <stdin>:017: In clause for predicate `mdb_query.query'/2:
  <stdin>:017:   warning: variable `_2' occurs more than once in this scope.
-<stdin>:017: Inferred :- pred query((list.list(int)), (list.list(int))).
+<stdin>:017: Inferred :- pred query(list.list(int), list.list(int)).
  <stdin>:017: Inferred :- mode query(out, out) is nondet.
  List = [2, 1, 3], _2 = [1, 3], true.
  ?- qperm([1,2,3], List), List = [4 | _].
@@ -112,7 +112,7 @@ List = [2, 1, 3], _2 = [1, 3], true.
  <stdin>:012:   warning: variable `_2' occurs more than once in this scope.
  <stdin>:017: In clause for predicate `mdb_query.query'/2:
  <stdin>:017:   warning: variable `_2' occurs more than once in this scope.
-<stdin>:017: Inferred :- pred query((list.list(int)), (list.list(int))).
+<stdin>:017: Inferred :- pred query(list.list(int), list.list(int)).
  <stdin>:017: Inferred :- mode query(out, out) is nondet.
  No solution.
  ?- quit.



More information about the reviews mailing list