* libltdl/config/ltmain.m4sh (func_dlltool_identify): New function. (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. 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 -- but obsoleted -- version of a patch first posted here: http://lists.gnu.org/archive/html/libtool-patches/2008-11/msg00019.html in response to a bug first posted here: http://lists.gnu.org/archive/html/bug-libtool/2008-05/msg00054.html This version of the patch corrects all issues raised in that thread and is updated to current master -- except for two issues: 1) This idiom eval '$ECHO ": $name " >> "$nlist"' eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" is still used, rather than $ECHO ": $name " >> "$nlist" eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" because, while "extra" evals are bad, the idiom predated this patch, and should be cleaned up -- if it needs to be -- in a separate patch. 2) At the end of the thread, Ralf had a suggestion for "saving" the name of the la file associated with each import library in the dlpreopen list. This avoids the need for func_win32_dllname_for_implib(), except when there IS no la file. I've implemented a version of that idea, but not here. The new implmentation completely obsoletes (but incorporates large parts of) this patch. So why post this one? For completeness, and to terminate the originating thread. I'll start a new thread with the new patch. ===== libltdl/config/ltmain.m4sh | 148 +++++++++++++++++++++++++++++++++++++++++--- libltdl/m4/libtool.m4 | 8 ++- 2 files changed, 145 insertions(+), 11 deletions(-) diff --git a/libltdl/config/ltmain.m4sh b/libltdl/config/ltmain.m4sh index 20ca07b..c7d0dc0 100644 --- a/libltdl/config/ltmain.m4sh +++ b/libltdl/config/ltmain.m4sh @@ -2001,10 +2001,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 func_win32_import_lib_p "$dlprefile"; then + func_win32_dllname_for_implib "$dlprefile" + dllname=$func_win32_dllname_for_implib_result + $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 || { @@ -2208,6 +2234,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_warning "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 @@ -5180,11 +5299,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 b7b566d..ee4b106 100644 --- a/libltdl/m4/libtool.m4 +++ b/libltdl/m4/libtool.m4 @@ -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