[Date Prev][Date Next] [Chronological] [Thread] [Top]

NT dynamic linking support



I am about to commit a set of changes to the tree that address the
dllimport/dllexport issues on NT. This replaces the previous
MINGW32-specific ifdefs with a more general solution that works for both
Mingw32 and MSVC. The
following message gives an overview of what we've done. If there are any
questions,
please let me know soon, I will probably move all this stuff in sometime
tomorrow. (Friday, Nov 26.)

-----Original Message-----
From: Jon Leichter [mailto:jon@symas.com]
Sent: Thursday, November 25, 1999 1:09 PM
To: Howard Chu
Howard, the rest of the changes were specifically for the new LIB****_F
macros
implementation. The set of changed files are:

./include/ldap_cdefs.h

./include/avl.h
./include/disptmpl.h
./include/getopt-compat.h
./include/lber.h
./include/lber_pvt.h
./include/ldap.h
./include/ldap_log.h
./include/ldap_pvt.h
./include/ldap_pvt_thread.h
./include/ldap_schema.h
./include/ldbm.h
./include/ldif.h
./include/lutil.h
./include/lutil_lockf.h
./include/lutil_md5.h
./include/lutil_sha1.h
./include/srchpref.h
./include/ac/assert.h
./include/ac/errno.h
./include/ac/setproctitle.h
./include/ac/socket.h
./include/ac/stdarg.h
./include/ac/string.h
./include/ac/unistd.h
./libraries/liblber/lber-int.h
./libraries/libldap/ldap-int.h
./servers/slapd/proto-slap.h
./servers/slapd/slap.h
./servers/slapd/main.c

./libraries/liblber/Makefile.in
./libraries/libldap/Makefile.in
./libraries/libldap_r/Makefile.in
./libraries/libldbm/Makefile.in
./libraries/libldif/Makefile.in
./libraries/liblutil/Makefile.in
./servers/slapd/Makefile.in

Here's the message for Kurt:

Kurt,

I recently re-evaluated the method used to get symbols properly imported
into
NT object files. In doing so, I realized that the last method I had
implemented was not as complete as it should have been. Also, you had
mentioned that you were unhappy with the multiple re-definitions of the
LDAP_F_PRE macro in the various header files. I was fairly unhappy with it
as
well, but my bandwidth at the time kept me from 'fixing' it.

I've now made new changes that I recommend you sync back into your source
tree. I think the new method is much cleaner, and I will explain it.

First, let me summarize the issue of DLL importing in NT. When an object
file
is generated by a compiler, any symbol referenced that actually gets
imported
from a DLL (or an EXE module) at run-time should be declared with
'dllimport'.
This is more important for external variables than it is for functions. By
doing this for functions, your code saves some CPU cycles because your code
calls the imported function directly, opposed to a stub function. However,
this is not an option for external variables. If you don't properly import
external variables, your object code will certainly crash when it tries to
reference such those symbols.

My philosophy is that if you're going to do something you might as well do
it
right. Thus, my implementation of getting symbols imported includes support
for both functions and variables. This makes the source files look more
consistent.

These are the changes that I've made:

- I updated ./include/ldap_cdefs.h. I got rid of the LDAP_F macro (and its
associated macros) completely. Instead, I've created new macros that handle
prototypes for each library, on an individual basis: LIBC_F, LIBAVL_F,
LIBLBER_F, LIBLDAP_F, LIBLDBM_F, LIBLDIF_F, LIBLUTIL_F, LIBSLAPD_F. Having a
separate macro for each library is quite necessary. Some header files
contain
function prototypes from more than one library at a time. Also, MANY object
files use symbols from different libraries at the same time. In many cases,
symbols are being imported from some libraries but not others.

- I changed all relevant header files (and source files that did explicit
externs from other other libraries). I deleted those old blocks of
preprocessing that you (and I) didn't like too much: #ifdef __MINGW32__
(etc).
I transformed all LDAP_F macro references to the appropriate LIB****_F
counterparts. I also added the LIB****_F macros to MANY variables and
functions that never defined LDAP_F to begin with.

- I updated all relevant Makefile.in files. I took out all references to the
dllexport keyword. This keyword is used to tell the compiler that there is
an
'intent' to export a symbol. It really doesn't cause a symbol to be exported
though. Having realized that there was no real need for this, I removed any
references to it. Also, I added dllimport definitions where they were
appropriate. I realized that I needed to do this in the Makefiles for
libldbm,
libldif, and liblutil.


Here are some discussion items:

- It seems as though the LDAP_F macro was initially defined by the person
(people) who worked on the MSVC build of OpenLDAP. The issue of
dllimport'ing
(and dllexport'ing) was recognized. However, I'll claim that the initial
implementation was not correct. Originally LDAP_F (in the MSVC build) was
implemented so that the 'dllimport' keyword would be defined if and only if
the _DLL macro was defined at preprocessing time. Well, in MSVC, the _DLL
macro is defined if and only if the MSVC project has been set up to link
with
the dynamic C run-time library. First of all, none of the MSVC project files
for OpenLDAP were setup to use the dynamic C run-time library. This means
that
'dllimport' was never being declared in the MSVC projects. Secondly, even if
you chose to use the dynamic C run-time library in the MSVC projects, the
implementation was not correct. Consider that the LDAP_F macro, which was
being specified for OpenLDAP function prototypes, would unconditionally
expand
out to the 'dllimport' keyword in this case. This is completely wrong. For
instance, when building slapd, it would be true that the object files WOULD
be
importing 'strcpy' from the dyanmic C run-time DLL, but it definitely would
not be the case that the object files would be importing the lutil_detach
function from the liblutil library, which is ALWAYS statically linked with
OpenLDAP object files. Thus, getting rid of the LDAP_F macro altogether
cannot
be a harmful to the MSVC build. Even if you ever wanted to build new MSVC
project files that generate object files that DO import external symbols,
you
can now do so more easily with this new implementation. Note that building
the
MSVC project files correctly is the real chore. As a side note, I have
compiled, linked, and tested the MSVC build of OpenLDAP with my new changes.

- The LIBC_F deserves some attention. Some OpenLDAP header files insist of
specifying an extern declaration for various functions that potentially live
in the target's C library. However, because the functions are part of the C
library, they are already likely declared by one of the header files of the
target's development environment. I've added the LIBC_F macro to maintain
consistency between what the native header files declare and what OpenLDAP's
header files declare. In NT (where this stuff matters), if 'strdup' is
declared in the native header files, it will be declared with 'dllimport' if
the development environment realizes that 'strdup' will be imported from the
dynamic C run-time library. Thus, in ac/string.h, the prototype should be
consistent. Thus, the LIBC_F macro will evaluate to the 'right' thing. This
is
the only purpose of LIBC_F. It's not necessary to define macros in the
Makefiles to use it.

- The LIBSLAPD_F macro deserves some attention. This macro is used in
conjunction with building module backends (opposed to static backend
objects).
When you build a module backend, your object files are likely to reference
symbols that will be part of slapd's address space at run-time. As a result,
your backend object files must dllimport the symbols from slapd that it
uses.
As a matter of fact, any symbols that are not implemented in the module
backend itself will be imported. Thus, when you build a module backend, the
Makefile should define all of the LIB****_F macros to ensure that the
preprocessed sources contain 'dllimport' keywords for any symbols that will
be
imported.

- When building slapd, you can verify that your symbols have been imported
properly by doing an 'nm -g' command on all of the .o files in the tree.
Undefined symbols that object files will import have the __imp_ keyword in
front of its name. You should expect to see this keyword in object files
that
get the symbol from a DLL (or EXE) at run-time. You should NOT expect to see
this keyword in object files that either implement the symbol or get it
statically linked in.


Jon Leichter
jon@symas.com