libtool-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get in


From: Charles Wilson
Subject: Re: [PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get installed.
Date: Tue, 11 Aug 2009 01:16:37 -0400
User-agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.22) Gecko/20090605 Thunderbird/2.0.0.22 Mnenhy/0.7.6.666

Dave Korn wrote:
> [ Please Cc me on replies, I'm not subbed up to list. ]
>   Windows DLLs, unlike Linux DSOs, have to live in the bin directory (or
> elsewhere on $PATH), not the lib dir.  Libtool handles this at --link time by
> setting the dlname in the generated .la file to a relative path
> "../bin/$dlname", working on the assumption that the library .la file will be
> installed into $prefix/lib, and this causes the DLL to be installed to 
> $prefix/bin.
> 
>   That heuristic fails

Note, for the rest of the libtool team -- there is also a pending patch
not yet posted to this list, complementary to Dave's, from Yaakov
Selkowitz.  Yaakov's patch improves the heuristic for many common cases,
eliminating some cases where Dave's -bindir option might be used.
However, even Yaakov's improvement doesn't solve the specific case vis.
gcc.  Besides, no matter how smart a heuristic is, there are cases where
it fails -- so providing a specific control to override the heuristic is
kinda necessary.  So, IMO, both Yaakov's and Dave's patch -- in some
form, are appropriate and complementary.

>   The attached patch provides a way to resolve this problem, by adding a
> "-bindir" option to libtool's --link mode command line.

Dave, I'm sorry I wasn't able to get to this in time to save you the
effort, but thanks for following thru.  Comments inline, but I have no
official authority to actually "approve" anything.

> diff --git a/Makefile.am b/Makefile.am
> index a18955e..129b890 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -494,7 +494,8 @@ TESTSUITE_AT      = tests/testsuite.at \
>                 tests/configure-iface.at \
>                 tests/stresstest.at \
>                 tests/cmdline_wrap.at \
> -               tests/darwin.at
> +               tests/darwin.at \
> +               tests/win32.at
>  
>  EXTRA_DIST     += $(srcdir)/$(TESTSUITE) $(TESTSUITE_AT) 
> $(srcdir)/tests/package.m4

OK.

> diff --git a/libltdl/config/general.m4sh b/libltdl/config/general.m4sh
> old mode 100644
> new mode 100755
> index 4bc304c..96072e2
> --- a/libltdl/config/general.m4sh
> +++ b/libltdl/config/general.m4sh
> @@ -98,6 +98,49 @@ func_dirname_and_basename ()
>    func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
>  }
>  
> +# func_relative_path libdir bindir
> +# generates a relative path from libdir to bindir, intended
> +# for supporting installation of windows DLLs into -bindir.
> +# call:
> +#   dirname:  Compute the dirname of FILE.  If nonempty,
> +#             add APPEND to the result, otherwise set result
> +#             to NONDIR_REPLACEMENT.
> +#             value returned in "$func_dirname_result"
> +func_relative_path ()
> +{
> +  local tlibdir tbindir tcancelled

We can't use the 'local' keyword.  You need to uglify these variables, e.g.
      func_relative_path_tlibdir
      func_relative_path_tbindir
      func_relative_path_tcancelled

> +  func_relative_path_result=
> +  tlibdir=${1%%/}
> +  tbindir=${2%%/}

We can't use these, even tho they are technically supported by posix sh.
(Actually, we kinda can -- IF m4 says so. What happens is you abstract
the call into a function -- like func_stripname -- and then use m4 to
generate the appropriate contents of that function.  For cygwin/bash, it
happens that the contents of func_stripname() actually do use the %, #
posixisms.  But, in "client" code, you have to do

    func_stripname '' '/' "$1"
    tlibdir=$func_stripname_result
    func_stripname '' '/' "$2"
    tbindir=$func_stripname_result

> +  while :; do
> +    # check if we have found a prefix of bindir
> +    tcancelled=${tbindir##$tlibdir}

Again, we can't do this (nor ${foo:=.}). See below...

> +    if test x$tcancelled != x$tbindir ;
> +    then
> +      # Found a matching prefix, exit loop.
> +      func_relative_path_result="${func_relative_path_result:=.}"
> +      break
> +    fi
> +    func_dirname $tlibdir
> +    tlibdir=${func_dirname_result}
> +    if test x$tlibdir = x ;
> +    then
> +      # Have to descend all the way to the root!
> +      func_relative_path_result="../$func_relative_path_result"
> +      break
> +    fi
> +    func_relative_path_result="../$func_relative_path_result"
> +  done

    while :; do
      # check if we have found a prefix of bindir
      case "$tbindir" in
        $tlibdir* ) # found a matching prefix
          func_stripname "$tlibdir" '' "$tbindir"
          tcancelled=$func_stripname_result
          if test -z "$func_relative_path_result"; then
            func_relative_path_result=.
          fi
          break
          ;;
        *) func_dirname $tlibdir
           tlibdir=${func_dirname_result}
           if test x$tlibdir = x ; then
             # Have to descend all the way to the root!
             func_relative_path_result=../$func_relative_path_result
             break
           fi
           func_relative_path_result=../$func_relative_path_result
           ;;
      esac
    done

> +  # Now calculate path; take care to avoid doubling-up slashes.
> +  func_relative_path_result="${func_relative_path_result%%/}${tcancelled%%/}"

and again:
    func_stripname '' '/' "$func_relative_path_result"
    func_relative_path_result=$func_stripname_result
    func_stripname '' '/' "$tcancelled"

func_relative_path_result=${func_relative_path_result}${func_stripname_result}


> +  # Normalisation. If bindir is libdir, return empty string,
> +  # if subdir return string beginning './', else relative path
> +  # ending with a slash; either way, target file name can be
> +  # directly appended.
> +  func_relative_path_result="${func_relative_path_result:=.}/"
> +  func_relative_path_result="${func_relative_path_result##./}"

And again...

     if test -z "$func_relative_path_result"; then
       func_relative_path_result=.
     else
       func_stripname './' '' "$func_relative_path_result"
       func_relative_path_result=$func_stripname_result
     fi

> +}
> +
>  # Generated shell functions inserted here

AND...because you're (now) calling the generated functions from
func_relative_path, then it needs to be defined below the '# Generated
shell functions inserted here' marker, not above it.  So, here's the
revised function (w/o the varname uglification):

func_relative_path ()
{
  local tlibdir tbindir tcancelled
  func_relative_path_result=
  func_stripname '' '/' "$1"
  tlibdir=$func_stripname_result
  func_stripname '' '/' "$2"
  tbindir=$func_stripname_result
  while :; do
    # check if we have found a prefix of bindir
    case "$tbindir" in
      $tlibdir* ) # found a matching prefix
        func_stripname "$tlibdir" '' "$tbindir"
        tcancelled=$func_stripname_result
        if test -z "$func_relative_path_result"; then
          func_relative_path_result=.
        fi
        break
        ;;
      *) func_dirname $tlibdir
         tlibdir=${func_dirname_result}
         if test x$tlibdir = x ; then
           # Have to descend all the way to the root!
           func_relative_path_result=../$func_relative_path_result
           break
         fi
         func_relative_path_result=../$func_relative_path_result
         ;;
    esac
  done
  func_stripname '' '/' "$func_relative_path_result"
  func_relative_path_result=$func_stripname_result
  func_stripname '' '/' "$tcancelled"
func_relative_path_result=${func_relative_path_result}${func_stripname_result}

  if test -z "$func_relative_path_result"; then
    func_relative_path_result=./
  else
    func_stripname './' '' "$func_relative_path_result/"
    func_relative_path_result=$func_stripname_result
  fi
}

>  # The name of this program:
> diff --git a/libltdl/config/ltmain.m4sh b/libltdl/config/ltmain.m4sh
> old mode 100644
> new mode 100755
> index ebd3909..5403d80
> --- a/libltdl/config/ltmain.m4sh
> +++ b/libltdl/config/ltmain.m4sh
> @@ -1129,6 +1129,8 @@ The following components of LINK-COMMAND are treated 
> specially:
>  
>    -all-static       do not do any dynamic linking at all
>    -avoid-version    do not add a version suffix if possible
> +  -bindir BINDIR    specify path to $prefix/bin (needed only when installing
> +                    a Windows DLL)
>    -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
>    -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
>    -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with 
> dlsym(3)
> @@ -3659,6 +3661,7 @@ func_mode_link ()
>      new_inherited_linker_flags=
>  
>      avoid_version=no
> +    bindir=
>      dlfiles=
>      dlprefiles=
>      dlself=no
> @@ -3751,6 +3754,11 @@ func_mode_link ()
>       esac
>  
>       case $prev in
> +     bindir)
> +       bindir="$arg"
> +       prev=
> +       continue
> +       ;;
>       dlfiles|dlprefiles)
>         if test "$preload" = no; then
>           # Add the symbol object into the linking commands.
> @@ -4012,6 +4020,11 @@ func_mode_link ()
>       continue
>       ;;
>  
> +      -bindir)
> +     prev=bindir
> +     continue
> +     ;;
> +
>        -dlopen)
>       prev=dlfiles
>       continue
> @@ -7706,7 +7719,17 @@ EOF
>         # place dlname in correct position for cygwin
>         tdlname=$dlname
>         case $host,$output,$installed,$module,$dlname in
> -         *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | 
> *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
> +         *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | 
> *cegcc*,*lai,yes,no,*.dll)
> +           # If a -bindir argument was supplied, place the dll there.
> +           if test "x$bindir" != x ;
> +           then
> +             func_relative_path "$install_libdir" "$bindir"
> +             tdlname="${func_relative_path_result}$dlname"
> +           else
> +             # Otherwise fall back on heuristic.

NOTE: this is where Yaakov's patch would go...

> +             tdlname=../bin/$dlname
> +           fi
> +           ;;
>         esac
>         $ECHO > $output "\
>  # $outputname - a libtool library file
> diff --git a/tests/win32.at b/tests/win32.at
> new file mode 100755
> index 0000000..1d36add
> --- /dev/null
> +++ b/tests/win32.at
> @@ -0,0 +1,170 @@
> +# win32.at - tests specific to Cygwin and MinGW
> +#
> +#   Copyright (C) 2009 Free Software Foundation, Inc.
> +#   Written by Dave Korn, 2009
> +#
> +#   This file is part of GNU Libtool.
> +#
> +# GNU Libtool is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU General Public License as
> +# published by the Free Software Foundation; either version 2 of
> +# the License, or (at your option) any later version.
> +#
> +# GNU Libtool is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with GNU Libtool; see the file COPYING.  If not, a copy
> +# can be downloaded from  http://www.gnu.org/licenses/gpl.html,
> +# or obtained by writing to the Free Software Foundation, Inc.,
> +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> +####
> +
> +noskip=:
> +case "$host_os" in
> +cygwin*|mingw*) ;;
> +*) noskip=false ;;
> +esac
> +
> +$noskip && {
> +
> +AT_BANNER([Win32 tests])
> +AT_SETUP([win32 compile check])
> +
> +# Verify compiling works.
> +
> +AT_DATA([simple.c] ,[[
> +int main() { return 0;}
> +]])
> +
> +$noskip && {
> +$CC $CPPFLAGS $CFLAGS -o simple simple.c 2>&1 > /dev/null || noskip=false
> +rm -f simple 
> +}
> +
> +AT_CHECK([$noskip || (exit 77)])
> +
> +AT_CLEANUP
> +
> +# Now the tests themselves.
> +
> +AT_SETUP([win32 dll basic])
> +
> +AT_DATA([foo.c],[[
> +int x=0;
> +]])
> +
> +AT_DATA([baz.c],[[
> +int y=0;
> +]])
> +
> +AT_DATA([bar.c],[[
> +extern int x;
> +int bar(void);
> +int bar() { return x;}
> +]])
> +
> +AT_DATA([main.c],[[
> +extern int x;
> +extern int y;
> +
> +int main() {
> +return x+y;
> +}
> +]])
> +
> +AT_CHECK([$LIBTOOL --mode=compile --tag=CC $CC -c -o foo.lo $CPPFLAGS 
> $CFLAGS foo.c],[0],[ignore],[ignore])
> +
> +AT_CHECK([$LIBTOOL --mode=compile --tag=CC $CC -c -o baz.lo $CPPFLAGS 
> $CFLAGS baz.c],[0],[ignore],[ignore])
> +
> +AT_CHECK([$LIBTOOL --mode=link --tag=CC $CC -no-undefined -shared -o 
> libfoo.la $CPPFLAGS $CFLAGS $LDFLAGS foo.lo baz.lo -rpath 
> /nonexistent],[0],[ignore],[ignore])
> +
> +AT_CHECK([$LIBTOOL --mode=compile --tag=CC $CC -c -o bar.lo $CPPFLAGS 
> $CFLAGS bar.c],[0],[ignore],[ignore])
> +
> +AT_CHECK([$LIBTOOL --mode=link --tag=CC $CC -no-undefined -shared -o 
> libbar.la $CPPFLAGS $CFLAGS $LDFLAGS bar.lo libfoo.la -rpath 
> /nonexistent],[0],[ignore],[ignore])
> +
> +AT_CHECK([$LIBTOOL --mode=compile --tag=CC $CC -c -o main.lo $CPPFLAGS 
> $CFLAGS main.c],[0],[ignore],[ignore])
> +
> +AT_CHECK([$LIBTOOL --mode=link --tag=CC $CC -o main$EXEEXT $CPPFLAGS $CFLAGS 
> $LDFLAGS main.lo libbar.la],[0],[ignore],[ignore])
> +
> +AT_CLEANUP
> +
> +AT_SETUP([win32 dll install to bindir])
> +
> +AT_DATA([foo.c],[[
> +int x=0;
> +]])
> +
> +AT_DATA([bar.c],[[
> +extern int x;
> +int bar(void);
> +int bar() { return x;}
> +]])
> +
> +AT_DATA([baz.c],[[
> +int y=0;
> +]])
> +
> +AT_CHECK([$LIBTOOL --mode=compile --tag=CC $CC -c -o foo.lo $CPPFLAGS 
> $CFLAGS foo.c],[0],[ignore],[ignore])
> +AT_CHECK([$LIBTOOL --mode=compile --tag=CC $CC -c -o baz.lo $CPPFLAGS 
> $CFLAGS baz.c],[0],[ignore],[ignore])
> +AT_CHECK([$LIBTOOL --mode=link --tag=CC $CC -no-undefined -shared -o 
> libfoo.la $CPPFLAGS $CFLAGS $LDFLAGS foo.lo baz.lo -rpath 
> /nonexistent],[0],[ignore],[ignore])
> +
> +AT_CHECK([$LIBTOOL --mode=compile --tag=CC $CC -c -o bar.lo $CPPFLAGS 
> $CFLAGS bar.c],[0],[ignore],[ignore])
> +
> +# Now try installing the libs.  There are the following cases:
> +# No -bindir
> +# -bindir below lib install dir
> +# -bindir is lib install dir
> +# -bindir beside lib install dir
> +# -bindir above lib dir
> +# -bindir above and beside lib dir
> +# -bindir in entirely unrelated prefix.
> +
> +curdir=`pwd`
> +libdir=${curdir}/usr/lib/gcc/i686-pc-cygwin/4.5.0
> +
> +# Do a basic install with no -bindir option for reference
> +
> +AT_CHECK([$LIBTOOL --mode=link --tag=CC $CC -no-undefined -shared -o 
> libbar.la $CPPFLAGS $CFLAGS $LDFLAGS bar.lo libfoo.la -rpath 
> ${libdir}],[0],[ignore],[ignore])

I'm not sure "-rpath" is the right way to test, here. I know you're
trying to avoid doing a full "configure --prefix= --bindir=" test, but
I've only rarely seen the -rpath flag used on win32, so I'm not sure
this test is exercising the normal usage pattern.

> +rm -rf ${curdir}/usr
> +mkdir -p ${libdir}
> +AT_CHECK([$LIBTOOL --mode=install $lt_INSTALL libbar.la $libdir],
> +      [], [ignore], [ignore])
> +
> +# And ensure it went where we expect.
> +AT_CHECK(test -f $libdir/../bin/???bar-0.dll)
> +
> +for x in \
> +     ${curdir}/usr/lib/gcc/i686-pc-cygwin/4.5.0/bin/ \
> +     ${curdir}/usr/lib/gcc/i686-pc-cygwin/4.5.0/bin \
> +     ${curdir}/usr/lib/gcc/i686-pc-cygwin/4.5.0/ \
> +     ${curdir}/usr/lib/gcc/i686-pc-cygwin/4.5.0 \
> +     ${curdir}/usr/lib/gcc/i686-pc-cygwin/bin/ \
> +     ${curdir}/usr/lib/gcc/i686-pc-cygwin/bin \
> +     ${curdir}/usr/lib/gcc/i686-pc-cygwin/ \
> +     ${curdir}/usr/lib/gcc/i686-pc-cygwin \
> +     ${curdir}/usr/lib/bin/ \
> +     ${curdir}/usr/lib/bin \
> +     ${curdir}/usr/bin/ \
> +     ${curdir}/usr/bin \
> +     ${curdir}/bin/ \
> +     ${curdir}/bin \
> +     /tmp/$$/foo/bar ;
> +do
> +
> +  AT_CHECK([$LIBTOOL --mode=link --tag=CC $CC -no-undefined -bindir $x 
> -shared -o libbar.la $CPPFLAGS $CFLAGS $LDFLAGS bar.lo libfoo.la -rpath 
> ${libdir}],[0],[ignore],[ignore])
> +
> +  rm -rf ${curdir}/usr ${curdir}/bin /tmp/$$
> +  mkdir -p ${libdir} $x ${curdir}/usr ${curdir}/bin /tmp/$$
> +  AT_CHECK([$LIBTOOL --mode=install $lt_INSTALL libbar.la $libdir],
> +      [], [ignore], [ignore])
> +  # Ensure it went to bindir this time.
> +  AT_CHECK(test -f $x/???bar-0.dll)
> +done
> +
> +AT_CLEANUP
> +
> +}
> +

OK.

Hope that helps, Dave.

--
Chuck






reply via email to

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