jep는 간략하게 설명하면 java로 python interpreter를 구현하여 C / C++ 기반의 library와는 호환이 어려웠던 jython과는 다르게, JNI를 통해 CPython을 호출함으로써 C / C++ 기반의 python library도 java 상에서 실행이 가능한 프로젝트이다.
Getting-Started 를 따라서 설치를 진행하다보면, 별도의 python library 사용 없는 간단한 python 코드의 경우 쉽게 실행 가능하다
Main.java:
import jep.Jep;
public class Main {
public static void main(String[] args) throws Exception{
try(Jep jep = new Jep(false)) {
jep.eval("from java.lang import System");
jep.eval("s = 'Hello World'");
jep.eval("System.out.println(s)");
jep.eval("print(s)");
jep.eval("print(s[1:-1])");
}
}
}
compile 및 실행
javac -cp /usr/local/lib/python2.7/dist-packages/jep/jep-3.6.3.jar Main.java
java -cp /usr/local/lib/python2.7/dist-packages/jep/jep-3.6.3.jar:. -Djava.library.path=/usr/local/lib/python2.7/dist-packages/jep Main
실행 결과:
Hello World
Hello World
ello Worl
그러나, Numpy와 같은 외부 라이브러리를 사용하려고 하면, 다음과 같은 에러를 확인할 수 있다:
Exception in thread "main" jep.JepException: :
Importing the multiarray numpy extension module failed. Most
likely you are trying to import a failed build of numpy.
If you're working with a numpy git repo, try `git clean -xdf` (removes all
files not under version control). Otherwise reinstall numpy.
at /usr/local/lib/python2.7/dist-packages/numpy/core/__init__.(__init__.py:24)
at /usr/local/lib/python2.7/dist-packages/numpy/lib/type_check.(type_check.py:11)
at /usr/local/lib/python2.7/dist-packages/numpy/lib/__init__.(__init__.py:8)
at /usr/local/lib/python2.7/dist-packages/numpy/add_newdocs.(add_newdocs.py:13)
at /usr/local/lib/python2.7/dist-packages/numpy/__init__.(__init__.py:142)
당연히 Numpy는 정상작동 하고 있는 상태여서 왜 이런 문제가 발생할까, 어떻게 해결할까 고민했는데 문제자체는 jep 가 포함된 java를 실행할 때 환경 변수의 문제였다.
(* jep github page의 버그 리포팅을 보면 python 2.7.11 에서는 문제가 있을 수도 있으므로, 2.7.10 이나 2.7.12 혹은 더 높은 버전을 사용하는 것을 추천한다.)
다음과 같이 실행 전에 환경변수를 주면 위와 같이 library import 시 제대로 못읽어오는 문제는 해결할 수 있다:
LD_LIBRARY_PATH="/usr/lib:/usr/local/lib/python2.7/dist-packages/"; export LD_LIBRARY_PATH
LD_PRELOAD="/usr/lib/x86_64-linux-gnu/libpython2.7.so"; export LD_PRELOAD
java -cp /usr/local/lib/python2.7/dist-packages/jep/jep-3.6.3.jar:. -Djava.library.path=/usr/local/lib/python2.7/dist-packages/jep Main
참고로, LD_LIBRARY_PATH와 LD_PRELOAD에 사용하는 python library 및 so 파일의 경로는 리눅스 배포판 마다 다르다.
나와 같이 python은 잘 사용하지 않아 아무것도 모르는 상태라면, 개인적으로 numpy와 같은 library가 잘 작동하고 있는지도 확인할 겸 jep test를 진행하는것을 추천한다.
상단의 jep의 github에서 해당 git 을 가져온 후, test를 진행해 보자:
python setup.py test
빌드 메시지들도 나오면서, 정상적으로 작동한다면 다음과 같이 끝나는 메시지를 얻을 수 있다:
$python setup.py test
numpy include found at /usr/local/lib/python2.7/dist-packages/numpy/core/include
running test
running build
running setup_java
running build_java
running build_javah
running build_jar
running build_py
running build_ext
running build_scripts
ln -sf jep.so build/lib.linux-x86_64-2.7/libjep.so
....................................................................................................................ssssssssssss......................
----------------------------------------------------------------------
Ran 150 tests in 1.869s
OK (skipped=12)
나의 경우 이미 실행을 해 빌드 메시지는 나오지 않았다.
test가 끝났다면 jep 디렉토리 내에 build 디렉토리가 생기고, build/scripts-{python.version}/jep 스크립트를 열어보면 다음과 같이 생겼다:
#!/bin/sh
VIRTUAL_ENV=
export VIRTUAL_ENV
LD_LIBRARY_PATH="/usr/lib:/usr/local/lib/python2.7/dist-packages/"; export LD_LIBRARY_PATH
LD_PRELOAD="/usr/lib/x86_64-linux-gnu/libpython2.7.so"; export LD_PRELOAD
if test "x$VIRTUAL_ENV" != "x"; then
PATH="$VIRTUAL_ENV/bin:$PATH"
export PATH
PYTHONHOME="$VIRTUAL_ENV"
export PYTHONHOME
fi
cp="/usr/local/lib/python2.7/dist-packages/jep/jep-3.6.3.jar"
if test "x$CLASSPATH" != "x"; then
cp="$cp":"$CLASSPATH"
fi
jni_path="/usr/local/lib/python2.7/dist-packages/jep"
args=$*
if test "x$args" = "x"; then
args="/usr/local/lib/python2.7/dist-packages/jep/console.py"
fi
exec java -classpath "$cp" -Djava.library.path="$jni_path" jep.Run $args
해당 스크립트를 참조하면 자신의 환경에서 LD_LIBRARY_PATH, LD_PRELOAD, -Djava.library.path, -classpath 에 어떤 파일 및 경로를 지정해야 하는지 쉽게 알 수 있다.
'Programming > Python' 카테고리의 다른 글
Streamlit SessionState (0) | 2021.04.05 |
---|---|
Python elasticsearch에서 custom header 추가하기 (0) | 2021.03.25 |
python rocksdb 에서 column family 사용하기 (0) | 2019.02.16 |