[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] [cygwin|mingw] fix dlpreopen with --disable-static
From: |
Charles Wilson |
Subject: |
[PATCH] [cygwin|mingw] fix dlpreopen with --disable-static |
Date: |
Sat, 08 Nov 2008 18:49:35 -0000 |
* libltdl/config/ltmain.m4sh (func_enable_tag): allow
--verbose to set opt_verbose
(func_win32_dllname_for_implib): New function.
(func_mode_link) [cygwin|mingw]: Use linklib (that is,
import lib) as dlpreopen file, rather than DLL.
(func_generate_dlsyms) [cygwin|mingw]: Use
func_win32_dllname_for_implib to extract DLL name from
import library. Also, properly extract dlsyms from the
import library.
* libltdl/m4/libtool.m4 (_LT_LINKER_SHLIBS) [cygwin|mingw][C++]:
Set exclude_expsyms correctly for $host.
(_LT_LINKER_SHLIBS) [cygwin|mingw|pw32][C]: Set exclude_expsyms
correctly for $host. Enable export_symbols_cmds to identify
DATA exports by _nm_ prefix.
---
I've had this patch sitting around since May, but some personal
issues have prevented me from following up on it...
Corrects: old testsuite failure demo-exec (in demo-shared group).
When configuring with --disable-static, dlpreopen is very confused.
First, libtool tries to extract the symbols -- using $NM and
$global_symbols_pipe -- from the DLL. That works...poorly:
Here's a snippet from helldl.exeS.c when --disable-static:
======
/* External symbol declarations for the compiler. */
extern int _CTOR_LIST__();
extern int _DTOR_LIST__();
extern char _RUNTIME_PSEUDO_RELOC_LIST_END__;
extern char _RUNTIME_PSEUDO_RELOC_LIST__;
extern int __CTOR_LIST__();
extern int __DTOR_LIST__();
...
extern int printf();
extern int puts();
extern int realloc();
...
lt__PROGRAM__LTX_preloaded_symbols[] =
{ { "@PROGRAM@", (void *) 0 },
{"cyghello-2.dll", (void *) 0},
{"_CTOR_LIST__", (void *) &_CTOR_LIST__},
{"_DTOR_LIST__", (void *) &_DTOR_LIST__},
...
{"puts", (void *) &puts},
{"realloc", (void *) &realloc},
{0, (void *) 0}
};
======
That's bad (but, at least foo(), hello(), and nothing ARE present).
So, first, I tried special-casing for cygwin|mingw, and using the
import library for dlpreopen. That works a little better...
======
/* External symbol declarations for the compiler. */
extern char _head_cyghello_2_dll;
extern char _imp__foo;
extern char _imp__hello;
extern char _imp__nothing;
extern char _nm__nothing;
extern char cyghello_2_dll_iname;
extern int foo();
extern int hello();
...
lt__PROGRAM__LTX_preloaded_symbols[] =
{ { "@PROGRAM@", (void *) 0 },
{"libhello.dll.a", (void *) 0},
{"_head_cyghello_2_dll", (void *) &_head_cyghello_2_dll},
{"_imp__foo", (void *) &_imp__foo},
...
{"foo", (void *) &foo},
{"hello", (void *) &hello},
{0, (void *) 0}
};
======
But there are still four problems:
1. 'nothing' is missing
2. the _imp_* and _nm_* symbols are not removed when
extracting the symbols from the library for dlpreopen
3. the _head_* / *_dll_iname symbols are not removed
4. the library name itself is wrong: the second entry in
lt__PROGRAM__LTX_preloaded_symbols is used by ltdl to
determine which DLL to dlopen. libhello.dll.a is
not a DLL and can't be dlopened.
By way of comparison, the (correct) contents of helldl.exeS.c
for a static library are:
======
/* External symbol declarations for the compiler. */
extern int foo();
extern int hello();
extern char nothing;
...
lt_dlsymlist
lt__PROGRAM__LTX_preloaded_symbols[] =
{ { "@PROGRAM@", (void *) 0 },
{"libhello.a", (void *) 0},
{"hello", (void *) &hello},
{"foo", (void *) &foo},
{"nothing", (void *) ¬hing},
{0, (void *) 0}
};
=======
Problem #1 is addressed by using the same "improved" export_symbols_cmds
for cygwin|mingw C, as is already used for cygwin|mingw C++.
Problem #2 is addressed by using the following
$SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//'
AFTER $global_symbol_pipe when inferring the exported symbols
of a module from the import library. We do not modify
$global_symbol_pipe itself, however (we don't want
$global_symbol_pipe to strip out _nm_ symbols, because
$export_symbols_cmds needs them to determine which symbols to
mark as DATA).
Problem #3 is addressed by providing a custom cygwin|mingw
value for exclude_expsyms.
Problem #4 is...tricky. We need a way to extract the name of
the associated DLL from an import library. I've implemented
two:
a) patch for dlltool to add --identify option
http://sourceware.org/ml/binutils/2008-11/msg00063.html
b) fallback when dlltool is not available, or doesn't have
the identify option. This workaround uses objdump and
parses the textual representation.
With these changes, I get helldl.exeS.c with the following contents,
when --disable-static:
======
/* External symbol declarations for the compiler. */
extern int foo();
extern int hello();
extern char nothing;
...
lt__PROGRAM__LTX_preloaded_symbols[] =
{ { "@PROGRAM@", (void *) 0 },
{"cyghello-2.dll", (void *) 0},
{"nothing", (void *) ¬hing},
{"hello", (void *) &hello},
{"foo", (void *) &foo},
{0, (void *) 0}
};
======
Finally, the attached patch also improves the following (some
of which I forgot to mention in the change history; I will
address that during the inevitable rewrites of this patch
and/or merge to master).
A) libtool --verbose does not actually set opt_verbose. In fact,
nothing ever sets opt_verbose true. Should all uses of opt_verbose
be replaced by !opt_silent, or should (as I have done in this patch)
--verbose set both opt_silent false, and opt_verbose true?
B) func_win32_libid() gives some confusing errors to users
when (a) using recursive make, and (b) MAKEFLAGS does not
contain $OBJDUMP. Add a diagnostic error message, rather
than allowing $SED to die a horrible death.
End result: demo-exec after demo-shared works (and, I'll bet, but haven't
tested, that a shared-only build of m4-2.0 will work now...)
I've only bootstrapped and run those specific tests from a git-based tree.
However, I've done a full testsuite run with these changes on a 2.2.6a-based
tree, with expected results (all old tests pass, and only 25 and 73 in the
new suite fail).
Comments?
libltdl/config/ltmain.m4sh | 146 +++++++++++++++++++++++++++++++++++++++++---
libltdl/m4/libtool.m4 | 6 +-
2 files changed, 142 insertions(+), 10 deletions(-)
diff --git a/libltdl/config/ltmain.m4sh b/libltdl/config/ltmain.m4sh
index 696b6ab..da5f668 100644
--- a/libltdl/config/ltmain.m4sh
+++ b/libltdl/config/ltmain.m4sh
@@ -334,6 +334,7 @@ func_enable_tag ()
--verbose| -v) preserve_args="$preserve_args $opt"
opt_silent=false
+ opt_verbose=true
;;
--tag) test "$#" -eq 0 && func_missing_arg "$opt" && break
@@ -1991,10 +1992,36 @@ extern \"C\" {
func_verbose "extracting global C symbols from \`$dlprefile'"
func_basename "$dlprefile"
name="$func_basename_result"
- $opt_dry_run || {
- eval '$ECHO ": $name " >> "$nlist"'
- eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'"
- }
+ case $host in
+ *cygwin | *mingw* )
+ # if an import library, we need to obtain dlname
+ if eval $file_magic_cmd \"\$dlprefile\" 2>/dev/null |
+ $SED -e 10q | $EGREP "import" >/dev/null; then
+ dllname=`func_win32_dllname_for_implib "$dlprefile"`
+ $opt_dry_run || {
+ if test -n "$dllname" ; then
+ eval '$ECHO ": $dllname " >> "$nlist"'
+ else
+ func_warning "Could not compute DLL name from $name"
+ eval '$ECHO ": $name " >> "$nlist"'
+ fi
+ eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe |
+ $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >>
'$nlist'"
+ }
+ else
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >>
'$nlist'"
+ }
+ fi
+ ;;
+ * )
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >>
'$nlist'"
+ }
+ ;;
+ esac
done
$opt_dry_run || {
@@ -2166,6 +2193,11 @@ func_win32_libid ()
win32_libid_type="x86 archive import"
;;
*ar\ archive*) # could be an import, or static
+ # In recursive makes, OBJDUMP is often omitted from the
+ # passed-down MAKEFLAGS. As a courtesy, flag an error when
+ # this happens (it's more humane than allowing the sed
+ # expression below to fail).
+ test -z "${OBJDUMP}" && func_fatal_error "\$OBJDUMP is not defined"
if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
$EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
win32_nmres=`eval $NM -f posix -A $1 |
@@ -2198,6 +2230,91 @@ func_win32_libid ()
}
+# func_win32_dllname_for_implib implib
+# Obtain the name of the DLL associated with the
+# specified import library.
+#
+func_win32_dllname_for_implib ()
+{
+ $opt_debug
+ f_win32_d_for_i_implib="$1"
+ f_win32_d_for_i_can_use_dlltool=no
+ f_win32_d_for_i_dllname=
+
+ # In recursive makes, DLLTOOL is often omitted from the
+ # passed-down MAKEFLAGS. As a courtesy, warn when this
+ # happens but don't fail; we have a workaround.
+ if test -z "${DLLTOOL}"; then
+ func_warning "\$DLLTOOL is not defined"
+ else
+ # check for --identify option
+ if eval $DLLTOOL --help | $EGREP -- '--identify' >/dev/null ; then
+ f_win32_d_for_i_can_use_dlltool=yes
+ fi
+ fi
+
+ if test "$f_win32_d_for_i_can_use_dlltool" = "yes"; then
+ f_win32_d_for_i_dllname=`$DLLTOOL --identify "$f_win32_d_for_i_implib"
2>/dev/null`
+ fi
+
+ # use fallback implementation when dlltool is not available, or
+ # does not have the --identify option.
+ if test -z "$f_win32_d_for_i_dllname"; then
+ # make sure argument is actually an import library
+ if eval $file_magic_cmd \"\$f_win32_d_for_i_implib\" 2>/dev/null |
+ $SED -e 10q | $EGREP "import" >/dev/null; then
+ # gcc puts dllname in the .idata$7 section of ONE member
+ # of the import library -- but the name of that member is
+ # random. No other member contains an .idata$7 section.
+ # So, use objdump to print the contents. We get something
+ # like the following (blank lines elided):
+ #
+ # |In archive /usr/lib/libncurses++.dll.a:
+ # |d000253.o: file format pe-i386
+ # |Contents of section .idata$7:
+ # | 0000 6379676e 63757273 65732b2b 2d382e64 cygncurses++-8.d
+ # | 0010 6c6c0000 ll..____________
+ # |d000006.o: file format pe-i386
+ # |d000252.o: file format pe-i386
+ # |Contents of section .idata$7:
+ # | 0000 00000000 ....____________
+ #
+ # where '_' represents a space character. So, we delete all
+ # lines that have less than 43 characters, and chomp the
+ # first 43 characters of the remaining lines. This gives us
+ #
+ # |cygncurses++-8.d
+ # |ll..____________
+ # |....____________
+ #
+ # We are not guaranteed that the name we want is first. So,
+ # remove all newlines, then remove all sequences of two
+ # or more . characters, then remove all sequences of two
+ # or more whitespace characters. Finally, remove leading and
+ # trailing whitespace. This would be simpler if we could
+ # assume that the dllname does not contain whitespace, but we
+ # DO assume the dllname doesn't contain *multiple* adjacent
+ # whitespace, nor *multiple* adjacent . characters.
+
+
+ # In recursive makes, OBJDUMP is often omitted from the
+ # passed-down MAKEFLAGS. As a courtesy, flag an error when
+ # this happens (it's more humane than allowing the sed
+ # expression below to fail).
+ test -z "${OBJDUMP}" && func_fatal_error "\$OBJDUMP is not defined"
+
+ f_win32_d_for_i_dllname=`$OBJDUMP -s --section '.idata$7'
$f_win32_d_for_i_implib |
+ $SED -e '/^.\{43\}/!d' -e 's/^.\{43\}//' |
+ $SED -e ':a;N;$!ba;s/\n//g' -e 's/\.\.\.*//g' \
+ -e 's/[ ][ ][ ]*//g' \
+ -e 's/^[ ]*//' -e 's/[ ]*$//'`
+ fi
+ fi
+ $ECHO "$f_win32_d_for_i_dllname"
+}
+
+
+
# func_extract_an_archive dir oldlib
func_extract_an_archive ()
@@ -5052,11 +5169,24 @@ func_mode_link ()
# that they are being used correctly in the link pass.
test -z "$libdir" && \
dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library"
- # Otherwise, use the dlname, so that lt_dlopen finds it.
- elif test -n "$dlname"; then
- newdlprefiles="$newdlprefiles $dir/$dlname"
+ # Otherwise, use the dlname, so that lt_dlopen finds it --
+ # except on mingw|cygwin, where we must use the import library
+ # for symbol extraction. Therefore, on those platforms, the name
+ # needed by lt_dlopen is extracted from the import library via
+ # func_win32_dllname_for_implib.
else
- newdlprefiles="$newdlprefiles $dir/$linklib"
+ case "$host" in
+ *cygwin* | *mingw* )
+ newdlprefiles="$newdlprefiles $dir/$linklib"
+ ;;
+ * )
+ if test -n "$dlname"; then
+ newdlprefiles="$newdlprefiles $dir/$dlname"
+ else
+ newdlprefiles="$newdlprefiles $dir/$linklib"
+ fi
+ ;;
+ esac
fi
fi # $pass = dlpreopen
diff --git a/libltdl/m4/libtool.m4 b/libltdl/m4/libtool.m4
index caf88b1..0ce770c 100644
--- a/libltdl/m4/libtool.m4
+++ b/libltdl/m4/libtool.m4
@@ -4170,6 +4170,7 @@ m4_require([_LT_TAG_COMPILER])dnl
AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
m4_if([$1], [CXX], [
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience |
$global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
case $host_os in
aix[[4-9]]*)
# If we're using GNU nm, then we don't want the "-C" option.
@@ -4185,12 +4186,12 @@ m4_if([$1], [CXX], [
;;
cygwin* | mingw* | cegcc*)
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience |
$global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1
DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[
]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms,
$1)=['_head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
;;
*)
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience |
$global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
;;
esac
- _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
], [
runpath_var=
_LT_TAGVAR(allow_undefined_flag, $1)=
@@ -4329,7 +4330,8 @@ _LT_EOF
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_TAGVAR(always_export_symbols, $1)=no
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience |
$global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1
DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq >
$export_symbols'
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience |
$global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1
DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[
]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms,
$1)=['_head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs
$compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base
-Xlinker --out-implib -Xlinker $lib'
--
1.6.0.2
- [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static,
Charles Wilson <=
- Re: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static, Ralf Wildenhues, 2008/11/12
- Re: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static, Charles Wilson, 2008/11/13
- Re: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static, Ralf Wildenhues, 2008/11/13
- Re: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static, Brian Dessent, 2008/11/13
- Re: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static, Ralf Wildenhues, 2008/11/24
- Re: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static, Brian Dessent, 2008/11/24
- Re: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static, Charles Wilson, 2008/11/24
- Re: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static, libtool, 2008/11/13
- Re: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static, Ralf Wildenhues, 2008/11/14
- Re: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static, Charles Wilson, 2008/11/14