2019-11-24 22:05:11 +00:00
|
|
|
'''
|
|
|
|
This module determine and expose various information about the java
|
|
|
|
environment.
|
|
|
|
'''
|
|
|
|
|
|
|
|
import sys
|
|
|
|
from os.path import join, exists, dirname, realpath
|
|
|
|
from os import getenv
|
|
|
|
from platform import machine
|
|
|
|
from subprocess import Popen, check_output, PIPE
|
|
|
|
from shlex import split
|
2022-11-26 15:49:24 +00:00
|
|
|
import logging
|
2020-04-24 23:18:56 +00:00
|
|
|
from textwrap import dedent
|
2022-10-16 12:56:56 +00:00
|
|
|
from shutil import which
|
2019-11-24 22:05:11 +00:00
|
|
|
|
2022-11-26 15:49:24 +00:00
|
|
|
log = logging.getLogger('kivy').getChild(__name__)
|
2019-11-29 21:39:32 +00:00
|
|
|
|
2019-11-24 22:05:11 +00:00
|
|
|
machine = machine() # not expected to change at runtime
|
|
|
|
|
|
|
|
# This dictionary converts values from platform.machine()
|
|
|
|
# to a "cpu" string. It is needed to set the correct lib path,
|
|
|
|
# found in the JRE_HOME, e.g.: <JRE_HOME>/lib/<cpu>/.
|
|
|
|
MACHINE2CPU = {
|
|
|
|
"i686": "i386",
|
|
|
|
"x86_64": "amd64",
|
|
|
|
"AMD64": "amd64",
|
|
|
|
"armv7l": "arm",
|
2021-09-03 14:15:01 +00:00
|
|
|
"aarch64": "aarch64",
|
2019-11-24 22:05:11 +00:00
|
|
|
"sun4u": "sparcv9",
|
|
|
|
"sun4v": "sparcv9"
|
|
|
|
}
|
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
DEFAULT_PLATFORM = sys.platform
|
|
|
|
|
2021-08-13 09:47:19 +00:00
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
def is_set(string):
|
|
|
|
return string is not None and len(string) > 0
|
|
|
|
|
2021-08-13 09:47:19 +00:00
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
def get_java_setup(platform=DEFAULT_PLATFORM):
|
|
|
|
'''
|
|
|
|
Returns an instance of JavaLocation.
|
|
|
|
'''
|
|
|
|
# prefer Env variables
|
|
|
|
JAVA_HOME = getenv('JAVA_HOME')
|
|
|
|
if not is_set(JAVA_HOME):
|
|
|
|
JAVA_HOME = getenv('JDK_HOME')
|
|
|
|
if not is_set(JAVA_HOME):
|
|
|
|
JAVA_HOME = getenv('JRE_HOME')
|
|
|
|
#TODO encodings
|
|
|
|
|
|
|
|
# Use java_home program on Mac
|
|
|
|
if not is_set(JAVA_HOME) and platform == 'darwin':
|
|
|
|
JAVA_HOME = get_osx_framework()
|
|
|
|
if not is_set(JAVA_HOME):
|
|
|
|
raise Exception('You must install Java for Mac OSX')
|
2021-08-13 09:47:19 +00:00
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
# go hunting for Javac and Java programs, in that order
|
|
|
|
if not is_set(JAVA_HOME):
|
|
|
|
JAVA_HOME = get_jdk_home(platform)
|
2021-08-13 09:47:19 +00:00
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
if not is_set(JAVA_HOME):
|
|
|
|
JAVA_HOME = get_jre_home(platform)
|
|
|
|
|
|
|
|
if JAVA_HOME is None:
|
|
|
|
raise RuntimeError("Could not find your Java installed. Please set the JAVA_HOME env var.")
|
|
|
|
|
|
|
|
if isinstance(JAVA_HOME, bytes):
|
|
|
|
JAVA_HOME = JAVA_HOME.decode('utf-8')
|
|
|
|
|
|
|
|
log.debug("Identified Java at %s" % JAVA_HOME)
|
|
|
|
|
|
|
|
# Remove /bin if it's appended to JAVA_HOME
|
|
|
|
if JAVA_HOME[-3:] == 'bin':
|
|
|
|
JAVA_HOME = JAVA_HOME[:-4]
|
|
|
|
|
|
|
|
if platform == "android":
|
|
|
|
return AndroidJavaLocation(platform, JAVA_HOME)
|
|
|
|
if platform == "win32": #only this?
|
|
|
|
return WindowsJavaLocation(platform, JAVA_HOME)
|
|
|
|
if platform == "darwin": #only this?
|
|
|
|
return MacOsXJavaLocation(platform, JAVA_HOME)
|
2022-07-26 02:20:44 +00:00
|
|
|
if 'bsd' in platform:
|
|
|
|
return BSDJavaLocation(platform, JAVA_HOME)
|
2020-05-29 09:26:49 +00:00
|
|
|
if platform in ('linux', 'linux2', 'sunos5'): #only this?
|
|
|
|
return UnixJavaLocation(platform, JAVA_HOME)
|
|
|
|
log.warning("warning: unknown platform %s assuming linux or sunOS" % platform)
|
|
|
|
return UnixJavaLocation(platform, JAVA_HOME)
|
|
|
|
|
|
|
|
|
2021-08-13 09:47:19 +00:00
|
|
|
class JavaLocation:
|
2020-05-29 09:26:49 +00:00
|
|
|
def __init__(self, platform, home):
|
|
|
|
self.platform = platform
|
|
|
|
self.home = home
|
|
|
|
|
|
|
|
def get_javahome(self):
|
|
|
|
'''
|
|
|
|
Returns the location of the identified JRE or JDK
|
|
|
|
'''
|
|
|
|
return self.home
|
|
|
|
|
|
|
|
|
|
|
|
def is_jdk(self):
|
|
|
|
'''
|
|
|
|
Returns true if the location is a JDK, based on existing of javac
|
|
|
|
'''
|
2020-06-22 10:58:32 +00:00
|
|
|
javac = self.get_javac()
|
|
|
|
return exists(javac)
|
2020-05-29 09:26:49 +00:00
|
|
|
|
|
|
|
def get_javac(self):
|
|
|
|
'''
|
|
|
|
Returns absolute path of the javac executable
|
|
|
|
'''
|
|
|
|
return join(self.home, "bin", "javac")
|
|
|
|
|
|
|
|
def get_include_dirs(self):
|
|
|
|
'''
|
|
|
|
Returns a list of absolute paths of JDK include directories, for compiling.
|
|
|
|
Calls _get_platform_include_dir() internally.
|
|
|
|
'''
|
|
|
|
return [
|
|
|
|
join(self.home, 'include'),
|
|
|
|
self._get_platform_include_dir()
|
|
|
|
]
|
|
|
|
|
|
|
|
def _get_platform_include_dir(self):
|
|
|
|
'''
|
|
|
|
Returns the platform-specific include directory, for setup.py
|
|
|
|
'''
|
|
|
|
pass
|
|
|
|
|
|
|
|
def get_library_dirs(self):
|
|
|
|
'''
|
|
|
|
Returns a list of absolute paths of JDK lib directories, for setup.py
|
|
|
|
'''
|
|
|
|
pass
|
|
|
|
|
|
|
|
def get_libraries(self):
|
|
|
|
'''
|
|
|
|
Returns the names of the libraries for this platform, for setup.py
|
|
|
|
'''
|
|
|
|
pass
|
|
|
|
|
|
|
|
def get_jnius_lib_location(self):
|
|
|
|
'''
|
|
|
|
Returns the full path of the Java library for runtime binding with.
|
|
|
|
Can be overridden by using JVM_PATH env var to set absolute path of the Java library
|
|
|
|
'''
|
|
|
|
libjvm_override_path = getenv('JVM_PATH')
|
|
|
|
if libjvm_override_path:
|
|
|
|
log.info(
|
|
|
|
dedent("""
|
|
|
|
Using override env var JVM_PATH (%s) to load libjvm.
|
|
|
|
Please report your system information (os version, java
|
|
|
|
version, etc), and the path that works for you, to the
|
|
|
|
PyJNIus project, at https://github.com/kivy/pyjnius/issues.
|
|
|
|
so we can improve the automatic discovery.
|
|
|
|
"""
|
|
|
|
),
|
|
|
|
libjvm_override_path
|
|
|
|
)
|
|
|
|
return libjvm_override_path
|
|
|
|
|
|
|
|
platform = self.platform
|
2022-06-05 21:23:30 +00:00
|
|
|
log.debug("looking for libjvm to initiate pyjnius, platform is %s", platform)
|
|
|
|
lib_locations = self._possible_lib_locations()
|
2020-05-29 09:26:49 +00:00
|
|
|
for location in lib_locations:
|
|
|
|
full_lib_location = join(self.home, location)
|
|
|
|
if exists(full_lib_location):
|
|
|
|
log.debug("found libjvm.so at %s", full_lib_location)
|
|
|
|
return full_lib_location
|
2021-08-13 09:47:19 +00:00
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
raise RuntimeError(
|
|
|
|
"""
|
|
|
|
Unable to find libjvm.so, (tried %s)
|
|
|
|
you can use the JVM_PATH env variable with the absolute path
|
|
|
|
to libjvm.so to override this lookup, if you know
|
|
|
|
where pyjnius should look for it.
|
|
|
|
|
|
|
|
e.g:
|
|
|
|
export JAVA_HOME=/usr/lib/jvm/java-8-oracle/
|
|
|
|
export JVM_PATH=/usr/lib/jvm/java-8-oracle/jre/lib/amd64/server/libjvm.so
|
|
|
|
# run your program
|
|
|
|
"""
|
|
|
|
% [join(self.home, loc) for loc in lib_locations]
|
|
|
|
)
|
2019-11-24 22:05:11 +00:00
|
|
|
|
2022-06-05 21:23:30 +00:00
|
|
|
def _possible_lib_locations(self):
|
2020-05-29 09:26:49 +00:00
|
|
|
'''
|
|
|
|
Returns a list of relative possible locations for the Java library.
|
|
|
|
Used by the default implementation of get_jnius_lib_location()
|
|
|
|
'''
|
|
|
|
pass
|
2019-11-24 22:05:11 +00:00
|
|
|
|
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
class WindowsJavaLocation(JavaLocation):
|
|
|
|
def get_javac(self):
|
2020-06-22 10:58:32 +00:00
|
|
|
return super().get_javac() + ".exe"
|
2019-11-24 22:05:11 +00:00
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
def get_libraries(self):
|
|
|
|
return ['jvm']
|
2021-08-13 09:47:19 +00:00
|
|
|
|
2020-06-22 11:50:10 +00:00
|
|
|
def get_library_dirs(self):
|
|
|
|
suffices = ['lib', join('bin', 'server')]
|
2021-08-13 09:47:19 +00:00
|
|
|
return [join(self.home, suffix) for suffix in suffices]
|
2019-11-24 22:05:11 +00:00
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
def _get_platform_include_dir(self):
|
|
|
|
return join(self.home, 'include', 'win32')
|
|
|
|
|
|
|
|
|
2021-08-13 09:47:19 +00:00
|
|
|
class UnixJavaLocation(JavaLocation):
|
2020-05-29 09:26:49 +00:00
|
|
|
def _get_platform_include_dir(self):
|
|
|
|
if self.platform == 'sunos5':
|
|
|
|
return join(self.home, 'include', 'solaris')
|
2019-11-24 22:05:11 +00:00
|
|
|
else:
|
2020-05-29 09:26:49 +00:00
|
|
|
return join(self.home, 'include', 'linux')
|
|
|
|
|
2022-06-05 21:23:30 +00:00
|
|
|
def _possible_lib_locations(self):
|
2020-05-29 09:26:49 +00:00
|
|
|
root = self.home
|
|
|
|
if root.endswith('jre'):
|
|
|
|
root = root[:-3]
|
2019-11-24 22:05:11 +00:00
|
|
|
|
2022-06-05 21:23:30 +00:00
|
|
|
cpu = get_cpu()
|
|
|
|
log.debug(
|
|
|
|
f"Platform {self.platform} may need cpu in path to find libjvm, which is: {cpu}"
|
|
|
|
)
|
|
|
|
|
2019-11-24 22:05:11 +00:00
|
|
|
return [
|
2020-05-29 09:26:49 +00:00
|
|
|
'lib/server/libjvm.so',
|
|
|
|
'jre/lib/{}/default/libjvm.so'.format(cpu),
|
|
|
|
'jre/lib/{}/server/libjvm.so'.format(cpu),
|
2019-11-24 22:05:11 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
|
2022-07-26 02:20:44 +00:00
|
|
|
# NOTE: Build works on FreeBSD. Other BSD flavors may need tuning!
|
|
|
|
class BSDJavaLocation(JavaLocation):
|
|
|
|
def _get_platform_include_dir(self):
|
|
|
|
os = self.platform.translate({ord(n): None for n in '0123456789'})
|
|
|
|
return join(self.home, 'include', os)
|
|
|
|
|
|
|
|
def _possible_lib_locations(self):
|
|
|
|
root = self.home
|
|
|
|
if root.endswith('jre'):
|
|
|
|
root = root[:-3]
|
|
|
|
|
|
|
|
cpu = get_cpu()
|
|
|
|
log.debug(
|
|
|
|
f"Platform {self.platform} may need cpu in path to find libjvm, which is: {cpu}"
|
|
|
|
)
|
|
|
|
|
|
|
|
return [
|
|
|
|
'lib/server/libjvm.so',
|
|
|
|
'jre/lib/{}/default/libjvm.so'.format(cpu),
|
|
|
|
'jre/lib/{}/server/libjvm.so'.format(cpu),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
class MacOsXJavaLocation(UnixJavaLocation):
|
|
|
|
def _get_platform_include_dir(self):
|
2020-05-29 09:34:55 +00:00
|
|
|
return join(self.home, 'include', 'darwin')
|
2020-05-29 09:26:49 +00:00
|
|
|
|
2022-06-05 21:23:30 +00:00
|
|
|
def _possible_lib_locations(self):
|
2020-05-29 09:34:55 +00:00
|
|
|
if '1.6' in self.home:
|
2020-05-29 09:26:49 +00:00
|
|
|
return ['../Libraries/libjvm.dylib'] # TODO what should this be resolved to?
|
2019-11-24 22:05:11 +00:00
|
|
|
|
|
|
|
return [
|
2020-05-29 09:26:49 +00:00
|
|
|
'jre/lib/jli/libjli.dylib',
|
|
|
|
# In that case, the Java version >=9.
|
|
|
|
'lib/jli/libjli.dylib',
|
|
|
|
# adoptopenjdk12 doesn't have the jli subfolder either
|
|
|
|
'lib/libjli.dylib',
|
2019-11-24 22:05:11 +00:00
|
|
|
]
|
2021-08-13 09:47:19 +00:00
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
# this is overridden due to the specifalities of version 1.6
|
|
|
|
def get_include_dirs(self):
|
|
|
|
framework = self.home
|
|
|
|
if '1.6' in framework:
|
|
|
|
return [join(
|
|
|
|
framework, (
|
|
|
|
'System/Library/Frameworks/'
|
|
|
|
'JavaVM.framework/Versions/Current/Headers'
|
|
|
|
)
|
|
|
|
)]
|
|
|
|
return super().get_include_dirs()
|
|
|
|
|
2021-08-13 09:47:19 +00:00
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
class AndroidJavaLocation(UnixJavaLocation):
|
2020-05-29 09:34:55 +00:00
|
|
|
def get_libraries(self):
|
2021-08-13 09:46:32 +00:00
|
|
|
return ['SDL2', 'log']
|
2020-05-29 09:26:49 +00:00
|
|
|
|
2022-05-29 07:49:55 +00:00
|
|
|
def get_include_dirs(self):
|
|
|
|
# When cross-compiling for Android, we should not use the include dirs
|
|
|
|
# exposed by the JDK. Instead, we should use the one exposed by the
|
|
|
|
# Android NDK (which are already handled via python-for-android).
|
|
|
|
return []
|
|
|
|
|
2020-05-29 09:26:49 +00:00
|
|
|
def get_library_dirs(self):
|
2021-08-13 09:46:32 +00:00
|
|
|
return []
|
2019-11-24 22:05:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
def get_jre_home(platform):
|
|
|
|
jre_home = None
|
2019-11-25 00:38:30 +00:00
|
|
|
if JAVA_HOME and exists(join(JAVA_HOME, 'jre')):
|
2019-11-24 22:05:11 +00:00
|
|
|
jre_home = join(JAVA_HOME, 'jre')
|
|
|
|
|
|
|
|
if platform != 'win32' and not jre_home:
|
2021-06-18 10:44:11 +00:00
|
|
|
try:
|
|
|
|
jre_home = realpath(
|
|
|
|
which('java')
|
|
|
|
).replace('bin/java', '')
|
|
|
|
except TypeError:
|
|
|
|
raise Exception('Unable to find java')
|
2019-11-24 22:05:11 +00:00
|
|
|
|
2020-06-04 15:38:27 +00:00
|
|
|
if is_set(jre_home):
|
|
|
|
return jre_home
|
2021-08-13 09:47:19 +00:00
|
|
|
|
2020-06-04 15:38:27 +00:00
|
|
|
# didnt find java command on the path, we can
|
|
|
|
# fallback to hunting in some default unix locations
|
|
|
|
for loc in ["/usr/java/latest/", "/usr/java/default/", "/usr/lib/jvm/default-java/"]:
|
|
|
|
if exists(loc + "bin/java"):
|
|
|
|
jre_home = loc
|
|
|
|
break
|
|
|
|
|
2019-11-24 22:05:11 +00:00
|
|
|
return jre_home
|
|
|
|
|
|
|
|
|
|
|
|
def get_jdk_home(platform):
|
|
|
|
jdk_home = getenv('JDK_HOME')
|
|
|
|
if not jdk_home:
|
|
|
|
if platform == 'win32':
|
|
|
|
TMP_JDK_HOME = getenv('JAVA_HOME')
|
|
|
|
if not TMP_JDK_HOME:
|
|
|
|
raise Exception('Unable to find JAVA_HOME')
|
|
|
|
|
|
|
|
# Remove /bin if it's appended to JAVA_HOME
|
|
|
|
if TMP_JDK_HOME[-3:] == 'bin':
|
|
|
|
TMP_JDK_HOME = TMP_JDK_HOME[:-4]
|
|
|
|
|
|
|
|
# Check whether it's JDK
|
|
|
|
if exists(join(TMP_JDK_HOME, 'bin', 'javac.exe')):
|
|
|
|
jdk_home = TMP_JDK_HOME
|
|
|
|
|
|
|
|
else:
|
2021-06-18 10:44:11 +00:00
|
|
|
try:
|
|
|
|
jdk_home = realpath(
|
|
|
|
which('javac')
|
|
|
|
).replace('bin/javac', '')
|
|
|
|
except TypeError:
|
|
|
|
raise Exception('Unable to find javac')
|
2019-11-24 22:05:11 +00:00
|
|
|
|
|
|
|
if not jdk_home or not exists(jdk_home):
|
2020-05-29 09:26:49 +00:00
|
|
|
return None
|
2019-11-24 22:05:11 +00:00
|
|
|
|
|
|
|
return jdk_home
|
|
|
|
|
2019-11-29 21:39:32 +00:00
|
|
|
|
2019-11-24 22:05:11 +00:00
|
|
|
def get_osx_framework():
|
|
|
|
framework = Popen(
|
|
|
|
'/usr/libexec/java_home',
|
|
|
|
stdout=PIPE, shell=True
|
|
|
|
).communicate()[0]
|
|
|
|
|
2022-10-16 12:56:56 +00:00
|
|
|
framework = framework.decode('utf-8')
|
2019-11-24 22:05:11 +00:00
|
|
|
return framework.strip()
|
|
|
|
|
|
|
|
|
|
|
|
def get_cpu():
|
|
|
|
try:
|
|
|
|
return MACHINE2CPU[machine]
|
|
|
|
except KeyError:
|
|
|
|
print(
|
|
|
|
"WARNING: Not able to assign machine()"
|
|
|
|
" = %s to a cpu value!" % machine
|
|
|
|
)
|
2021-09-02 13:19:59 +00:00
|
|
|
print(f" Using cpu = '{machine}' instead!")
|
|
|
|
return machine
|