web-dev-qa-db-fra.com

Comment générer une bibliothèque d'importation (fichier LIB) à partir d'une DLL?

Est-il possible de générer automatiquement une bibliothèque d'importation MSVC (fichier LIB) à partir d'une DLL? Comment?

51
Albert

Vous pouvez générer un fichier DEF en utilisant dumpbin/exports :

dumpbin /exports sqlite3.dll > exports.txt
echo LIBRARY SQLITE3 > sqlite3.def
echo EXPORTS >> sqlite3.def
for /f "skip=19 tokens=4" %A in (exports.txt) do echo %A >> sqlite3.def

Le bibliothécaire peut utiliser ce fichier DEF pour générer la LIB:

lib /def:sqlite3.def /out:sqlite3.lib /machine:x86

Tous les noms de fichiers (exports.txt, sqlite3.dll, sqlite3.def, etc.) doit être précédé de chemins d'accès complets.

62
Dark Falcon

Je sais que le sujet est ancien, mais je n'ai toujours pas trouvé de script ou de fichier batch sur Internet pour le faire. Donc, basé sur la réponse de Dark Falcon, j'ai créé ce script, que vous pouvez enregistrer sous dll2lib.bat et exécuter:

REM Usage: dll2lib [32|64] some-file.dll
REM
REM Generates some-file.lib from some-file.dll, making an intermediate
REM some-file.def from the results of dumpbin /exports some-file.dll.
REM Currently must run without path on DLL.
REM (Fix by removing path when of lib_name for LIBRARY line below?)
REM
REM Requires 'dumpbin' and 'lib' in PATH - run from VS developer Prompt.
REM 
REM Script inspired by http://stackoverflow.com/questions/9946322/how-to-generate-an-import-library-lib-file-from-a-dll
SETLOCAL
if "%1"=="32" (set machine=x86) else (set machine=x64)
set dll_file=%2
set dll_file_no_ext=%dll_file:~0,-4%
set exports_file=%dll_file_no_ext%-exports.txt
set def_file=%dll_file_no_ext%.def
set lib_file=%dll_file_no_ext%.lib
set lib_name=%dll_file_no_ext%

dumpbin /exports %dll_file% > %exports_file%

echo LIBRARY %lib_name% > %def_file%
echo EXPORTS >> %def_file%
for /f "skip=19 tokens=1,4" %%A in (%exports_file%) do if NOT "%%B" == "" (echo %%B @%%A >> %def_file%)

lib /def:%def_file% /out:%lib_file% /machine:%machine%

REM Clean up temporary intermediate files
del %exports_file% %def_file% %dll_file_no_ext%.exp

Je suis sûr que le script peut utiliser l'amélioration, mais j'espère que c'est utile.

13
Conrad Poelman

Ce script crée * .lib à partir de * .dll transmis dans% 1:

@echo off

setlocal enabledelayedexpansion
for /f "tokens=1-4" %%1 in ('dumpbin /exports %1') do (
    set /a ordinal=%%1 2>nul
    set /a hint=0x%%2 2>nul
    set /a rva=0x%%3 2>nul
    if !ordinal! equ %%1 if !hint! equ 0x%%2 if !rva! equ 0x%%3 set exports=!exports! /export:%%4
)

for /f %%i in ("%1") do set dllpath=%%~dpni
start lib /out:%dllpath%.lib /machine:x86 /def: %exports%

Vous pouvez le nommer implib.bat et exécuter: implib.bat C:\folder\mydll.dll qui produit C:\dossier\mydll.lib

8
vyshulga

Pour ceux qui sont sous Linux et souhaitent créer une bibliothèque d'importation appropriée (.lib) pour un .dll produit par MinGW, il y a encore deux étapes impliquées:

  • Créer un fichier .def à partir de .dll
  • Créer un fichier .lib à partir de .def

En utilisant MSVC, on pourrait traiter la sortie de dumpbin /exports foo.dll. Sous Linux, vous devez traiter la sortie de objdump -p (de binutils). Le fichier définition du module généré devrait ressembler à:

LIBRARY foo.dll
EXPORTS
    your_symbol @1
     another_symbol @2
     ; ... et cetera

Pour convertir le fichier .def en un fichier .lib, utilisez llvm-dlltool (MinGW (binutils) dlltool est non approprié). Exemple d'appel pour une bibliothèque 64 bits:

llvm-dlltool -m i386:x86-64 -d foo.def -l foo.lib

Explication:

  • -m i386:x86-64: générer une bibliothèque 64 bits. Utilisation -m i386 si vous avez besoin d'une bibliothèque 32 bits à la place.
  • -d foo.def: lire les symboles exportés du fichier foo.def
  • -l foo.lib: écrire une bibliothèque d'importation dans foo.lib
  • Si un .def le fichier ne contient pas de ligne LIBRARY, vous devez ajouter le -D foo.dll option (avec juste le nom de fichier et aucun préfixe de répertoire).

Et voici un script pour l'automatiser:

# Given libxyz-1.dll, create import library libxyz-1.lib
make_implib() {
    local machine=$1 dll="$2" dllname deffile libfile

    dllname="${dll##*/}"
    deffile="${dll%.dll}.def"
    libfile="${dll%.dll}.lib"

    # Extract exports from the .edata section, writing results to the .def file.
    LC_ALL=C objdump -p "$dll" | awk -vdllname="$dllname" '
    /^\[Ordinal\/Name Pointer\] Table$/ {
        print "LIBRARY " dllname
        print "EXPORTS"
        p = 1; next
    }
    p && /^\t\[ *[0-9]+\] [a-zA-Z0-9_]+$/ {
        gsub("\\[|\\]", "");
        print "    " $2 " @" $1;
        ++p; next
    }
    p > 1 && /^$/ { exit }
    p { print "; unexpected objdump output:", $0; exit 1 }
    END { if (p < 2) { print "; cannot find export data section"; exit 1 } }
    ' > "$deffile"

    # Create .lib suitable for MSVC. Cannot use binutils dlltool as that creates
    # an import library (like the one found in lib/*.dll.a) that results in
    # broken executables. For example, assume executable foo.exe that uses fnA
    # (from liba.dll) and fnB (from libb.dll). Using link.exe (14.00.24215.1)
    # with these broken .lib files results in an import table that lists both
    # fnA and fnB under both liba.dll and libb.dll. Use of llvm-dlltool creates
    # the correct archive that uses Import Headers (like official MS tools).
    llvm-dlltool -m "$machine" -d "$deffile" -l "$libfile"
    rm -f "$deffile"
}

# Example invocations:
make_implib i386:x86_64 usr/x86_64-w64-mingw32/sys-root/mingw/bin/libgnutls-30.dll
make_implib i386 usr/i686-w64-mingw32/sys-root/mingw/bin/libgnutls-30.dll

(Notez qu'il y a un bogue dans llvm-dlltool qui produit un fichier .lib plus volumineux que nécessaire si le nom de la bibliothèque est plus long que 15 caractères. Mis à part la taille, il est entièrement fonctionnel cependant. Il est résolu par https : //reviews.llvm.org/D5586 )

Testé avec:

  • llvm-dlltool de LLVM 7.0.0-1 (Arch Linux)
  • objdump depuis binutils 2.31.1-3 (Arch Linux)
  • dlltool de binutils-mingw-w64-x86 64_2.30-7ubuntu1 + 8ubuntu1 (Ubuntu 18.04)
  • link.exe de Visual Studio 2015 14.00.24215.1 (Windows 7)
5
Lekensteyn

Est-il possible de générer automatiquement une bibliothèque d'importation MSVC (fichier LIB) à partir d'une DLL? Comment?

En plus de la réponse de Dark Falcon, Microsoft a publié des procédures sur Comment créer des bibliothèques d'importation sans .OBJ ou source .

La première procédure de Microsoft est la même que celle de Dark Falcon. La deuxième procédure est un peu plus lourde, mais elle montre comment le faire avec un fichier objet à l'aide de stubs. Il fonctionne avec différentes conventions et classes d'appel.

Voici la deuxième procédure de la base de connaissances:

  1. Lorsque "__declspec (dllimport)" est utilisé dans un prototype ou une déclaration, remplacez-le par "__declspec (dllexport)".
  2. Pour les fonctions qui ne renvoient pas de valeur, pour les fonctions C dans la source C et pour les fonctions C dans le code source C++ (utilisé avec la construction 'extern "C"'), remplacez le point-virgule qui termine le prototype de la fonction par une paire correspondante de accolades ("{}").
  3. Pour les fonctions C++ (globales ou membres) qui renvoient une valeur, vous devez créer un corps fictif pour la fonction et renvoyer une valeur fictive du type approprié. (Ne pas avoir d'instruction return dans la fonction est illégal.) Cela vaut également pour les fonctions membres de classe. Gardez à l'esprit que le but de cette procédure est d'inciter l'utilitaire LIB à générer la bibliothèque d'importation correcte, de sorte que ces corps factices n'ont aucun effet.
  4. Pour les classes C++, vous pouvez supprimer les fonctions membres en utilisant les prototypes dans la déclaration de classe, tant que vous désactivez l'incrustation de fonction lors de la compilation.
  5. Les arguments de fonction sont généralement simplement spécifiés par type dans un fichier d'en-tête. Par exemple, Geta (int). Un identificateur d'argument factice doit être spécifié lors de l'ajout du corps de la fonction factice Geta (int x). Sinon, l'erreur C2055 est générée.
4
jww