java.lang.UnsatisfiedLinkError no *****. dll em java.library.path


92

Como posso carregar um arquivo dll personalizado em meu aplicativo da web? Tentei o seguinte:

  • Copiei todas as dlls necessárias na system32pasta e tentei carregar uma delas no ServletconstrutorSystem.loadLibrary
  • Dlls necessários copiados em tomcat_home/shared/libetomcat_home/common/lib

Todas essas dlls estão no WEB-INF/libaplicativo da web

Respostas:


154

Para System.loadLibrary()funcionar, a biblioteca (no Windows, uma DLL) deve estar em um diretório em algum lugar do seu PATH ou em um caminho listado na java.library.pathpropriedade do sistema (para que você possa iniciar o Java como java -Djava.library.path=/path/to/dir).

Além disso, para loadLibrary(), você especifica o nome base da biblioteca, sem o .dllno final. Então, para /path/to/something.dll, você apenas usaria System.loadLibrary("something").

Você também precisa olhar exatamente o UnsatisfiedLinkErrorque está obtendo. Se disser algo como:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no foo in java.library.path

então ele não consegue encontrar a biblioteca foo (foo.dll) em seu PATHou java.library.path. Se disser algo como:

Exception in thread "main" java.lang.UnsatisfiedLinkError: com.example.program.ClassName.foo()V

então, algo está errado com a própria biblioteca no sentido de que o Java não é capaz de mapear uma função Java nativa em seu aplicativo para sua contraparte nativa real.

Para começar, eu colocaria algum registro em torno de sua System.loadLibrary()chamada para ver se ela é executada corretamente. Se ele lançar uma exceção ou não estiver em um caminho de código que é realmente executado, você sempre obterá o último tipo UnsatisfiedLinkErrorexplicado acima.

Como nota lateral, a maioria das pessoas coloca suas loadLibrary()chamadas em um bloco inicializador estático na classe com os métodos nativos, para garantir que ele seja sempre executado exatamente uma vez:

class Foo {

    static {
        System.loadLibrary('foo');
    }

    public Foo() {
    }

}

1
Colocando todas as dlls em System32 e usando System.loadLibrary ("something") funcionou. Eu estava fazendo System.loadLibrary ("something.dll") anteriormente. Por que não consigo carregar todas as dlls do WEB-INF? Acho que carrega todos os frascos por padrão. O que posso fazer para carregar essas dlls de WEB-INF diretamente em vez de System32 / especificá-las em java.library.path
Ketan Khairnar

2
+1 para 'use "bla" em vez de "bla.dll" para loadLibrary()comentários - muito útil quando você não tem ideia do que está fazendo de errado.
MarnixKlooster ReinstateMonica

20
No meu sistema (Linux e java7), preciso de um libprefixo. Então System.loadLibrary("foo")precisa libfoo.so.
kristianlm

2
Obrigado. Funcionou para mim quando atualizei "PATH" para windows de modo que contenha uma pasta com o arquivo * .so.
user613114

15

Alterar a variável 'java.library.path' no tempo de execução não é suficiente porque ela é lida apenas uma vez pela JVM. Você deve redefini-lo como:

System.setProperty("java.library.path", path);
//set sys_paths to null
final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
sysPathsField.setAccessible(true);
sysPathsField.set(null, null);

Por favor, faça uma recompensa em: Changing Java Library Path at Runtime .


10

A resposta original de Adam Batkin levará você a uma solução, mas se você reimplantar seu webapp (sem reiniciar seu contêiner da web), deverá ocorrer o seguinte erro:

java.lang.UnsatisfiedLinkError: Native Library "foo" already loaded in another classloader
   at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1715)
   at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1646)
   at java.lang.Runtime.load0(Runtime.java:787)
   at java.lang.System.load(System.java:1022)

Isso acontece porque o ClassLoader que carregou originalmente sua DLL ainda faz referência a essa DLL. No entanto, seu webapp agora está sendo executado com um novo ClassLoader e, como a mesma JVM está em execução e uma JVM não permite 2 referências à mesma DLL, você não pode recarregá- la. Portanto, seu webapp não pode acessar a DLL existente e não pode carregar uma nova. Então .... você está preso.

Documentação do ClassLoader do Tomcat descreve por que seu webapp recarregado é executado em um novo ClassLoader isolado e como você pode contornar essa limitação (em um nível muito alto).

A solução é estender um pouco a solução de Adam Batkin:

   package awesome;

   public class Foo {

        static {
            System.loadLibrary('foo');
        }

        // required to work with JDK 6 and JDK 7
        public static void main(String[] args) {
        }

    }

Em seguida, coloque um jar contendo APENAS esta classe compilada na pasta TOMCAT_HOME / lib.

Agora, dentro do seu webapp, você só precisa forçar o Tomcat a fazer referência a essa classe, o que pode ser feito da seguinte maneira:

  Class.forName("awesome.Foo");

Agora sua DLL deve ser carregada no carregador de classe comum e pode ser referenciada a partir de seu webapp mesmo depois de ser reimplantada.

Faz sentido?

Uma cópia de referência de trabalho pode ser encontrada no código do google, static-dll-bootstrapper .


1
Essa resposta é excelente para servidores de aplicativos e deve ter sua própria pergunta, pois é desperdiçada nessa pergunta.
JoshDM de

8

Você pode usar System.load() para fornecer um caminho absoluto que é o que você deseja, em vez de um arquivo na pasta da biblioteca padrão para o respectivo sistema operacional.

Se você quiser aplicativos nativos que já existem, use System.loadLibrary(String filename). Se você deseja fornecer o seu, provavelmente é melhor usar load ().

Você também deve ser capaz de usar loadLibraryo java.library.pathconjunto corretamente. Veja ClassLoader.javapara fonte de implementação mostrando ambos os caminhos sendo verificados (OpenJDK)


Obrigado. Usar o load é IMHO muito mais fácil e intuitivo. Não foi possível fazer o loadLibrary funcionar independentemente do que eu fiz ...
Plankalkül

2
Esta solução não funciona para bibliotecas que carregam suas próprias bibliotecas nativas.
Justin Skiles,

7

No caso em que o problema é que System.loadLibrary não consegue encontrar a DLL em questão, um equívoco comum (reforçado pela mensagem de erro do Java) é que a propriedade de sistema java.library.path é a resposta. Se você definir a propriedade de sistema java.library.path para o diretório onde sua DLL está localizada, então System.loadLibrary realmente encontrará sua DLL. No entanto, se sua DLL, por sua vez, depender de outras DLLs, como costuma ser o caso, java.library.path não pode ajudar, porque o carregamento das DLLs dependentes é gerenciado inteiramente pelo sistema operacional, que nada sabe sobre java.library. caminho. Portanto, é quase sempre melhor ignorar java.library.path e simplesmente adicionar o diretório da DLL a LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS) ou Path (Windows) antes de iniciar a JVM.

(Observação: estou usando o termo "DLL" no sentido genérico de DLL ou biblioteca compartilhada.)


5

Se você precisa carregar um arquivo relativo a algum diretório onde você já está (como no diretório atual), aqui está uma solução fácil:

File f;

if (System.getProperty("sun.arch.data.model").equals("32")) {
    // 32-bit JVM
    f = new File("mylibfile32.so");
} else {
    // 64-bit JVM
    f = new File("mylibfile64.so");
}
System.load(f.getAbsolutePath());

4

Para quem procura java.lang.UnsatisfiedLinkError: no pdf_java in java.library.path

Eu estava enfrentando a mesma exceção; Tentei de tudo e coisas importantes para fazer funcionar são:

  1. Versão correta do pdf lib.jar (no meu caso, era a versão errada do jar mantido no tempo de execução do servidor)
  2. Faça uma pasta e mantenha o jar pdflib nela e adicione a pasta na sua variável PATH

Funcionou com o tomcat 6.


3
  1. Se você acredita que adicionou um caminho de lib nativo para %PATH%, tente testar com:

    System.out.println(System.getProperty("java.library.path"))

Deve mostrar se a dll está ativada %PATH%

  1. Reinicie o IDE Idea, que pareceu funcionar para mim depois que configurei a variável env, adicionando-a ao %PATH%

2

Pobre de mim! passou um dia inteiro atrás disso. Escrevendo aqui embaixo se algum corpo replica esse problema.

Eu estava tentando carregar como Adam sugeriu, mas fui pego com a exceção AMD64 vs IA 32. Se em qualquer caso, depois de trabalhar de acordo com o passo a passo de Adam (sem dúvida a melhor escolha), tente ter uma versão de 64 bits do jre mais recente. Certifique-se de seu JRE E JDK são de 64 bits e você os adicionou corretamente ao seu classpath.

Meu exemplo de trabalho vai aqui: erro de link não satisfeito


0

Para o Windows, descobri que quando carreguei os filles (jd2xsx.dll chama & ftd2xx.dll) na pasta windowws / system32 isso resolveu os problemas. Então, tive um problema com meu fd2xx.dll mais recente relacionado a parâmetros, por isso tive que carregar a versão mais antiga dessa dll. Terei que descobrir isso mais tarde.

Observação: o jd2xsx.dll chama o ftd2xx.dll, portanto, apenas definir o caminho para o jd2xx.dll pode não funcionar.


0

Estou usando Mac OS X Yosemite e Netbeans 8.02, obtive o mesmo erro e a solução simples que encontrei é como a acima, isso é útil quando você precisa incluir biblioteca nativa no projeto. Então, faça o próximo para o Netbeans:

1.- Right click on the Project
2.- Properties
3.- Click on RUN
4.- VM Options: java -Djava.library.path="your_path"
5.- for example in my case: java -Djava.library.path=</Users/Lexynux/NetBeansProjects/NAO/libs>
6.- Ok

Espero que possa ser útil para alguém. O link onde encontrei a solução está aqui: java.library.path - O que é e como usar


Olá, Alex, tenho uma pergunta se há algum problema se o caminho da biblioteca incluir algum espaçamento no caminho nesta linhaVM Options: java -Djava.library.path="your_path"
Lokesh Pandey

Humm, não estou trabalhando com Java há um ano, mas como podem aparecer conflitos, recomendo evitar adicionar espaços vazios no caminho do arquivo .
alexventuraio

0

Eu tive o mesmo problema e o erro foi devido a uma renomeação da dll. Pode acontecer que o nome da biblioteca também esteja escrito em algum lugar dentro da dll. Quando coloquei de volta o nome original, consegui carregar usandoSystem.loadLibrary


0

É simples, basta escrever java -XshowSettings: properties na linha de comando do Windows e colar todos os arquivos no caminho mostrado por java.library.path.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.