Starting Java from Tcl

Executing Java from a Tcl script to perform a specific task is not a trivial exercise. Apart for being able to set the class path and other similar quirks, the task of solely locating the JVM (and the Java executable) to run your program is not as easy as you think. I am posting here some initial code for this very task; please amend and improve if you find it useful.

The only command exported by the code below is java_find and it delivers the same results on both Windows and UNIX (somebody else for Macs). It takes two optional arguments: vnumber_p "points" at a variable that will contain the version number of the JVM found. vnum_match contains a string match like pattern to point at a specific version of the JVM when looking for it. The command returns the full path to the matching java executable binary.

The Windows implementation is inspired by the information contained in [L1 ]. The UNIX implementation is inspired by... our own installations on many machines here, so there is probably a lot of room for improvement. On UNIX, there does not seem to be any other way than starting java to retrieve its current version number.

Emmanuel Frecon


 if { $tcl_platform(platform) == "unix" } {
     proc __jre_version { j_root { vnumber_p "" } { vnum_match "*" } } {
         if { $vnumber_p != "" } {
             upvar $vnumber_p vnumber
         }

         set j_exe [file join $j_root java]
         if { [file executable $j_exe] } {
             set success [catch [exec $j_exe -version] res]
             set vstart [string first "version" $res]
             if { $vstart >= 0 } {
                 set vstart [string first "\"" $res $vstart]
                 incr vstart
                 set vend [string first "\"" $res $vstart]
                 incr vend -1
                 set vnumber [string range $res $vstart $vend]
             }
             if { [string match $vnum_match $vnumber] } {
                 return $j_exe
             }
         }

         return ""
     }


     proc java_find { { vnumber_p "" } { vnum_match "*" } } {
         global env

         if { $vnumber_p != "" } {
             upvar $vnumber_p vnumber
         }

         set vnumber ""
         if { [array names env PATH] != "" } {
             foreach dir [split $env(PATH) ":"] {
                 set j_exe [__jre_version $dir vnumber $vnum_match]
                 if { $j_exe != "" } {
                     return $j_exe
                 }
             }
         }

         if { [array names env JAVA_HOME] != "" } {
             set j_exe [__jre_version [file join $env(JAVA_HOME) bin] \
                            vnumber $vnum_match]
             if { $j_exe != "" } {
                 return $j_exe
             }
         }

         if { [file isdirectory "/usr/java"] } {
             set j_exe [__jre_version "/usr/java/bin" vnumber $vnum_match]
             if { $j_exe != "" } {
                 return $j_exe
             }

             foreach dir [glob "/usr/java/*"] {
                 set j_exe [__jre_version [file join $dir bin] vnumber \
                                $vnum_match]
                 if { $j_exe != "" } {
                     return $j_exe
                 }
             }
         }
         return ""
     }
 } elseif { $tcl_platform(platform) == "windows" } {
     package require registry

     proc __jre_get { jre_root { vnumber_p "" } { vnum_match "*" } } {
         set java_home ""

         if { $vnumber_p != "" } {
             upvar $vnumber_p vnumber
         }

         set res [catch [list registry get "$jre_root" CurrentVersion] vnumber]
         if { $res == 0 && [string match $vnum_match $vnumber] } {
             catch [list registry get "${jre_root}\\${vnumber}" JavaHome] java_home
         } else {
             foreach vnumber [registry keys $jre_root] {
                 if { [string match $vnum_match $vnumber] } {
                     set res [catch [list registry get "${jre_root}\\${vnumber}" \
                                         JavaHome] java_home]
                     if { $res == 0 } {
                         break
                     }
                 }
             }
         }

         return $java_home
     }

     proc __jre_exec { jre_root { vnumber_p "" } { vnum_match "*" } } {
         if { $vnumber_p != "" } {
             upvar $vnumber_p vnumber
         }

         set j_home [__jre_get $jre_root vnumber $vnum_match]
         if { $j_home != "" } {
             # Make a Tcl-friendly path of the horrible windows backslashes
             set j_home [regsub -all "\\\\" $j_home "/"]
             set j_exe [file join $j_home "bin" "java.exe"]
             if { [file executable $j_exe] } {
                 return $j_exe
             }
         }

         return ""
     }


     proc java_find { { vnumber_p "" } { vnum_match "*" } } {
         if { $vnumber_p != "" } {
             upvar $vnumber_p vnumber
         }

         set vnumber ""
         set root "HKEY_LOCAL_MACHINE\\Software\\JavaSoft"
         set j_exe [__jre_exec "$root\\Java Runtime Environment" vnumber \
                        $vnum_match]
         if { $j_exe == "" } {
             set j_exe [__jre_exec "$root\\Java Development Kit" vnumber \
                            $vnum_match]
             if { $j_exe == "" } {
                 set root "HKEY_LOCAL_MACHINE\\Software\\IBM"
                 set j_exe [__jre_exec "$root\\Java Runtime Environment" \
                                vnumber $vnum_match]
                 if { $j_exe == "" } {
                     set j_exe [__jre_exec "$root\\Java Development Kit" \
                                    vnumber $vnum_match]
                 }
             }
         }

         return $j_exe
     }
 }

[ Category Java ]