从DLL生成LIB

从DLL生成LIB

cheungmine

2013-5-14

windows程序链接到一个动态链接库.dll时需要一个导入库.lib。遗憾的是这样的导入库很多时候是不存在的,那么就需要我们自己从.dll生成对应的导入库.lib。假设我们的windows程序为WinApp.exe,它静态链接到一个动态库libABC.dll。我们在WinApp.exe的源代码中可以这样写:

// (程序清单1)
// WinApp.c
//

#include <windows.h>

#include "C:/DEVPACK/LIBABC/include/ABCapi.h"
# pragma comment(lib, "C:/DEVPACK/LIBABC/lib/libABC.lib");

int main()
{
    // 下面可以直接使用 LIBABC 的函数
    ABCInit();
    ABCAddValues(a, b);
    ABCUninit();

    exit(0);
}
但是问题是,我们手里只有libABC.dll和头文件。没有libABC.lib。这就需要我们从命令行工具生成出libABC.lib。从DLL生成LIB的过程是:DLL->DEF->LIB。需要生成一个叫做模块定义文件(.def)的中间文件。一个典型的模块定义文件(libABC.def)如下(程序清单2):
LIBRARY libABC

EXPORTS
    ABCInit
    ABCUninit
    ABCAddValues
    ...
windows的vs系列开发工具提供了这个命令行dumpbin,它的调用方式是打开cmd,然后输入下面的命令:
dumpbin /EXPORTS libABC.dll > libABC.def

上面的命令执行后生成的libABC.def文件包含了对于生成LIB无用的信息,我们必须手工处理掉,然后才能带入下面的命令中生成LIB。假设我们已经把libABC.def处理成(程序清单2)的样子。接下来使用另外一个命令行工具,通过这个def文件生成LIB:

lib /def:libABC.def /machine:i386 /out:libABC.dll

总结下来,整个过程有3步:
1)DLL->def
2)处理def
3)使用处理后的def->LIB

整个过程在第2步不是自动化的,我曾经写过一个脚本完成第2步的自动化。后来发现MinGW提供了这样的工具:pexports。默认的MinGW没有安装pexports,你需要运行下面的命令在MinGW中安装:

$ mingw-get install pexports
于是,产生处理好的def的工作就变得非常简单:
$ pexports libABC.dll > libABC.def
无论是dumpbin还是lib这2个命令都需要VS的运行环境。因此必须先设置环境变量,通过运行一个在%VS??COMNTOOLS%的路径下的批处理文件vsvars32.bat(??表示版本号,可以查看windows环境变量得到这个信息),来完成VS环境变量设置。过程就是打开windows cmd,输入下面的命令:
%VS100COMNTOOLS%vsvars32.bat
最后我把整个处理过程写成了python脚本,这个脚本执行起来特别简单,打开MinGW命令行,进入libABC.dll所在的目录,输入下面的命令:
$ python mklib-win32.py libABC
或者
$ python mklib-win32.py libABC.dll

最后,我把mklib-win32.py贴出来,以飨读者:

#!/usr/bin/python
# filename: mklib-win32.py
# make import x86_32 import-lib from windows win32 dll
# author: cheungmine@gmail.com
# date: 2013-5
# version: 0.1
#
# MinGW:
#   $ python build-win32.py target_dll
#   $ python build-win32.py libtiff-5.dll
#   $ python build-win32.py libtiff-5
#   $ python build-win32.py tiff-5
#   $ python build-win32.py c:/path/to/libtiff-5
# ERROR: $ python build-win32.py c:\path\to\libtiff-5
#
# file operation:
# import shutil
#
## copy file:
#   shutil.copy(myfile, tmpfile)
#
## copy time of file:
#   shutil.copy2(myfile, tmpfile)
#
## copy file dir tree, the 3rd parameter means:
##   True: symbol link
##   False: use phyical copy
#   shutil.copytree(root_of_tree, destination_dir, True)
###############################################################################

import os
import platform
import time
import getopt
import optparse
import sys
import string

###############################################################################
# get installed VS???COMNTOOLS environment:
###############################################################################
def get_vspath():
  _vspath = os.getenv('VS110COMNTOOLS')
  if not _vspath:
    _vspath = os.getenv('VS100COMNTOOLS')
    if not _vspath:
      _vspath = os.getenv('VS90COMNTOOLS')
      if not _vspath:
        _vspath = os.getenv('VS80COMNTOOLS')
        if not _vspath:
          print "VS??COMNTOOLS not found"
          sys.exit()
        else:
          print "VS80COMNTOOLS =", _vspath
      else:
        print "VS90COMNTOOLS =", _vspath
    else:
      print "VS100COMNTOOLS =", _vspath
  else:
    print "VS110COMNTOOLS =", _vspath
  return _vspath

###############################################################################
# step (1): create a windows module definition: target_lib.def
#   MSCMD:
#     > dumpbin /EXPORTS target_lib.dll > ~target_lib.def
#   or MinGW:
#     $ pexports target_lib.dll > target_lib.def
# step (2): use this target_lib.def to create module import file: target_lib.lib
#   MSCMD:
#     > lib /def:target_lib.def /machine:i386 /out:target_lib.lib
###############################################################################
def make_lib(workdir, tgtname):
  print "[2-1] create a windows module definition: lib%s.def" % tgtname
  dump_def = 'cd "%s"&pexports lib%s.dll > lib%s.def' % \
    (work_dir, tgtname, tgtname)
  ret = os.system(dump_def)
  if ret == 0:
    print "[2-2] use (lib%s.def) to create import module: lib%s.lib" % (tgtname, tgtname)
    lib_cmd = 'cd "%s"&lib /def:lib%s.def /machine:i386 /out:lib%s.lib' % (workdir, tgtname, tgtname)
    cmds = 'cd "%s"&vsvars32.bat&%s&cd "%s"' % (vs_path, lib_cmd, cwd_path)
    ret = os.system(cmds)
    if ret == 0:
      print "INFO: mklib (%s/lib%s.lib) success." % (cwd_path, tgtname)
      return 0;
    else:
      print "ERROR: mklib (%s/lib%s.lib) failed." % (cwd_path, tgtname)
      return (-2)
  else:
    print "ERROR: mklib (%s/lib%s.def) failed." % (cwd_path, tgtname)
    return (-1);

###############################################################################
# current directory:
cwd_path = os.getcwd()
vs_path = get_vspath()

work_dir = "./"

# lib name == parent folder name
target_dll = "ERROR_dll_not_found"

if sys.argv.__len__() == 1:
  work_dir, target_dll = os.path.split(cwd_path)
elif sys.argv.__len__() == 2:
  work_dir = os.path.dirname(sys.argv[1])
  target_dll = os.path.basename(sys.argv[1])
else:
  print "ERROR: invalid argument"
  sys.exit(-1)

if target_dll[0:3] == "lib":
  target_dll = target_dll[3:]
tgtname, extname = os.path.splitext(target_dll)

if extname != ".dll":
  tgtname = target_dll

if work_dir == "":
  work_dir = cwd_path

print "working directory:", work_dir
print "======== make import (lib%s.lib) from (lib%s.dll) ========" % \
  (tgtname, tgtname)

make_lib(work_dir, tgtname)

sys.exit(0)

由于近期开发windows x64程序,因此需要生成64位的DLL对应的LIB,于是我又在mklib-win32.py的基础上完成了mklib-win64.py的脚本,具体原理我就不说了,读者注意脚本之中的细微之处不难理解:

#!/usr/bin/python
# filename: mklib-win64.py
# make import x86_64 import-lib from windows x64 dll
# author: cheungmine@gmail.com
# date: 2013-5
# version: 0.1
#
# MinGW:
#   $ python build-win64.py target_dll
#   $ python build-win64.py libtiff-5.dll
#   $ python build-win64.py libtiff-5
#   $ python build-win64.py tiff-5
#   $ python build-win64.py c:/path/to/libtiff-5
# ERROR: $ python build-win64.py c:\path\to\libtiff-5
#
# file operation:
# import shutil
#
## copy file:
#   shutil.copy(myfile, tmpfile)
#
## copy time of file:
#   shutil.copy2(myfile, tmpfile)
#
## copy file dir tree, the 3rd parameter means:
##   True: symbol link
##   False: use phyical copy
#   shutil.copytree(root_of_tree, destination_dir, True)
###############################################################################

import os
import platform
import time
import getopt
import optparse
import sys
import string

###############################################################################
# get installed VS???COMNTOOLS environment:
###############################################################################
def get_vspath():
  _vspath = os.getenv('VS110COMNTOOLS')
  if not _vspath:
    _vspath = os.getenv('VS100COMNTOOLS')
    if not _vspath:
      _vspath = os.getenv('VS90COMNTOOLS')
      if not _vspath:
        _vspath = os.getenv('VS80COMNTOOLS')
        if not _vspath:
          print "VS??COMNTOOLS not found"
          sys.exit()
        else:
          print "VS80COMNTOOLS =", _vspath
      else:
        print "VS90COMNTOOLS =", _vspath
    else:
      print "VS100COMNTOOLS =", _vspath
  else:
    print "VS110COMNTOOLS =", _vspath
  return _vspath

###############################################################################
# step (1): create a windows module definition: target_lib.def
#   MSCMD:
#     > dumpbin /EXPORTS target_lib.dll > ~target_lib.def
#   or MinGW:
#     $ pexports target_lib.dll > target_lib.def
# step (2): use this target_lib.def to create module import file: target_lib.lib
#   MSCMD:
#     > lib /def:target_lib.def /machine:amd64 /out:target_lib.lib
###############################################################################
def make_lib(workdir, tgtname):
  print "[2-1] create a windows module definition: lib%s.def" % tgtname
  dump_def = 'cd "%s"&pexports lib%s.dll > lib%s.def' % \
    (work_dir, tgtname, tgtname)
  ret = os.system(dump_def)
  if ret == 0:
    print "[2-2] use (lib%s.def) to create import module: lib%s.lib" % (tgtname, tgtname)
    lib_cmd = 'cd "%s"&lib /def:lib%s.def /machine:amd64 /out:lib%s.lib' % (workdir, tgtname, tgtname)
    cmds = 'cd "%s"&vcvarsall.bat x86_amd64&%s&cd "%s"' % (vs_path, lib_cmd, cwd_path)
    ret = os.system(cmds)
    if ret == 0:
      print "INFO: mklib (%s/lib%s.lib) success." % (cwd_path, tgtname)
      return 0;
    else:
      print "ERROR: mklib (%s/lib%s.lib) failed." % (cwd_path, tgtname)
      return (-2)
  else:
    print "ERROR: mklib (%s/lib%s.def) failed." % (cwd_path, tgtname)
    return (-1);

###############################################################################
# current directory:
cwd_path = os.getcwd()
vs_path = get_vspath() + "..\\..\\VC\\"
work_dir = "./"

# lib name == parent folder name
target_dll = "ERROR_dll_not_found"

if sys.argv.__len__() == 1:
  work_dir, target_dll = os.path.split(cwd_path)
elif sys.argv.__len__() == 2:
  work_dir = os.path.dirname(sys.argv[1])
  target_dll = os.path.basename(sys.argv[1])
else:
  print "ERROR: invalid argument"
  sys.exit(-1)

if target_dll[0:3] == "lib":
  target_dll = target_dll[3:]
tgtname, extname = os.path.splitext(target_dll)

if extname != ".dll":
  tgtname = target_dll

if work_dir == "":
  work_dir = cwd_path

print "working directory:", work_dir
print "======== make import (lib%s.lib) from (lib%s.dll) ========" % \
  (tgtname, tgtname)

make_lib(work_dir, tgtname)

sys.exit(0)

我做了个试验,就是用MinGW构建sqlite3,默认没有构建出我需要的dll,于是我首先进入sqlite3.o所在的目录,运行下面的命令手工构建出dll:

$ gcc -shared -fPIC sqlite3.o -o libsqlite3.dll -s
然后用mklib-win64.py生成lib文件:

$ python mklib-win64.py libsqlite3.dll
最后生成了64位版本的libsqlite3.lib,通过VS2010编写的程序测试,完全正确。

#include "C:/DEVPACK/MinGW/local64/dst/sqlite3/include/sqlite3.h"
# pragma comment(lib, "C:/DEVPACK/MinGW/local64/dst/sqlite3/lib/libsqlite3.lib");

......

void test_sqlite3()
{
  int ret;
  sqlite3       *dbconn;
  sqlite3_stmt  *stmt;
  char          *errmsg;

  ret = sqlite3_open_v2("C:/workspace/antelope/test.db", &dbconn,
    SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX |
    SQLITE_OPEN_SHAREDCACHE, 0);

  if (ret != SQLITE_OK) {
    fprintf(stdout, "ERROR: sqlite3_open_v2() error (%d).\n",
      ret);
  }
}

于是,便有了此文!


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值