2009-09-03 44 views
5

OSGi không thể tìm thấy tệp DLL của tôi và tôi không thể tìm ra lý do tại sao.Tải DLL (sử dụng JNA) bên trong một gói OSGi

Hiện tại tôi có tệp DLL (foo.dll) ở gốc gói của mình, tôi cũng đã thử có trong thư mục libs.

Các Manifest cho bó trong câu hỏi trông giống như sau:

Manifest-Version: 1.0 
Bundle-ManifestVersion: 2 
Bundle-Name: foobundle 
Bundle-SymbolicName: com.foo.bar 
Bundle-Version: 1.0.0 
Bundle-Vendor: me 
Import-Package: com.sun.jna, 
com.sun.jna.ptr, 
com.sun.jna.win32 
Export-Package: com.foo.bar 
Bundle-NativeCode: foo.dll; 
osname=WindowsXP; 
processor=x86 

Sau đó, trong giao diện JNA của tôi, tôi thực hiện một LoadLibrary (theo tài liệu):

public interface MyFooInterface extends com.sun.jna.Library{ 
    static final MyFooInterface INSTANCE = (MyFooInterface)com.sun.jna.Native.loadLibrary("foo", MyFooInterface .class); 

    // specific interface defs here... 
} 

Sau đó, trong lớp khác Tôi cố gắng sử dụng giao diện JNA

// ...code 
int var = MyFooInterface.INSTANCE.bar(); 
// ...more code 

Tôi có JNA được cung cấp qua một gói khác le (xuất khẩu com.sun.jna và các gói khác được nhập ở trên), nhưng cũng đã thử đóng gói nó với gói được định nghĩa ở đây (và thêm nó vào đường dẫn lớp trong trường hợp đó, v.v.).

Tôi cũng đã cố chỉ định Bundle-NativeCode: /foo.dll.

Cũng quan tâm, đó là những đặc tính OSGi liên quan (mà tôi kéo lên bằng getprop)

org.osgi.framework.os.name=WindowsXP 
org.osgi.framework.processor=x86 

Ngay cả sau khi tất cả điều này (và với mọi thử thách tôi thực hiện) Tôi luôn luôn kết thúc với các lỗi sau (và ngăn xếp ngăn xếp không được hiển thị):

java.lang.UnsatisfiedLinkError: Unable to load library 'foo': The specified module could not be found. 

... vậy tôi còn thiếu gì?

Chỉnh sửa: Tôi cũng nên lưu ý rằng tôi đã thử nghiệm và đã thành công mã giao diện JNA và DLL mà nó nói đến như là một phần của chương trình Kiểm tra JUnit.

Chỉnh sửa 2: Thêm mã này vào lớp đang gọi thư viện dường như cho phép JNA tìm thư viện (khi gọi Native.loadLibrary được gọi sau). Có vẻ như tôi sẽ có thể tránh cuộc gọi này dựa trên chỉ thị Bundle-NativeCode trong Tệp kê khai. Rõ ràng một khi thư viện được tải Native.loadLibrary lấy ví dụ hiện tại của nó, nhưng tôi không muốn phụ thuộc vào chiến thuật này rất cụ thể theo thứ tự.

static{ 
    System.loadLibrary("foo"); 
} 
+0

Bạn đang sử dụng cài đặt OSGi nào? – omerkudat

+0

Tôi đang sử dụng Equinox (đặc tả R4) –

+0

Bạn có thể muốn nêu rõ phiên bản Java nào bạn đang sử dụng vì tôi chưa bao giờ gặp JNA trước đây và nó không phải là một phần của Java và bao gồm 6. – SteveD

Trả lời

7

Sự cố là cuộc gọi thư viện tải JNA chuyên biệt, không phải là nhận thức OSGi. Khi bạn gọi loadLibrary từ một gói OSGi, nó sẽ sử dụng trình nạp lớp OSGi (là gói nhận biết) để tìm vị trí của DLL, và trong trường hợp này, giải nén nó ra khỏi bó và làm cho nó có thể tải thông qua System.loadLibrary() cuộc gọi chống lại một địa điểm cụ thể.

Vì JNA này có vẻ là (a) không phải là nhận thức OSGi, và (b) dồi dào, tại sao không chỉ sử dụng System.loadLibrary() thay thế?

Nếu bạn cần viết cả hai, sau đó thực hiện System.loadLibrary() trong phương thức start() của bundle trong BundleActivator, nó sẽ mang thư viện gốc vào (bạn có thể muốn đảm bảo rằng nếu nó không thể được tải, không thể khởi động gói trong mọi trường hợp).

+0

Cuối cùng JNA phải gọi Native.loadLibrary hoặc Native.register của chính nó (sau khi truy tìm thông qua trình gỡ rối theo cùng một chuỗi các sự kiện) để cho phép truy cập gốc hoặc hướng trực tiếp mà JNA cung cấp. Tôi đã tìm thấy rằng các giải pháp, mặc dù một trong đó có vẻ không đạt yêu cầu là để gọi System.loadLibrary đầu tiên, như bạn đề nghị, tiếp theo sau đó bằng một cuộc gọi đến Native.loadLibrary hoặc Native.register ở nơi thích hợp. –

+0

Bạn có thể thấy tính năng này hoạt động trên Windows, nhưng có lẽ không có trên các nền tảng khác. Tôi nhớ lại một vấn đề trong đó tải một DLL với phụ thuộc hoạt động trên Windows (bằng cách tải A đầu tiên, sau đó B, khi B phụ thuộc vào A) nhưng có vấn đề trên máy Mac. Tôi không biết tại sao có thể như vậy ... nhưng chỉ là một lời cảnh báo rằng bạn có thể có một giải pháp nền tảng cụ thể trong tay bạn. Ít nhất, bạn nên kiểm tra (thay vì giả định) cho các nền tảng không phải Windows. – AlBlue

+0

System.loadLibrary sử dụng trình nạp lớp OSGi - câu lệnh Bundle-NativeCode trong tệp kê khai là hoàn toàn bắt buộc để định vị tệp DLL - vì vậy bất kể hệ điều hành, giải pháp này sẽ tìm mã gốc. Nếu foo.dll phụ thuộc vào bar.dll nó sẽ trở nên rất quan trọng để tải chúng theo thứ tự, nhưng đó là một vấn đề khác và may mắn thay không phải là trường hợp ở đây. Cảm ơn cho những người đứng đầu lên, mặc dù. –

0

Tôi đề nghị bạn cố gắng đóng gói dll như một jar:

jar cvf foo.dll.jar foo.dll 

và tải jar như một lib thường xuyên.

+0

Tôi không chắc chắn đó là một cách tiếp cận khả thi, tôi cần tải DLL như một thư viện gốc, và tôi đã chắc chắn rằng nó được đóng gói như là một phần của gói OSGi đang cố gắng sử dụng nó. –

+0

Tôi đang sử dụng tecnhique này trong JNLP để tải libs gốc. Các jvm có thể tìm thấy libs bản địa bên trong lọ –

+0

Vì vậy, FWIW tôi đã thử nó và không tốt. Tôi đã xây dựng foo.jar và thêm nó vào đường dẫn lớp của tôi (thêm dòng: Bundle-ClassPath: libs/foo.jar, .) Vào Tệp kê khai ở trên và thư viện vẫn không thể tìm thấy. Vấn đề bắt nguồn từ nhiều hơn JVM không thể nhìn thấy nó, nó cần phải được tải thông qua trình nạp lớp/đường dẫn OSGi. –

1

Nhìn vào tài liệu JNA, nó khẳng định:

  • Hãy thư viện mục tiêu của bạn có sẵn cho chương trình Java của bạn. Có hai cách để thực hiện việc này:
    • Phương pháp ưa thích là đặt thuộc tính hệ thống jna.library.path thành đường dẫn đến thư viện mục tiêu của bạn. Thuộc tính này tương tự như java.library.path nhưng chỉ áp dụng cho các thư viện được tải bởi JNA.
    • Thay đổi biến môi trường truy cập thư viện thích hợp trước khi khởi chạy VM. Đây là PATH trên Windows, LD_LIBRARY_PATH trên Linux và DYLD_LIBRARY_PATH trên OSX.

Vì vậy, để có được xung quanh thiếu sót này, bạn có thể giải quyết các đường dẫn tuyệt đối của thư viện và tải đó.

Giả sử rằng trình nạp lớp chuẩn của Eclipse, bạn có thể thực hiện ClassLoader.findLibrary() để tìm thư viện cục bộ trong gói.

+0

Điều này xảy ra với vấn đề về đóng gói và phân phối ứng dụng, đặt người bản xứ ở vị trí có thể dự đoán trong ứng dụng của bạn tổng hợp vị trí này để tiêm vào các thuộc tính JVM với "jna.library.path". – whatnick

Các vấn đề liên quan