除非 .jar 包含在 bootclasspath 中,否则无法编译

Unable to compile unless .jar is included in bootclasspath

我正在尝试使用 gradle 构建一个 android 项目:这是一个带有 ndk 风格的库项目,带有外部 .jar,由 Unity 提供。

我真的不认为 gradle 文件的详细信息很重要,只要说我将外部 jar 文件(由 Unity 提供)包含在其中就足够了:

  dependencies {
    compile files('libs/unity.jar')
  }

实际上似乎有效,因为在 java 编译期间,gradle 发出如下命令:

BASE="<Some directory>"
javac -d "${BASE}/PluginsSources/Android/libproject/build/intermediates/classes/fat/debug" \
    -g -encoding UTF-8 \
    -bootclasspath /Users/myusername/Applications/adt/sdk/platforms/android-23/android.jar \
    -sourcepath "${BASE}/PluginsSources/Android/libproject/build/tmp/compileFatDebugJavaWithJavac/emptySourcePathRef" \
    -classpath "${BASE}/PluginsSources/Android/libproject/libs/unity.jar" \
    "${BASE}/PluginsSources/Android/libproject/src/main/java/org/example/ScriptBridge/JavaClass.java" \
    "${BASE}/PluginsSources/Android/libproject/build/generated/source/r/fat/debug/org/example/ScriptBridge/R.java" \
    "${BASE}/PluginsSources/Android/libproject/build/generated/source/buildConfig/fat/debug/org/example/ScriptBridge/BuildConfig.java" \
    -XDuseUnsharedTable=true

缩进和BASE 变量是您真正添加的。请注意,unity.jar 是一个 class 路径条目。

问题是,编译失败,因为 javac 在编译时显然无法在 unity.jar 中找到 class,除非那个 jar 被放入-bootclass路径选项 (!!).

为什么会这样? AFAIK,classes 的搜索路径应该是分层的,在启动 classpath 之后,javac 应该搜索 classpath...

是否可以告诉 gradle 将一些 jar 插入引导classpath somhow(这会笨拙地解决问题)?

有cleaner/better方法吗?

感谢您的任何见解!

编辑:

仔细检查后,看起来 classpath 有效(惊喜!)并且 Unity Technologies 没有创建变体-class路径弹性 jar,因为它是接管的第一步毕竟这个世界...

问题出在 compile 语句的路径中,在用正确的 jar 相对路径替换它之后,一切都按预期工作。

问题的答案是:

Q1:为什么会出现这种情况?

因为java无法在不存在的jar中找到class

问题 2:是否可以告诉 gradle 将一些 jar 粘贴到引导程序中 classpath somhow?

查看下面的答案

Q3:有cleaner/better方法吗?

是的:确保您 linking 的路径是正确的可能是一个好的开始:)

请注意,gradle 不会因缺少 jars 而发出任何错误,即使是在调试模式下(这是一个臭名昭著的恕我直言)。


旧答案

我必须以某种方式自己解决这个问题(我不认为我的解决方法是最佳的,但考虑到对这个问题的关注,我想它已经很好了...)

Q1:为什么会出现这种情况?

据我了解,没有翻转的原因。

文档:

How Classes are Found (Oracle canon)

明确指出bootstrap中的class是:

Bootstrap classes are the classes that implement the Java 2 Platform.

即用于实现平台的 classes。这就是为什么 android.jar 在那里,而 unity.jar 不应该 .

问题 2:是否可以告诉 gradle 将一些 jar 粘贴到 bootclasspath somhow 中?

是的!以下 link 详细说明:

Modify bootclasspath in compiler args (gradle forums)

那就是:

allprojects {
  gradle.projectsEvaluated {
    tasks.withType(JavaCompile) {
      options.compilerArgs << "Xbootclasspath/a:src/main/libs/unity.jar"
    }
  }
}

在我的项目中,它映射到在 android 之后加载一个 unity.jar 存档,位于我的 android 库的 src/main/libs 目录中。

Q3:有cleaner/better的方法吗?

我不这么认为,至少在不理解为什么 jar 首先需要放在 bootstrap 中(这会使这里的大部分问题变得毫无意义):改变 bootstrap class路径不是高级程序员应该做的事情,所以我不希望gradle提供更简洁的快捷方式。

我仍在等待对这个问题有一些见解的人(我不能在这上面花费更多的时间),但我希望这无论如何都会对某人有所帮助。