저는 파이썬에서 C++ 클래스를 호출하고 싶어서 최근에 스스로 방법을 찾았습니다. 저는 (Thrift를 사용하여 전에 했던 것처럼 - Python과 C++을 위한 Apache Thrift 사용하기를 보세요.) 분리된 프로세스 를 호출하고 싶지 않았고 C++ 라이브러리를 직접 호출하고 싶었습니다.
저는 진행하기 전에 이를 Java로 하기 위한 다양한 방법이 있다는 것을 말하고 싶습니다. 그리고 저는 작동한 것 중 하나를 선택하였습니다. 다른 기술도 사용 가능하며 어떤 기술이 '최상'인지에 대한 의견은 상당히 분분해 보입니다.
C++ 클래스로 시작하기 위해 평범하게 작성하였습니다.
%%writefile foo.cpp
#include <iostream>
// A simple class with a constuctor and some methods...
// 생성자와 몇 개의 메소드를 가지는 간단한 클래스...
class Foo
{
public:
Foo(int);
void bar();
int foobar(int);
private:
int val;
};
Foo::Foo(int n)
{
val = n;
}
void Foo::bar()
{
std::cout << "Value is " << val << std::endl;
}
int Foo::foobar(int n)
{
return val + n;
}
Writing foo.cpp
다음 ctypes 시스템은 C++을 사용할 수 없기 때문에 C++ 코드 주변에 C wrapper를 놓을 것입니다. 이를 하기 위해 파일 제일 밑에 다음 부분에 코드를 추가합니다.
add_src = """
extern "C"
{
Foo* Foo_new(int n) {return new Foo(n);}
void Foo_bar(Foo* foo) {foo->bar();}
int Foo_foobar(Foo* foo, int n) {return foo->foobar(n);}
}"""
f = open('foo.cpp', 'a')
f.write(add_src)
f.close()
호출하기 원하는 각 메소드를 클래스 기반이 아닌 이름으로 제공해야 함을 알아두세요.
우리는 우리 코드에서 libfoo.so 파일을 빌드해야 합니다.
다음을 쉘에서 입력하세요.
!g++ -c -fPIC foo.cpp -o foo.o
!g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o
!ls -lrt
total 32 drwxr-xr-x 1 root root 4096 May 6 13:44 sample_data -rw-r--r-- 1 root root 586 May 20 08:43 foo.cpp -rw-r--r-- 1 root root 4424 May 20 08:44 foo.o -rwxr-xr-x 1 root root 13320 May 20 08:44 libfoo.so
!cat foo.cpp
#include <iostream> // A simple class with a constuctor and some methods... // 생성자와 몇 개의 메소드를 가지는 간단한 클래스... class Foo { public: Foo(int); void bar(); int foobar(int); private: int val; }; Foo::Foo(int n) { val = n; } void Foo::bar() { std::cout << "Value is " << val << std::endl; } int Foo::foobar(int n) { return val + n; } extern "C" { Foo* Foo_new(int n) {return new Foo(n);} void Foo_bar(Foo* foo) {foo->bar();} int Foo_foobar(Foo* foo, int n) {return foo->foobar(n);} }
또는 CMake를 사용할 수 있습니다.
다음은 foo.cpp를 빌드하기 위한 CMakeLists.txt 입니다.
cmake_minimum_required(VERSION 2.8.9)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}")
set(CMAKE_MACOSX_RPATH 1)
project (foo)
set (SOURCE foo.cpp)
add_library(foo MODULE ${SOURCE})
저는 Mac에서 빌드를 해서 MacOS를 위해 4번째 줄을 추가하였습니다. 리눅스에서도 잘 작동하겠지만 필요는 없습니다.
이제 C++로 컴파일 된 내용을 작성합니다. 우리는 클래스에 대한 Python wrapper를 빌드하려 합니다.
%%writefile foo.py
import ctypes
lib = ctypes.cdll.LoadLibrary('./libfoo.so')
class Foo(object):
def __init__(self, val):
lib.Foo_new.argtypes = [ctypes.c_int]
lib.Foo_new.restype = ctypes.c_void_p
lib.Foo_bar.argtypes = [ctypes.c_void_p]
lib.Foo_bar.restype = ctypes.c_void_p
lib.Foo_foobar.argtypes = [ctypes.c_void_p, ctypes.c_int]
lib.Foo_foobar.restype = ctypes.c_int
self.obj = lib.Foo_new(val)
def bar(self):
lib.Foo_bar(self.obj)
def foobar(self, val):
return lib.Foo_foobar(self.obj, val)
Writing foo.py
리턴 값의 타입과 argument 타입을 정의하는 요구사항을 적으세요. (하나도 리턴하지 않으면 예시로 void를 리턴합니다.) 이것이 없으면 segmentation fault(등)를 얻을 것입니다.
이제 모든 것을 다 하였고 모듈을 빌드해야 합니다. 파이썬에서 간단히 그것을 import할 수 있습니다.
예를 들어
from foo import Foo
# 우리는 5라는 값으로 Foo 객체를 생성할 것입니다...
f=Foo(5)
# f.bar()를 호출하는 것은 값을 포함한 메시지를 출력할 것입니다...
f.bar()
# 이제 f, Foo 객체에서 저장되어 있는 값에 값(7)을 더하기 위해 foobar를 사용합니다.
print (f.foobar(7))
# 또 한 번 같은 메소드를 호출합니다 - 이 번엔 일반적인 파이썬 정수를
# 보여줄 것입니다...
x = f.foobar(2)
print (type(x))
!python
Python 3.7.10 (default, May 3 2021, 02:48:31) [GCC 7.5.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from foo import Foo >>> f=Foo(5) >>> f.bar() Value is 5 >>> print (f.foobar(7)) 12 >>> x = f.foobar(2) >>> x 7 >>> print (type(x)) <class 'int'> >>> quit()
이 간단한 데모를 위한 전체 소스 코드는 여기에 있습니다.
!apt-get update
!apt-get install openjdk-8-jdk-headless -qq > /dev/null
Hit:1 http://archive.ubuntu.com/ubuntu bionic InRelease Get:2 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB] Get:3 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic InRelease [15.9 kB] Hit:4 http://ppa.launchpad.net/cran/libgit2/ubuntu bionic InRelease Get:5 https://cloud.r-project.org/bin/linux/ubuntu bionic-cran40/ InRelease [3,626 B] Get:6 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB] Hit:7 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic InRelease Get:8 http://ppa.launchpad.net/graphics-drivers/ppa/ubuntu bionic InRelease [21.3 kB] Get:9 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB] Ign:10 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 InRelease Ign:11 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 InRelease Get:12 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 Release [697 B] Hit:13 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 Release Get:14 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 Release.gpg [836 B] Get:15 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages [2,183 kB] Get:16 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [2,583 kB] Get:17 http://archive.ubuntu.com/ubuntu bionic-updates/restricted amd64 Packages [452 kB] Get:18 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic/main Sources [1,767 kB] Get:19 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic/main amd64 Packages [904 kB] Get:20 https://cloud.r-project.org/bin/linux/ubuntu bionic-cran40/ Packages [60.5 kB] Get:21 http://ppa.launchpad.net/graphics-drivers/ppa/ubuntu bionic/main amd64 Packages [41.5 kB] Ign:23 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 Packages Get:23 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 Packages [772 kB] Get:24 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [2,152 kB] Get:25 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [1,412 kB] Get:26 http://security.ubuntu.com/ubuntu bionic-security/restricted amd64 Packages [423 kB] Fetched 13.0 MB in 4s (3,488 kB/s) Reading package lists... Done
import os
os.environ["JAVA_HOME"] = "/usr/lib/jvm/java-8-openjdk-amd64"
os.environ["PATH"] = "/usr/lib/jvm/java-8-openjdk-amd64/bin:" + os.environ["PATH"]
!java -version
openjdk version "1.8.0_292" OpenJDK Runtime Environment (build 1.8.0_292-8u292-b10-0ubuntu1~18.04-b10) OpenJDK 64-Bit Server VM (build 25.292-b10, mixed mode)
!wget https://services.gradle.org/distributions/gradle-3.4.1-bin.zip -P /tmp
--2021-05-20 08:55:53-- https://services.gradle.org/distributions/gradle-3.4.1-bin.zip Resolving services.gradle.org (services.gradle.org)... 104.18.191.9, 104.18.190.9, 2606:4700::6812:be09, ... Connecting to services.gradle.org (services.gradle.org)|104.18.191.9|:443... connected. HTTP request sent, awaiting response... 301 Moved Permanently Location: https://downloads.gradle-dn.com/distributions/gradle-3.4.1-bin.zip [following] --2021-05-20 08:55:53-- https://downloads.gradle-dn.com/distributions/gradle-3.4.1-bin.zip Resolving downloads.gradle-dn.com (downloads.gradle-dn.com)... 104.18.165.99, 104.18.164.99, 2606:4700::6812:a563, ... Connecting to downloads.gradle-dn.com (downloads.gradle-dn.com)|104.18.165.99|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 70310446 (67M) [application/zip] Saving to: ‘/tmp/gradle-3.4.1-bin.zip’ gradle-3.4.1-bin.zi 100%[===================>] 67.05M 177MB/s in 0.4s 2021-05-20 08:55:53 (177 MB/s) - ‘/tmp/gradle-3.4.1-bin.zip’ saved [70310446/70310446]
!sudo unzip -d /opt/gradle /tmp/gradle-*.zip
Archive: /tmp/gradle-3.4.1-bin.zip creating: /opt/gradle/gradle-3.4.1/ inflating: /opt/gradle/gradle-3.4.1/LICENSE creating: /opt/gradle/gradle-3.4.1/media/ inflating: /opt/gradle/gradle-3.4.1/media/gradle-icon-16x16.png inflating: /opt/gradle/gradle-3.4.1/media/gradle-icon-24x24.png inflating: /opt/gradle/gradle-3.4.1/media/gradle.icns inflating: /opt/gradle/gradle-3.4.1/media/gradle-icon-512x512.png inflating: /opt/gradle/gradle-3.4.1/media/gradle-icon-32x32.png inflating: /opt/gradle/gradle-3.4.1/media/gradle-icon-128x128.png inflating: /opt/gradle/gradle-3.4.1/media/gradle-icon-64x64.png inflating: /opt/gradle/gradle-3.4.1/media/gradle-icon-256x256.png inflating: /opt/gradle/gradle-3.4.1/media/gradle-icon-48x48.png creating: /opt/gradle/gradle-3.4.1/init.d/ inflating: /opt/gradle/gradle-3.4.1/init.d/readme.txt inflating: /opt/gradle/gradle-3.4.1/NOTICE inflating: /opt/gradle/gradle-3.4.1/getting-started.html creating: /opt/gradle/gradle-3.4.1/bin/ inflating: /opt/gradle/gradle-3.4.1/bin/gradle.bat inflating: /opt/gradle/gradle-3.4.1/bin/gradle creating: /opt/gradle/gradle-3.4.1/lib/ inflating: /opt/gradle/gradle-3.4.1/lib/gradle-script-kotlin-0.5.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/kotlin-compiler-embeddable-1.1-M02.jar inflating: /opt/gradle/gradle-3.4.1/lib/kotlin-reflect-1.1-M02.jar inflating: /opt/gradle/gradle-3.4.1/lib/kotlin-runtime-1.1-M02.jar inflating: /opt/gradle/gradle-3.4.1/lib/kotlin-stdlib-1.1-M02.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-launcher-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-wrapper-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-installation-beacon-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-base-services-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-jvm-services-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-core-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-cli-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-ui-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-tooling-api-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-native-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-logging-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/slf4j-api-1.7.10.jar inflating: /opt/gradle/gradle-3.4.1/lib/guava-jdk5-17.0.jar inflating: /opt/gradle/gradle-3.4.1/lib/commons-lang-2.6.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-process-services-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/groovy-all-2.4.7.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-model-core-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-model-groovy-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/asm-all-5.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/ant-1.9.6.jar inflating: /opt/gradle/gradle-3.4.1/lib/commons-collections-3.2.2.jar inflating: /opt/gradle/gradle-3.4.1/lib/commons-io-2.2.jar inflating: /opt/gradle/gradle-3.4.1/lib/jcip-annotations-1.0.jar inflating: /opt/gradle/gradle-3.4.1/lib/javax.inject-1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-base-services-groovy-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-messaging-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-resources-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-docs-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-open-api-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/dom4j-1.6.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/jaxen-1.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/jansi-1.14.jar inflating: /opt/gradle/gradle-3.4.1/lib/jul-to-slf4j-1.7.10.jar inflating: /opt/gradle/gradle-3.4.1/lib/log4j-over-slf4j-1.7.10.jar inflating: /opt/gradle/gradle-3.4.1/lib/jcl-over-slf4j-1.7.10.jar inflating: /opt/gradle/gradle-3.4.1/lib/ant-launcher-1.9.6.jar inflating: /opt/gradle/gradle-3.4.1/lib/kryo-2.20.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-freebsd-amd64-libcpp-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-freebsd-amd64-libstdcpp-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-freebsd-i386-libcpp-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-freebsd-i386-libstdcpp-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-linux-amd64-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-linux-i386-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-osx-amd64-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-osx-i386-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-windows-amd64-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-windows-i386-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-linux-amd64-ncurses5-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-linux-amd64-ncurses6-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-linux-i386-ncurses5-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/native-platform-linux-i386-ncurses6-0.13.jar inflating: /opt/gradle/gradle-3.4.1/lib/reflectasm-1.07-shaded.jar inflating: /opt/gradle/gradle-3.4.1/lib/minlog-1.2.jar inflating: /opt/gradle/gradle-3.4.1/lib/objenesis-1.2.jar creating: /opt/gradle/gradle-3.4.1/lib/plugins/ inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-plugins-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-code-quality-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-jetty-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-antlr-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-osgi-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-maven-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-ide-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-announce-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-scala-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-signing-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-ear-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-javascript-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-build-comparison-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-diagnostics-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-reporting-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-publish-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-ivy-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-jacoco-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-build-init-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-platform-base-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-platform-jvm-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-language-jvm-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-language-java-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-language-groovy-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-language-scala-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-platform-native-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-platform-play-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-ide-play-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-language-native-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-ide-native-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-testing-base-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-testing-native-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-testing-jvm-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-plugin-development-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-plugin-use-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-resources-http-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-resources-sftp-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-resources-s3-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-tooling-api-builders-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-composite-builds-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-build-cache-http-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-workers-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-dependency-management-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gradle-test-kit-3.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/commons-cli-1.2.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jetty-6.1.26.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jetty-util-6.1.26.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/servlet-api-2.5-20081211.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jetty-plus-6.1.26.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jsp-2.1-6.1.14.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jetty-annotations-6.1.26.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/geronimo-annotation_1.0_spec-1.0.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/biz.aQute.bndlib-3.2.0.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/maven-core-3.0.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/pmaven-common-0.8-20100325.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/pmaven-groovy-0.8-20100325.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/commons-codec-1.6.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/bcpg-jdk15on-1.51.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/rhino-1.7R3.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/gson-2.7.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/simple-4.1.21.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jatl-0.2.2.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/junit-4.12.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/testng-6.3.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/httpclient-4.4.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/nekohtml-1.9.14.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jsch-0.1.53.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/aws-java-sdk-s3-1.11.6.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/aws-java-sdk-kms-1.11.6.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/aws-java-sdk-core-1.11.6.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jackson-core-2.6.6.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jackson-annotations-2.6.6.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jackson-databind-2.6.6.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/joda-time-2.8.2.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/ivy-2.2.0.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/xbean-reflect-3.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/bcprov-jdk15on-1.51.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jetty-naming-6.1.26.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/core-3.1.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jsp-api-2.1-6.1.14.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/maven-settings-3.0.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/maven-settings-builder-3.0.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/plexus-utils-2.0.6.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/plexus-interpolation-1.14.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/plexus-container-default-1.5.5.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/plexus-classworlds-2.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/plexus-cipher-1.7.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/plexus-sec-dispatcher-1.3.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/maven-compat-3.0.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/maven-model-builder-3.0.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/maven-model-3.0.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/maven-artifact-3.0.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/maven-repository-metadata-3.0.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/maven-plugin-api-3.0.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/maven-aether-provider-3.0.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/wagon-file-2.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/wagon-http-2.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/wagon-provider-api-2.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/wagon-http-shared4-2.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/aether-api-1.13.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/aether-impl-1.13.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/aether-spi-1.13.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/aether-util-1.13.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/aether-connector-wagon-1.13.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/bsh-2.0b4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jcommander-1.12.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/snakeyaml-1.6.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/httpcore-4.4.4.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/jcifs-1.3.17.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/xercesImpl-2.9.1.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/xml-apis-1.3.04.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/plexus-component-annotations-1.5.5.jar inflating: /opt/gradle/gradle-3.4.1/lib/plugins/hamcrest-core-1.3.jar inflating: /opt/gradle/gradle-3.4.1/lib/gradle-version-info-3.4.1.jar
import os
os.environ["GRADLE_HOME"] = "/opt/gradle/gradle-3.4.1"
os.environ["PATH"] = "/opt/gradle/gradle-3.4.1/bin:" + os.environ["PATH"]
!gradle -v
------------------------------------------------------------ Gradle 3.4.1 ------------------------------------------------------------ Build time: 2017-03-03 19:45:41 UTC Revision: 9eb76efdd3d034dc506c719dac2955efb5ff9a93 Groovy: 2.4.7 Ant: Apache Ant(TM) version 1.9.6 compiled on June 29 2015 JVM: 1.8.0_292 (Private Build 25.292-b10) OS: Linux 5.4.109+ amd64
저는 Java에서 C++ 클래스를 호출하고 싶어서 최근에 스스로 방법을 찾았습니다. 저는 C++ 라이브러리를 직접 호출하고 싶었습니다.
저는 진행하기 전에 이를 Java로 하기 위한 다양한 방법이 있다는 것을 말하고 싶습니다. 그리고 저는 작동한 것 중 하나를 선택하였습니다. 다른 기술도 사용 가능하며 어떤 기술이 '최상'인지에 대한 의견은 상당히 분분해 보입니다.
C++ 클래스로 시작하기 위해 평범하게 작성하였습니다.
#include <iostream>
// A simple class with a constuctor and some methods...
// 생성자와 몇 개의 메소드를 가지는 간단한 클래스...
class Foo {
public:
Foo(int);
void bar();
int foobar(int);
private:
int val;
};
Foo::Foo(int n) {
val = n;
}
void Foo::bar() {
std::cout << "Value is " << val << std::endl;
}
int Foo::foobar(int n) {
return val + n;
}
JNA에서는 C++을 사용할 수 없기 때문에 C++ 코드 주변에 C wrapper를 놓을 것입니다. 이를 하기 위해 파일 제일 밑에 다음 부분에 코드를 추가합니다.
// ctypes는 C와만 대화할 수 있기 때문에 C++ 클래스를 위한 C 함수를 정의합니다.
extern "C" {
Foo* Foo_new(int n) { return new Foo(n); }
void Foo_bar(Foo* foo) { foo->bar(); }
int Foo_foobar(Foo* foo, int n) { return foo->foobar(n); }
}
호출하기 원하는 각 메소드를 클래스 기반이 아닌 이름으로 제공해야 함을 알아두세요.
우리는 우리 코드에서 libfoo.so 파일을 빌드해야 합니다.
다음을 쉘에서 입력하세요.
$ g++ -c -fPIC foo.cpp -o foo.o
$ g++ -shared -W1,-soname,libfoo.so -o libfoo.so foo.o
gradle에서 JNA를 fat-jar로 컴파일하기 위해 빌드 스크립트를 만들었습니다.
gradle 3.4.1에서 잘 작동함을 확인하였습니다.
%%writefile build.gradle
// Java 프로그램을 위한 기능을 제공하는 플러그인
apply plugin: 'java'
//
apply plugin: 'com.github.johnrengelman.shadow'
// gradle 스크립트에서 외부 라이브러리를 참
buildscript {
// JCenter라는 저장소. Maven과 Gradle 등 각종 빌드 도구에서 사용할 수 있는 공개 저장소
repositories {
jcenter()
}
// 의존 라이브러리. fat-jar를 만들기 위해 shadowJar라는 라이브러리 사용.
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
}
}
// 저장소 설정
repositories {
// Apache Maven 중앙 저장소를 이용하기 위한 것
mavenCentral()
}
// 의존 라이브러리.
dependencies {
// 컴파일시 의존 라이브러리. JNA 라이브러리 4.1을 추가로 사용해야 함.
compile 'net.java.dev.jna:jna:4.1.0'
compile 'net.java.dev.jna:jna-platform:4.1.0'
}
// jar task가 실행될 때 마다 shadowJar가 실행되게 하려면, 아래처럼 jar에 finalizedBy를 달아주면 된다.
jar {
finalizedBy shadowJar
// jar 파일을 만드려면 manifest 파일 정보가 필요함.
// main class는 hello 패키지에 Foo 클래스임.
manifest {
attributes 'Main-Class': 'hello.Foo',
'Implementation-Title': 'Foo jna Project',
'Implementation-Version': '1.0'
}
}
Writing build.gradle
자바 소스는 src/main/java/hello/Foo.java 로 작성하였습니다.
!mkdir -p src/main/java/hello
%%writefile src/main/java/hello/Foo.java
package hello;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Library;
import com.sun.jna.Pointer;
public class Foo {
public interface FooLib extends Library {
Pointer Foo_new(int n);
void Foo_bar(Pointer foo);
int Foo_foobar(Pointer foo, int n);
}
private String sopath;
private FooLib INSTANCE;
private Pointer self;
private void loadLibrary(int n) {
INSTANCE = (FooLib)Native.loadLibrary(
sopath, FooLib.class
);
self = INSTANCE.Foo_new(n);
}
public Foo(int n) {
sopath = "libfoo.so";
loadLibrary(n);
}
public Foo(String sopath, int n) {
this.sopath = sopath;
loadLibrary(n);
}
public void bar() {
INSTANCE.Foo_bar(self);
}
public int foobar(int n) {
return INSTANCE.Foo_foobar(self, n);
}
public static void main(String[] args) {
String path = System.getProperty("user.dir") + "/libfoo.so";
//String path = "/content/libfoo.so";
System.out.println(path);
Foo f = new Foo(path,5);
f.bar();
System.out.println("f.foobar(7) = " + f.foobar(7));
int x = f.foobar(2);
System.out.println("x = " + x);
}
}
Writing src/main/java/hello/Foo.java
gradle로 Java 소스를 build 합니다.
!gradle build
Starting a Gradle Daemon (subsequent builds will be faster) > Starting Daemon> Starting Daemon > Connecting to Daemon> Loading> Loading > settings> Loading> Configuring> Configuring > 0/1 projects> Configuring > 0/1 projects > root project> Configuring > 0/1 projects > root project > Compiling /content/build.gradle into local build cache > Compiling build file '/content/build.gradle' to cross build script cache> Configuring > 0/1 projects > root project > Compiling /content/build.gradle into local build cache> Configuring > 0/1 projects > root project> Configuring > 0/1 projects > root project > Resolving dependencies ':classpath'Download https://jcenter.bintray.com/com/github/jengelman/gradle/plugins/shadow/2.0.1/shadow-2.0.1.pom > Configuring > 0/1 projects > root project > Resolving dependencies ':classpath' Download https://jcenter.bintray.com/org/codehaus/groovy/groovy-backports-compat23/2.4.4/groovy-backports-compat23-2.4.4.pom > Configuring > 0/1 projects > root project > Resolving dependencies ':classpath' > Configuring > 0/1 projects > root projectDownload https://jcenter.bintray.com/com/github/jengelman/gradle/plugins/shadow/2.0.1/shadow-2.0.1.jar > Configuring > 0/1 projects > root project> Configuring > 0/1 projects > root project > 19 KB/3.09 MB downloaded> Configuring > 0/1 projects > root project > 45 KB/3.09 MB downloaded> Configuring > 0/1 projects > root project > 62 KB/3.09 MB downloaded> Configuring > 0/1 projects > root project > 109 KB/3.09 MB downloaded> Configuring > 0/1 projects > root project > 156 KB/3.09 MB downloaded> Configuring > 0/1 projects > root project > 292 KB/3.09 MB downloaded> Configuring > 0/1 projects > root project > 551 KB/3.09 MB downloaded> Configuring > 0/1 projects > root project > 825 KB/3.09 MB downloaded> Configuring > 0/1 projects > root project > 1.30 MB/3.09 MB downloaded> Configuring > 0/1 projects > root project > 2.16 MB/3.09 MB downloaded > Configuring > 0/1 projects > root projectDownload https://jcenter.bintray.com/org/codehaus/groovy/groovy-backports-compat23/2.4.4/groovy-backports-compat23-2.4.4.jar > Configuring > 0/1 projects > root project > Configuring > 0/1 projects > root project > Compiling /content/build.gradle into local build cache > Compiling build file '/content/build.gradle' to cross build script cache> Configuring > 0/1 projects > root project> Configuring > 0/1 projects> Configuring > 1/1 projects> Configuring> Building 0% > :compileJava> Building 0% > :compileJava > Resolving dependencies ':compileClasspath':compileJava Download https://repo1.maven.org/maven2/net/java/dev/jna/jna/4.1.0/jna-4.1.0.pom Download https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform/4.1.0/jna-platform-4.1.0.pom Download https://repo1.maven.org/maven2/net/java/dev/jna/jna/4.1.0/jna-4.1.0.jar > Building 0% > :compileJava > 162 KB/893 KB downloaded Download https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform/4.1.0/jna-platform-4.1.0.jar > Building 0% > :compileJava > 560 KB/1.40 MB downloaded > Building 0% > :compileJava> Building 0%:processResources NO-SOURCE :classes :jar > Building 33% > :shadowJar:shadowJar > Building 33%:assemble :compileTestJava NO-SOURCE :processTestResources NO-SOURCE :testClasses UP-TO-DATE :test NO-SOURCE :check UP-TO-DATE :build BUILD SUCCESSFUL Total time: 11.328 secs
빌드를 하면 build/libs 경로에 2개 파일이 생성됩니다.
!ls -lrt build/libs/*.jar
-rw-r--r-- 1 root root 1878 May 20 09:05 build/libs/content.jar -rw-r--r-- 1 root root 1606286 May 20 09:05 build/libs/content-all.jar
다음은 실행 결과입니다.
!java -jar build/libs/content-all.jar
/content/libfoo.so Value is 5 f.foobar(7) = 12 x = 7
다음처럼 Makefile을 생성합니다.
%%writefile Makefile
SRCS = foo.cpp
OBJS = foo.o
CFLAGS = $(CFLAG) -D_REENTRANT -D_THREAD_SAFE -D$(_OSTYPE_)
CPPFLAGS= $(CPPFLAG) -D_REENTRANT -D_THREAD_SAFE -D$(_OSTYPE_)
all : libfoo.so
libfoo.so :
g++ -fPIC -c $(SRCS)
g++ -shared -Wl,-soname,$@ -o $@ $(OBJS)
gradle build
clean:
rm -f *.o core *.out .*list *.ln *.so
gradle clean
Writing Makefile
C++, Java 소스를 make로 한꺼번에 build 할 수 있습니다.
!make clean && make
rm -f *.o core *.out .*list *.ln *.so gradle clean > Connecting to Daemon> Loading> Configuring > 1/1 projects:clean BUILD SUCCESSFUL Total time: 1.179 secs g++ -fPIC -c foo.cpp g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o gradle build > Connecting to Daemon> Building 0% > :compileJava:compileJava :processResources NO-SOURCE :classes :jar > Building 33% > :shadowJar:shadowJar > Building 33%:assemble :compileTestJava NO-SOURCE :processTestResources NO-SOURCE :testClasses UP-TO-DATE :test NO-SOURCE :check UP-TO-DATE :build BUILD SUCCESSFUL Total time: 1.708 secs
!java -jar build/libs/content-all.jar
/content/libfoo.so Value is 5 f.foobar(7) = 12 x = 7
!ls -lrt /content
total 52 drwxr-xr-x 1 root root 4096 May 6 13:44 sample_data -rw-r--r-- 1 root root 586 May 19 08:28 foo.cpp -rw-r--r-- 1 root root 4424 May 19 08:28 foo.o -rwxr-xr-x 1 root root 13320 May 19 08:28 libfoo.so -rw-r--r-- 1 root root 580 May 19 08:28 foo.py drwxr-xr-x 2 root root 4096 May 19 08:29 __pycache__ -rw-r--r-- 1 root root 1375 May 19 08:33 build.gradle drwxr-xr-x 3 root root 4096 May 19 08:33 src drwxr-xr-x 5 root root 4096 May 19 08:33 build