Как сгенерировать библиотеку импорта (LIB-файл) из DLL?

Можно ли автоматически создать библиотеку импорта MSVC (LIB-файл) из библиотеки DLL? Как?

4 ответа

Решение

Вы можете создать файл DEF, используя 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

Библиотекарь может использовать этот файл DEF для генерации LIB:

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

Все имена файлов (exports.txt, sqlite3.dll, sqlite3.defи т. д.) должны начинаться с полных путей.

Я знаю, что тема старая, но я все еще не мог найти сценарий или командный файл в Интернете для этого. Итак, основываясь на ответе Dark Falcon, я создал этот скрипт, который вы можете сохранить как dll2lib.bat и запустить:

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://stackru.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

Я уверен, что сценарий может использовать улучшения, но я надеюсь, что это полезно.

Этот скрипт создает *.lib из *.dll, переданной в%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%

Вы можете назвать его implib.bat и запустить: implib.bat C:\folder\mydll.dll который выдает C:\folder\mydll.lib

Для тех, кто работает в Linux и хотел бы создать соответствующую библиотеку импорта (.lib) для.dll, созданной MinGW, снова нужно выполнить два шага:

  • Создать файл.def из.dll
  • Создать.lib файл из.def

Используя MSVC, можно обработать вывод dumpbin /exports foo.dll, В Linux вы должны обработать вывод objdump -p (из binutils). Сгенерированный файл определения модуля должен выглядеть следующим образом:

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

Чтобы преобразовать файл.def в файл.lib, используйте llvm-dlltool (MinGW (binutils) dlltool не подходит). Пример вызова для 64-битной библиотеки:

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

Объяснение:

  • -m i386:x86-64: создать 64-битную библиотеку. использование -m i386 если вам нужна 32-битная библиотека
  • -d foo.def: прочитать экспортированные символы из файла foo.def
  • -l foo.lib: написать библиотеку импорта в foo.lib
  • Если .def файл не содержит LIBRARY линия, вы должны добавить -D foo.dll опция (только с именем файла и без префикса каталога).

А вот скрипт для его автоматизации:

# 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

(Обратите внимание, что в llvm-dlltool есть ошибка, которая выдает файл.lib большего размера, чем необходимо, если имя библиотеки длиннее 15 символов. Помимо размера, оно полностью функционально. Это исправлено https://reviews.llvm.org/D55860)

Протестировано с:

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

Можно ли автоматически создать библиотеку импорта MSVC (LIB-файл) из библиотеки DLL? Как?

В дополнение к ответу Dark Falcon Microsoft опубликовала процедуры в разделе "Как создать библиотеки импорта без.OBJs или исходного кода".

Первая процедура Microsoft такая же, как у Dark Falcon. Вторая процедура немного более громоздка, но показывает, как это сделать с помощью объектного файла с использованием заглушек. Он работает с различными соглашениями о вызовах и классами.

Вот вторая процедура из КБ:

  1. Когда "__declspec(dllimport)" используется в прототипе или объявлении, измените его на "__declspec(dllexport)".
  2. Для функций, которые не возвращают значение, для функций C в исходном коде C и для функций C в исходном коде C++ (используется с конструкцией 'extern "C"), замените точку с запятой, которая завершает прототип функции, соответствующей парой Фигурные скобки ("{}").
  3. Для функций C++ (глобальных или членских), которые возвращают значение, вы должны создать фиктивное тело для функции и вернуть фиктивное значение соответствующего типа. (Отсутствие оператора return в функции недопустимо.) Это также относится и к функциям-членам класса. Имейте в виду, что цель этой процедуры - заставить утилиту LIB создать правильную библиотеку импорта, чтобы эти фиктивные тела не действовали.
  4. Для классов C++ вы можете заглушить функции-члены, используя прототипы в объявлении класса, до тех пор, пока вы отключаете встраивание функций при компиляции.
  5. Аргументы функции обычно просто указываются по типу в заголовочном файле. Например, Geta(int). Идентификатор фиктивного аргумента должен быть указан при добавлении тела фиктивной функции Geta(int x). В противном случае выдается ошибка C2055.
Другие вопросы по тегам