libtool-patches
[Top][All Lists]
Advanced

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

[PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get instal


From: Dave Korn
Subject: [PATCH+Assign request][cygwin|mingw] Control where win32 DLLs get installed.
Date: Tue, 11 Aug 2009 03:54:07 +0100
User-agent: Thunderbird 2.0.0.17 (Windows/20080914)

[ Please Cc me on replies, I'm not subbed up to list. ]

    Hi libtool team,

  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 when the .la file is being installed to a deep
subdirectory of $prefix/lib; for example, when GCC installs the .la files for
the language runtime libraries into $prefix/lib/gcc/$target/$version, the DLLs
all end up in $prefix/lib/gcc/$target/bin/, which isn't what we want.

  The attached patch provides a way to resolve this problem, by adding a
"-bindir" option to libtool's --link mode command line.  Libtool then calculates
a relative path from the .la file's install dir to the -bindir argument, instead
of using the heuristic; in the absence of a -bindir argument, it falls back to
the old behaviour.  The intention is to provide a very simple mode of usage
where maintainers, when adding "-no-undefined" to their makefiles, simply follow
up with "-bindir $bindir"; for this reason, -bindir, like -no-undefined, is
accepted and ignored on other platforms.

  Built and tests run on i686-pc-cygwin with no regressions and all new tests
passing.  Please review carefully, I'm new to libtool and don't know if I've
followed all the right conventions.

  As this is a fairly hefty patch I figure I probably need to sign an assign;
please set the works in motion for that.  I already have a number of assignments
on record with the FSF and they have my up-to-date address details, so we can
probably skip filling out the .future form and just ask the FSF clerk to snail
me a libtool assign straight off.

  This patch lacks any extension to the docs in libtool.texi.  I'll write that
while we're waiting for the assignment process and your review comments, and
submit a final spin when that's done.  I'm also testing a bootstrap of GCC with
this patch applied to check that it works in a real-world application.

libtool/ChangeLog:

        * Makefile.am (TESTSUITE_AT): Add win32.at.
        * libltdl/config/general.m4sh (func_relative_path): New function.
        * libltdl/config/ltmain.m4sh (func_mode_link): Accept new -bindir
        option and use it, if supplied, to place Windows DLLs.
        * tests/win32.at: New file for Windows-specific tests.

    cheers,
      DaveK

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
 
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
+  func_relative_path_result=
+  tlibdir=${1%%/}
+  tbindir=${2%%/}
+  while :; do
+    # check if we have found a prefix of bindir
+    tcancelled=${tbindir##$tlibdir}
+    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
+  # Now calculate path; take care to avoid doubling-up slashes.
+  func_relative_path_result="${func_relative_path_result%%/}${tcancelled%%/}"
+  # 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##./}"
+}
+
 # Generated shell functions inserted here.
 
 # 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.
+               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])
+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
+
+}
+

reply via email to

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