最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Android C to Java SWIG unable to compile: incompatible types: byte cannot be converted to SWIGTYPE_p_uint8_t - Stack Overflow

programmeradmin4浏览0评论

I am trying to use a c library that is our command protocol. The structure of the library is such that each command has a tx and rx struct type and there is a reader and writer to build or reconstruct the packet on send and receive. However, as that code is proprietary I have created a sample project and the rest of this question is in reference to that code as it demonstrates the same issue.

I receive the following error messages when trying to compile the library that SWIG generates:

error: incompatible types: int cannot be converted to SWIGTYPE_p_int32_t
    swigtest_native_swigJNI.process(foo.getCPtr(baz), baz, SWIGTYPE_p_void.getCPtr(data), SWIGTYPE_p_int32_t.getCPtr(sz));
                                                                                                                     ^

error: incompatible types: byte cannot be converted to SWIGTYPE_p_uint8_t
    swigtest_native_swigJNI.foo_bar_set(swigCPtr, this, SWIGTYPE_p_uint8_t.getCPtr(value));
                                                                                   ^

I have tried to throw different type mappings and specifying the functions in the interface files to no avail. The code that is used below and on the link is the closest I have gotten to compile.

Thank you for your time.


Linked is a sample project demonstrating the error sample project. It was created as an Android Native C++ template with the below modifications/code.

CMakeLists.txt:

cmake_minimum_required(VERSION 3.22.1)

project("swigtest")

set(CMAKE_C_STANDARD 99)

find_package(SWIG REQUIRED) # Locate SWIG installation
include(UseSWIG) # Add SWIG to CMake

set(SWIG_INTERFACE interface.i) # Path to SWIG interface file
set(CMAKE_SWIG_FLAGS -package com.micro_leads.swigtest.test) # Custom package name parameter

set_property(SOURCE interface.i PROPERTY SWIG_MODULE_NAME swigtest_native_swig) # Set module name

include_directories(${JAVA_INCLUDE_PATH})
include_directories(
        .
)

file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/.swig ${CMAKE_SOURCE_DIR}/../java/com/micro_leads/swigtest/test)
file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/../java/com/micro_leads/swigtest/test)

# Add native source files
set(SOURCES
        native-lib.h
        native-lib.c
)

add_library(${CMAKE_PROJECT_NAME} SHARED
        # List C/C++ source files with relative paths to this CMakeLists.txt.
        ${SOURCES}
)

# Add SWIG library
swig_add_library(
        "${CMAKE_PROJECT_NAME}_native_swig" # name
        LANGUAGE java # language
        SOURCES ${SWIG_INTERFACE} # interface file
        OUTFILE_DIR ${CMAKE_SOURCE_DIR}/.swig # output wrapper file path
        OUTPUT_DIR ${CMAKE_SOURCE_DIR}/../java/com/micro_leads/swigtest/test # output Java files path
)

set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)

# Link swig lib with native lib
target_link_libraries("${CMAKE_PROJECT_NAME}_native_swig" ${JNI_LIBRARIES} ${CMAKE_PROJECT_NAME})

target_link_libraries(${CMAKE_PROJECT_NAME}
        # List libraries link to the target library
        android
        log
        ${JNI_LIBRARIES}
)

native-lib.h:

#include <stdint.h>

extern "C" {
typedef struct _foo {
    uint8_t bar;
} foo;

void process(foo *baz, const void *data, int32_t sz);
};

native-lib.c:

#include <string.h>

extern "C" {

void process(foo *baz, const void *data, int32_t sz) {
    if (sizeof(foo) < sz) { return; }

    memcpy(baz, data, sz);
}
};

interface.i

%module swigtest_native_swig

%{
#include "native-lib.h"
%}

%include "./typemaps.i"

%include "native-lib.h"

typemaps.i:

%typemap(jtype) foo "foo"
%typemap(jstype) foo "foo"
%typemap(jni) foo "jobject"
%typemap(in) foo {
    jsclass cls = (*jenv)->FindClass(jenv, "foo");
    jmethodID constructor = (*jenv)->GetMethodID(jenv, cls, "<init>", "(B)V");
    jfieldID bar_field = (*jenv)->GetFieldID(jenv, cls, "bar", "B");
    jobject obj = (*jenv)->NewObject(jenv, cls, constructor, $1.bar);
    $result = obj;
}
%typemap(out) foo {
    jclass cls = (*jenv)->FindClass(jenv, "foo");
    jfieldID bar_field = (*jenv)->GetFieldID(jenv, cls, "bar", "B");

    $result.bar = (*jenv)->GetByteField(jenv, $input, bar_field);
}

%typemap(jtype) uint8_t "byte"
%typemap(jstype) uint8_t "byte"
%typemap(jni) uint8_t "jbyte"
%typemap(javaout) uint8_t {
    return ($jnicall);
}
%typemap(in) uint8_t {
    $1 = (uint8_t)$input;
}
%typemap(out) uint8_t {
    $result = (jbyte)$1;
}

%typemap(jtype) (const void *, int32_t) "kotlin.ByteArray"
%typemap(jstype) (const void *, int32_t) "kotlin.ByteArray"
%typemap(jni) (const void *, int32_t) "jbyteArray"
%typemap(javaout) (const void *, int32_t) {
    return ($jnicall);
}
%typemap(in) (const void *data, int32_t size) {
    if ($input == null || $input.length != size) {
        throw new IllegalArgumentException("Expected a byte array of length " + size);
    }
    memcpy($1, $input, size);
}
%typemap(out) (const void *, int32_t) {
    jbyteArray result = (*jenv)->NewByteArray(jenv, size);
    if (result != NULL && $1 != NULL) {
        (*jenv)->SetByteArrayRegion(jenv, result, 0, size, (const jbyte *)$1);
    }
    $result = result;
}

MainActivity.kt:

package com.micro_leads.swigtest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import com.micro_leads.swigtest.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

//        val foo = test.foo()
//        test.swigtest_native_swig.process(foo, 1, 1)
    }

    companion object {
        // Used to load the 'swigtest' library on application startup.
        init {
            System.loadLibrary("swigtest")
            System.loadLibrary("swigtest_native_swig")
        }
    }
}

I am trying to use a c library that is our command protocol. The structure of the library is such that each command has a tx and rx struct type and there is a reader and writer to build or reconstruct the packet on send and receive. However, as that code is proprietary I have created a sample project and the rest of this question is in reference to that code as it demonstrates the same issue.

I receive the following error messages when trying to compile the library that SWIG generates:

error: incompatible types: int cannot be converted to SWIGTYPE_p_int32_t
    swigtest_native_swigJNI.process(foo.getCPtr(baz), baz, SWIGTYPE_p_void.getCPtr(data), SWIGTYPE_p_int32_t.getCPtr(sz));
                                                                                                                     ^

error: incompatible types: byte cannot be converted to SWIGTYPE_p_uint8_t
    swigtest_native_swigJNI.foo_bar_set(swigCPtr, this, SWIGTYPE_p_uint8_t.getCPtr(value));
                                                                                   ^

I have tried to throw different type mappings and specifying the functions in the interface files to no avail. The code that is used below and on the link is the closest I have gotten to compile.

Thank you for your time.


Linked is a sample project demonstrating the error sample project. It was created as an Android Native C++ template with the below modifications/code.

CMakeLists.txt:

cmake_minimum_required(VERSION 3.22.1)

project("swigtest")

set(CMAKE_C_STANDARD 99)

find_package(SWIG REQUIRED) # Locate SWIG installation
include(UseSWIG) # Add SWIG to CMake

set(SWIG_INTERFACE interface.i) # Path to SWIG interface file
set(CMAKE_SWIG_FLAGS -package com.micro_leads.swigtest.test) # Custom package name parameter

set_property(SOURCE interface.i PROPERTY SWIG_MODULE_NAME swigtest_native_swig) # Set module name

include_directories(${JAVA_INCLUDE_PATH})
include_directories(
        .
)

file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/.swig ${CMAKE_SOURCE_DIR}/../java/com/micro_leads/swigtest/test)
file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/../java/com/micro_leads/swigtest/test)

# Add native source files
set(SOURCES
        native-lib.h
        native-lib.c
)

add_library(${CMAKE_PROJECT_NAME} SHARED
        # List C/C++ source files with relative paths to this CMakeLists.txt.
        ${SOURCES}
)

# Add SWIG library
swig_add_library(
        "${CMAKE_PROJECT_NAME}_native_swig" # name
        LANGUAGE java # language
        SOURCES ${SWIG_INTERFACE} # interface file
        OUTFILE_DIR ${CMAKE_SOURCE_DIR}/.swig # output wrapper file path
        OUTPUT_DIR ${CMAKE_SOURCE_DIR}/../java/com/micro_leads/swigtest/test # output Java files path
)

set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)

# Link swig lib with native lib
target_link_libraries("${CMAKE_PROJECT_NAME}_native_swig" ${JNI_LIBRARIES} ${CMAKE_PROJECT_NAME})

target_link_libraries(${CMAKE_PROJECT_NAME}
        # List libraries link to the target library
        android
        log
        ${JNI_LIBRARIES}
)

native-lib.h:

#include <stdint.h>

extern "C" {
typedef struct _foo {
    uint8_t bar;
} foo;

void process(foo *baz, const void *data, int32_t sz);
};

native-lib.c:

#include <string.h>

extern "C" {

void process(foo *baz, const void *data, int32_t sz) {
    if (sizeof(foo) < sz) { return; }

    memcpy(baz, data, sz);
}
};

interface.i

%module swigtest_native_swig

%{
#include "native-lib.h"
%}

%include "./typemaps.i"

%include "native-lib.h"

typemaps.i:

%typemap(jtype) foo "foo"
%typemap(jstype) foo "foo"
%typemap(jni) foo "jobject"
%typemap(in) foo {
    jsclass cls = (*jenv)->FindClass(jenv, "foo");
    jmethodID constructor = (*jenv)->GetMethodID(jenv, cls, "<init>", "(B)V");
    jfieldID bar_field = (*jenv)->GetFieldID(jenv, cls, "bar", "B");
    jobject obj = (*jenv)->NewObject(jenv, cls, constructor, $1.bar);
    $result = obj;
}
%typemap(out) foo {
    jclass cls = (*jenv)->FindClass(jenv, "foo");
    jfieldID bar_field = (*jenv)->GetFieldID(jenv, cls, "bar", "B");

    $result.bar = (*jenv)->GetByteField(jenv, $input, bar_field);
}

%typemap(jtype) uint8_t "byte"
%typemap(jstype) uint8_t "byte"
%typemap(jni) uint8_t "jbyte"
%typemap(javaout) uint8_t {
    return ($jnicall);
}
%typemap(in) uint8_t {
    $1 = (uint8_t)$input;
}
%typemap(out) uint8_t {
    $result = (jbyte)$1;
}

%typemap(jtype) (const void *, int32_t) "kotlin.ByteArray"
%typemap(jstype) (const void *, int32_t) "kotlin.ByteArray"
%typemap(jni) (const void *, int32_t) "jbyteArray"
%typemap(javaout) (const void *, int32_t) {
    return ($jnicall);
}
%typemap(in) (const void *data, int32_t size) {
    if ($input == null || $input.length != size) {
        throw new IllegalArgumentException("Expected a byte array of length " + size);
    }
    memcpy($1, $input, size);
}
%typemap(out) (const void *, int32_t) {
    jbyteArray result = (*jenv)->NewByteArray(jenv, size);
    if (result != NULL && $1 != NULL) {
        (*jenv)->SetByteArrayRegion(jenv, result, 0, size, (const jbyte *)$1);
    }
    $result = result;
}

MainActivity.kt:

package com.micro_leads.swigtest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import com.micro_leads.swigtest.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

//        val foo = test.foo()
//        test.swigtest_native_swig.process(foo, 1, 1)
    }

    companion object {
        // Used to load the 'swigtest' library on application startup.
        init {
            System.loadLibrary("swigtest")
            System.loadLibrary("swigtest_native_swig")
        }
    }
}
Share Improve this question asked Mar 4 at 21:24 IstafeinIstafein 1229 bronze badges 0
Add a comment  | 

1 Answer 1

Reset to default 2

SWIG doesn't know the definition of int32_t. Add %include <stdint.i> to the interface file.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论