libtool-patches
[Top][All Lists]
Advanced

[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 *) &nothing},
  {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 *) &nothing},
  {"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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]