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 take 2


From: Charles Wilson
Subject: [PATCH] [cygwin|mingw] fix dlpreopen with --disable-static take 2
Date: Fri, 2 Jan 2009 20:39:15 -0500

* libltdl/config/general.m4sh: Adjust copyright date.
(func_tr_sh): New function.
* libltdl/config/ltmain.m4sh: Adjust copyright date.
(func_dlltool_identify): New function.
(func_win32_dllname_for_implib): New function.
(func_generate_dlsyms) [cygwin|mingw]: Obtain DLL name
corresponding to import library by using value stored in
unique variable libfile_$(transliterated implib name).
If that fails, use func_win32_dllname_for_implib to extract
DLL name from import library directly. Also, properly extract
dlsyms from the import library.
(func_mode_link) [cygwin|mingw]: Prefer to dlpreopen DLLs
over static libs when both are available.  When dlpreopening
DLLs, Use linklib (that is, import lib) as dlpreopen file,
rather than DLL. Store name of associated la file in
unique variable libfile_$(transliterated implib name)
for later use.
* libltdl/m4/libtool.m4: Adjust copyright date.
(_LT_COPYING): Adjust copyright date.
(_LT_CMD_GLOBAL_SYMBOLS): adjust sed expressions for
lt_cv_sys_global_symbol_to_c_name_address and
lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
as trailing space after module name is optional.
(_LT_LINKER_SHLIBS) [cygwin|mingw][C++]:
Set exclude_expsyms correctly for $host. Simplify regular
expression in export_symbols_cmds.
(_LT_LINKER_SHLIBS) [cygwin|mingw|pw32][C]: Set exclude_expsyms
correctly for $host. Enable export_symbols_cmds to identify
DATA exports by _nm_ prefix.
---

This is a revised version of patch(es) posted here
http://lists.gnu.org/archive/html/libtool-patches/2008-11/msg00019.html
and here:
http://lists.gnu.org/archive/html/libtool-patches/2009-01/msg00001.html

In response to a bug reported here:
http://lists.gnu.org/archive/html/bug-libtool/2008-05/msg00054.html

Please see those threads for a discussion of the need for this
patch and the approach taken here. One change reflected in the
patch below, but not discussed in the preceeding threads, is 
that for systems-supporting-PE-DLLs (e.g. cygwin, mingw, cegcc),
the linker will automatically link against the import library 
instead of the static library if both are present in the search
path.  However, earlier versions of this patch -- and indeed, 
un-patched libtool -- would, in the both-are-present case,
extract symbols from the static library always, even tho the
final dlpreopen link was against the import library.

This situation led to an erroneous symbol list:

lt__PROGRAM__LTX_preloaded_symbols[] =
{  { "@PROGRAM@", (void *) 0 },
  {"libhello.a", (void *) 0}, <<<< HERE
  {"nothing", (void *) &nothing},
  {"hello", (void *) &hello},
  {"foo", (void *) &foo},
  {0, (void *) 0}
};

when the correct symbol list should be:

lt__PROGRAM__LTX_preloaded_symbols[] =
{  { "@PROGRAM@", (void *) 0 },
  {"cyghello-2.dll", (void *) 0}, <<<< HERE
  {"nothing", (void *) &nothing},
  {"hello", (void *) &hello},
  {"foo", (void *) &foo},
  {0, (void *) 0}
};

The patch below therefore modifies func_generate_dlsyms to
prefer the DLL/import library over the static library when
both are present -- but only for PE-DLL platforms. Other
platforms still prefer to dlpreopen static libraries when
both are present.

bootstrapped on cygwin, tested the
  demo-{conf|shared|static} + demo-make + demo-exec
test cases with success. Full test suite in progress.

=====


 libltdl/config/general.m4sh |   15 +++-
 libltdl/config/ltmain.m4sh  |  198 ++++++++++++++++++++++++++++++++++++++-----
 libltdl/m4/libtool.m4       |   16 ++--
 3 files changed, 201 insertions(+), 28 deletions(-)

diff --git a/libltdl/config/general.m4sh b/libltdl/config/general.m4sh
index 4bc304c..c4de91a 100644
--- a/libltdl/config/general.m4sh
+++ b/libltdl/config/general.m4sh
@@ -1,6 +1,6 @@
 m4_if([general.m4sh -- general shell script boiler plate -*- Autoconf -*-
 
-   Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
    Written by Gary V. Vaughan, 2004
 
    This file is part of GNU Cvs-utils.
@@ -412,5 +412,18 @@ func_show_eval_locale ()
       fi
     fi
 }
+
+# func_tr_sh
+# turn $1 into a string suitable for a shell variable name
+# result is stored in $func_tr_sh_result
+func_tr_sh ()
+{
+  func_tr_sh_result=`echo "$1" | $SED -e 's/[^A-Za-z0-9_]/_/g'`
+  # ensure result begins with non-digit
+  case "$func_tr_sh_result" in
+    [A-Za-z_][A-Za-z0-9_] ) ;;
+    * ) func_tr_sh_result=_$func_tr_sh_result ;;
+  esac
+}
 ]])
 
diff --git a/libltdl/config/ltmain.m4sh b/libltdl/config/ltmain.m4sh
index 20ca07b..503457c 100644
--- a/libltdl/config/ltmain.m4sh
+++ b/libltdl/config/ltmain.m4sh
@@ -5,7 +5,7 @@ m4_divert_push([SCRIPT])# @configure_input@
 # Written by Gordon Matzigkeit <address@hidden>, 1996
 
 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-# 2006, 2007, 2008 Free Software Foundation, Inc.
+# 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 # This is free software; see the source for copying conditions.  There is NO
 # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
@@ -1988,7 +1988,7 @@ extern \"C\" {
              eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > 
"$nlist"T'
              eval '$MV "$nlist"T "$nlist"'
              case $host in
-               *cygwin | *mingw* | *cegcc* )
+               *cygwin* | *mingw* | *cegcc* )
                  eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
                  eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
                  ;;
@@ -2001,10 +2001,49 @@ 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* | *cegcc* )
+             # if an import library, we need to obtain dlname
+             if func_win32_import_lib_p "$dlprefile"; then
+               func_tr_sh "$dlprefile"
+               eval "curr_lafile=\$libfile_$func_tr_sh_result"
+               dlprefile_dlbasename=""
+               if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+                 # Use subshell, to avoid clobbering current variable values
+                 dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+                 if test -n "$dlprefile_dlname" ; then
+                   func_basename "$dlprefile_dlname"
+                   dlprefile_dlbasename="$func_basename_result"
+                 else
+                   # no lafile. user explicitly requested -dlpreopen <import 
library>.
+                   func_win32_dllname_for_implib "$dlprefile"
+                   dlprefile_dlbasename=$func_win32_dllname_for_implib_result
+                 fi
+               fi
+               $opt_dry_run || {
+                 if test -n "$dlprefile_dlbasename" ; then
+                   eval '$ECHO ": $dlprefile_dlbasename" >> "$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 # not an import lib
+               $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 || {
@@ -2208,6 +2247,99 @@ func_win32_libid ()
   $ECHO "$win32_libid_type"
 }
 
+# func_dlltool_identify
+# Determine if $DLLTOOL supports the --identify option
+func_dlltool_identify ()
+{
+  $opt_debug
+  if test -z "$func_dlltool_identify_result"; then
+    case `$DLLTOOL --help` in
+    *--identify*) func_dlltool_identify_result=: ;;
+    *) func_dlltool_identify_result=false ;;
+    esac
+  fi
+  $func_dlltool_identify_result
+}
+
+# func_win32_dllname_for_implib implib
+# Obtain the name of the DLL associated with the
+# specified import library. Result is available
+# in $func_win32_dllname_for_implib_result.
+#
+func_win32_dllname_for_implib ()
+{
+  $opt_debug
+  func_win32_dllname_for_implib_result=""
+
+  if func_dlltool_identify ; then
+    func_win32_dllname_for_implib_result=`$DLLTOOL --identify "$1" 2>/dev/null`
+    # if this fails, the fallback code is unlikely to succeed, so
+    # we don't bother...
+  else
+    # use fallback dlltool does not have the --identify option.
+    # make sure argument is actually an import library
+    if func_win32_import_lib_p "$1"; then
+      func_warn "Using fallback code to determine dllname for $1; consider 
updating binutils to version 2.20 (2.19.50.20081115), or newer."
+      # 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.
+
+      func_win32_dllname_for_implib_result=`$OBJDUMP -s --section '.idata$7' 
"$1" |
+        $SED '/^[^      ]*\.o:/{
+           s/.*//
+           p
+           d
+         }
+         /^.\{43\}/!d
+         s/^.\{43\}//' |
+        $SED -n '
+         :more
+         N
+         /\n$/b work
+         $!b more
+         :work
+         s/\n//g
+         s/\.\.\.*//g
+         s/[      ][      ][      ]*//g; s/^[     ]*//; s/[       ]*$//
+         /./{
+           p
+           q
+         }
+         '`
+    fi
+  fi
+}
+
+
 
 
 # func_extract_an_archive dir oldlib
@@ -5172,20 +5304,46 @@ func_mode_link ()
          if test -z "$libdir" && test "$linkmode" = prog; then
            func_fatal_error "only libraries may -dlpreopen a convenience 
library: \`$lib'"
          fi
-         # Prefer using a static library (so that no silly _DYNAMIC symbols
-         # are required to link).
-         if test -n "$old_library"; then
-           newdlprefiles="$newdlprefiles $dir/$old_library"
-           # Keep a list of preopened convenience libraries to check
-           # 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"
-         else
-           newdlprefiles="$newdlprefiles $dir/$linklib"
-         fi
+         case "$host" in
+           # special handling for platforms with PE-DLLs.
+           *cygwin* | *mingw* | *cegcc* )
+             # Linker will automatically link against shared library if both
+             # static and shared are present.  Therefore, ensure we extract
+             # symbols from the import library if a shared library is present
+             # (otherwise, the dlopen module name will be incorrect).  We do
+             # this by putting the import library name into $newdlprefiles.
+             # We recover the dlopen module name by 'saving' the la file
+             # name in a special purpose variable, and (later) extracting the
+             # dlname from the la file.
+             if test -n "$dlname"; then
+               func_tr_sh "$dir/$linklib"
+               eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+               newdlprefiles="$newdlprefiles $dir/$linklib"
+             else
+               newdlprefiles="$newdlprefiles $dir/$old_library"
+               # Keep a list of preopened convenience libraries to check
+               # that they are being used correctly in the link pass.
+               test -z "$libdir" && \
+                 dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library"
+             fi
+           ;;
+           * )
+             # Prefer using a static library (so that no silly _DYNAMIC symbols
+             # are required to link).
+             if test -n "$old_library"; then
+               newdlprefiles="$newdlprefiles $dir/$old_library"
+               # Keep a list of preopened convenience libraries to check
+               # 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"
+             else
+               newdlprefiles="$newdlprefiles $dir/$linklib"
+             fi
+           ;;
+         esac
        fi # $pass = dlpreopen
 
        if test -z "$libdir"; then
diff --git a/libltdl/m4/libtool.m4 b/libltdl/m4/libtool.m4
index b7b566d..3f658ac 100644
--- a/libltdl/m4/libtool.m4
+++ b/libltdl/m4/libtool.m4
@@ -1,7 +1,7 @@
 # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
 #
 #   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-#                 2006, 2007, 2008 Free Software Foundation, Inc.
+#                 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 #   Written by Gordon Matzigkeit, 1996
 #
 # This file is free software; the Free Software Foundation gives
@@ -10,7 +10,7 @@
 
 m4_define([_LT_COPYING], [dnl
 #   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-#                 2006, 2007, 2008 Free Software Foundation, Inc.
+#                 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 #   Written by Gordon Matzigkeit, 1996
 #
 #   This file is part of GNU Libtool.
@@ -3310,8 +3310,8 @@ esac
 lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int 
\1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
 
 # Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  
{\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  
{\"\2\", (void *) \&\2},/p'"
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ 
]]*\) $/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ 
]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ 
 {\"lib\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ 
 {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  
{\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ 
]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) 
\(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) 
\([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
 
 # Handle CRLF in mingw tool chain
 opt_cr=
@@ -4108,6 +4108,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.
@@ -4122,13 +4123,13 @@ m4_if([$1], [CXX], [
     _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
   ;;
   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(export_symbols_cmds, $1)='$NM $libobjs $convenience | 
$global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 
DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ 
]]/s/.* //'\'' | sort | uniq > $export_symbols'
+    _LT_TAGVAR(exclude_expsyms, 
$1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+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)=
@@ -4267,7 +4268,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/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ 
]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, 
$1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+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.4





reply via email to

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