Initial commit

This commit is contained in:
Eagle517
2026-01-14 10:27:57 -06:00
commit c1576fee30
11290 changed files with 1552799 additions and 0 deletions

View 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 &lt;static_lib> [-o &lt;dll_name>] [&lt;linker_flags>] [--relink]
</tt>
</blockquote>
where:
<dl>
<dt>
<tt>&lt;static_lib></tt>
</dt>
<dd>
Static library you want to convert
</dd>
<dt>
<tt>-o &lt;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>&lt;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=&lt;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>&lt;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>&lt;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>&lt;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&lt;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 &lt;iostream.h>
void foo()
{
cout&lt;&lt;"hi!"&lt;&lt;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>

View 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