You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用JNI从Kotlin调用C函数及SWIG编译arm64架构报错问题

问题解决方案

一、修改原生代码支持Kotlin JNI调用

Kotlin的JNI调用逻辑和Java完全一致,原生函数不能直接暴露原有C接口,必须符合JNI调用规范,两种实现方式可选:

  • 手动编写JNI适配层
    1. 先在Kotlin侧声明对应external方法,配置库加载逻辑,示例:
    class FeatureCompute {
        companion object {
            init {
                System.loadLibrary("compute_feature_set")
            }
        }
        // 包名、类名、方法名必须和后续JNI函数签名严格对应
        external fun computeFeatureSet(
            input: DoubleArray,
            fData: DoubleArray,
            fSize: IntArray,
            dData: DoubleArray,
            dSize: IntArray,
            deData: DoubleArray,
            deSize: IntArray,
            v: DoubleArray,
            mp: DoubleArray,
            r: DoubleArray,
            fM: DoubleArray
        )
        external fun terminateCompute()
    }
    
    1. 用JDK自带的javac -h命令(旧版本用javah)根据Kotlin编译出的class文件生成JNI头文件,生成的函数固定格式为Java_<包名下划线分隔>_<类名>_<方法名>,每个函数前两个参数固定为JNIEnv* env(JNI环境指针)、jobject thiz(实例方法对应调用对象,静态方法替换为jclass clazz),后续参数为Kotlin类型映射的JNI类型。
    2. 实现生成的JNI函数:通过JNI提供的GetDoubleArrayElements/GetIntArrayElements接口,把Kotlin传入的数组参数转为原生层可操作的double/int指针,校验数组长度符合业务要求(比如input长度必须为1102、v长度必须为7)后,调用你原有的compute_feature_set业务函数;调用完成后通过ReleaseDoubleArrayElements/ReleaseIntArrayElements释放资源,把结果写回数组供Kotlin侧读取。
    3. 所有暴露给JNI的函数声明必须包裹在extern "C"块中,避免C++编译时符号名改编导致找不到函数。
  • 用SWIG自动生成适配层
    不需要手动写JNI桥接代码,只要编写正确的SWIG接口文件,SWIG会自动生成Java/Kotlin侧的调用代码和原生层的桥接逻辑,直接调用你原有C函数即可。

二、SWIG链接阶段Undefined symbols for architecture arm64报错修复

你遇到的报错信息:

Undefined symbols for architecture arm64:

该报错是链接阶段无法找到对应符号实现,按以下优先级排查:

  1. 解决C/C符号名不匹配问题
    你编译C源码用的是gcc(按C规则编译生成符号),链接用的是g
    (按C++规则查找符号),两边符号修饰规则不一致就会报找不到符号。解决方式:
  • 要么统一用gcc完成编译和链接流程;
  • 要么在你原有C函数的头文件声明外层加上extern "C"包裹,强制C++编译器按C规则查找符号:
    #ifdef __cplusplus
    extern "C" {
    #endif
    // 原有两个函数声明放在这里
    extern void compute_feature_set(double input[1102], double F_data[],
                                    int F_size[2], double D_data[],
                                    int D_size[3], double De_data[],
                                    int De_size[4],
                                    double V[7], double *mp,
                                    double r[12], double *fM);
    extern void compute_feature_set_terminate(void);
    #ifdef __cplusplus
    }
    #endif
    
  1. 检查SWIG接口文件(.i)配置
    如果.i文件没有正确声明要导出的函数,SWIG生成的wrap代码会引用不存在的符号,链接必然失败。最小可用的.i文件示例:
%module compute_feature_set
%{
// 给wrap编译阶段用,引入你原生函数的声明
#include "compute_feature_set.h"
%}
// 给SWIG解析用,列出所有需要暴露给上层调用的函数
extern void compute_feature_set(double input[1102], double F_data[],
                                int F_size[2], double D_data[],
                                int D_size[3], double De_data[],
                                int De_size[4],
                                double V[7], double *mp,
                                double r[12], double *fM);
extern void compute_feature_set_terminate(void);
  1. 校验编译目标架构一致性
    在arm64架构的Mac设备上,执行lipo -info *.o检查所有生成的目标文件架构,如果存在x86_64架构的文件,重新编译时加上-arch arm64参数指定目标架构。
  2. 注意平台库后缀差异
    macOS系统下动态库后缀为.dylib而非Linux的.so,链接时建议把输出文件名改为libcompute_feature_set.dylib,避免后续Kotlin侧加载库失败。

内容的提问来源于stack exchange,提问作者FerasAS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 04:30:52