[Top][All Lists]
[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
- [PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get installed., Dave Korn, 2009/08/10
- Re: [PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get installed.,
Charles Wilson <=
- Re: [PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get installed., Dave Korn, 2009/08/11
- Re: [PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get installed., Charles Wilson, 2009/08/11
- Re: [PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get installed., Peter Rosin, 2009/08/11
- Re: [PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get installed., Dave Korn, 2009/08/11
- Re: [PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get installed., Peter Rosin, 2009/08/11
- Re: [PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get installed., Dave Korn, 2009/08/11
Re: [PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get installed., Dave Korn, 2009/08/11