Как загрузить файл JDI .dylib с зависимостью, не получая UnsatifiedLinkError? - PullRequest
0 голосов
/ 04 ноября 2018

Цель: Ссылка Java на Swift

Проблема: Я получаю UnsatisfiedLinkError при попытке загрузить файл JNI .dylib, связанный с файлом Swift .dylib при вызове System#loadLibrary(String).

Ожидаемое поведение: Зависимость Java .dylib будет автоматически загружена, или вызов System.loadLibrary("SwiftCode") загрузит зависимость (единственное решение, которое я смог придумать).

Примечание: Я объединяю этот учебник github и эту статью Medium , чтобы создать мой файл JNI .dylib и этот учебник создать мой файл Swift .dylib.

Полная трассировка стека:

Exception in thread "main" java.lang.UnsatisfiedLinkError: /Users/hillmacbookpro/IdeaProjects/JavaToSwift/src/native/libSwiftHelloWorld.dylib: dlopen(/Users/hillmacbookpro/IdeaProjects/JavaToSwift/src/native/libSwiftHelloWorld.dylib, 1): Library not loaded: libSwiftCode.dylib
  Referenced from: /Users/hillmacbookpro/IdeaProjects/JavaToSwift/src/native/libSwiftHelloWorld.dylib
  Reason: image not found
    at java.base/java.lang.ClassLoader$NativeLibrary.load0(Native Method)
    at java.base/java.lang.ClassLoader$NativeLibrary.load(ClassLoader.java:2408)
    at java.base/java.lang.ClassLoader$NativeLibrary.loadLibrary(ClassLoader.java:2465)
    at java.base/java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2662)
    at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2627)
    at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:829)
    at java.base/java.lang.System.loadLibrary(System.java:1833)
    at helloworld.SwiftHelloWorld.<clinit>(SwiftHelloWorld.java:7)

Структура файла:

src
  - helloworld
      - SwiftHelloWorld.java
  - native
      - libSwiftHelloWorld.dylib
      - libSwiftCode.dylib

MCVE:

SwiftHelloWorld.java:

package helloworld;

public class SwiftHelloWorld {

    static {
        System.loadLibrary("SwiftCode"); // loading SwiftHelloWorld's dependency first
        System.loadLibrary("SwiftHelloWorld"); // exception thrown here, can't find dependency?
    }

    public static native void printHelloWorldImpl();

    public static void main(final String[] args) {
        printHelloWorldImpl();
    }

}

libSwiftHelloWorld.dylib: Создано с использованием этих двух команд терминала:

export JAVA_HOME="$(/usr/libexec/java_home -v 11)"; gcc -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin/" -o libSwiftHelloWorld.dylib -dynamiclib helloworld_SwiftHelloWorld.c libSwiftCode.dylib

и эти файлы:

  • helloworld_SwiftHelloWorld.c

    #include <jni.h>
    #include <stdio.h>
    #include "helloworld_SwiftHelloWorld.h"
    #include "helloworld_SwiftHelloWorld_swift.h"
    
    JNIEXPORT void JNICALL Java_helloworld_SwiftHelloWorld_printHelloWorldImpl
      (JNIEnv *env, jclass clazz) {
    
        int result = swiftHelloWorld(42);
        printf("%s%i%s", "Hello World from JNI! ", result, "\n");
    
    }
    
  • helloworld_SwiftHelloWorld.h: автоматически сгенерированный заголовок JNI из javac -h native/ helloworld/SwiftHelloWorld.java

  • helloworld_SwiftHelloWorld_swift.h

    int swiftHelloWorld(int);
    

libSwiftCode.dylib: Создано с использованием swiftc SwiftCode.swift -emit-library -o libSwiftCode.dylib и файла SwiftCode.swift:

import Foundation

// force the function to have a name callable by the c code
@_silgen_name("swiftHelloWorld")
public func swiftHelloWorld(number: Int) -> Int {
    print("Hello world from Swift: \(number)")
    return 69
}

Смежные вопросы:

Другие примечания: Я устанавливаю для параметров виртуальной машины Java значение -Djava.library.path=src/native, родительский каталог обоих файлов .dylib. Я использую macOS.

Редактировать: Я пытался предшествовать команде для компиляции SwiftCode.swift с xcrun, как показано в этой статье (в разделе «Код Compile Swift»), но я все еще получаю та же ошибка.

1 Ответ

0 голосов
/ 05 ноября 2018

macOS ld встраивает путь зависимости библиотеки в двоичный файл. Загрузчик, загружающий libSwiftHelloWorld.dylib, найдет libSwiftCode.dylib, только если последний находится в текущем каталоге. Загрузка зависимости в Java не работает, потому что для загрузчика это другая библиотека.

Вы можете изменить встроенный путь для libSwiftCode.dylib с помощью аргумента -install_name (т.е. swiftc ... -Xlinker -install_name -Xlinker <your path>). Если после этого вы перестроите libSwiftHelloWorld.dylib, он будет ссылаться на указанный вами путь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...