How to create mingw32 libraries from DLLs

Most binary distributions created for the Windows platform are built using Microsoft Visual C++. This does not mean that you have to develop or build extensions using this compiler (unless they are exporting C++ symbols!). All you need is a suitable link library and then your mingw-built application can use the same DLLs as everyone else. For information about the native windows version of the GNU C compiler go to http://www.mingw.org/ . Note that the newest versions of Mingw gcc will automatically link to .LIB files in most cases, so the approach described below may not be needed.

To build a useful mingw32 gcc link library from the Tcl dlls we can either work from the DLL or the .LIB files provided. We need to get hold of a copy of sed for win32 from somewhere like http://www.wzw.tu-muenchen.de/~syring/win32/UnxUtils.html and either use the nm provided with mingw32 gcc or get dumpbin from a Microsoft download site.

(2001-10-25): I have used the sed from the DJGPP package for MS-DOS under Windows. Go to http://www.delorie.com/djgpp/zip-picker.html , select an ftp server, and look for the file pub/simtelnet/gnu/djgpp/v2gnu/sed3028b.zip on that server. You will probably need a minimal install of DJGPP to make it work.

Working from a DLL

Placing Makefile in your tcl lib directory (...\Tcl\lib) should do what is needed. You need dumpbin and sed in your path plus the exports.sed script given below. Unfortunately dumpbin is only provided with Microsoft compilers so...

It turns out that you can use mingw32 supplied objdump -p to get the export symbols from a DLL. You can use the dllextract.sed script below with objdump - see the makefile. - PT

Working from a .LIB file

.LIB files are the normal Microsoft compiler link libraries. Edit the Makefile by uncommenting the *.def sections and commenting the alternative .def sections. The dlltool section remains the same.

The Tcl Stubs Library

The stubs libraries are not DLL's but static libraries. The current mingw32 package (mingw1.1) can cope with the distributed ActiveTcl files but they need renaming thus:

  copy tclstub83.lib libtclstub83.a
  copy tkstub83.lib libtkstub83.a

 # Makefile - Copyright (C) 2001 Pat Thoyts <[email protected]>
 #
 # How to create a gcc compatible linker library for a DLL from an MSVC 
 # produced .LIB file or DLL. If you want to use the .LIB files, swap over
 # the commented sections and build the .DEF file using the other method.

 DLLTOOL=dlltool --kill-at

 all: libtcl83.a libtk83.a

 #-------------------------------------------------------------------------

 tcl83.def:
         echo EXPORTS > $@
         dumpbin /exports ..\bin\tcl83.dll | sed -nf exports.sed >> $@
 #tcl83.def:
 #        echo EXPORTS > $@
 #        nm tcl83.lib | sed -n "/00000000 T/s/\([^_]*_\)//p" >> $@

 #tcl83.def:
 #        echo EXPORTS > $@
 #      objdump -p ..\bin\tcl83.dll | sed -nf dllextract.sed >> $@

 libtcl83.a: tcl83.def
         $(DLLTOOL) --dllname ../bin/tcl83.dll --input-def $< --output-lib $@

 #-------------------------------------------------------------------------

 tk83.def:
         echo EXPORTS > $@
         dumpbin /exports ..\bin\tk83.dll | sed -nf exports.sed >> $@
 #tk83.def:
 #        echo EXPORTS > $@
 #        nm tk83.lib | sed -n "/00000000 T/s/\([^_]*_\)//p" >> $@

 #tk83.def:
 #        echo EXPORTS > $@
 #      objdump -p ..\bin\tk83.dll | sed -nf dllextract.sed >> $@

 libtk83.a: tk83.def
         $(DLLTOOL) --dllname ../bin/tk83.dll --input-def $< --output-lib $@

 #-------------------------------------------------------------------------

 clean:
         @del tcl83.def
         @del tk83.def

 realclean: clean
         @del libtcl83.a
         @del libtk83.a

 .PHONY: clean realclean


 #
 # Local variables:
 #   mode: makefile
 # End:
 #

 # exports.sed - Copyright (C) 2001 Pat Thoyts <[email protected]>
 #
 # Build an exports list from a Windows DLL.
 #
 /[         ]*ordinal hint/,/^[         ]*Summary/{
  /^[         ]\+[0123456789]\+/{
    s/^[         ]\+[0123456789]\+[ \t]\+[0123456789ABCDEFabcdef]\+[         ]\+[0123456789ABCDEFabcdef]\+[         ]\+\(.*\)/\1/p
  }
 }

 # dllextract.sed - Copyright (C) 2001 Pat Thoyts <[email protected]>
 #
 # Build an exports list from a Windows DLL using 'objdump -p'
 #
 /^\[Ordinal\/Name Pointer\] Table/,/^$/{
   /^\[Ordinal\/Name Pointer\] Table/d
   /\[/s/[         ]\+\[[         ]*\([0123456789]\+\)\] \(.*\)/\2/p
 }

FPX: I found it annoying that the path to the Tcl and Tk DLLs was being set to "../bin/". Windows then refused to find the DLLs through usual means (in PATH or in the current directory). So for me, I edited the Makefile and changed the --dllname option to read "--dllname tcl83.dll" instead of "--dllname ../bin/tcl83.dll".


EL: This page is particular useful for every day work with MingW. You can translate virtually any dll into a lib*.a file by means of this page. It is handy to have a script for this:

 ################################################################################
 # makelib.tcl
 #
 # creates an MinGW conform lib*.a static library from a dll
 # argument:
 #    dll - path to the requested dll
 ################################################################################

 set dllextract_sed {
 /^\[Ordinal\/Name Pointer\] Table/,/^$/{
    /^\[Ordinal\/Name Pointer\] Table/d
    /\[/s/[         ]\+\[[         ]*\([0123456789]\+\)\] \(.*\)/\2/p
  }
 }

 set dll [lindex $argv 0]
 if {$dll == ""} {
     puts "creates an MinGW conform lib*.a static library from a dll"
     puts "usage: tclsh makedll.tcl <path/to/dll>"
     exit 0
 }

 set dllroot [file tail [file rootname $dll]]
 set dlldef $dllroot.def
 if {[regexp {^lib} $dllroot]} {
     set dlla $dllroot.a
 } else {
     set dlla "lib$dllroot.a"
 }

 puts "writing $dlldef"
 set res [exec objdump -p $dll | sed -n $dllextract_sed]
 set fh [open $dlldef "w"]
 puts $fh "EXPORTS"
 puts $fh $res
 close $fh

 puts "creating $dlla"
 exec dlltool --dllname $dll --input-def $dlldef --output-lib $dlla
 puts "goodbye"
 exit 0

JD: DLL to import library (lib) (for example a MinGW .lib) Rename "lib*.a" to "*.lib" and you're done. "makelib.tcl" did not work for me with cygwin's tclsh and cygwin's sed. So I changed it to pass dllextract.sed to cygwin's sed. Replace lines for "set dllextract_sed..." by:

 set dllextract_sed "-f[file join [file dirname [info script]] "dllextract.sed"]"

Put dllextract.sed and makelib.tcl into the same folder and it should work.


Go back to Building Tcl DLL's for Windows