[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: How to manage multiple JVMs



Joe Emenaker wrote:
> For this reason, I kinda have to keep JDK 1.0 around. However, I
> sometimes need JDK 1.1 for other projects.  As things stand now, I
> either have to keep them on separate machines or wrestle with the
> stuff in /etc/alternates.

I've run into the same problem.  (I've got several installs of Kaffe
and several versions of Sun's JDK).  I've attached my solution,
'jdkselector'.  It lets you describe your various installed JVMs (in a
file ~/.jdks), like this:

/home/tullmann/kaffe-core/install/kaffe-1.1-kaffe-jit-debug-unix:
	kaffe debug jit freebsd

/home/tullmann/kaffe-core/install/kaffe-1.1-kaffe-jit-debug-oskitunix:
	kaffe debug jit static oskitunix freebsd

/usr/local/java:
	sun jit 1.1 1.1.7

/usr/local/jdk1.1.8:
	sun jit 1.1 1.1.8

Through the magic of perl and shell aliases, I can "choose" a JVM by
running 'javame [description]' (.e.g, 'javame kaffe oskitunix'), and
it will re-set my path to point to the entry with the best matching
description. (the 2nd entry in the list for the example).  'javame sun
1.1.8' would re-set my path to point to the last entry.  (It picks the
entry with the most matching keywords.)

Note that this really only works with more recent JDKs that only need
to have their 'java' in the path to work (old JDKs/Kaffe needed a
bunch of other magic env vars set).  

[Note that jdkselector doesn't do any of the .jar magic directory
stuff you wanted.  I belive Kaffe's (undocumented) ~/.kafferc file
that does what you want, though.]

I've attached the perl script (~300 lines) and my actual .jdks file as
an example.  Hope this is useful,

Pat

----- ----- ---- ---  ---  --   -    -      -         -               -
Pat Tullmann                                       tullmann@cs.utah.edu
     It said "Windows 95 or better" so FreeBSD should run on it.
#!/usr/local/bin/perl -w
#
# jdkselector
#
# Copyright (c) 2000 Patrick Tullmann <tullmann@cs.utah.edu>
# All rights Reserved.
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License, version 2, as
# published by the Free Software Foundation.

#
# jdkselector:
#
# Looks for descriptions of installed JDKS in ${HOME}/.jdks.  Uses
# command line arguments to select one of those JDKs.  Echos a shell
# script to make that JDK the in-path JDK.
#
# Really only makes sense with an alias (csh syntax):
#   alias javame	'eval `jdkselector -csh \!*`'
#   alias javamedbg	'jdkselector -csh \!*'
# (sh syntax, I think)
#   alias javame="eval `jdkselector -sh \!*`"
#   alias javamedbg="eval `jdkselector -sh \!*`"
#
# The ~/.jdks file should consist of pairs of lines, the
# first is a directory, the second line starts with a tab
# and includes descriptors for that directory.  For example:
#
# /home/tullmann/java/
# 	sun 1.1 1.1.8 jit
#
# Comments like these are allowed.
#

use strict;

&Main(@ARGV);

sub Main() {
    my @argv = @_;
    my $jdkConf = "$ENV{HOME}/.jdks";
    my @descs = ();

    # Default debugging level
    $::debugLevel = 0;
    $::shell = 'csh';
    $::showOptions = 0;

    foreach (@argv) {
	my $arg = $_;
	if (/^-?-h$/ || /^-?-help$/) {
	    &usage();
	} elsif (/^-csh$/ || /^-sh$/) {
	    $::shell = $arg;
	} elsif (/^-list$/ || /^-l$/ || /^-options/) {
	    $::showOptions = 1;
	} elsif (/^-?-debug=?(.*)/) {
	    if (defined($1)) {
		$::debugLevel = $1;
	    } else {
		$::debugLevel = 1;
	    }
	} else {
	    push(@descs, $arg);
	}
    }

    &debug(1, "Descriptions: " . join(' ', @descs) . "\n");

    my $configs = &loadConfig($jdkConf);

    if ($::showOptions == 1) {
	&showConfigs($configs)
    } else {
	my $jdk = &pickConfig($configs, @descs);
	&emitJDKScript($jdk);
    }
}

sub loadConfig() {
    my ($jdkConf) = @_;
    my @configs = ();

    -T $jdkConf || die "no .jdk config file: $jdkConf";

    open(CNF, "<$jdkConf") || die "cannot open $jdkConf";
    
    my $dir = '';
    while(<CNF>) {
	s/\#.*$//;  # strip out comments
	
	if (/^\t/) {
	    ## Lines starting with tab are descriptions

	    my @words = split;

	    if ($dir eq '') {
		&warning("$jdkConf contains descriptions without directory.  Ignoring.\n");
	    }

	    push(@configs, [$dir, \@words]);
	} elsif (/^\s*(.*):/) {
	    ## Lines containing a ':' are directories
	    $dir = $1;
	} elsif (/^\s*$/) {
	    ## Blank lines are ignored
	} else {
	    chop;
	    &warning("Ignoring line '$_' in $jdkConf.\n");
	}
    }

    close(CNF);
    
    return \@configs;
}

sub showConfigs() {
    my $configs_r = shift;

    foreach my $cnf (@{$configs_r}) {
	my ($dir, $words_r) = @{$cnf};
	my @words = @{$words_r};
	
	print STDERR "$dir (" .join(' ', @words) . ")\n";
    }

    ## Just shut the shell eval up
    print "echo Done\n";
}

sub pickConfig() {
    my $configs_r = shift;
    my @argv = @_;
    my %config = ();

  CONFIG:
    foreach my $cnf (@{$configs_r}) {
	my ($dir, $words_r) = @{$cnf};
	my @words = @{$words_r};

	&debug(2, "Trying: $dir (" .join(' ', @words) . ").\n");

	## Find first match, drops through if argv is empty (correct)
      ARG:
	foreach my $arg (@argv) {
	    foreach my $w (@words) {
		next ARG if $w eq $arg;
	    }
	    ## $arg didn't match any of the words.
	    next CONFIG;
	}

	## All the args matched
	&debug(1, "Picked: $dir (" .join(' ', @words) . ").\n");

	$config{jdkhome} = $dir;
	$config{bindir} = $dir . "/bin";
	return \%config;
    }

    ## Nothing found
    return undef;
}

sub setenv_sh() {
    my ($var, $value) = @_;
    print "\"${var}\"=\"${value}\";\n";
}

sub setenv_csh() {
    my ($var, $value) = @_;
    print "setenv \"${var}\" \"${value}\";\n";
}

sub setpath_sh() {
    my @path = @_;
    &setenv_sh('PATH', join(':',@path));
}

sub setpath_csh() {
    my @path = @_;
    print "set path = ( " . join(' ', @path) . " );\n";
}

sub makealias_sh() {
    my ($func, $body) = @_;
    $body =~ s/\'/\\\'/g;
    print "$func() '$body';\n";
}

sub makealias_csh() {
    my ($func, $body) = @_;
    $body =~ s/\'/\\\'/g;
    print "alias $func '$body';\n";
}

sub rehash_sh() {
    print "hash java;\n";
}

sub rehash_csh() {
    print "rehash;\n";
}


sub emitJDKScript() {
    my $config_r = shift;

    if (!defined($config_r)) {
	&debug(1, "No configuration matches.\n");
	print "echo Nothing matches.\n";

	return;
    }
	
    if (! -d $config_r->{bindir}) {
	&debug(1, "Selected configuration's directory doesn't exist: $config_r->{bindir}\n");
	print "echo Selected configuartion dir is bogus: $config_r->{bindir}\n";
	return;
    }

    ### Determine caller's shell, set functions accordingly
    my $setenv = \&setenv_sh;
    my $makealias = \&makealias_sh;
    my $rehash = \&rehash_sh;
    my $setpath = \&setpath_sh;
    if ($::shell =~ /csh/) {
	$setenv = \&setenv_csh;
	$makealias = \&makealias_csh;
	$rehash = \&rehash_csh;
	$setpath = \&setpath_csh;
    }
    
    ### Determine if we have to strip an old JDK path out of PATH
    my $oldJDK = '';
    if (defined($ENV{CURRENT_JDK_PATH})) {
	$oldJDK = $ENV{CURRENT_JDK_PATH};
    }
    
    ### Get current path, remove old JDK, add new JDK
    my @path = split(':', $ENV{PATH});
    my $newDir = $config_r->{bindir};
    my $appendDot = 0;

    if ($oldJDK ne '') {
	my $i = 0;
	my @dellist = ();
	foreach my $d (@path) {
	    &debug(4,"path element $i: $d\n");
	    if ($d eq $oldJDK) {
		## Nuke it
		push(@dellist, ($i));
	    } elsif ($d eq '.') {
		## Nuke it, and set a flag
		push(@dellist, ($i));
		$appendDot = 1;
	    } else {
		$i++;
	    }
	}

	foreach my $del (@dellist) {
	    &debug(4,"removing from path: $path[$del]\n");
	    splice(@path,$del,1);
	}
    }

    # Now append our newDir to path
    push(@path, ($newDir));

    # Append dot if necessary
    push(@path, ('.')) if ($appendDot != 0);

    ### Output shell script to update state
    &$setenv('CURRENT_JDK_PATH', $newDir);
    &$setpath(@path);
    &$rehash();
    &$makealias('jver', "echo \"$newDir\"; ls -la `where java`; java -version");
}

sub usage() {
    print STDERR "javame <descriptions>\n";
    exit 0;
}

sub debug() {
    my $lvl = shift;
    my @args = @_;
    if ($lvl < $::debugLevel) {
	printf STDERR @_;
    }
}

sub warning() {
    my @args = @_;
    print STDERR "WARNING: ";
    printf STDERR @args;
}

#eof
## Format:
#
#<dir>:
#	<descriptions>
#
#Order matters.
#

/n/alta/r/tullmann/kaffe-core/install/kaffe-1.1-kaffe-jit-debug-unix:
	kaffe debug jit freebsd

/n/alta/r/tullmann/kaffe-core/install/kaffe-1.1-kaffe-jit-debug-unix-static:
	kaffe debug jit static freebsd

/n/alta/r/tullmann/kaffe-core/install/kaffe-1.1-kaffe-jit-debug-unix-static:
	kaffe opt optimized optimize jit static freebsd

/n/alta/r/tullmann/kaffe-core/install/kaffe-1.1-kaffe-jit-debug-oskitunix:
	kaffe debug jit static oskitunix freebsd

/n/alta/r/tullmann/kaffe-core/install/kaffe-1.1-kaffe-jit-xprof-unix-static:
	kaffe xprof prof profile gprof profiling static freebsd jit

/n/alta/z/tullmann/janos/install/janosvm-jit-debug-moaboskitunix-static/:
	janosvm jit debug moaboskitunix moab oskitunix freebsd

#/n/alta/z/tullmann/janos/install/janosvm-jit-debug-unix/:
#	janos

/usr/local/java:
	sun jit 1.1 1.1.7

/usr/local/jdk1.1.8:
	sun jit 1.1 1.1.8

/usr/local/jdk1.2.2:
	sun jit 1.2 1.2.2

#eof

Reply to: