Como corrigir um UnsatisfiedLinkError (não é possível encontrar bibliotecas dependentes) em um projeto JNI

85

Estou trabalhando em um projeto Java que usa o JNI. O JNI chama uma biblioteca personalizada que eu mesmo escrevi, digamos mylib.dll, e que depende de uma biblioteca de terceiros, libsndfile-1.dll.

Quando executo meu programa, ele trava com

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

Pesquisei neste site (e em outros) e tentei várias soluções:

  1. Corri o dependency walker. O DW deu alguns avisos - que duas bibliotecas exigidas pelo libsndfile, MPR.DLL e SHLWAPI.DLL, tinham "importações não resolvidas" - mas o DW FAQ disse que esses avisos poderiam ser ignorados com segurança.

  2. Corrigi os nomes dos métodos em mylib.dll, conforme sugerido aqui . Os nomes dos métodos foram de alguma forma mutilados pelo compilador, mas adicionei sinalizadores de linker e os nomes dos métodos dll agora correspondem exatamente aos do meu arquivo de cabeçalho jni.

  3. Coloquei todas essas DLLs no mesmo diretório - o mesmo diretório do .jar que as chama - para garantir que estejam no PATH certo.

Sem dados.

Alguém tem ideia do que está acontecendo?

Estou fazendo meu desenvolvimento no Visual Studio 2010 em um MacBook Pro (via Parallels). Estou fazendo meus testes no Windows XP em um laptop toshiba.

dB '
fonte
1
você definiu -Djava.library.path?
Jochen Bedersdorfer
Não, na verdade, porque não estou iniciando o programa a partir da linha de comando. Estou escrevendo uma biblioteca para Processing (processing.org) e Processing é responsável por lançar meu código. No entanto, verifiquei o caminho da biblioteca java em tempo de execução e a pasta que contém minhas DLLs está nele.
dB '23 de
Como eu disse, todas as DLLs estão na mesma pasta, ao lado do meu arquivo .jar. Portanto, não acho que o problema é que eles não estão no caminho. Mas obrigado mesmo assim.
dB '23 de
7
No Windows, tivemos que colocar arquivos .dll no diretório [JRE] \ bin (mesmo lugar onde estão java.exe, etc.) para fazer o Java os ver automaticamente sem ter que mexer com opções de linha de comando ou variáveis ​​de ambiente.
QuantumMechanic
4
Hmm ... ok, tentei colocar todos os meus .dlls em [JRE] \ bin. Isso funciona!
dB '23 de

Respostas:

52

Tenho certeza de que o caminho de classe e o caminho de pesquisa da biblioteca compartilhada têm pouco a ver um com o outro. De acordo com The JNI Book (que reconhecidamente é antigo), no Windows, se você não usar a java.library.pathpropriedade do sistema, a DLL precisa estar no diretório de trabalho atual ou em um diretório listado na PATHvariável de ambiente do Windows .


Atualizar:

Parece que a Oracle removeu o PDF de seu site. Atualizei o link acima para apontar para uma instância do PDF que vive na Universidade do Texas - Arlington.

Além disso, você também pode ler a versão HTML da Oracle da Especificação JNI . Ele está na seção Java 8 do site Java e, portanto, esperamos estar por aí por um tempo.


Atualização 2:

Pelo menos no Java 8 (não verifiquei as versões anteriores), você pode fazer:

java -XshowSettings:properties -version

para encontrar o caminho de pesquisa da biblioteca compartilhada. Procure o valor da java.library.pathpropriedade nessa saída.

QuantumMechanic
fonte
2
Sim, CLASSPATHnão é usado de todo. Eu também não tenho certeza se o cwdé usado. java.library.pathou simplesmente PATHfuncionará. @dB ', o lugar onde você os tem agora está errado .
Ernest Friedman-Hill
Muito obrigado, pessoal! Acho que parte do problema aqui foi uma confusão da minha parte entre a variável de ambiente PATH do Windows, java.library.path e o java CLASSPATH. Tudo faz mais sentido agora.
dB '23 de
Você pode explicar como você superou este problema?
SL_User de
5
@SL_User Acho que se você adicionar o diretório onde as bibliotecas estão à variável de ambiente "path" e reiniciar o prompt de comando ou terminal, isso deve corrigir. Java procura jars no classpath e bibliotecas no path.
xxjjnn
1
Com base nesta resposta, parece que o comando para a Atualização 2 está disponível pelo menos desde o Java 7: stackoverflow.com/a/8472139/901641
ArtOfWarfare
18

Quero informar este caso interessante, depois de tentar todo o método acima, o erro ainda está aí. O estranho é que funciona em um computador com Windows 7, mas não é no Windows XP. Então eu uso o dependency walker e descobri no Windows XP que não há VC ++ Runtime como meu requisito de dll. Depois de instalar o pacote VC ++ Runtime aqui, ele funciona perfeitamente. O que me perturbou é que ele continua dizendo Não consigo encontrar bibliotecas dependentes, enquanto intuitivamente a dll dependente de JNI está lá, no entanto, finalmente descobri que a dll dependente de JNI requer outra dl dependente. Eu espero que isso ajude.

longbkit
fonte
4
A mensagem está correta, embora enganosa neste caso. Eu tinha tempos de execução do VC ++ ausentes na caixa de teste e a biblioteca compilada no modo de depuração (dependendo dos tempos de execução de depuração não redistribuíveis). Dependency Walker foi de grande ajuda para descobrir isso.
Johnny Baloney
teve o mesmo problema ao usar a biblioteca jnetpcap. a dependência winpcap não estava mais instalada na máquina e a mensagem de exceção era enganosa
BlackFlag
estou pensando que este pode ser o meu caso.
I.Tyger
Hoje em dia, o andador da dependência está ficando muito "demorado". Ele não conseguiu abrir uma dll recente do Windows 10/64 bits, então ainda não tenho ideia de qual biblioteca está faltando ... Uau.
Mark Storer
5

Verifique se o caminho da sua biblioteca está correto ou não. Claro, você pode usar o seguinte código para verificar o caminho do caminho da biblioteca: System.out.println(System.getProperty("java.library.path"));

Você pode indicar o java.library.path ao iniciar um aplicativo Java:

java -Djava.library.path=path ...
caopeng
fonte
4

Se você carregar uma versão de 32 bits de sua dll com um JRE de 64 bits, poderá ter esse problema. Este foi o meu caso.

EFalco
fonte
Provavelmente, este também é o meu caso; se alguém estiver ciente de soluções alternativas conhecidas, eu estaria interessado; exceto o carregamento de uma versão de 64 bits, pois neste caso o processo não é uma dll chromedriver.exe, mas o driver Selenium para o Chrome, que até onde eu posso dizer só vem na versão de 32 bits.
SantiBailors
4

Teve problema idêntico com a máquina XP ao instalar javacve opencvem combinação com o Eclipse. Descobri que estavam faltando os seguintes arquivos:

  • msvcp100.dll
  • msvcr100.dll

Depois de instalados, o projeto foi compilado e executado corretamente.

Rob van Riswick
fonte
Tenho o problema semelhante que desaparece após a instalação do "Microsoft Visual C ++ 2010 SP1 Redistributable Package (x86)"
Kirill Mikhailov
2
  • Resposta curta: para o erro "não é possível encontrar a biblioteca dependente", verifique seu $ PATH (corresponde ao marcador nº 3 abaixo)
  • Resposta longa:
    1. Mundo Java puro: jvm usa "Classpath" para encontrar arquivos de classe
    2. Mundo JNI (java / limite nativo): jvm usa "java.library.path" (cujo padrão é $ PATH) para encontrar dlls
    3. mundo nativo puro: o código nativo usa $ PATH para carregar outros dlls
user2038596
fonte
2

Eu encontrei um ótimo artigo escrito por alguns amigos da Keepafe que passou pela mesma coisa que eu. Funcionou para mim, então espero que ajude você também! Leia se estiver interessado ( Os perigos de carregar bibliotecas nativas no Android ) ou apenas use

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

e substituir

System.loadLibrary("myLibrary");

com

ReLinker.loadLibrary(context, "mylibrary");
Rhysl
fonte
1

Eu costumava ter exatamente o mesmo problema e finalmente foi resolvido.

Coloquei todas as DLLs dependentes na mesma pasta em que mylib.dll foi armazenado e certifique-se de que o compilador JAVA possa encontrá-lo (se não houver mylib.dll no caminho de compilação, haverá um erro relatando isso durante a compilação). O importante que você precisa observar é que você deve se certificar de que todas as libs dependentes são da mesma versão de mylib.dll, por exemplo, se seu mylib.dll for uma versão de lançamento, você também deve colocar a versão de lançamento de todas as suas bibliotecas dependentes lá .

Espero que isso possa ajudar outras pessoas que tenham encontrado o mesmo problema.

Steven Peng
fonte
1

Eu tive o mesmo problema e tentei tudo o que está postado aqui para corrigi-lo, mas nada funcionou para mim. No meu caso, estou usando o Cygwin para compilar a dll. Parece que a JVM tenta encontrar as DLLs JRE no caminho virtual do Cygwin. Eu adicionei o caminho do diretório virtual do Cygwin às DLLs do JRE e agora funciona. Eu fiz algo como:

SET PATH = "/ cygdrive / c / Arquivos de programas / Java / jdk1.8.0_45";% PATH%

estebanuri
fonte
1

Na minha situação, eu estava tentando executar um serviço da web em java no Tomcat 7 por meio de um conector no Eclipse. O aplicativo funcionou bem quando implantei o arquivo war em uma instância do Tomcat 7 em meu laptop. O aplicativo requer um driver jdbc tipo 2 para "IBM DB2 9.5". Por alguma razão estranha, o conector no Eclispe não pôde ver ou usar os caminhos nas variáveis ​​de ambiente do IBM DB2 para alcançar os arquivos dll instalados em meu laptop como o cliente jcc. A mensagem de erro afirmou que não conseguiu encontrar o arquivo dll db2jcct2 ou não conseguiu encontrar as bibliotecas dependentes para esse arquivo dll. Por fim, excluí o conector e o reconstruí. Então funcionou corretamente. Estou adicionando essa solução aqui como documentação, porque não consegui encontrar essa solução específica em nenhum outro lugar.

Bwfrieds
fonte
0

Criar uma biblioteca estática funcionou para mim, compilando usando g++ -static. Ele empacota as bibliotecas dependentes junto com a construção.

César
fonte
0

instalar o Microsoft Visual C ++ 2010 SP1 Redistributable Corrigido

Sunil Kumar
fonte
0

coloque as dlls necessárias na pasta e defina o caminho da pasta na variável de ambiente PATH. certifique-se de que a variável PATH de ambiente atualizada seja refletida.

user3122472
fonte
0

Eu estava enfrentando o mesmo problema com a biblioteca ffmpeg depois de fundir dois projetos Android como um projeto.

Na verdade, o problema estava chegando devido a duas versões diferentes da biblioteca ffmpeg, mas elas foram carregadas com os mesmos nomes na memória. Uma biblioteca foi colocada no JNiLibs enquanto a outra estava dentro de outra biblioteca usada como módulo. Não fui capaz de modificar o código do módulo, pois era somente leitura, então renomei o usado em meu próprio código para ffmpegCamera e carreguei-o na memória com o mesmo nome.

System.loadLibrary("ffmpegCamera");

Isso resolveu o problema e agora as duas versões das bibliotecas estão carregando bem como nome e id de processo separados na memória.

Mohsin Raza
fonte
0

Ao chamar System.loadLibrary(), o JVM irá olhar nojava.library.path sua biblioteca nativa. No entanto, se essa biblioteca nativa declarar quaisquer dependências em outras bibliotecas nativas, o sistema operacional terá a tarefa de localizar essas dependências da biblioteca nativa.

Como o sistema operacional não tem o conceito de java.library.path, ele não verá nenhum diretório que você colocar no java.library.path. Em vez disso, ele pesquisará apenas os diretórios na variável de ambiente PATH do sistema operacional. Isso é totalmente adequado se a dependência da biblioteca nativa for uma biblioteca nativa do sistema operacional, pois ela será encontrada no PATH. No entanto, se a dependência da biblioteca nativa for uma biblioteca nativa que você ou outra pessoa criou, ela não será encontrada no PATH a menos que você a coloque lá. Este comportamento é estranho, inesperado e não bem documentado, mas está documentado no rastreador de problemas do OpenJDK aqui . Você também pode encontrar outra resposta StackOverflow reforçando essa explicação aqui .

Portanto, você tem algumas opções. Você pode carregar cada biblioteca nativa na ordem de dependência correta usando System.loadLibrary()ou pode modificar o PATH para incluir os diretórios onde suas bibliotecas nativas estão armazenadas.

Região 39
fonte
-2
  1. Vá para http://tess4j.sourceforge.net/usage.html e clique emVisual C++ Redistributable for VS2012
  2. Baixe e execute VSU_4\vcredist_x64.exeou VSU_4\vcredist_x84.exedependendo da configuração do seu sistema
  3. Coloque seus dllarquivos dentro da libpasta, junto com suas outras bibliotecas (por exemplo \lib\win32-x86\your dll files).
Pratik Varpe
fonte