Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<packaging>jar</packaging>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
Expand Down
46 changes: 43 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@
import sys
import sysconfig
import warnings
from distutils.command.build_ext import build_ext as old_build_ext

from setuptools import setup, Extension
from distutils.command.build_ext import build_ext as old_build_ext

if sys.version_info < (3, 7):
print('Python versions prior to 3.7 are not supported for PemJa.',
Expand Down Expand Up @@ -77,6 +76,8 @@ def is_osx():
def is_bsd():
return 'bsd' in sysconfig.get_platform()

def is_windows():
return 'win' in sysconfig.get_platform()

def get_python_libs():
libs = []
Expand All @@ -103,6 +104,33 @@ def get_java_linker_args():
return ['-framework JavaVM']
return []

def get_java_libraries():
if is_windows():
return ['jvm']
return []

def get_java_lib_folders():
if not is_osx():
import fnmatch
if is_windows():
jre = os.path.join(get_java_home(), 'lib')
else:
jre = os.path.join(get_java_home(), 'jre', 'lib')
if not os.path.exists(jre):
jre = os.path.join(get_java_home(), 'lib')
folders = []
for root, dirnames, filenames in os.walk(jre):
if is_windows():
for filename in fnmatch.filter(filenames, '*jvm.lib'):
folders.append(os.path.join(
root, os.path.dirname(filename)))
else:
for filename in fnmatch.filter(filenames, '*jvm.so'):
folders.append(os.path.join(
root, os.path.dirname(filename)))

return list(set(folders))
return []

def get_java_include():
inc_name = 'include'
Expand Down Expand Up @@ -132,6 +160,10 @@ def get_java_include():
if os.path.exists(include_darwin):
paths.append(include_darwin)

include_win32 = os.path.join(inc, 'win32')
if os.path.exists(include_win32):
paths.append(include_win32)

include_bsd = os.path.join(inc, 'freebsd')
if os.path.exists(include_bsd):
paths.append(include_bsd)
Expand All @@ -158,18 +190,26 @@ def build_extension(self, ext):
ext.extra_compile_args.append('-std=c99')
old_build_ext.build_extension(self, ext)

def run(self):
old_build_ext.run(self)
if is_windows():
for lib in self.get_outputs():
dll = lib.replace('.pyd', '.dll')
self.copy_file(lib, dll)

extensions = ([
Extension(
name="pemja_core",
sources=get_files('src/main/c/pemja/core', '.c'),
libraries=get_python_libs(),
libraries=get_java_libraries() + get_python_libs(),
library_dirs = get_java_lib_folders(),
extra_link_args=get_java_linker_args(),
include_dirs=get_java_include() + ['src/main/c/pemja/core/include'],
language=3),
Extension(
name="pemja_utils",
sources=get_files('src/main/c/pemja/utils', '.c'),
library_dirs = get_java_lib_folders(),
extra_link_args=get_java_linker_args(),
include_dirs=get_java_include() + ['src/main/c/pemja/utils/include'],
language=3)
Expand Down
8 changes: 8 additions & 0 deletions src/main/c/pemja/core/PythonInterpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
#include "MainInterpreter.h"
#include "PythonInterpreter.h"

// use windows mingw32
#if (defined(_WIN32) || defined(_WIN64)) && defined(__MINGW32__)
PyMODINIT_FUNC PyInit_pemja_core(void) {
// pass
}
#else
#endif

// ---------------------------------- jni functions ------------------------


Expand Down
2 changes: 1 addition & 1 deletion src/main/c/pemja/core/include/pyutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ JcpAPI_FUNC(PyObject*) JcpPyObject_FromJObject(JNIEnv*, jobject);
/* Functions to return a Python primitive object from a C primitive value */
JcpAPI_FUNC(PyObject*) JcpPyBool_FromLong(long);
JcpAPI_FUNC(PyObject*) JcpPyInt_FromInt(int);
JcpAPI_FUNC(PyObject*) JcpPyInt_FromLong(long);
JcpAPI_FUNC(PyObject*) JcpPyInt_FromLong(jlong);
JcpAPI_FUNC(PyObject*) JcpPyFloat_FromDouble(double);
JcpAPI_FUNC(PyObject*) JcpPyString_FromChar(jchar);

Expand Down
2 changes: 1 addition & 1 deletion src/main/c/pemja/core/pylib.c
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ JcpPyObject_SetJLong(JNIEnv *env, intptr_t ptr, const char *name, jlong value)

Jcp_BEGIN_ALLOW_THREADS

_JcpPyObject_SetPyObject(jcp_thread->globals, name, JcpPyInt_FromLong((long) value));
_JcpPyObject_SetPyObject(jcp_thread->globals, name, JcpPyInt_FromLong(value));

Jcp_END_ALLOW_THREADS
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/c/pemja/core/python_class/pyjfield.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ JcpPyJField_Get(PyJFieldObject* self, PyJObject* pyjobject)
object = (*env)->GetLongField(env, pyjobject->object, self->fd_id);
}

result = JcpPyInt_FromLong((long) object);
result = JcpPyInt_FromLong(object);
break;
}
case JFLOAT_ID: {
Expand Down
2 changes: 1 addition & 1 deletion src/main/c/pemja/core/python_class/pyjmethod.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ pyjmethod_call(PyJMethodObject *self, PyObject *args, PyObject *kwargs)
goto EXIT_ERROR;
}

pyobject = JcpPyInt_FromLong((long) object);
pyobject = JcpPyInt_FromLong(object);
break;
}
case JFLOAT_ID: {
Expand Down
4 changes: 2 additions & 2 deletions src/main/c/pemja/core/pyutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ JcpPyInt_FromInt(int value)
/* Function to return a Python Float from a float value */

PyObject*
JcpPyInt_FromLong(long value)
JcpPyInt_FromLong(jlong value)
{

return PyLong_FromLongLong(value);
Expand Down Expand Up @@ -600,7 +600,7 @@ JcpPyInt_FromJLong(JNIEnv* env, jobject value)
return NULL;
}

return JcpPyInt_FromLong((long) l);
return JcpPyInt_FromLong(l);
}


Expand Down
49 changes: 35 additions & 14 deletions src/main/c/pemja/utils/CommonUtils.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <dlfcn.h>
#include <CommonUtils.h>

#if (defined(_WIN32) || defined(_WIN64)) && defined(__MINGW32__)
#include <windows.h>
#include <Python.h>
PyMODINIT_FUNC PyInit_pemja_utils(void) {
// pass
}
#else
// linux and macos
#include <dlfcn.h>
#endif

JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved)
{
Expand All @@ -29,17 +39,28 @@ JNI_OnLoad(JavaVM *vm, void *reserved)
JNIEXPORT void JNICALL Java_pemja_utils_CommonUtils_loadLibrary0
(JNIEnv *env, jobject obj, jstring library)
{
void* dlresult = dlopen((*env)->GetStringUTFChars(env, library, 0), RTLD_NOW | RTLD_GLOBAL);
if (dlresult) {
// The dynamic linker maintains reference counts so closing it is a no-op.
dlclose(dlresult);
} else {
/*
* Ignore errors and hope that the library is loaded globally or the
* extensions are linked. If developers need to debug the cause they
* should print the result of dlerror.
*/
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
char* fileName = (*env)->GetStringUTFChars(env, library, 0);
#if (defined(_WIN32) || defined(_WIN64))
HINSTANCE dlresult = LoadLibrary(fileName);
if (dlresult) {
FreeLibrary(dlresult);
} else {
fprintf(stderr, "load dll failed. 0x%x\n", GetLastError());
exit(EXIT_FAILURE);
}
#else
void* dlresult = dlopen(fileName, RTLD_NOW | RTLD_GLOBAL);
if (dlresult) {
// The dynamic linker maintains reference counts so closing it is a no-op.
dlclose(dlresult);
} else {
/*
* Ignore errors and hope that the library is loaded globally or the
* extensions are linked. If developers need to debug the cause they
* should print the result of dlerror.
*/
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
#endif
}
10 changes: 7 additions & 3 deletions src/main/java/pemja/core/PythonInterpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ private void configSearchPaths(String[] paths) {
if (paths != null) {
exec("import sys");
for (int i = paths.length - 1; i >= 0; i--) {
exec(String.format("sys.path.insert(0, '%s')", paths[i]));
exec(String.format("sys.path.insert(0, r'%s')", paths[i]));
}
}
}
Expand Down Expand Up @@ -335,6 +335,10 @@ private static class MainInterpreter implements Serializable, AutoCloseable {

private static final MainInterpreter instance = new MainInterpreter();

private static final String unixLibPattern = "^pemja_core\\.cpython-.*\\.so$";

private static final String windowsLibPattern = "^pemja_core\\.cp.*\\.dll$";

private final CountDownLatch damonThreadStart = new CountDownLatch(1);

private final CountDownLatch damonThreadFinish = new CountDownLatch(1);
Expand All @@ -352,9 +356,9 @@ private MainInterpreter() {}
@SuppressWarnings("unchecked")
synchronized void initialize(String pythonExec) {
if (!isStarted) {
String pattern = CommonUtils.INSTANCE.isWindows() ? windowsLibPattern : unixLibPattern;
String pemjaLibPath =
CommonUtils.INSTANCE.getLibraryPathWithPattern(
pythonExec, "^pemja_core\\.cpython-.*\\.so$");
CommonUtils.INSTANCE.getLibraryPathWithPattern(pythonExec, pattern);
String pythonLibPath = CommonUtils.INSTANCE.getPythonLibrary(pythonExec);
String pemjaModulePath = CommonUtils.INSTANCE.getPemJaModulePath(pythonExec);

Expand Down
7 changes: 6 additions & 1 deletion src/main/java/pemja/utils/CommonUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ private CommonUtils() {}
@SuppressWarnings("unchecked")
public void loadLibrary(String pythonExec, String library) {
if (!initialized) {
String pattern = isWindows() ? "^pemja_utils\\.cp.*\\.dll$" : "^pemja_utils\\.cpython-.*\\.so$";
String utilsLibPath =
getLibraryPathWithPattern(pythonExec, "^pemja_utils\\.cpython-.*\\.so$");
getLibraryPathWithPattern(pythonExec, pattern);
try {
System.load(utilsLibPath);
} catch (UnsatisfiedLinkError error) {
Expand Down Expand Up @@ -161,6 +162,10 @@ public boolean isLinuxOs() {
return os.startsWith("Linux");
}

public boolean isWindows() {
return System.getProperty("os.name", "").startsWith("Windows");
}

private String execute(String[] commands) throws IOException {
ProcessBuilder pb = new ProcessBuilder(commands);
pb.redirectErrorStream(true);
Expand Down
1 change: 0 additions & 1 deletion src/test/java/pemja/core/PythonInterpreterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ public void prepareTestEnvironment() {
this.testDir =
new String[] {
String.join(
File.separator,
File.separator,
System.getProperty("user.dir"),
"src",
Expand Down