使用JNI的Bazel C++程序:Jar相对路径问题求助
解决Bazel构建JNI程序时C++找不到Jar包的问题
问题根源
Bazel构建后,C++二进制文件会被放到bazel-bin的子目录中(比如//src:app对应bazel-bin/src/app),如果JavaNativeInterface.jar没有被同步到该目录,代码里的相对路径.:JavaNativeInterface.jar自然无法定位到文件。你之前用genrule没生效,大概率是没把生成的Jar关联到cc_binary的依赖链里。
可行解决方案
方案1:让Bazel自动复制Jar到二进制目录
直接通过cc_binary的data字段声明对Jar的依赖,Bazel会自动把Jar同步到二进制所在的bazel-bin子目录,此时相对路径就能正常工作。
示例BUILD配置:
# 先定义filegroup引用源码目录中的Jar filegroup( name = "jni_jar", srcs = ["JavaNativeInterface.jar"], ) cc_binary( name = "jni_app", srcs = ["main.cpp"], # 将Jar加入data依赖,Bazel会自动同步到二进制目录 data = [":jni_jar"], # 添加JNI必要的链接配置(示例为Linux下JVM库) linkopts = ["-ljvm"], includes = ["/usr/lib/jvm/java-11-openjdk-amd64/include"], )
构建完成后,JavaNativeInterface.jar会和jni_app二进制文件处于同一目录,C++代码里的-Djava.class.path=.:JavaNativeInterface.jar就能正确找到Jar。
方案2:通过Bazel Runfiles机制获取绝对路径(更可靠)
如果不想依赖相对路径,可以利用Bazel的Runfiles环境变量动态获取Jar的绝对路径,彻底避免路径依赖问题。
修改C++代码:
#include <cstdlib> #include <string> // ... 其他JNI初始化代码 const char* runfiles_dir = std::getenv("RUNFILES_DIR"); if (runfiles_dir != nullptr) { // 替换为你的Bazel工作区名称(WORKSPACE文件中的name字段,或项目根目录名) std::string jar_path = std::string(runfiles_dir) + "/your_workspace_name/JavaNativeInterface.jar"; options[1].optionString = const_cast<char*>(jar_path.c_str()); } else { // 兼容非Bazel运行场景, fallback到相对路径 options[1].optionString = (char*)"-Djava.class.path=.:JavaNativeInterface.jar"; }
这种方式无论二进制在哪个目录运行,只要是Bazel构建的产物,都能通过RUNFILES_DIR准确定位到Jar文件。
关于genrule失效的说明
如果之前用genrule复制Jar,必须确保genrule的输出被cc_binary的data字段引用,否则Bazel不会把生成的Jar同步到二进制目录。比如正确的genrule用法:
genrule( name = "copy_jar", srcs = ["JavaNativeInterface.jar"], outs = ["copied_jar.jar"], cmd = "cp $< $@", ) cc_binary( name = "jni_app", srcs = ["main.cpp"], data = [":copy_jar"], # 引用genrule的输出产物 # 其他配置... )
但这种方式其实没必要,直接用方案1的data依赖原Jar更简洁高效。
内容的提问来源于stack exchange,提问作者poiu144
相关产品推荐
相关产品推荐

