Cách sửa lỗi UnsatisfiedLinkError (Không tìm thấy thư viện phụ thuộc) trong dự án JNI


85

Tôi đang làm việc trên một dự án Java sử dụng JNI. JNI gọi một thư viện tùy chỉnh mà tôi đã tự viết, giả sử mylib.dll, và điều đó phụ thuộc vào thư viện của bên thứ 3, libsndfile-1.dll.

Khi tôi chạy chương trình của mình, nó bị lỗi

java.lang.UnsatisfiedLinkError:  C:\...path...\mylib.dll: Can't find dependent libraries.

Tôi đã tìm kiếm trang web này (và những trang khác) và tôi đã thử một số bản sửa lỗi:

  1. Tôi chạy bộ đi bộ phụ thuộc. DW đã đưa ra một vài cảnh báo - rằng hai thư viện được yêu cầu bởi libsndfile, MPR.DLL và SHLWAPI.DLL, có "các lần nhập chưa được giải quyết" - nhưng DW FAQ nói rằng những cảnh báo này có thể được bỏ qua một cách an toàn.

  2. Tôi đã sửa các tên phương thức trong mylib.dll, như được đề xuất ở đây . Các tên phương thức bằng cách nào đó đã bị trình biên dịch hiểu nhầm, nhưng tôi đã thêm cờ trình liên kết và tên phương thức dll giờ khớp chính xác với tên trong tệp tiêu đề jni của tôi.

  3. Tôi đặt tất cả các DLL này trong cùng một thư mục - cùng một thư mục với .jar gọi chúng - để đảm bảo rằng chúng ở đúng PATH.

Không có con xúc xắc.

Có ai có bất kỳ ý tưởng những gì đang xảy ra?

Tôi đang phát triển Visual Studio 2010 trên MacBook pro (thông qua Parallels). Tôi đang thực hiện thử nghiệm của mình trong Windows XP trên máy tính xách tay toshiba.


1
bạn đã đặt -Djava.library.path chưa?
Jochen Bedersdorfer

Tôi chưa thực sự khởi chạy chương trình từ dòng lệnh. Tôi đang viết thư viện cho Xử lý (processing.org) và Xử lý chịu trách nhiệm khởi chạy mã của tôi. Tuy nhiên, tôi đã kiểm tra đường dẫn thư viện java trong thời gian chạy và thư mục chứa các tệp DLL của tôi nằm trên đó.
dB '

Như tôi đã nói, tất cả các tệp DLL đều nằm trong cùng một thư mục, bên cạnh tệp .jar của tôi. Vì vậy, tôi không nghĩ vấn đề là họ không đi đúng hướng. Nhưng dù gì cũng cảm ơn.
dB '

7
Trên Windows, chúng tôi đã phải đặt các tệp .dll trong thư mục [JRE] \ bin (cùng nơi chứa java.exe, v.v.) để Java tự động xem chúng mà không cần phải cài đặt các tùy chọn dòng lệnh hoặc biến môi trường.
QuantumMechanic

4
Hừm ... được rồi, tôi đã thử đặt tất cả .dlls của mình vào [JRE] \ bin. Những công việc này!
dB '

Câu trả lời:


52

Tôi khá chắc chắn rằng classpath và đường dẫn tìm kiếm thư viện được chia sẻ ít liên quan đến nhau. Theo The JNI Book (thừa nhận là cũ), trên Windows nếu bạn không sử dụng thuộc tính java.library.pathhệ thống, DLL cần phải nằm trong thư mục làm việc hiện tại hoặc trong thư mục được liệt kê trong PATHbiến môi trường Windows .


Cập nhật:

Có vẻ như Oracle đã xóa tệp PDF khỏi trang web của mình. Tôi đã cập nhật liên kết ở trên để trỏ đến một bản PDF sống tại Đại học Texas - Arlington.

Ngoài ra, bạn cũng có thể đọc phiên bản HTML của Đặc tả JNI của Oracle . Nó nằm trong phần Java 8 của trang web Java và vì vậy hy vọng sẽ tồn tại trong một thời gian.


Cập nhật 2:

Ít nhất trong Java 8 (tôi chưa kiểm tra các phiên bản trước đó) bạn có thể làm:

java -XshowSettings:properties -version

để tìm đường dẫn tìm kiếm thư viện được chia sẻ. Tìm giá trị của thuộc java.library.pathtính trong đầu ra đó.


2
Vâng, CLASSPATHkhông được sử dụng ở tất cả. Tôi cũng không chắc cái cwdnày đã được sử dụng hay chưa. java.library.pathhoặc đơn giản là PATHsẽ hoạt động. @dB ', nơi bạn có chúng bây giờ là sai .
Ernest Friedman-Hill

Cảm ơn các bạn rất nhiều! Tôi nghĩ rằng một phần của vấn đề ở đây là do tôi nhầm lẫn giữa biến môi trường Windows PATH, java.library.path và java CLASSPATH. Bây giờ tất cả có ý nghĩa hơn.
dB '

Xin vui lòng giải thích bạn đã vượt qua vấn đề này như thế nào?
SL_User

5
@SL_User Tôi nghĩ nếu bạn thêm thư mục chứa các thư viện vào biến môi trường "đường dẫn" và khởi động lại dấu nhắc lệnh hoặc thiết bị đầu cuối thì nó sẽ khắc phục được. Java tìm kiếm các lọ trong đường dẫn classpath và các thư viện trong đường dẫn.
xxjjnn

1
Dựa trên câu trả lời này, có vẻ như lệnh for Update 2 đã có sẵn từ ít nhất Java 7: stackoverflow.com/a/8472139/901641
ArtOfWarfare

18

Tôi muốn thông báo về trường hợp thú vị này, sau khi thử tất cả các phương pháp trên, lỗi vẫn còn đó. Điều kỳ lạ là nó hoạt động trên máy tính Windows 7, nhưng trên Windows XP thì không. Sau đó, tôi sử dụng công cụ đi bộ phụ thuộc và thấy trên Windows XP không có VC ++ Runtime như yêu cầu dll của tôi. Sau khi cài đặt gói VC ++ Runtime ở đây, nó hoạt động như một sự quyến rũ. Điều khiến tôi băn khoăn là nó liên tục thông báo Không thể tìm thấy các thư viện phụ thuộc, trong khi trực giác dll phụ thuộc JNI ở đó, tuy nhiên, cuối cùng hóa ra dll phụ thuộc JNI yêu cầu một dl phụ thuộc khác. Tôi hi vọng cái này giúp được.


4
Thông báo là đúng mặc dù gây hiểu lầm trong trường hợp này. Tôi đã thiếu cả thời gian chạy VC ++ trên hộp kiểm tra và thư viện được biên dịch trong chế độ gỡ lỗi (tùy thuộc vào thời gian chạy gỡ lỗi không phân phối được). Sự phụ thuộc Walker là một trợ giúp đắc lực để tìm ra điều này.
Johnny Baloney

gặp vấn đề tương tự khi sử dụng jnetpcap-library. các winpcap phụ thuộc không được cài đặt trên máy tính này nữa và thông điệp ngoại lệ được gây hiểu lầm
BlackFlag

Tôi nghĩ đây có thể là trường hợp của tôi.
I.Tyger

Ngày nay, xe tập đi phụ thuộc đang trở nên khá "dài trong răng". Nó không thể mở dll Windows 10/64-bit gần đây, vì vậy tôi vẫn không biết thư viện nào bị thiếu ... Whee.
Mark Storer


5

Vui lòng xác minh đường dẫn thư viện của bạn có đúng hay không. Tất nhiên, bạn có thể sử dụng mã sau để kiểm tra đường dẫn đường dẫn thư viện của mình: System.out.println(System.getProperty("java.library.path"));

Bạn có thể chỉ định java.library.path khi khởi chạy ứng dụng Java:

java -Djava.library.path=path ...

4

Nếu bạn tải phiên bản dll 32 bit của mình với JRE 64 bit, bạn có thể gặp sự cố này. Đây là trường hợp của tôi.


Đây cũng là trường hợp của tôi; nếu ai đó biết về các cách giải quyết đã biết, tôi sẽ quan tâm; ngoại trừ việc tải phiên bản 64 bit, như trong trường hợp này, quy trình không phải là dll mà chromedriver.exelà trình điều khiển Selenium cho Chrome, theo như tôi có thể nói chỉ có ở phiên bản 32 bit.
SantiBailors

4

Đã gặp sự cố tương tự trên máy XP khi cài đặt javacvopencvkết hợp với Eclipse. Hóa ra là tôi đã thiếu các tệp sau:

  • msvcp100.dll
  • msvcr100.dll

Khi chúng được cài đặt, dự án được biên dịch và chạy OK.


Tôi đã là vấn đề tương tự mà biến mất sau khi cài đặt "Microsoft Visual C ++ 2010 SP1 Redistributable Package (x86)"
Kirill Mikhailov

2
  • Câu trả lời ngắn gọn: đối với lỗi "không thể tìm thấy thư viện phụ thuộc", hãy kiểm tra $ PATH của bạn (tương ứng với dấu đầu dòng # 3 bên dưới)
  • Câu trả lời dài:
    1. Thế giới java thuần túy: jvm sử dụng "Classpath" để tìm tệp lớp
    2. JNI world (java / native border): jvm sử dụng "java.library.path" (mặc định là $ PATH) để tìm dlls
    3. thế giới gốc thuần túy: mã gốc sử dụng $ PATH để tải các dll khác

2

Tôi đã tìm thấy một bài viết tuyệt vời của một số bạn bè tại keepafe đã trải qua điều tương tự như tôi đã làm. Nó hiệu quả với tôi, vì vậy hy vọng nó cũng giúp ích cho bạn! Hãy đọc nếu bạn quan tâm ( Mối nguy hiểm của việc tải thư viện bản địa trên Android ) hoặc chỉ cần sử dụng

compile 'com.getkeepsafe.relinker:relinker:1.2.3'

và thay thế

System.loadLibrary("myLibrary");

với

ReLinker.loadLibrary(context, "mylibrary");

1

Tôi đã từng có chính xác vấn đề tương tự, và cuối cùng nó đã được giải quyết.

Tôi đặt tất cả các DLL phụ thuộc vào cùng một thư mục nơi mylib.dll được lưu trữ và đảm bảo rằng Trình biên dịch JAVA có thể tìm thấy nó (nếu không có mylib.dll trong đường dẫn biên dịch, sẽ có lỗi báo cáo điều này trong quá trình biên dịch). Điều quan trọng bạn cần chú ý là bạn phải đảm bảo rằng tất cả các lib phụ thuộc có cùng phiên bản với mylib.dll, ví dụ: nếu mylib.dll của bạn là phiên bản phát hành thì bạn cũng nên đặt phiên bản phát hành của tất cả các lib phụ thuộc vào đó. .

Hy vọng điều này có thể giúp những người khác gặp phải vấn đề tương tự.


1

Tôi đã gặp vấn đề tương tự và tôi đã thử mọi thứ được đăng ở đây để khắc phục nhưng không có cách nào phù hợp với tôi. Trong trường hợp của tôi, tôi đang sử dụng Cygwin để biên dịch dll. Có vẻ như JVM cố gắng tìm các JRE DLL trong đường dẫn Cygwin ảo. Tôi đã thêm đường dẫn thư mục ảo của Cygwin vào các tệp DLL của JRE và nó hoạt động ngay bây giờ. Tôi đã làm một cái gì đó như:

SET PATH = "/ cygdrive / c / Program Files / Java / jdk1.8.0_45";% PATH%


1

Trong tình huống của tôi, tôi đang cố gắng chạy dịch vụ web java trong Tomcat 7 thông qua trình kết nối trong Eclipse. Ứng dụng chạy tốt khi tôi triển khai tệp chiến tranh vào một phiên bản của Tomcat 7 trên máy tính xách tay của mình. Ứng dụng yêu cầu trình điều khiển jdbc loại 2 cho "IBM DB2 9.5". Vì một số lý do kỳ lạ, trình kết nối trong Eclispe không thể nhìn thấy hoặc sử dụng các đường dẫn trong các biến môi trường DB2 của IBM, để truy cập các tệp dll được cài đặt trên máy tính xách tay của tôi dưới dạng ứng dụng khách jcc. Thông báo lỗi cho biết rằng nó không thể tìm thấy tệp dll db2jcct2 hoặc nó không thể tìm thấy các thư viện phụ thuộc cho tệp dll đó. Cuối cùng, tôi đã xóa trình kết nối và xây dựng lại nó. Sau đó, nó hoạt động bình thường. Tôi đang thêm giải pháp này ở đây làm tài liệu, vì tôi không tìm thấy giải pháp cụ thể này ở bất kỳ nơi nào khác.


0

Tạo thư viện tĩnh làm việc cho tôi, sử dụng biên dịch g++ -static. Nó gói các thư viện phụ thuộc cùng với bản dựng.


0

cài đặt Microsoft Visual C ++ 2010 SP1 Redistributable Đã sửa nó


0

đặt các dlls cần thiết trong thư mục và đặt đường dẫn thư mục trong biến môi trường PATH. đảm bảo biến PATH môi trường cập nhật được phản ánh.


0

Tôi đã gặp phải vấn đề tương tự với thư viện ffmpeg sau khi hợp nhất hai dự án Android thành một dự án.

Trên thực tế, sự cố đã đến do hai phiên bản thư viện ffmpeg khác nhau nhưng chúng được tải cùng tên trong bộ nhớ. Một thư viện được đặt trong JNiLibs trong khi thư viện khác nằm trong một thư viện khác được sử dụng làm mô-đun. Tôi không thể sửa đổi mã của mô-đun vì nó chỉ được đọc vì vậy tôi đã đổi tên mã được sử dụng trong mã của riêng tôi thành ffmpegCamera và tải nó vào bộ nhớ với cùng tên.

System.loadLibrary("ffmpegCamera");

Điều này đã giải quyết được sự cố và giờ đây cả hai phiên bản thư viện đang tải cũng như tên và id quy trình riêng biệt trong bộ nhớ.


0

Khi gọi System.loadLibrary(), JVM sẽ tìm java.library.paththư viện gốc của bạn. Tuy nhiên, nếu thư viện gốc đó khai báo bất kỳ phụ thuộc nào trên các thư viện gốc khác, thì hệ điều hành sẽ có nhiệm vụ tìm kiếm các phụ thuộc thư viện gốc đó.

Vì hệ điều hành không có khái niệm về java.library.path, nên nó sẽ không thấy bất kỳ thư mục nào bạn đặt trên java.library.path. Thay vào đó, nó sẽ chỉ tìm kiếm các thư mục trên biến môi trường PATH của hệ điều hành. Điều này hoàn toàn ổn nếu phần phụ thuộc thư viện gốc là thư viện gốc của hệ điều hành vì nó sẽ được tìm thấy trên PATH. Tuy nhiên, nếu phần phụ thuộc thư viện gốc là thư viện gốc mà bạn hoặc người khác đã tạo, thì nó sẽ không được tìm thấy trên PATH trừ khi bạn đặt nó ở đó. Hành vi này là lạ, không mong muốn và không được ghi lại đầy đủ, nhưng nó được ghi lại trong trình theo dõi vấn đề OpenJDK tại đây . Bạn cũng có thể tìm thấy một câu trả lời StackOverflow khác củng cố giải thích này, tại đây .

Vì vậy, bạn có một vài lựa chọn. Bạn có thể tải từng thư viện gốc theo đúng thứ tự phụ thuộc bằng cách sử dụng System.loadLibrary(), hoặc bạn có thể sửa đổi PATH để bao gồm các thư mục nơi các thư viện gốc của bạn được lưu trữ.


-2
  1. Tới http://tess4j.sourceforge.net/usage.html và click vàoVisual C++ Redistributable for VS2012
  2. Tải xuống và chạy VSU_4\vcredist_x64.exehoặc VSU_4\vcredist_x84.exetùy thuộc vào cấu hình hệ thống của bạn
  3. Đặt các dlltệp của bạn bên trong libthư mục, cùng với các thư viện khác của bạn (ví dụ \lib\win32-x86\your dll files:).
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.