Skip to content

如何使用 Bazel 正确构建 JNI 动态库? #338

Open

Description

@hsz0797

我在尝试通过 JNI 调用隐语 PIR 的功能,需要构建一个.so动态库给 Java 使用。
目前我手动用 g++ -shared 去链接,但遇到了依赖符号缺失问题(例如 absl::lts_20240722::Symbolize,以及 SEAL 的 MemoryPoolMT)。
我注意到 bazel-bin/external 下已经有编译好的依赖(seal、absl、yacl 等),但是我不确定应该如何用 Bazel 把它们正确打包进 libyinyu_pir_jni.so。
在隐语的工程里,是否有推荐的方式/示例来用 Bazel 构建 JNI 动态库?

Activity

  1. hsz0797 commented on Sep 15, 2025

    @hsz0797
    Author

    Image我自己尝试使用bazel构建动态库,测试的时候出现了找不到函数的问题java.lang.UnsatisfiedLinkError: 'long com.secretflow.pir.SecretFlowPirNativeUtils.BucketSenderMake(java.lang.String, java.lang.String, int, int, int, java.lang.String, boolean)'

  2. huocun-ant commented on Sep 15, 2025

    @huocun-ant
    Collaborator

    使用 cc_shared_library 试试,
    类似

    exports_files(
        [
            "exported_symbols.lds",
        ],
        visibility = ["//visibility:private"],
    )
    cc_shared_library(
        name = "shared",
        additional_linker_inputs = [
            ":exported_symbols.lds",
        ],
        shared_lib_name = "shared.so",
        user_link_flags = [
            "-Wl,--version-script=$(location :exported_symbols.lds)",
        ],
        deps = [":xxx"],
    )
    

    其中,exported_symbols.lds文件可以导出你想使用的接口函数名,类似:

    VERS_1.0 {
        global:
            c_func_*;
    };
    
  3. hsz0797 commented on Sep 15, 2025

    @hsz0797
    Author

    试了一下,又有新问题,搞不明白了
    Image

    这是BUILD.bazel,exported_symbols.lds导出了想使用的接口函数名

    `# demo/src/main/jni/BUILD.bazel
    load("@rules_cc//cc:defs.bzl", "cc_library", "cc_binary")

    exports_files(["exported_symbols.lds"])

    cc_library(
    name = "jni_headers",
    hdrs = [
    "jni.h",
    "jni_md.h",
    ],
    includes = ["."],
    visibility = ["//visibility:public"],
    )

    cc_library(
    name = "yinyu_pir_native_lib",
    srcs = [
    "com_secretflow_pir_SecretFlowPirNativeUtils.cpp",
    ],
    hdrs = [
    "com_secretflow_pir_SecretFlowPirNativeUtils.h",
    ],
    includes = ["."],
    copts = [
    "-std=c++17",
    "-fPIC",
    ],
    deps = [
    ":jni_headers",
    "//psi/wrapper/apsi/api:sender_c_wrapper",
    "//psi/wrapper/apsi/api:receiver_c_wrapper",
    "//psi/wrapper/apsi/api:sender",
    "//psi/wrapper/apsi/api:receiver",
    "//psi/wrapper/apsi/api:wrapper_util",
    ],
    visibility = ["//visibility:public"],
    )

    cc_binary(
    name = "yinyu_pir_jni",
    deps = [
    ":yinyu_pir_native_lib",
    ],
    linkshared = 1,
    linkstatic = 0,
    additional_linker_inputs = [":exported_symbols.lds"],
    linkopts = [
    "-Wl,--version-script=$(location :exported_symbols.lds)",
    "-Wl,-rpath,$ORIGIN",
    ],
    data = [":exported_symbols.lds"],
    visibility = ["//visibility:public"],
    )
    `

  4. huocun-ant commented on Sep 17, 2025

    @huocun-ant
    Collaborator

    C++的函数签名会name mangle,如果是是Java想访问C++的函数,可以搞个C的header,也就是所有导出的函数使用extern "C" {} 包起来,可以网上搜一下标准写法,另外建议给这一组C 接口提供一个公共的前缀,这样方便导出,如果导出的接口中会包含C++的类作为参数,可以用void*暴露出去

  5. huocun-ant commented on Sep 17, 2025

    @huocun-ant
    Collaborator

    编译好的so可以使用命令 ldd -r xxx.so看看是不是需要别的so或者有unresolve的符号

  6. huocun-ant commented on Sep 17, 2025

    @huocun-ant
    Collaborator

    这个提示的符号可以使用如下命令查看:

    Image
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions