[m-rev.] for review: generate executables in the Java grade as JARs

Julien Fischer jfischer at opturion.com
Tue Apr 7 12:18:13 AEST 2015


For review by anyone.

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

Generate executables in the Java grade as JARs.

When building an executable in the Java grade, the Mercury compiler generates
all the class files in the Mercury subdirectory and then generates a wrapper
script or batch file that points towards these class files.  This makes
deploying executables built in the Java grade rather awkward.  This change
makes the Mercury compiler package up all the class files for an executable
into a JAR file and modifies the wrapper scripts to point to this JAR file.

NOTE: the JAR file we generate cannot be executed with 'java -jar ...'.  This
is because in that mode of operation the Java interpreter ignores all user
classpath settings, such as those that tell the interpreter where the Mercury
standard library is.  (We could support this mode of operation by setting any
required library classpath directories in the archive's manifest, but that
would mean either hardcoding installation specific directories in the manifest
or copying any required .jars to a known location relative to the executable's
class files.  Generating such self-contained archives may be useful in some
cases, but it is not something this change addresses.)

compiler/compile_target_code.m:
         Rename the link target type for Java executables.

         Add a predicate for creating Java "executables": this involves generating
         an archive (as we do for libraries) and then generating the wrapper script
         or batch file.

         Simplify some code that generates an error message.

compiler/module_cmds.m:
         Change the wrapper scripts for Java executables to point towards
         the .jar file generated instead of the class files in the Mercury
         subdirectory.

         Ditto for the wrapper batch files.

compiler/make.m:
compiler/make.program_target.m:
compiler/make.util.m:
         Conform to the above changes.

README.Java:
         Mention that class files for the executable are packaged up in
         an archive.

NEWS:
         Announce this change.

Julien.

diff --git a/NEWS b/NEWS
index c5a3a9f..eb6f7f2 100644
--- a/NEWS
+++ b/NEWS
@@ -195,6 +195,9 @@ Changes to the Mercury compiler:
  * The compiler now reports an error for binary/octal/hexadecimal integer
    literals that cannot be represented in the compiler's native int type.

+* Class files generated for executables in the Java grade are now automatically
+  packaged up into Java archives (JARs).
+
  Changes to the extras distribution:

  * We have added support for Unicode and other enhancements to the lex and
diff --git a/README.Java b/README.Java
index ddf3b9d..5e59d30 100644
--- a/README.Java
+++ b/README.Java
@@ -47,7 +47,8 @@ Now you can run hello

  Note that hello is a simple shell script that invokes the program using the
  Java interpreter.  The actual class files are stored in the Mercury
-subdirectory in `classs'.
+subdirectory in `classs'.  These class files will be packaged up into Java
+archive (JAR) named `hello.jar'.

  If you are using the Windows command-line interpreter, i.e. cmd.exe, then
  setting the value of the option --target-env-type to "windows" will cause the
diff --git a/compiler/compile_target_code.m b/compiler/compile_target_code.m
index 924db06..4a82e8c 100644
--- a/compiler/compile_target_code.m
+++ b/compiler/compile_target_code.m
@@ -116,7 +116,7 @@
      ;       shared_library
      ;       csharp_executable
      ;       csharp_library
-    ;       java_launcher
+    ;       java_executable
      ;       java_archive
      ;       erlang_launcher
      ;       erlang_archive.
@@ -248,6 +248,7 @@
  :- import_module libs.trace_params.
  :- import_module parse_tree.error_util.
  :- import_module parse_tree.file_names.
+:- import_module parse_tree.java_names.
  :- import_module parse_tree.module_cmds.
  :- import_module parse_tree.write_deps_file.
  :- import_module parse_tree.prog_foreign.
@@ -1751,8 +1752,9 @@ link(ErrorStream, LinkTargetType, ModuleName, ObjectsList, Globals, Succeeded,
          create_csharp_exe_or_lib(Globals, ErrorStream, LinkTargetType,
              ModuleName, OutputFileName, ObjectsList, LinkSucceeded, !IO)
      ;
-        LinkTargetType = java_launcher,
-        create_java_shell_script(Globals, ModuleName, LinkSucceeded, !IO)
+        LinkTargetType = java_executable,
+        create_java_executable(Globals, ErrorStream, ModuleName,
+            OutputFileName, ObjectsList, LinkSucceeded, !IO)
      ;
          LinkTargetType = java_archive,
          create_java_archive(Globals, ErrorStream, OutputFileName, ObjectsList,
@@ -1806,9 +1808,7 @@ link_output_filename(Globals, LinkTargetType, ModuleName, Ext, OutputFileName,
          module_name_to_file_name(Globals, ModuleName, Ext,
              do_create_dirs, OutputFileName, !IO)
      ;
-        ( LinkTargetType = java_launcher
-        ; LinkTargetType = erlang_launcher
-        ),
+        LinkTargetType = erlang_launcher,
          % These may be shell scripts or batch files.
          globals.get_target_env_type(Globals, TargetEnvType),
          (
@@ -1827,6 +1827,11 @@ link_output_filename(Globals, LinkTargetType, ModuleName, Ext, OutputFileName,
          module_name_to_file_name(Globals, ModuleName, Ext,
              do_create_dirs, OutputFileName, !IO)
      ;
+        LinkTargetType = java_executable,
+        Ext = ".jar",
+        module_name_to_file_name(Globals, ModuleName, Ext,
+            do_create_dirs, OutputFileName, !IO)
+    ;
          LinkTargetType = java_archive,
          Ext = ".jar",
          module_name_to_file_name(Globals, ModuleName, Ext,
@@ -2147,7 +2152,7 @@ get_mercury_std_libs(Globals, TargetType, StdLibs) :-
              LibExt = ".dll",
              MercuryLinkage = "csharp"
          ;
-            ( TargetType = java_launcher
+            ( TargetType = java_executable
              ; TargetType = java_archive
              ; TargetType = erlang_launcher
              ; TargetType = erlang_archive
@@ -2305,7 +2310,7 @@ link_lib_args(Globals, TargetType, StdLibDir, GradeDir, LibExt, Name,
          ),
          LibPrefix = ""
      ;
-        ( TargetType = java_launcher
+        ( TargetType = java_executable
          ; TargetType = java_archive
          ; TargetType = erlang_launcher
          ; TargetType = erlang_archive
@@ -2367,7 +2372,7 @@ make_link_lib(Globals, TargetType, LibName, LinkOpt) :-
          LinkOpt = quote_arg(LinkLibOpt ++ LibName ++ Suffix)
      ;
          ( TargetType = static_library
-        ; TargetType = java_launcher
+        ; TargetType = java_executable
          ; TargetType = java_archive
          ; TargetType = erlang_launcher
          ; TargetType = erlang_archive
@@ -2452,7 +2457,7 @@ get_system_libs(Globals, TargetType, SystemLibs) :-
          ( TargetType = static_library
          ; TargetType = csharp_executable
          ; TargetType = csharp_library
-        ; TargetType = java_launcher
+        ; TargetType = java_executable
          ; TargetType = java_archive
          ; TargetType = erlang_launcher
          ; TargetType = erlang_archive
@@ -2511,7 +2516,7 @@ get_restricted_command_line_link_opts(Globals, LinkTargetType,
              ; LinkTargetType = shared_library
              ; LinkTargetType = csharp_executable
              ; LinkTargetType = csharp_library
-            ; LinkTargetType = java_launcher
+            ; LinkTargetType = java_executable
              ; LinkTargetType = java_archive
              ; LinkTargetType = erlang_launcher
              ; LinkTargetType = erlang_archive
@@ -2566,7 +2571,7 @@ post_link_make_symlink_or_copy(ErrorStream, LinkTargetType, ModuleName,
              ( LinkTargetType = executable
              ; LinkTargetType = csharp_executable
              ; LinkTargetType = csharp_library
-            ; LinkTargetType = java_launcher
+            ; LinkTargetType = java_executable
              ; LinkTargetType = java_archive
              ; LinkTargetType = erlang_launcher
              ),
@@ -2902,7 +2907,7 @@ create_csharp_exe_or_lib(Globals, ErrorStream, LinkTargetType, MainModuleName,
          ( LinkTargetType = executable
          ; LinkTargetType = static_library
          ; LinkTargetType = shared_library
-        ; LinkTargetType = java_launcher
+        ; LinkTargetType = java_executable
          ; LinkTargetType = java_archive
          ; LinkTargetType = erlang_launcher
          ; LinkTargetType = erlang_archive
@@ -3025,6 +3030,27 @@ write_cli_shell_script(Globals, ExeFileName, Stream, !IO) :-
          "exec \"$CLI_INTERPRETER\" \"$DIR/", ExeFileName, "\" \"$@\"\n"
      ], !IO).

+%-----------------------------------------------------------------------------%
+%
+% Create Java "executables" or archives.
+%
+
+:- pred create_java_executable(globals::in, io.text_output_stream::in,
+    module_name::in, file_name::in, list(file_name)::in, bool::out,
+    io::di, io::uo) is det.
+
+create_java_executable(Globals, ErrorStream, MainModuleName, JarFileName,
+        ObjectList, Succeeded, !IO) :-
+    create_java_archive(Globals, ErrorStream, JarFileName, ObjectList,
+        CreateJarSucceeded, !IO),
+    (
+        CreateJarSucceeded = yes,
+        create_java_shell_script(Globals, MainModuleName, Succeeded, !IO)
+    ;
+        CreateJarSucceeded = no,
+        Succeeded = no
+    ).
+
  :- pred create_java_archive(globals::in, io.output_stream::in, file_name::in,
      list(file_name)::in, bool::out, io::di, io::uo) is det.

@@ -3072,11 +3098,9 @@ create_java_archive(Globals, ErrorStream, JarFileName, ObjectList, Succeeded,
          )
      ;
          OpenResult = error(Error),
-        io.write_string(ErrorStream, "Error creating `", !IO),
-        io.write_string(ErrorStream, TempFileName, !IO),
-        io.write_string(ErrorStream, "': ", !IO),
-        io.write_string(ErrorStream, io.error_message(Error), !IO),
-        io.nl(ErrorStream, !IO),
+        io.error_message(Error, ErrorMsg),
+        io.format(ErrorStream, "Error creating `%s': %s\n",
+            [s(TempFileName), s(ErrorMsg)], !IO),
          Succeeded = no
      ).

@@ -3160,7 +3184,7 @@ get_object_code_type(Globals, FileType, ObjectCodeType) :-
          ( FileType = static_library
          ; FileType = csharp_executable
          ; FileType = csharp_library
-        ; FileType = java_launcher
+        ; FileType = java_executable
          ; FileType = java_archive
          ; FileType = erlang_launcher
          ; FileType = erlang_archive
diff --git a/compiler/make.m b/compiler/make.m
index 37c19a0..e1baa8d 100644
--- a/compiler/make.m
+++ b/compiler/make.m
@@ -586,7 +586,7 @@ get_executable_type(Globals) = ExecutableType :-
          ExecutableType = csharp_executable
      ;
          CompilationTarget = target_java,
-        ExecutableType = java_launcher
+        ExecutableType = java_executable
      ;
          CompilationTarget = target_erlang,
          ExecutableType = erlang_launcher
diff --git a/compiler/make.program_target.m b/compiler/make.program_target.m
index a751b69..36492f7 100644
--- a/compiler/make.program_target.m
+++ b/compiler/make.program_target.m
@@ -69,7 +69,7 @@ make_linked_target(Globals, LinkedTargetFile, LinkedTargetSucceeded,
          ; FileType = static_library
          ; FileType = csharp_executable
          ; FileType = csharp_library
-        ; FileType = java_launcher
+        ; FileType = java_executable
          ; FileType = java_archive
          ; FileType = erlang_launcher
          ; FileType = erlang_archive
@@ -465,7 +465,7 @@ build_linked_target_2(Globals, MainModuleName, FileType, OutputFileName,
          ; FileType = shared_library
          ; FileType = csharp_executable
          ; FileType = csharp_library
-        ; FileType = java_launcher
+        ; FileType = java_executable
          ; FileType = java_archive
          ; FileType = erlang_archive
          ),
@@ -672,7 +672,7 @@ linked_target_cleanup(Globals, MainModuleName, FileType, OutputFileName,
          ; FileType = shared_library
          ; FileType = csharp_executable
          ; FileType = csharp_library
-        ; FileType = java_launcher
+        ; FileType = java_executable
          ; FileType = java_archive
          ; FileType = erlang_launcher
          ; FileType = erlang_archive
@@ -1927,7 +1927,7 @@ make_main_module_realclean(Globals, ModuleName, !Info, !IO) :-
          shared_library,
          csharp_executable,
          csharp_library,
-        java_launcher,
+        java_executable,
          java_archive,
          erlang_launcher,
          erlang_archive
diff --git a/compiler/make.util.m b/compiler/make.util.m
index 96376c0..c8a9935 100644
--- a/compiler/make.util.m
+++ b/compiler/make.util.m
@@ -1514,7 +1514,7 @@ linked_target_file_name(Globals, ModuleName, TargetType, FileName, !IO) :-
          module_name_to_file_name(Globals, ModuleName, ".dll",
              do_not_create_dirs, FileName, !IO)
      ;
-        ( TargetType = java_launcher
+        ( TargetType = java_executable
          ; TargetType = erlang_launcher
          ),
          % These are shell scripts.
diff --git a/compiler/module_cmds.m b/compiler/module_cmds.m
index e4b9d28..2b67abc 100644
--- a/compiler/module_cmds.m
+++ b/compiler/module_cmds.m
@@ -750,6 +750,9 @@ use_win32 :-
  %

  create_java_shell_script(Globals, MainModuleName, Succeeded, !IO) :-
+    Ext = ".jar",
+    module_name_to_file_name(Globals, MainModuleName, Ext, do_not_create_dirs,
+        JarFileName, !IO),
      get_target_env_type(Globals, TargetEnvType),
      (
          ( TargetEnvType = env_type_posix
@@ -757,7 +760,7 @@ create_java_shell_script(Globals, MainModuleName, Succeeded, !IO) :-
          ; TargetEnvType = env_type_msys
          ),
          create_launcher_shell_script(Globals, MainModuleName,
-            write_java_shell_script(Globals, MainModuleName),
+            write_java_shell_script(Globals, MainModuleName, JarFileName),
              Succeeded, !IO)
      ;
          % XXX should create a .ps1 file on PowerShell.
@@ -765,23 +768,19 @@ create_java_shell_script(Globals, MainModuleName, Succeeded, !IO) :-
          ; TargetEnvType = env_type_powershell
          ),
          create_launcher_batch_file(Globals, MainModuleName,
-            write_java_batch_file(Globals, MainModuleName),
+            write_java_batch_file(Globals, MainModuleName, JarFileName),
              Succeeded, !IO)
      ).

  :- pred write_java_shell_script(globals::in, module_name::in,
-    io.text_output_stream::in, io::di, io::uo) is det.
-
-write_java_shell_script(Globals, MainModuleName, Stream, !IO) :-
-    % In shell scripts always use / separators, even on Windows.
-    get_class_dir_name(Globals, ClassDirName),
-    string.replace_all(ClassDirName, "\\", "/", ClassDirNameUnix),
+    file_name::in, io.text_output_stream::in, io::di, io::uo) is det.

+write_java_shell_script(Globals, MainModuleName, JarFileName, Stream, !IO) :-
      get_mercury_std_libs_for_java(Globals, MercuryStdLibs),
      globals.lookup_accumulating_option(Globals, java_classpath,
          UserClasspath),
      % We prepend the .class files' directory and the current CLASSPATH.
-    Java_Incl_Dirs = ["\"$DIR/" ++ ClassDirNameUnix ++ "\""] ++
+    Java_Incl_Dirs = ["\"$DIR/" ++ JarFileName ++ "\""] ++
          MercuryStdLibs ++ ["$CLASSPATH" | UserClasspath],
      ClassPath = string.join_list("${SEP}", Java_Incl_Dirs),

@@ -802,17 +801,15 @@ write_java_shell_script(Globals, MainModuleName, Stream, !IO) :-
          "exec \"$JAVA\" jmercury.", ClassName, " \"$@\"\n"
      ], !IO).

-:- pred write_java_batch_file(globals::in, module_name::in,
+:- pred write_java_batch_file(globals::in, module_name::in, file_name::in,
      io.text_output_stream::in, io::di, io::uo) is det.

-write_java_batch_file(Globals, MainModuleName, Stream, !IO) :-
-    get_class_dir_name(Globals, ClassDirName),
-
+write_java_batch_file(Globals, MainModuleName, JarFileName, Stream, !IO) :-
      get_mercury_std_libs_for_java(Globals, MercuryStdLibs),
      globals.lookup_accumulating_option(Globals, java_classpath,
          UserClasspath),
      % We prepend the .class files' directory and the current CLASSPATH.
-    Java_Incl_Dirs = ["%DIR%\\" ++ ClassDirName] ++ MercuryStdLibs ++
+    Java_Incl_Dirs = ["%DIR%\\" ++ JarFileName] ++ MercuryStdLibs ++
          ["%CLASSPATH%" | UserClasspath],
      ClassPath = string.join_list(";", Java_Incl_Dirs),




More information about the reviews mailing list