• 从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);
      }
    }
    

    于是,便有了此文!

  • 相关阅读:
    数据结构—堆排序
    关于《数据结构》课本KMP算法的理解
    KMP字符串匹配算法
    POJ 3784 Running Median(动态维护中位数)
    C++ STL 全排列
    数据结构——哈夫曼(Huffman)树+哈夫曼编码
    算法与数据结构实验6:逆序对(归并排序)
    C++ STL 优先队列 priority_queue 详解(转)
    现在和未来
    Karen and Coffee CF 816B(前缀和)
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3078490.html
Copyright © 2020-2023  润新知