• [^] # Re: dll hell

    Posté par (site web personnel, Mastodon) . En réponse à la dépêche GIMP 2.10.6 : rien ne nous arrête !. Évalué à 10.

    Déjà un peu d'explication du problème pour bien comprendre. Windows cherche les DLLs dans cet ordre:

    • Le répertoire où se trouve le binaire
    • le répertoire courant
    • les divers répertoires système
    • enfin les répertoires listés dans le PATH.

    Pour le binaire principal gimp-2-10, c'est facile car il suffit de mettre toutes nos DLLs dans le même répertoire $PREFIX/bin/. Elles seront toujours trouvées en premier.
    Le problème est pour les plug-ins qui sont dans $PREFIX/lib/gimp/2.0/plug-ins/ et lorsque ces plug-ins souhaitent utiliser certaines des bibliothèques livrées avec GIMP (qui sont donc dans $PREFIX/bin/).

    On pourrait simplement mettre les librairies à côté de chaque plug-in, mais cela signifierait dupliquer les bibliothèques un certain nombre de fois. Et en plus ça ne permettrait plus aux plug-ins tiers de profiter des biblios livrées. Donc ce n'est pas acceptable.

    À la base, on rajoutait donc $PREFIX/bin au début du PATH (qui est spécifié dans un script de lancement). Mais si jamais une application installe une DLL (que nous utilisons, mais dans une version incompatible) dans un répertoire système, alors cette DLL est trouvée avant et les ennuis commencent.

    Une autre solution à laquelle je pensais est de jouer avec le répertoire courant (le faire pointer sur $PREFIX/bin) mais il se trouve que si SafeDllSearchMode est activé (apparemment une valeur de la base de registre), le répertoire courant est soudainement cherché après les répertoires système aussi! Donc ça marcherait plus (enfin surtout ça dépendrait de la configuration de l'OS).

    La solution est donc d'utiliser SetDllDirectoryW() pour donner la priorité à $PREFIX/bin, et pour être précis le mettre entre le répertoire du binaire (permettant aux plug-ins de bypasser nos biblios au besoin) et les répertoires système. C'est donc une solution au niveau du code.

    Un cas supplémentaire que nous avons corrigé dans 2.10.6 fut les plug-ins 32-bit lancé dans un environnement 64-bit. Dans ce cas, on doit leur donner un répertoire différent avec des versions 32-bit de nos bibliothèques (on le met dans $PREFIX/32/bin par défaut, mais j'ai mis un flag pour changer ce répertoire à la compilation). Je détecte donc le bitness d'un plug-in avant de le lancer et lui assigne le bon répertoire de bibliothèques avec SetDllDirectoryW().

    Un nouveau cas dont j'ai récemment pris connaissance (et pas encore corrigé) est les plug-ins scripts lancés par un interpréteur 32-bit sur environnement 64-bit (si le script utilise des bibliothèques compilées). Dans ce cas, on devra détecter le bitness de l'interpréteur.
    Par exemple notre installeur embarque seulement Python en 32-bit (je ne suis pas sûr pourquoi). Donc des scripts python un peu complexe qui utilise des biblios C risquent de ne pas fonctionner.

    Film d'animation libre en CC by-sa/Art Libre, fait avec GIMP et autre logiciels libres: ZeMarmot [ http://film.zemarmot.net ]