2011-12-06 2 views
0

SWIG를 사용하여 많은 C API 세트에 대해 JNI 레이어를 생성하고 있으며 아래 상황에서 가장 좋은 방법이 무엇인지 궁금합니다. 아래는 SWIG뿐 아니라 일반적으로 JNI와 관련이 있습니다.SWIG 인터페이스 파일을 수정하여 C void * 및 구조체 반환 유형

SWIG 인터페이스 파일 (JNI 논리)을 많이 사용해야하거나 C 데이터 래퍼 함수를 ​​만들어서 여러 데이터 요소 (예 : 다양한 데이터 요소가 포함 된 char 배열)를 반환해야한다면 C 함수가 구조체에 대한 포인터를 반환 할 때? C 함수가 프리미티브 또는 구조체 유형이든 실제 데이터 형식을 반환하도록 C API를 수정해야합니까? 대량의 로직을 추가하고 중간 레이어 (SWIG 인터페이스 파일/JNI 로직)를 만들고 싶다면 확실하지 않습니다. 생각?

답변

2

내 접근 방식은 과거에는 가능한 한 적은 코드로 작성하여 작동하도록했습니다. 나는 그것이 작동하도록 코드를 작성해야 할 때 내가 선호의 순서를 쓰기 : C 또는 C와 같은

  1. 쓰기 ++에에게 원래의 라이브러리 - 모두가이 코드를 사용할 수 있습니다, 당신은 필요 없어 공급 "접착제"-

  2. 대상 언어 더 쓰기 (예를 들어 꿀꺽 꿀꺽 그들에 대해 알고, 사용의 반환 형식을 C++에서 더 많은 과부하를 추가 C에서 함수의 더 많은 버전을 추가) 아무것도 Java 또는 꿀꺽 꿀꺽 특정 쓰기 함께 도서관의 일부 비트를 가져와야합니다. 이 경우에는 Java가됩니다.

    이것이 "순수한"Java인지, SWIG 외부인지, 아니면 내 관점에서 SWIG 인터페이스 파일의 일부인지는 중요하지 않습니다. 자바 인터페이스의 사용자는 두 가지를 구별 할 수 없어야합니다. 그러나 SWIG를 사용하여 여러 가지 사례에서 반복을 피할 수 있습니다.

  3. SWIG 형식 맵을 통해 일부 JNI를 작성하십시오. 이것은 당신이 그것을 쓰는 것에 익숙하지 않다면 추악하고, 오류가 발생하기 쉽고, 유지하기가 더 어렵고 (틀림없이) SWIG + Java에만 유용합니다. SWIG typemaps를 사용하면 적어도 랩하는 모든 유형에 대해 한 번만 쓰는 것을 의미합니다.

    시간 나는 2 이상이 선호하는 것 중 하나 이상이다

    1. 이 많이 나오면
    2. 내가 모든 대상 언어를 모르는 (반복적 인 코드를 저장) 이 경우 언어의 C API를 사용하는 것이 아마도 해당 언어로 된 내용을 쓰는 것보다 쉽습니다.
    3. 사용자는이 것을 기대합니다
    4. 또는 이전 스타일을 사용할 수 없습니다.

기본적으로이 가이드 라인은 당신이 작성해야 추가, 대상 언어 특정 코드의 양을 최소화하고 그 때의 복잡성을 감소 동안 가능한 라이브러리의 많은 사용자에게 기능을 제공하려는 제안 당신은 그것을 써야만합니다.sockaddr_in*의 특정 사례를 들어


:

접근 한

내가 노력하겠다고 및 수행이 포인터보다 더 많은 것을 포장하지 않도록입니다 가장 먼저하는 일. 이것은 기본적으로 sw30이 SWIGTYPE_p_sockaddr_in 일과 함께하는 것입니다. Java에서이 "알 수없는"유형은 매우 유용하게 사용할 수 있습니다. 한 가지만 다른 것으로 전달하거나 컨테이너/멤버로 저장하는 등의 작업 만 수행하면됩니다.

public static void main(String[] argv) { 
    Module.takes_a_sockaddr(Module.returns_a_sockaddr()); 
} 

C에서, 다른 함수를 쓰기 좋아하는 당신이 뭔가를 할 수있는 일을하지 않는 경우 : 이것은하지만이 경우되지 대단한

const char * sockaddr2host(struct sockaddr_in *in); // Some code to get the host as a string 
unsigned short sockaddr2port(struct sockaddr_in *in); // Some code to get the port 

- 일부 복잡성을 가지고 주소 패밀리를 다루기 위해서는 주소 패밀리가 필요합니다. (그 이유는 처음에 sockaddr_in을 사용하는 이유입니다.)하지만 Java에만 한정된 것은 아니며 구문이 명확하지 않으며 모든 예외가 자동으로 발생합니다. 그 여전히 나는 자바의 조금 쓰기에 대해 생각하기 시작 것 충분하지 않은 경우

접근법 2

- 당신은 개인 회원으로 SWIGTYPE_p_sockaddr_in 유형을 숨겨 더 좋은 인터페이스를 노출 수 자신의 Java 유형에 대한 호출을 작성하고, 유형을 구성하는 Java에서 리턴하는 함수에 대한 호출을 랩핑합니다 (예 :

public class MyExtension { 
    private MyExtension() { } 
    private SWIGTYPE_p_sockaddr_in detail; 
    public static MyExtension native_call() { 
    MyExtension e = new MyExtension(); 
    e.detail = Module.real_native_call(); 
    return e; 
    } 

    public void some_call_that_takes_a_sockaddr() { 
    Module.real_call(detail); 
    } 
} 

쓸 SWIG가 없으므로 쓸 JNI가 없습니다. SWIG를 사용하여 %pragma(modulecode)을 사용하여 실제 모듈 SWIG에서 모든 오버로드를 생성 할 수 있습니다. 이는 Java 사용자에게 더 자연스럽고 (아마도 특별한 경우처럼 보이지는 않지만) 더 이상 복잡하지는 않습니다. 열심히 일하는 것은 여전히 ​​SWIG에 의해 수행되고 있습니다. 이것은 Java 측에서 반복적 인 코딩을 피하는 약간의 닦기를 제공합니다.

접근 방식은 3

이것은 기본적으로 my previous answer의 두 번째 부분이 될 것입니다. 자바 사용자가 보편적으로 느끼고 기분이 좋고 C 라이브러리를 수정할 필요가 없기 때문에 좋다. 본질적으로 typemap은 Java 사용자가 기대하는 것에서 C가 작동하는 것으로 변환하고 어느 쪽도 상대방의 전망에 대해 알지 못하는 JNI 호출을 캡슐화하기위한 클린 - 틱 구문을 제공합니다.

단점은 유지 보수하기가 어렵고 디버깅하기가 어렵다는 점입니다. 제 경험으로 SWIG는 이와 같은 것들에 대한 가파른 학습 곡선을 가지고 있지만, 일단 여러분이 C와 같은 재사용 및 캡슐화를 통해 제공하는 힘과 같은 typemaps를 작성하는 데 너무 많은 노력을 기울이지 않는다면 type-> Java 타입 매핑은 매우 유용하고 강력합니다.

팀에 속해 있지만 SWIG 인터페이스를 실제로 이해하는 유일한 사람이라면 큰 "버스에 치면 어떨까요?" 전체적으로 프로젝트에 영향을줍니다. (아마 당신을 불공평하게 만드는 데 꽤 유용 할 것입니다!)

+0

C 함수에서 반환되는 C 구조체 포인터에 관해이 문제를 해결할 수 있습니까? 일반적으로 SWIG typemap을 지정할 필요가 없도록 C 함수 구조 값을 연결하는 "string"유형을 반환하는 래퍼 C 함수를 추가하겠습니까? 예를 들어 sockaddr_in을 반환하는 것은 처리하기가 약간 어렵습니다.C#에는 C# 클라이언트의 데이터를 쉽게 가져올 수있는 라이브러리에 내장 된 구조에 대한 멋진 포인터가 있지만 Java에서 동일하게 찾을 수는 없습니다. – c12

+0

@ c12 - 각 단계에서 수행하고자하는 작업을 보여주는 업데이트를 추가했습니다. 이것은 왜 "Swig에서 X를 어떻게 감쌀 까?" X를 래핑하는 것이 가능한 2 ~ 3 가지 방법을 제안합니다. – Flexo