| # bindir.at - Test the -bindir option |
| # |
| # Copyright (C) 2009-2019, 2021-2025 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. If not, see <https://www.gnu.org/licenses/>. |
| #### |
| |
| #### |
| # In this testcase, and in the chunk of code that makes use |
| # of $bindir in ltmain.in, we would very much have liked to |
| # automatically decide which systems require dynamically-loaded |
| # libraries to be installed to a directory in $PATH according |
| # to the libtool properties that tell us that "the system provides |
| # no way to hard-code library paths into executables, and also |
| # has no $shlibpath_var independent of the PATH variable", in |
| # Ralf's words. But it turns out this is not possible, as:- |
| # |
| #> * Dave Korn wrote on Fri, Aug 14, 2009 at 04:30:27AM CEST: |
| #>>> Ralf Wildenhues wrote: |
| #>>> |
| #>>>>> But in this particular case, I would argue that either you look at |
| #>>>>> the libtool variables shlibpath_var and hardcode_action for "PATH" |
| #>>>>> and "unsupported". |
| #>>> |
| #>>> On Cygwin, $hardcode_action = "immediate" in the generated libtool |
| #>>> script. Did you perhaps mean $hardcode_shlibpath_var, which is indeed |
| #>>> "unsupported"? |
| #> |
| #> Oh brother, yes, I forgot about those bogus hardcode_libdir_flag_spec |
| #> settings. They fool _LT_LINKER_HARDCODE_LIBPATH. I don't remember whether |
| #> they were needed in order to not break some semantics in ltmain (they |
| #> probably were). |
| #> |
| #> Anyway, $hardcode_action = "immediate" is definitely wrong, but fixing that |
| #> now is also way out of scope of this patch. So I guess we need to stick to |
| #> host matching in the code, and work out a separate fix for the setting of |
| #> $hardcode_libdir_flag_spec. |
| # |
| # So alas we punt for now, and just hardcode the relevant OSs that require |
| # this functionality. That's Cygwin, MinGW and CeGCC for now; see the case |
| # statement in ltmain.in around where the 'tdlname' variable is set. |
| |
| #### |
| # First a simple test that we can build and run an executable with a couple of |
| # tiny libraries. |
| |
| AT_SETUP([bindir basic lib test]) |
| |
| bindirneeded=: |
| case $host_os in |
| cygwin*|mingw*|windows*|cegcc*) |
| ;; |
| *) |
| bindirneeded=false |
| ;; |
| esac |
| |
| #### |
| # These routines save the PATH before a test and restore it after, |
| # prepending a chosen directory to the path on the platforms where |
| # -bindir is needed after saving. |
| # |
| |
| func_save_and_prepend_path () |
| { |
| save_PATH=$PATH |
| if $bindirneeded; then |
| PATH=$1$PATH_SEPARATOR$PATH |
| fi |
| export PATH |
| } |
| |
| func_restore_path () |
| { |
| PATH=$save_PATH |
| export PATH |
| } |
| |
| AT_DATA([foo.c],[[ |
| int x=11; |
| ]]) |
| |
| AT_DATA([baz.c],[[ |
| extern int x; |
| int baz (void); |
| int baz (void) { return x;} |
| ]]) |
| |
| AT_DATA([bar.c],[[ |
| extern int baz (void); |
| int y=3; |
| int bar (void); |
| int bar (void) { return y + baz ();} |
| ]]) |
| |
| AT_DATA([main.c],[[ |
| #include <stdlib.h> |
| extern int baz (void); |
| extern int bar (void); |
| int main() { |
| if (baz () + bar () - 25) abort (); |
| return 0; |
| } |
| ]]) |
| |
| |
| curdir=`pwd` |
| eval "`$LIBTOOL --config | $GREP '^objdir='`" |
| |
| 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 -o libfoo.la $CPPFLAGS $CFLAGS $LDFLAGS foo.lo baz.lo -rpath $curdir/$objdir],[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 -o libbar.la $CPPFLAGS $CFLAGS $LDFLAGS bar.lo libfoo.la -rpath $curdir/$objdir],[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 libfoo.la],[0],[ignore],[ignore]) |
| |
| # Check both static and shared versions run. We don't install them |
| # here, that will be covered by the later tests; we've rpath'd things |
| # so that they can all be run in situ. |
| |
| LT_AT_NOINST_EXEC_CHECK([./main]) |
| |
| # Ensure libraries can be found on PATH, if we are on one |
| # of the affected platforms, before testing the shared version. |
| |
| func_save_and_prepend_path "$curdir/$objdir" |
| $bindirneeded && { |
| LT_AT_NOINST_EXEC_CHECK([$objdir/main]) |
| } |
| |
| # In fact, prepending the PATH as above is superfluous on the windows |
| # platforms that this feature is primarily aimed at, as the DLL search |
| # path always includes the directory from which the app was launched. |
| # To make sure it still works even when not side-by-side, we'll install |
| # the main executable and execute it from there while the PATH still |
| # points to the shared libs in the .libs subdir. On other platforms, |
| # the rpaths we set at link time will guarantee it runs from the bindir. |
| |
| mkdir $curdir/bin |
| AT_CHECK([$LIBTOOL --mode=install $lt_INSTALL main$EXEEXT $curdir/bin/main$EXEEXT], [], [ignore], [ignore]) |
| LT_AT_EXEC_CHECK([$curdir/bin/main$EXEEXT], [0], [ignore], [ignore], []) |
| func_restore_path |
| |
| AT_CLEANUP |
| |
| #### |
| # This is the main testcase. For a variety of bindir and libdir |
| # settings, it verifies that all the files get installed exactly |
| # where we want them to go, and that they can be executed once |
| # installed. |
| # |
| |
| AT_SETUP([bindir install tests]) |
| |
| bindirneeded=: |
| case $host_os in |
| cygwin*|mingw*|windows*|cegcc*) |
| ;; |
| *) |
| bindirneeded=false |
| ;; |
| esac |
| |
| eval "`$LIBTOOL --config | $GREP '^build_libtool_libs='`" |
| AT_CHECK([test yes = "$build_libtool_libs" || exit 77]) |
| |
| #### |
| # These routines save the PATH before a test and restore it after, |
| # prepending a chosen directory to the path on the platforms where |
| # -bindir is needed after saving. |
| # |
| |
| func_save_and_prepend_path () |
| { |
| save_PATH=$PATH |
| if $bindirneeded; then |
| PATH=$1$PATH_SEPARATOR$PATH |
| fi |
| export PATH |
| } |
| |
| func_restore_path () |
| { |
| PATH=$save_PATH |
| export PATH |
| } |
| |
| AT_DATA([foo.c],[[ |
| int x=11; |
| ]]) |
| |
| AT_DATA([baz.c],[[ |
| extern int x; |
| int baz (void); |
| int baz (void) { return x;} |
| ]]) |
| |
| AT_DATA([bar.c],[[ |
| extern int baz (void); |
| int y=3; |
| int bar (void); |
| int bar (void) { return y + baz ();} |
| ]]) |
| |
| AT_DATA([main.c],[[ |
| #include <stdlib.h> |
| extern int baz (void); |
| extern int bar (void); |
| int main() { |
| if (baz () + bar () - 25) abort (); |
| return 0; |
| } |
| ]]) |
| |
| # We only need to compile once, but we'll need to relink for each different value |
| # of libdir in order to set the rpath, and we'll install for each combination of |
| # libdir and bindir. |
| |
| 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=compile --tag=CC $CC -c -o bar.lo $CPPFLAGS $CFLAGS bar.c],[0],[ignore],[ignore]) |
| AT_CHECK([$LIBTOOL --mode=compile --tag=CC $CC -c -o main.lo $CPPFLAGS $CFLAGS main.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` |
| for libdir in \ |
| $curdir/usr/lib/gcc/i686-pc-cygwin/4.5.0 \ |
| $curdir/usr/lib/gcc/../gcc/.//i686-pc-cygwin/4.5.0/../../././//. \ |
| $curdir/usr/lib/ \ |
| $curdir/usr/lib \ |
| $curdir/baz \ |
| $curdir/baz/lib/; |
| do |
| |
| # Do a basic install with no -bindir option for reference. We use the sbin/ |
| # dir for the main exe to avoid the potential "this only works because it's |
| # side-by-side with the libs" default DLL search path problem mentioned above. |
| rm -rf $libdir $curdir/bin $curdir/sbin $curdir/baz $curdir/usr |
| AS_MKDIR_P($libdir) |
| AS_MKDIR_P($curdir/sbin) |
| AT_CHECK([$LIBTOOL --mode=link --tag=CC $CC -no-undefined -o libfoo.la $CPPFLAGS $CFLAGS $LDFLAGS foo.lo bar.lo baz.lo -rpath $libdir],[0],[ignore],[ignore]) |
| AT_CHECK([$LIBTOOL --mode=link --tag=CC $CC -o main$EXEEXT $CPPFLAGS $CFLAGS $LDFLAGS main.lo libfoo.la -rpath $libdir],[0],[ignore],[ignore]) |
| AT_CHECK([$LIBTOOL --mode=install $lt_INSTALL libfoo.la $libdir], [], [ignore], [ignore]) |
| AT_CHECK([$LIBTOOL --mode=install $lt_INSTALL main$EXEEXT $curdir/sbin/main$EXEEXT], [], [ignore], [ignore]) |
| |
| # And ensure it went where we expect. Could be looking for any of |
| # 'cygfoo-0.dll', 'libfoo-0.dll', 'foo-0.dll', or 'libfoo.so.0'. We'll |
| # simplify this check by taking advantage of the fact that if it's a DLL, |
| # it has to go in bindir, so we'll not check for both forms in libdir. |
| if $bindirneeded; then |
| AT_CHECK([test -f "$libdir"/../bin/???foo-0.dll || ls "$libdir"/../bin/*foo*0*], [], [ignore], [ignore]) |
| else |
| AT_CHECK([ls $libdir/*foo*], [], [ignore], [ignore]) |
| fi |
| |
| # And that it can be executed. |
| func_save_and_prepend_path "$libdir/../bin" |
| LT_AT_EXEC_CHECK([$curdir/sbin/main$EXEEXT], [0], [ignore], [ignore], []) |
| func_restore_path |
| |
| for bindir 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/bin \ |
| $curdir/usr/lib/bin \ |
| $curdir/usr/bin/ \ |
| $curdir/usr/bin \ |
| /tmp/foo/bar; |
| do |
| |
| # Clear any old stuff out before we install. Because bindir |
| # may be in /tmp, we have to take care to create it securely |
| # and not to delete and recreate it if we do. |
| rm -rf $libdir $curdir/bin $curdir/sbin $curdir/baz $curdir/usr |
| |
| tmp= |
| case $bindir in |
| /tmp*) |
| # Create a temporary directory $tmp in $TMPDIR (default /tmp). |
| # Use mktemp if possible; otherwise fall back on mkdir, |
| # with $RANDOM to make collisions less likely. |
| : ${TMPDIR=/tmp} |
| { |
| tmp=` |
| (umask 077 && mktemp -d "$TMPDIR/fooXXXXXX") 2>/dev/null |
| ` && |
| test -n "$tmp" && test -d "$tmp" |
| } || { |
| tmp=$TMPDIR/foo$$-$RANDOM |
| (umask 077 && mkdir "$tmp") |
| } || AT_CHECK([exit 77]) |
| bindir=$tmp/bar |
| ;; |
| *) |
| # Clear any old stuff out before we install. |
| rm -rf $bindir |
| AS_MKDIR_P($bindir) |
| ;; |
| esac |
| |
| # Relink with new rpaths. |
| AT_CHECK([$LIBTOOL --mode=link --tag=CC $CC -no-undefined -bindir $bindir -o libfoo.la $CPPFLAGS $CFLAGS $LDFLAGS foo.lo bar.lo baz.lo -rpath $libdir],[0],[ignore],[ignore]) |
| AT_CHECK([$LIBTOOL --mode=link --tag=CC $CC -o main$EXEEXT $CPPFLAGS $CFLAGS $LDFLAGS main.lo libfoo.la],[0],[ignore],[ignore]) |
| |
| # Recreate directories (bindir already done) and install. |
| AS_MKDIR_P($libdir) |
| AS_MKDIR_P($curdir/sbin) |
| AT_CHECK([$LIBTOOL --mode=install $lt_INSTALL libfoo.la "$libdir"], [], [ignore], [ignore]) |
| AT_CHECK([$LIBTOOL --mode=install $lt_INSTALL main$EXEEXT "$curdir/sbin/main$EXEEXT"], [], [ignore], [ignore]) |
| |
| # Ensure it went to bindir rather than default dir this time. |
| if $bindirneeded; then |
| AT_CHECK([test -f "$bindir"/???foo-0.dll || ls "$bindir"/*foo*0*], [], [ignore], [ignore]) |
| else |
| AT_CHECK([ls "$libdir"/*foo*], [], [ignore], [ignore]) |
| fi |
| |
| # And that it can be executed. |
| func_save_and_prepend_path "$bindir" |
| LT_AT_EXEC_CHECK([$curdir/sbin/main$EXEEXT], [0], [ignore], [ignore], []) |
| func_restore_path |
| |
| # Clean up if we made a temp dir. Subdirs under our testdir get rm'd |
| # and recreated at the top of the loop. Securely created subdirs under |
| # /tmp get created precisely once and rm'd when we're done with them. |
| if test ! -z "$tmp"; then |
| rm -rf "$tmp" |
| fi |
| |
| done |
| done |
| |
| AT_CLEANUP |