libtool-patches
[Top][All Lists]
Advanced

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

[patch] win32: eliminate wrapper script in main build dir


From: Charles Wilson
Subject: [patch] win32: eliminate wrapper script in main build dir
Date: Sun, 10 Jun 2007 14:23:58 -0400
User-agent: Thunderbird 1.5.0.12 (Windows/20070509)

This patch is an updated version of the one posted here:
http://lists.gnu.org/archive/html/libtool-patches/2007-04/msg00052.html
It is updated to reflect ongoing changes in HEAD, and avoids the mingw regressions mentioned in that email.

Theory:
================================================================
On cygwin/mingw, a wrapper executable is used which should invoke a wrapper script that is the typical libtool wrapper script used on other platforms. However, it should be hidden inside $objdir, and given a name distinct from its target. I chose:
    .libs/foo_ltshwrapper
The exectuable wrapper generates this file, on the fly, every time it is invoked. Therefore, this wrapper script *does not exist* until the target executable is invoked. This behavior is already incorporated in libtool-HEAD.

In general, libtool ALSO uses the wrapper script to "save" information about the target, and often sources it. On mingw/cygwin, this patch insures that a suitable wrapper script is generated at the same time the wrapper executable is created -- in fact, with this patch libtool now uses the wrapper executable to generate it. However, I choose a *different* name than the one above:
    .libs/foo_ltshwrapperTMP
Of course, other platforms continue to create a wrapper script as ./foo and do not use the executable wrapper at all.

Thus, with this patch, the '.' directory will contain only wrapper executables, and no wrapper scripts -- eliminating "foo.exe" vs "foo" confusion. In $objdir, there will exist
    .libs/foo.exe
    .libs/foo_ltshwrapperTMP
    .libs/foo_ltshwrapper [ recreated on-demand ]
(okay, maybe the names are backwards, but that's a two line cosmetic patch)

Now, it is possible that we could use the *same* .libs/foo_ltshwrapper file for both "execute" and "func_source" purposes. However:
  (a) I never want the executable wrapper to fail because the
      wrapper script is missing
  (b) I don't want the timestamp of the func_source()'ed wrapper
      script to depend on whether/when the target was executed
  (c) It is possible that, in the future, we will need to store
      different state in one of these two: for instance, the
      wrapper executable may eventually take another cmdline arg
      like "--lt-relink-cmd '.....'".  By using separate files,
      one "invisible" (created on the fly by the executable wrapper
      as a transparent part of its execv()-the-target proess), and
      one "visible" that is timestamped at the same time as the
      executable wrapper, we retain enough flexibility for the
      future.

I'd like to be able to delete the "invisible" wrapper script after use, but that's hard to arrange since we're using execv(): there is no execv(target)-and-tell-target-to-delete-itself-afterwards.

On mingw, we (now) use _spawnv() and wait for the child, so presumably on that platform we could delete the on-the-fly wrapper script after use. But (1) I don't want mingw and cygwin to behave differently (one cleans up the temporary wrapper, the other doesn't), and (2) I'm not ready to change the wrapper's behavior in general to be wait-for-child. I did it on mingw out of necessity (see below). In any case, the execv-vs-spawnv and delete-after-use behavior can be addressed later. Comments?

Portability issue?
================================================================
Implementation of func_ltwrapper_executable_p() greps $1 for the expanded form of $magic. This works because the wrapper executable contains the wrapper script contents verbatim, and the wrapper script tests $libtool_install_magic against the expanded $magic.

We're already grepping binary files, without this patch. func_ltwrapper_p() can (and often is) called with a binary as $1. However, it delegates to func_lalib_p(), which does:
    $SED -e 4q "$1" 2>/dev/null \
      | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1


Mingw-specific
================================================================
The original version of this patch -- and my initial forward port of it to current HEAD -- induced new testsuite regressions on mingw:
< PASS: tests/demo-relink.test
> FAIL: tests/demo-relink.test
< PASS: tests/depdemo-relink.test
> FAIL: tests/depdemo-relink.test
 26: DESTDIR with in-package deplibs FAILED (destdir.at:131)
 29: C subdir-objects                FAILED (am-subdir.at:81)
 50: config.status                   FAILED (early-libtool.at:115)
 51: config.lt                       FAILED (early-libtool.at:220)

These turned out to be side effects of the wrapper script no longer being present in the main build dir. Up to this point, the msys shell was always using the wrapper script and not the wrapper executable. However, with the wrapper script missing, msys was now forced to use the wrapper executable. Because on mingw, execv() doesn't actually replace the current process, all 'expect fail' tests were getting an exit code of 0 -- from the wrapper. Hence, on mingw we now use _spawnv(), and manually pass the child's return value back to the caller.

Also, $OBJDUMP fails badly when called on a non-existant file, so some $EXEEXT fixups in destdir.at were needed. These two changes, included in the attached patch, eliminated the new regressions on mingw and caused no issues on linux or cygwin.



So, using the final version of the patch (as attached):
TEST RESULTS:
=================================================

___________________________________________________________
cygwin
======================
All 115 tests passed
(9 tests were not run)
======================
 14: Java convenience archives       FAILED (convenience.at:273)
 16: Link order of deplibs.          FAILED (link-order2.at:129)
 32: lt_dlopenadvise library loading FAILED (lt_dladvise.at:316)
 54: Run tests with low max_cmd_len  FAILED (cmdline_wrap.at:43)
This is the expected output, for now.

___________________________________________________________
mingw (assuming you 'export INSTALL=/usr/bin/install.exe')
====================================
All 115 tests passed
(9 tests were not run)
====================================
 14: Java convenience archives       FAILED (convenience.at:273)
 16: Link order of deplibs.          FAILED (link-order2.at:129)
 32: lt_dlopenadvise library loading FAILED (lt_dladvise.at:314)
 54: Run tests with low max_cmd_len  FAILED (cmdline_wrap.at:43)
These are the same as cygwin.
None of these errors represent regressions on this platform.

___________________________________________________________
Linux
====================
All 106 tests passed
====================
52 tests behaved as expected.
2 tests were skipped.



CHANGELOG
=================================================
2007-04-22  Charles Wilson  <address@hidden>

        * libltdl/config/ltmain.m4sh (func_ltwrapper_script_p):
        new function detects if $1 is a libtool sh wrapper
        (func_ltwrapper_executable_p): new function detects
        if $1 is a libtool executable wrapper
        (func_ltwrapper_p): modified to detect is $1 is ANY
        sort of libtool wrapper
        (func_ltwrapper_temp_scriptname): new function generates
        appropriate pathname for temporary libtool wrapper script
        if libtool executable wrappers are in use.  This temporary
        script is suitable for use with func_source().
        (func_mode_execute): handle $file that is a libtool wrapper
        script and $file that is a libtool wrapper executable
        differently.
        (func_mode_install) [cygwin|mingw]: if $file is a libtool
        wrapper executable, use func_ltwrapper_temp_scriptname()
        to determine wrapper script name.  After determining name
        of wrapper script, use func_ltwrapper_script_p() instead
        of func_ltwrapper_p().
        (func_mode_link) [cygwin|mingw]: don't call dirname and
        basename directly; use func_dirname() and func_basename()
        when computing cwrapper names.  Use cwrapper to generate
        wrapper script, and use pathname returned by
        func_ltwrapper_temp_scriptname() instead of $output.
        (func_mode_link) [NOT cygwin|mingw]: move wrapper script
        generation for non-win32 inside case statement, as default
        case.
        (func_mode_uninstall) [$name's extension != .lo|.la]:
        'clean' mode must handle $file differently if it is a libtool
        wrapper script, or if it is a libtool wrapper executable.
        (func_emit_libtool_cwrapperexe_source) [main, mingw]:
        use _spawnv and return child's exit code manually rather
        than rely on (broken) execv.
        * tests/destdir.at: $EXEEXT fixups.


Index: libltdl/config/ltmain.m4sh
===================================================================
RCS file: /cvsroot/libtool/libtool/libltdl/config/ltmain.m4sh,v
retrieving revision 1.79
diff -u -r1.79 ltmain.m4sh
--- libltdl/config/ltmain.m4sh  9 Jun 2007 17:46:40 -0000       1.79
+++ libltdl/config/ltmain.m4sh  10 Jun 2007 07:22:05 -0000
@@ -661,13 +661,61 @@
     test "$lalib_p" = yes
 }
 
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+    func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+    func_ltwrapper_executable_p_result=no
+    if ! func_ltwrapper_script_p "$1" ; then
+      case "$1" in
+        *.exe ) if grep "$magic" "$1" >/dev/null ; then
+                    func_ltwrapper_executable_p_result=yes
+                fi ;;
+        * )     if grep "$magic" "${1}.exe" >/dev/null ; then
+                    func_ltwrapper_executable_p_result=yes
+                fi ;;
+      esac
+    fi
+    test "$func_ltwrapper_executable_p_result" = "yes"
+}
+
+# func_ltwrapper_temp_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_temp_scriptname ()
+{
+    func_ltwrapper_temp_scriptname_result=""
+    if func_ltwrapper_executable_p "$1"; then
+        func_dirname "$1"
+        func_basename "$1"
+        func_stripname '' '.exe' "$func_basename_result"
+       if test -z "$func_dirname_result"; then
+          
func_ltwrapper_temp_scriptname_result="./$objdir/${func_stripname_result}_ltshwrapperTMP"
+        else
+          
func_ltwrapper_temp_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapperTMP"
+        fi
+    fi     
+}
+
 # func_ltwrapper_p file
-# True iff FILE is a libtool wrapper script.
+# True iff FILE is a libtool wrapper script or wrapper executable
 # This function is only a basic sanity check; it will hardly flush out
 # determined imposters.
 func_ltwrapper_p ()
 {
-    func_lalib_p "$1"
+    func_ltwrapper_script_p "$1" || func_ltwrapper_execuable_p "$1"
 }
 
 
@@ -1649,11 +1697,17 @@
       -*) ;;
       *)
        # Do a test to see if this is really a libtool program.
-       if func_ltwrapper_p "$file"; then
-         func_source "$file"
-
+       if func_ltwrapper_script_p "$file"; then
+          func_source "$file"
          # Transform arg to wrapped name.
          file="$progdir/$program"
+        else
+          if func_ltwrapper_executable_p "$file"; then
+            func_ltwrapper_temp_scriptname "$file"
+           func_source "$func_ltwrapper_temp_scriptname_result"
+           # Transform arg to wrapped name.
+           file="$progdir/$program"
+          fi
        fi
        ;;
       esac
@@ -2085,14 +2139,19 @@
        # Do a test to see if this is really a libtool program.
        case $host in
        *cygwin*|*mingw*)
-           func_stripname '' '.exe' "$file"
-           wrapper=$func_stripname_result
+            if func_ltwrapper_executable_p "$file"; then
+             func_ltwrapper_temp_scriptname "$file"
+             wrapper="$func_ltwrapper_temp_scriptname_result"
+            else
+              func_stripname '' '.exe' "$file"
+              wrapper="$func_stripname_result"
+            fi
            ;;
        *)
            wrapper=$file
            ;;
        esac
-       if func_ltwrapper_p "$wrapper"; then
+       if func_ltwrapper_script_p "$wrapper"; then
          notinst_deplibs=
          relink_command=
 
@@ -2561,6 +2620,7 @@
   char *tmp_pathspec;
   char *actual_cwrapper_path;
   char *shwrapper_name;
+  intptr_t rval = 127;
   FILE *shwrapper;
 
   const char *dumpscript_opt = "--lt-dump-script";
@@ -2688,19 +2748,28 @@
            case $host_os in
              mingw*)
                cat <<EOF
-  execv ("$lt_newargv0", (const char * const *) newargz);
+  /* execv doesn't actually work on mingw as expected on unix */
+  rval = _spawnv (_P_WAIT, "$lt_newargv0", (const char * const *) newargz);
+  if (rval == -1)
+    {
+      /* failed to start process */
+      LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target 
\"$lt_newargv0\": errno = %d\n", errno)); 
+      return 127;
+    }
+  return rval;
+}
 EOF
                ;;
              *)
                cat <<EOF
   execv ("$lt_newargv0", newargz);
+  return rval; /* =127, but avoids unused variable warning */
+}
 EOF
                ;;
            esac
 
            cat <<"EOF"
-  return 127;
-}
 
 void *
 xmalloc (size_t num)
@@ -6708,8 +6777,13 @@
        esac
        case $host in
          *cygwin* | *mingw* )
-           output_name=`basename $output`
-           output_path=`dirname $output`
+           func_basename "$output"
+           output_name="$func_basename_result"
+           func_dirname "$output"
+           output_path="$func_dirname_result"
+           if test -z "$output_path"; then
+             output_path=.
+           fi
            cwrappersource="$output_path/$objdir/lt-$output_name.c"
            cwrapper="$output_path/$output_name.exe"
            $RM $cwrappersource $cwrapper
@@ -6717,19 +6791,30 @@
 
            func_emit_libtool_cwrapperexe_source > $cwrappersource
 
-         # we should really use a build-platform specific compiler
-         # here, but OTOH, the wrappers (shell script and this C one)
-         # are only useful if you want to execute the "real" binary.
-         # Since the "real" binary is built for $host, then this
-         # wrapper might as well be built for $host, too.
-         $opt_dry_run || $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource
+           # we should really use a build-platform specific compiler
+           # here, but OTOH, the wrappers (shell script and this C one)
+           # are only useful if you want to execute the "real" binary.
+           # Since the "real" binary is built for $host, then this
+           # wrapper might as well be built for $host, too.
+           $opt_dry_run || $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource
+
+           # Now, create the wrapper script for func_source use:
+           func_ltwrapper_temp_scriptname $cwrapper
+           $RM $func_ltwrapper_temp_scriptname_result
+           trap "$RM $func_ltwrapper_temp_scriptname_result; exit 
$EXIT_FAILURE" 1 2 15
+           $opt_dry_run || {
+             $cwrapper --lt-dump-script > 
$func_ltwrapper_temp_scriptname_result
+           }
+           chmod +x $func_ltwrapper_temp_scriptname_result
+         ;;
+         * )
+           $RM $output
+           trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+           func_emit_libtool_wrapper_script no > $output
+           chmod +x $output
          ;;
        esac
-       $RM $output
-       trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
-
-       func_emit_libtool_wrapper_script no > $output
-       chmod +x $output
       }
       exit $EXIT_SUCCESS
       ;;
@@ -7179,8 +7264,15 @@
          esac
          # Do a test to see if this is a libtool program.
          if func_ltwrapper_p "$file"; then
-           relink_command=
-           func_source $dir/$noexename
+            if func_ltwrapper_executable_p "$file"; then
+              func_ltwrapper_temp_scriptname "$file"
+              relink_command=
+              func_source $func_ltwrapper_temp_scriptname_result
+              rmfiles="$rmfiles $func_ltwrapper_temp_scriptname_result"
+            else
+             relink_command=
+             func_source $dir/$noexename
+            fi
 
            # note $name still contains .exe if it was in $file originally
            # as does the version of $file that was added into $rmfiles
Index: tests/destdir.at
===================================================================
RCS file: /cvsroot/libtool/libtool/tests/destdir.at,v
retrieving revision 1.5
diff -u -r1.5 destdir.at
--- tests/destdir.at    25 Mar 2007 12:12:43 -0000      1.5
+++ tests/destdir.at    10 Jun 2007 07:22:05 -0000
@@ -127,8 +127,8 @@
 LT_AT_EXEC_CHECK([$bindir/m])
 
 # TODO: make this more portable:
-if test "$OBJDUMP" != false && ($OBJDUMP -p $bindir/m) >/dev/null 2>&1; then
-  AT_CHECK([$OBJDUMP -p $bindir/m | $EGREP -i "R(UN)?PATH.*$DESTDIR"], [1])
+if test "$OBJDUMP" != false && ($OBJDUMP -p $bindir/m$EXEEXT) >/dev/null 2>&1; 
then
+  AT_CHECK([$OBJDUMP -p $bindir/m$EXEEXT | $EGREP -i "R(UN)?PATH.*$DESTDIR"], 
[1])
   . $libdir/liba.la
   set x $library_names
   lname=$2

reply via email to

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