Android下SWIG实现C转Java编译失败:类型不兼容错误求助
编译SWIG生成库时遇到类型不兼容错误
我正在使用一款自研命令协议的C库,每个命令都包含tx和rx结构体类型,还有收发时用于构建/重构数据包的读写器。由于原代码是专有内容,我制作了一个示例项目复现问题。
编译SWIG生成的库时,出现以下错误:
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)); ^
我尝试过使用不同的类型映射,并在接口文件中指定函数,但均未奏效。以下是当前最接近编译成功的代码版本,示例项目基于Android Native C++模板创建,修改/添加的代码如下:
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") } } }
内容的提问来源于stack exchange,提问作者Istafein
相关产品推荐
相关产品推荐

