From 2910e2fddcd4f4c4669c14d0bbd81e7b213462bb Mon Sep 17 00:00:00 2001 From: James Laird Date: Fri, 9 May 2014 17:22:56 +1000 Subject: [PATCH] Add control of JVM startup options --- docs/source/api.rst | 16 ++++++++ jnius/jnius_env.pxi | 4 +- jnius/jnius_jvm_desktop.pxi | 57 ++++++++++---------------- jnius_config.py | 79 +++++++++++++++++++++++++++++++++++++ setup.py | 1 + 5 files changed, 120 insertions(+), 37 deletions(-) create mode 100644 jnius_config.py diff --git a/docs/source/api.rst b/docs/source/api.rst index d819e02..dde5f7e 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -327,3 +327,19 @@ example:: Signature: ()V } + +JVM options and the class path +------------------------------ + +JVM options need to be set before `import jnius` is called, as they cannot be changed after the VM starts up. +To this end, you can:: + + import jnius_config + jnius_config.add_options('-Xrs', '-Xmx4096') + jnius_config.set_classpath('.', '/usr/local/fem/plugins/*') + import jnius + +If a classpath is set with these functions, it overrides any CLASSPATH environment variable. +Multiple options or path entries should be supplied as multiple arguments to the `add_` and `set_` functions. +If no classpath is provided and CLASSPATH is not set, the path defaults to `'.'`. +This functionality is not available on Android. diff --git a/jnius/jnius_env.pxi b/jnius/jnius_env.pxi index 40da529..84b58ff 100644 --- a/jnius/jnius_env.pxi +++ b/jnius/jnius_env.pxi @@ -4,11 +4,13 @@ cdef JNIEnv *default_env = NULL cdef extern int gettid() cdef JavaVM *jvm = NULL -cdef JNIEnv *get_jnienv(): +cdef JNIEnv *get_jnienv() except NULL: global default_env # first call, init. if default_env == NULL: default_env = get_platform_jnienv() + if default_env == NULL: + return NULL default_env[0].GetJavaVM(default_env, &jvm) # return the current env attached to the thread diff --git a/jnius/jnius_jvm_desktop.pxi b/jnius/jnius_jvm_desktop.pxi index c20ed09..9a24b81 100644 --- a/jnius/jnius_jvm_desktop.pxi +++ b/jnius/jnius_jvm_desktop.pxi @@ -4,6 +4,7 @@ cdef extern jint __stdcall JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) cdef extern from "jni.h": int JNI_VERSION_1_4 + int JNI_OK jboolean JNI_FALSE ctypedef struct JavaVMInitArgs: jint version @@ -16,52 +17,36 @@ cdef extern from "jni.h": cdef JNIEnv *_platform_default_env = NULL -def classpath(): - import platform - from glob import glob - from os import environ - from os.path import realpath, dirname, join - - if platform.system() == 'Windows': - split_char = ';' - else: - split_char = ':' - - paths = [realpath('.'), join(dirname(__file__), 'src'), ] - if 'CLASSPATH' not in environ: - return split_char.join(paths) - - cp = environ.get('CLASSPATH') - pre_paths = paths + cp.split(split_char) - # deal with wildcards - for path in pre_paths: - if not path.endswith('*'): - paths.append(path) - else: - paths.extend(glob(path + '.jar')) - paths.extend(glob(path + '.JAR')) - result = split_char.join(paths) - return result - -cdef void create_jnienv(): +cdef void create_jnienv() except *: cdef JavaVM* jvm cdef JavaVMInitArgs args - cdef JavaVMOption options[1] + cdef JavaVMOption *options + cdef int ret cdef bytes py_bytes + import jnius_config - cp = classpath() - py_bytes = ('-Djava.class.path={0}'.format(cp)) - options[0].optionString = py_bytes - options[0].extraInfo = NULL + optarr = jnius_config.options + optarr.append("-Djava.class.path=" + jnius_config.expand_classpath()) + + options = malloc(sizeof(JavaVMOption) * len(optarr)) + for i, opt in enumerate(optarr): + options[i].optionString = (opt) + options[i].extraInfo = NULL args.version = JNI_VERSION_1_4 args.options = options - args.nOptions = 1 + args.nOptions = len(optarr) args.ignoreUnrecognized = JNI_FALSE - JNI_CreateJavaVM(&jvm, &_platform_default_env, &args) + ret = JNI_CreateJavaVM(&jvm, &_platform_default_env, &args) + free(options) -cdef JNIEnv *get_platform_jnienv(): + if ret != JNI_OK: + raise SystemError("JVM failed to start") + + jnius_config.vm_running = True + +cdef JNIEnv *get_platform_jnienv() except NULL: if _platform_default_env == NULL: create_jnienv() return _platform_default_env diff --git a/jnius_config.py b/jnius_config.py new file mode 100644 index 0000000..bb5ba95 --- /dev/null +++ b/jnius_config.py @@ -0,0 +1,79 @@ +__all__ = ('set_options', 'add_options', 'get_options', + 'set_classpath', 'add_classpath', 'get_classpath', + 'expand_classpath') + +import platform +if platform.system() == 'Windows': + split_char = ';' +else: + split_char = ':' + +vm_running = False +options = [] +classpath = None + +def set_options(*opts): + "Sets the list of options to the JVM. Removes any previously set options." + if vm_running: + raise ValueError("VM is already running, can't set options") + globals()['options'] = opts + +def add_options(*opts): + "Appends options to the list of VM options." + if vm_running: + raise ValueError("VM is already running, can't set options") + global options + options.extend(opts) + +def get_options(): + "Retrieves the current list of VM options." + global options + return list(options) + + +def set_classpath(*path): + """ + Sets the classpath for the JVM to use. Replaces any existing classpath, overriding the CLASSPATH environment variable. + """ + if vm_running: + raise ValueError("VM is already running, can't set classpath") + global classpath + classpath = path + +def add_classpath(*path): + """ + Appends items to the classpath for the JVM to use. + Replaces any existing classpath, overriding the CLASSPATH environment variable. + """ + if vm_running: + raise ValueError("VM is already running, can't set classpath") + global classpath + if classpath is None: + classpath = list(path) + else: + classpath.extend(path) + +def get_classpath(): + "Retrieves the classpath the JVM will use." + from os import environ + from os.path import realpath + global classpath + + if classpath is not None: + return list(classpath) + + if 'CLASSPATH' in environ: + return environ['CLASSPATH'].split(split_char) + + return [realpath('.')] + +def expand_classpath(): + from glob import glob + paths = [] + # deal with wildcards + for path in get_classpath(): + if not path.endswith('*'): + paths.append(path) + else: + paths.extend(glob(path + '.[Jj][Aa][Rr]')) + return split_char.join(paths) diff --git a/setup.py b/setup.py index d992005..ce68313 100644 --- a/setup.py +++ b/setup.py @@ -108,6 +108,7 @@ setup(name='jnius', version=version, cmdclass={'build_ext': build_ext}, packages=['jnius'], + py_modules=['jnius_config'], url='http://pyjnius.readthedocs.org/', author='Mathieu Virbel and Gabriel Pettier', author_email='mat@kivy.org,gabriel@kivy.org',