gpt4 book ai didi

scala - 使用 Java 7 在 Scala 中编写 JNI 时出现 javah 错误

转载 作者:行者123 更新时间:2023-12-04 08:28:00 25 4
gpt4 key购买 nike

在 java 6 中,我可以在 Scala 中很好地使用 JNI。我会有这样的代码:

package mypackage
object MyClass {
System.loadLibrary("myclass-native")
@native def foo(): Int = sys.error("")
}

然后我会跑:
javah -classpath target/scala-2.9.1/classes -d target/jni mypackage.MyClass$

而且我会得到我的头文件就好了。

在 java 7 中,我收到以下错误:
Exception in thread "main" java.lang.IllegalArgumentException: Not a valid class name: mypackage.MyClass.
at com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:177)
at com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:68)
at com.sun.tools.javah.JavahTask.run(JavahTask.java:509)
at com.sun.tools.javah.JavahTask.run(JavahTask.java:335)
at com.sun.tools.javah.Main.main(Main.java:46)

这就像 javah 不再接受类名中的美元符号,但我需要在 Scala 中使用美元符号来获得静态方法的等效项。

供引用 Java 6:
$ java -version
java version "1.6.0_29"
Java(TM) SE Runtime Environment (build 1.6.0_29-b11)
Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02, mixed mode)
$ javah -version
javah version "1.6.0_29"

使用 Java 7:
$ java -version
java version "1.7.0_03"
OpenJDK Runtime Environment (IcedTea7 2.1.1pre) (7~u3-2.1.1~pre1-1ubuntu2)
OpenJDK 64-Bit Server VM (build 22.0-b10, mixed mode)
$ javah -version
javah version "1.7.0_03"

有没有人在 java 7 中将 javah 用于 JNI 和 Scala?

编辑

作为错误发布在 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7185778

最佳答案

了解正在发生的事情的最好方法是通过 OpenJDK 网站直接访问源代码。如果我们看 com.sun.tools.javac.api.JavacTool

 public JavacTask getTask(Writer out,
JavaFileManager fileManager,
DiagnosticListener<? super JavaFileObject> diagnosticListener,
Iterable<String> options,
Iterable<String> classes,
Iterable<? extends JavaFileObject> compilationUnits)
{
try {
Context context = new Context();
ClientCodeWrapper ccw = ClientCodeWrapper.instance(context);

final String kindMsg = "All compilation units must be of SOURCE kind";
if (options != null)
for (String option : options)
option.getClass(); // null check
if (classes != null) {
for (String cls : classes)
if (!SourceVersion.isName(cls)) // implicit null check
throw new IllegalArgumentException("Not a valid class name: " + cls);
}
if (compilationUnits != null) {
compilationUnits = ccw.wrapJavaFileObjects(compilationUnits); // implicit null check
for (JavaFileObject cu : compilationUnits) {
if (cu.getKind() != JavaFileObject.Kind.SOURCE)
throw new IllegalArgumentException(kindMsg);
}
}

if (diagnosticListener != null)
context.put(DiagnosticListener.class, ccw.wrap(diagnosticListener));

if (out == null)
context.put(Log.outKey, new PrintWriter(System.err, true));
else
context.put(Log.outKey, new PrintWriter(out, true));

if (fileManager == null)
fileManager = getStandardFileManager(diagnosticListener, null, null);
fileManager = ccw.wrap(fileManager);
context.put(JavaFileManager.class, fileManager);
processOptions(context, fileManager, options);
Main compiler = new Main("javacTask", context.get(Log.outKey));
return new JavacTaskImpl(compiler, options, context, classes, compilationUnits);
} catch (ClientCodeException ex) {
throw new RuntimeException(ex.getCause());
}

}

您可以看到违规行:
  if (!SourceVersion.isName(cls)) // implicit null check
throw new IllegalArgumentException("Not a valid class name: " + cls);

那么现在让我们来看看 javax.lang.model.SourceVersion
   /**
* Returns whether or not {@code name} is a syntactically valid
* qualified name in the latest source version. Unlike {@link
* #isIdentifier isIdentifier}, this method returns {@code false}
* for keywords and literals.
*
* @param name the string to check
* @return {@code true} if this string is a
* syntactically valid name, {@code false} otherwise.
* @jls 6.2 Names and Identifiers
*/
public static boolean isName(CharSequence name) {
String id = name.toString();

for(String s : id.split("\\.", -1)) {
if (!isIdentifier(s) || isKeyword(s))
return false;
}
return true;
}

所以你可以看到我们期望返回 true(但返回 false)的方法是:
  public static boolean isIdentifier(CharSequence name) {
String id = name.toString();

if (id.length() == 0) {
return false;
}
int cp = id.codePointAt(0);
if (!Character.isJavaIdentifierStart(cp)) {
return false;
}
for (int i = Character.charCount(cp);
i < id.length();
i += Character.charCount(cp)) {
cp = id.codePointAt(i);
if (!Character.isJavaIdentifierPart(cp)) {
return false;
}
}
return true;
}

问题是 !Character.isJavaIdentifierPart(cp)
现在,如果我们查看 1.6 版本:
public static boolean isJavaIdentifierPart(int codePoint) {
boolean bJavaPart = false;

if (codePoint >= MIN_CODE_POINT && codePoint <= FAST_PATH_MAX) {
bJavaPart = CharacterDataLatin1.isJavaIdentifierPart(codePoint);
} else {
int plane = getPlane(codePoint);
switch(plane) {
case(0):
bJavaPart = CharacterData00.isJavaIdentifierPart(codePoint);
break;
case(1):
bJavaPart = CharacterData01.isJavaIdentifierPart(codePoint);
break;
case(2):
bJavaPart = CharacterData02.isJavaIdentifierPart(codePoint);
break;
case(3): // Undefined
case(4): // Undefined
case(5): // Undefined
case(6): // Undefined
case(7): // Undefined
case(8): // Undefined
case(9): // Undefined
case(10): // Undefined
case(11): // Undefined
case(12): // Undefined
case(13): // Undefined
bJavaPart = CharacterDataUndefined.isJavaIdentifierPart(codePoint);
break;
case(14):
bJavaPart = CharacterData0E.isJavaIdentifierPart(codePoint);
break;
case(15): // Private Use
case(16): // Private Use
bJavaPart = CharacterDataPrivateUse.isJavaIdentifierPart(codePoint);
break;
default:
// the argument's plane is invalid, and thus is an invalid codepoint
// bJavaPart remains false;
break;
}
}
return bJavaPart;
}

和 1.7 版本:
  public static boolean isJavaIdentifierPart(int codePoint) {
return CharacterData.of(codePoint).isJavaIdentifierPart(codePoint);
}

这里发生了一些重构,如果您查看 CharacterData,您会发现它返回一些从 /openjdk/make/tools/GenerateCharacter/CharacterData**.java.template 中的模板动态生成的类。构建Java发行版时:
// Character <= 0xff (basic latin) is handled by internal fast-path
// to avoid initializing large tables.
// Note: performance of this "fast-path" code may be sub-optimal
// in negative cases for some accessors due to complicated ranges.
// Should revisit after optimization of table initialization.

static final CharacterData of(int ch) {
if (ch >>> 8 == 0) { // fast-path
return CharacterDataLatin1.instance;
} else {
switch(ch >>> 16) { //plane 00-16
case(0):
return CharacterData00.instance;
case(1):
return CharacterData01.instance;
case(2):
return CharacterData02.instance;
case(14):
return CharacterData0E.instance;
case(15): // Private Use
case(16): // Private Use
return CharacterDataPrivateUse.instance;
default:
return CharacterDataUndefined.instance;
}
}
}

我认为您可以尝试在 Debug模式下运行 javah 并查看两种情况下会发生什么,然后向 OpenJDK 人员发送精确的错误报告,因为此重构显然已经引入了该错误。

关于scala - 使用 Java 7 在 Scala 中编写 JNI 时出现 javah 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10669704/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com