Initial commit
This commit is contained in:
231
TBE/MinGW/doc/a2dll/a2dll.html
Normal file
231
TBE/MinGW/doc/a2dll/a2dll.html
Normal file
@@ -0,0 +1,231 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
a2dll: An utility (to help) to convert static library into Win32 DLL
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>
|
||||
a2dll: An utility (to help) to convert static library into Win32 DLL
|
||||
</h1>
|
||||
<h2>
|
||||
Synopsis
|
||||
</h2>
|
||||
<p>
|
||||
a2dll is shell script (see <a href="#requirements">requirements</a>) to
|
||||
automotize process of converting existing static libraries (produced
|
||||
by gnu-win32 tools, of course) into DLL. First of all, yes it's possible:
|
||||
if you have binary static distribution of some library (i.e. library
|
||||
itself and its headers), that's all you need to convert it to DLL and
|
||||
use in your programs. Read <a href="static2dll_howto.txt">HOWTO</a> for
|
||||
underlying magic. So, you may not waste time if you need DLL: just
|
||||
grab existing static distribution and convert. Also, you may use it to
|
||||
build Win32 DLL of your library. Also, until GNU libtool will allow
|
||||
seamless building of Win32 DLLs, you may build static lib (what
|
||||
libtool of course supports) and then convert it to DLL.
|
||||
<blockquote>
|
||||
<tt>
|
||||
a2dll <static_lib> [-o <dll_name>] [<linker_flags>] [--relink]
|
||||
</tt>
|
||||
</blockquote>
|
||||
where:
|
||||
<dl>
|
||||
<dt>
|
||||
<tt><static_lib></tt>
|
||||
</dt>
|
||||
<dd>
|
||||
Static library you want to convert
|
||||
</dd>
|
||||
<dt>
|
||||
<tt>-o <dll_name></tt>
|
||||
</dt>
|
||||
<dd>
|
||||
Name of resulting dll. If not given, three first chars of input
|
||||
name are stripped and <tt>.a</tt> suffix replaced with <tt>.dll</tt> .
|
||||
So, from '<tt>libfoo.a</tt>' you'll get '<tt>foo.dll</tt>'.
|
||||
</dd>
|
||||
<dt>
|
||||
<tt><linker_flags></tt>
|
||||
</dt>
|
||||
<dd>
|
||||
Linker flags:
|
||||
<ul>
|
||||
<li>Use '<tt>-s</tt>' to get library without debugging symbols and information.
|
||||
<li>Use '<tt>--driver-name=<name></tt>' to link library with specified
|
||||
linker (well, compiler, to be precise). For example, for C++ library use
|
||||
<tt>--driver-name=g++</tt> .
|
||||
<li>You should list all libraries on which your library depends with
|
||||
<tt>-l</tt> switches and directories they are reside in with <tt>-L</tt>
|
||||
switches. For example, if your library uses PCRE library you just built and
|
||||
not yet installed, use something like <tt>-L../pcre -lpcre</tt>
|
||||
</ul>
|
||||
</dd>
|
||||
<dt>
|
||||
<tt>--relink</tt>
|
||||
</dt>
|
||||
<dd>
|
||||
Skip exploding library stage (see below). Use this flag to continue
|
||||
process after some error occured.
|
||||
</dd>
|
||||
</dl>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
Performing
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
a2dll works in following way:
|
||||
<ol>
|
||||
<li>If you did not specify <tt>--relink</tt> option,
|
||||
explodes source library under newly-created <tt>.dll</tt> subdirectory.
|
||||
|
||||
<li>Links all resulting objects into DLL with exporting all non-static
|
||||
symbols. On this stage, link errors
|
||||
(such as underfined symbols) may occur. In such case, a2dll terminates
|
||||
and all linker messages are available in '<tt>ld.err</tt>' file. You
|
||||
should correct errors (mostly by finding out additional
|
||||
dependecies, but sometimes by deleting 'superfluos' objects under .dll)
|
||||
and re-run a2dll with all the options you gave it before,
|
||||
plus new dependencies, plus <tt>--relink</tt> flag. You may need to
|
||||
repeat this several times.
|
||||
|
||||
<li>Renames original static library with suffix <tt>.static</tt> .
|
||||
|
||||
<li>Creates import library for produced DLL with the name of original
|
||||
static library.
|
||||
|
||||
<li>Check whether DLL exports data symbols. If no, congratulations,
|
||||
you've done. However, if some present, it lists all of them in file
|
||||
'<tt><dll_name>.data</tt>' . Presense of such symbols generally
|
||||
means that you should patch library's headers to mark those symbols
|
||||
as dll-imported. But don't hurry with that, first, do following:
|
||||
<ol>
|
||||
<li>Look into <tt><dll_name>.data</tt> file. If all what you see
|
||||
is something like '<tt>internal_counter_of_bogons</tt>' or
|
||||
'<tt>_ksdauso</tt>', don't worry - those symbols are hardly part of
|
||||
external interface of the library.
|
||||
<li>If all you need is to link your application against that
|
||||
library, try it. If it succeeds, congratulation.
|
||||
<li>Only if above is failed, or you are going to distribute produced
|
||||
library, so you need to be sure that everything is ok, proceed with
|
||||
marking symbols in headers. Read <a href="static2dll_howto.txt">Static2DLL
|
||||
HOWTO</a> for more information on suggested ways of doing this. Use
|
||||
'<tt>grep -f <tt><dll_name>.data</tt> *.h</tt>' command to find
|
||||
out where offending symbols defined in library headers.
|
||||
</ol>
|
||||
</ol>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
Examples
|
||||
</h2>
|
||||
<p>
|
||||
Since converting static libraries to DLLs is not fully automated and
|
||||
formal process, some experience with it is required. Learing
|
||||
by example is known to be one of the efficient way of communicating
|
||||
experince, so I would like to provide some realistic examples of
|
||||
converting statics to DLLs with the help of a2dll.
|
||||
</p>
|
||||
|
||||
<h3>
|
||||
Zlib
|
||||
</h3>
|
||||
<p>
|
||||
Build libz.a . Now, run '<tt>a2dll libz.a</tt>'. It builds cleanly,
|
||||
but warns us about data symbols. Let's look at them:
|
||||
<blockquote>
|
||||
<pre>
|
||||
inflate_mask
|
||||
z_errmsg
|
||||
</pre>
|
||||
</blockquote>
|
||||
What they could be. The first one is probably some internal variable,
|
||||
while second is probably array of error messages. As we know, zlib
|
||||
provides functional way of getting error messages, something like. So
|
||||
our hypothesis is that job's done. Let's prove it:
|
||||
'<tt>grep -f z.dll.data zlib.h</tt>'. Yes, we're right: no mentioning
|
||||
of those symbols in interface header file.
|
||||
</p>
|
||||
|
||||
<h3>
|
||||
libstdc++
|
||||
</h3>
|
||||
<p>
|
||||
I've got an idea to DLLize libstdc++ coming with my mingw32 distribution.
|
||||
'<tt>a2dll "libstdc++.a"</tt>'. Note that we don't use
|
||||
<tt>--driver-name=g++</tt> - that option need to be used when we link
|
||||
something <i>against</i> libstdc++ . But when we link libstdc++
|
||||
<i>itself</i>, we need libc (whatever it is in mingw32), nothing else.
|
||||
But, process aborts due to linker errors. <tt>ld.err</tt> tells us:
|
||||
<blockquote>
|
||||
<pre>
|
||||
strerror.o(.text+0x303): undefined reference to `sys_nerr'
|
||||
vfork.o(.text+0x7): undefined reference to `fork'
|
||||
waitpid.o(.text+0x15): undefined reference to `wait'
|
||||
</pre>
|
||||
</blockquote>
|
||||
Well, strerror, vfork, waitpid are libc functions, what they do in
|
||||
libstdc++? Probably, stubs, delete them and
|
||||
'<tt>a2dll "libstdc++.a" --relink</tt>'. Of course,
|
||||
<tt>stdc++.dll.data</tt> is here. Looking into it, I may tell you
|
||||
that everything starting with '<tt>__ti<digit></tt>' is RTTI
|
||||
internal data structures and everything starting with
|
||||
'<tt>_vt$</tt>' is virtual tables (use c++filt if in doubt),
|
||||
you can leave them alone.
|
||||
(If so, why I don't filter them? Because "you can leave them alone"
|
||||
is hypothesis for now, I haven't linked too much C++ libraries to
|
||||
be sure). From the rest, there's stuff starting
|
||||
with '<tt>_IO_</tt>'. That's probably some internal variables, let's
|
||||
don't do anything about them, unless we'll be forced to. Than, as
|
||||
c++filt shows, there're some static members of templated classes. Darkness.
|
||||
Forget for now. Than, there's '<tt>io_defs__</tt>'. Does your C++ application
|
||||
reference something like that? Mine not. So, what is left? Our four
|
||||
happy friends, <tt>cin, cout, cerr,</tt> and <tt>clog</tt>. Do mark them as
|
||||
__declspec(dllimport) in <tt>iostream.h</tt>.
|
||||
</p>
|
||||
|
||||
<h3>
|
||||
Some C++ library
|
||||
</h3>
|
||||
<p>
|
||||
Suppose we have following file:
|
||||
<pre>
|
||||
#include <iostream.h>
|
||||
|
||||
void foo()
|
||||
{
|
||||
cout<<"hi!"<<endl;
|
||||
}
|
||||
</pre>
|
||||
and want to turn it into DLL. Create static liba.a from it. Now,
|
||||
'<tt>a2dll liba.a --driver-name=g++</tt>'. Well, our DLL contains
|
||||
single function, why then it complains about data symbols? Oh, it's
|
||||
those stupid RTTI structures. Next time, compile with <tt>-fno-rtti</tt> unless
|
||||
you really need it, ok? Ditto for <tt>-fno-exceptions</tt> .
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
<a name="requirements">
|
||||
Requirements
|
||||
</h2>
|
||||
<p>
|
||||
a2dll requires POSIX shell (<tt>sh</tt>) to run. It is developed and
|
||||
tested with <tt>ash</tt> from
|
||||
<a href="http://pw32.sourceforge.net">PW32</a> distribution. Additionally,
|
||||
a2dll requires following utilities to perform its tasks:
|
||||
<ul>
|
||||
<li>GNU fileutils: mkdir, mv, rm
|
||||
<li>GNU textutils: wc
|
||||
<li>GNU grep
|
||||
<li>GNU awk
|
||||
<li>GNU binutils: dllwrap, dlltool (and the rest of binutils and gcc, of course)
|
||||
<li>pexports, an utility to dump symbols exported by dll. You'll need a
|
||||
version 0.43 or above, capable of distinguishing between code and data symbols, as one
|
||||
from <a href="http://www.is.lg.ua/~paul/devel/binutils.html">here</a>.
|
||||
</ul>
|
||||
</p>
|
||||
<hr noshade>
|
||||
<i><a href="mailto:Paul.Sokolovsky@technologist.com">Paul Sokolovsky</a></i>
|
||||
</body>
|
||||
</html>
|
||||
141
TBE/MinGW/doc/a2dll/static2dll_howto.txt
Normal file
141
TBE/MinGW/doc/a2dll/static2dll_howto.txt
Normal file
@@ -0,0 +1,141 @@
|
||||
How to build Win32 Dynamic-Loading Library (DLL) from existing static library
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-------
|
||||
NOTE: To perform steps below, you'll need contemparary dlltool, for
|
||||
example from Mumit Khan's gcc-2.95.2 packages.
|
||||
-------
|
||||
|
||||
|
||||
This document describes step-by-step procedure of building Win32 DLL from
|
||||
static library. It suitable for both your own and third-party (i.e. ones
|
||||
which you know, and would like to, little about) libs. However, for your
|
||||
own libraries you may adopt more handy and adequate method (exporting all
|
||||
symbols, as done here, may be not the best solution). However, procedure
|
||||
given here describes easiest and fastest way if what you want is just
|
||||
create proper DLL and forget about it. This documets assumes that
|
||||
you have, or will, read documentation for Mumit Khan's dllwrappers
|
||||
tools (dllwrap & dlltool utilities).
|
||||
|
||||
Before proceeding with description of process, some notes about
|
||||
distinction of DLLs and usual *nix-style shared libraries (.so, referred
|
||||
as SO below) (read also if you don't have experience with .so):
|
||||
|
||||
[Once again note that there's a big gap between abstract information
|
||||
below and specific practical steps which follow; if you want to fill
|
||||
that gap, read standard documentation.]
|
||||
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
1. Usually, compilation of objects for shared libraries requires different
|
||||
set of compiler options comparing to static counterparts. For example,
|
||||
many systems require -fpic flag to generate position-independent code.
|
||||
However, for Win32, both static libs and DLLs are created from the same
|
||||
set of objects. Despite this little advantage, DLLs have following big
|
||||
disadvantage:
|
||||
|
||||
2. Once have been created, shared libraries require no additional fuzz
|
||||
for usage. When so-using executable is loaded, every reference to
|
||||
so-symbol gets fixed up to point directly to SO. Win32 has different
|
||||
system: every executable importing DLL has special section, .idata, to hold
|
||||
pointers to imported symbols. During loading, OS loader fills this section
|
||||
with actual info. And application is supposed, when needed DLL-symbol, first
|
||||
lookup its pointer in .idata, and only then have access by that pointer,
|
||||
As you see, for DLL-imported symbols, additional level of indirection is
|
||||
required. This stems probably from dark times of real-mode 16-bit Windows,
|
||||
working on 8086 processor lacking virtual memory. Having all import-related
|
||||
stuff in one single place facilated runtime relocation, which was needed
|
||||
to effictively manage memory there. So or other, but it is that way.
|
||||
So, as you see, special compiler support required to compile client of
|
||||
DLL (note strange symmetry - *nix require special support to compile library,
|
||||
while Win32 - to compile client. Former is better, I agree).
|
||||
|
||||
3. As was said before, with SO you use library just as you would static
|
||||
version. This is not so for Win32. Win32 DLL is self-contained executable,
|
||||
not supposed to be linked against. Instead, client is linked with special
|
||||
auxilary library, called 'import library' or 'implib'. Implib contains
|
||||
information to properly layout .idata section to be filled in by OS loader
|
||||
with information about DLL.
|
||||
|
||||
|
||||
Building DLL from existing static library
|
||||
-----------------------------------------
|
||||
|
||||
We assume that you already build static lib, which we will call 'libfoo.a'.
|
||||
However, building yourself is not requirement, to perform these instructions,
|
||||
you don't needed sources of library - only library itself and its headers.
|
||||
|
||||
1. Fisrt step would be to create export definition file (or just def). You
|
||||
can do this directly from library:
|
||||
|
||||
dlltool libfoo.a --export-all-symbols --output-def foo.def
|
||||
|
||||
2. Now, we can create DLL itself. This may be done by two ways: 1) link
|
||||
dummy file referencing each symbol in libfoo.a (created by script acting on
|
||||
output from 'nm libfoo.a') against libfoo.a (so, each foo's object for
|
||||
sure will be in foo.dll) or 2) exploding library and linking all its objects
|
||||
together. I consider second way cleaner and show it:
|
||||
|
||||
mkdir tmp
|
||||
cp libfoo.a tmp/
|
||||
cd tmp
|
||||
ar x libfoo.a
|
||||
dllwrap *.o --def ../foo.def -o ../foo.dll [usual -l libraries here]
|
||||
cd ..
|
||||
|
||||
3. Let's create implib. If you want totally transparent transition from
|
||||
static to DLL, call it 'libfoo.a'. However, if you want to keep destinction,
|
||||
'libfoo.dll.a' is good:
|
||||
|
||||
dlltool --def foo.def --ouput-lib libfoo.dll.a
|
||||
|
||||
4. Now grep foo.def for entries containing 'DATA'. If there's none -
|
||||
congratulations, your library uses functional-only interface and you've done.
|
||||
Else, most unpleasant work left - patch headers to include dllimport tag.
|
||||
|
||||
If you want to do it once-and-for-all (you should), do following:
|
||||
|
||||
a) make something like 'dl_import.h' and put there:
|
||||
-----
|
||||
#if !defined(STATIC) && defined(_WIN32)
|
||||
#define _DL_IMPORT __delcspec(dllimport)
|
||||
#else
|
||||
#define _DL_IMPORT
|
||||
#endif
|
||||
-----
|
||||
, if you want to use DLL by default (note that you will need to compile
|
||||
library itself with STATIC defined), or
|
||||
-----
|
||||
#if defined(DLL) && defined(_WIN32)
|
||||
#define _DL_IMPORT __delcspec(dllimport)
|
||||
#else
|
||||
#define _DL_IMPORT
|
||||
#endif
|
||||
-----
|
||||
, if you want to include -DDLL each time you compile DLL client.
|
||||
|
||||
b) for each def symbol having DATA attribute, find header where its declared
|
||||
as extern. If that header doesn't have '#include "dl_import.h"' at the top,
|
||||
add it. Put '_DL_IMPORT' in front of 'extern' (strictly speaking, position
|
||||
matters and proper place is after both extern and type, but for data
|
||||
declaration above works also (at least for me)). For example, if it was
|
||||
|
||||
extern void *(*my_malloc)(int sz);
|
||||
|
||||
becoming
|
||||
|
||||
_DL_IMPORT extern void *(*my_malloc)(int sz);
|
||||
|
||||
will suffice. Procedd with next symbol.
|
||||
|
||||
However, if you're lazy for that, you may stretch the pleasure and mark
|
||||
symbol as _DL_IMPORT only whenever you encounter it in undefined symbol
|
||||
error during linking of client.
|
||||
|
||||
5. That's all! Now, just compile client either as usually or with -DDLL,
|
||||
and link either as usually or with -lfoo.dll .
|
||||
|
||||
Paul.Sokolovsky@technologist.com
|
||||
1999-08-28
|
||||
Reference in New Issue
Block a user