[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[cygwin] cwrapper emits wrapper script
From: |
Charles Wilson |
Subject: |
[cygwin] cwrapper emits wrapper script |
Date: |
Fri, 20 Apr 2007 21:03:02 -0400 |
User-agent: |
Thunderbird 1.5.0.10 (Windows/20070221) |
This patch depends on this one:
http://lists.gnu.org/archive/html/libtool-patches/2007-04/msg00048.html
With this patch, on cygwin/mingw the wrapper script created by libtool
in '.' is used only for reading back in via func_source(); THIS copy of
the wrapper script is not used during the "run the uninstalled target"
sequence *at all*.
In existing libtool, on cygwin/mingw, the following files are created:
foo.exe -- a wrapper executable, that launches...
foo -- a wrapper scripts, which sets env vars and launches...
.libs/foo.exe -- the actual target executable
However, the presence of both foo and foo.exe in the same directory
causes some problems with coreutils/shells' "autodetect .exe's" logic.
And it's downright unusable when the cygwin "transparent_exe" option is
active. So, eventually we want to eliminate ./foo entirely on these
platforms, and rely entirely on ./foo.exe and .libs/foo.exe (with
perhaps some other files in .libs/)
With this patch, after a successful build the following files are created:
foo.exe -- the wrapper executable. It does NOT launch the
wrapper script 'foo' in thisdir (.)
foo -- a wrapper script. It could be used to launch the
target executable, but isn't normally used for that.
This wrapper is sourced by func_source() when
necessary.
.libs/foo.exe -- the target executable
When the wrapper foo.exe is launched, it generates a new wrapper script
.libs/foo_ltshwrapper
which is identical [1] to the one in the "real" directory (./foo). Then,
the executable wrapper execs THAT new wrapper script, which sets the env
vars and execs the real target.
At present, the .libs/foo_ltwrappersh is recreated every single time the
wrapper executable is run; later, timestamps could be used to avoid
this, but that's an optimization.
Furthermore, the wrapper executable can be invoked with the
'-ltdumpscript' option, which will emit the script on *stdout*. This is
intended for future progress toward eliminating the ./foo wrapper script
entirely, on cygwin/mingw.
[1] This patch changes the *all* wrapper scripts on all platforms by
adding the following:
WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
... remove "/.libs" from $thisdir ...
fi
The ./foo wrapper (and all wrappers on non-cygwin/mingw) looks just like
the above, so the additional code is permanently disabled. However, the
script emitted by the wrapper executable on cygwin/mingw is modified so
that WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=yes, activating the additional
code. This is because the script needs to compute "$thisdir" as being
the main directory, in which .libs/* exists.
Also: as it happens, currently under cygwin AND mingw, the executable
wrapper is *not used* unless explicitly invoked with the .exe ending.
Since the tests do not do so, the executable wrappers have not been
exercised on either platform for a while. They do still work on cygwin,
but not mingw: calling the msvcrt.dll version of execv("/bin/sh", ...)
doesn't work. (The testsuite on mingw has been passing because the MSYS
shell launches the wrapper *script* directly, instead of the wrapper
executable). This patch ALSO fixes the wrapper executable on mingw, by
DOS-izing "/bin/sh" when emitting those lines of the executable
wrapper's source code.
POSSIBLE LIMITATION:
assumes that if S_ISLNK is defined, then $host has lstat() and
realpath(). Since the only place this matters (at present) is cygwin
and mingw, this assumption is safe: cygwin has all three, mingw has
none. The new code [chase_symlinks()] which makes this assumption was
added so that symlinks to the wrapper executable would work as expected
(on systems where symlinks exist) just like symlinks to the wrapper
script work.
TESTING:
___________________________________________________________
Tested on cygwin (full testsuite) with expected results:
======================
All 115 tests passed
(9 tests were not run) [no gfortran]
======================
14: Java convenience archives FAILED (convenience.at:273)
16: Link order of deplibs. FAILED (link-order2.at:129)
49: Run tests with low max_cmd_len FAILED (cmdline_wrap.at:42)
This is the expected output, for now.
___________________________________________________________
Linux, full testsuite:
======================
All 105 tests passed
(1 tests were not run)
======================
37: compiling softlinked libltdl FAILED (nonrecursive.at:90)
38: compiling copied libltdl FAILED (nonrecursive.at:114)
39: installable libltdl FAILED (nonrecursive.at:140)
40: compiling softlinked libltdl FAILED (recursive.at:67)
41: compiling copied libltdl FAILED (recursive.at:87)
42: installable libltdl FAILED (recursive.at:109)
Each of these looks like:
configure:10874: error: possibly undefined macro: AS_CASE
If this token and others are legitimate, please use m4_pattern_allow.
See the Autoconf documentation.
configure:10881: error: possibly undefined macro: AS_IF
stdout:
../../libtool-2.1a/tests/nonrecursive.at:90: exit code was 1, expected 0
37. nonrecursive.at:78: 37. compiling softlinked libltdl
(nonrecursive.at:78): FAILED (nonrecursive.at:90)
I don't think this error is germane; my linux box has autoconf-2.59 and
automake-1.9.4 but I was using a dist-bzip2 package created from cygwin
with autoconf-2.61 and automake-1.10. I do not know why, on linux,
these tests complain about AS_CASE and AS_IF: those macros *are* defined
in /usr/share/autoconf/m4sugar/m4sh.m4. Speculation: conflict between
older versions on target system, and newer version used to configure the
package. Judging by the old-tests, and the fact that the only part that
could affect linux is the additions to the wrapper script -- and those
are permanently disabled thanks to WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no,
I surmise this patch has no deleterious impact on any non-cygwin/mingw
system.
___________________________________________________________
mingw (old tests only because no dejagnu)
====================================
1 of 114 tests failed
(10 tests were not run)
Please report to address@hidden
====================================
Failed test was: tests/mdemo-dryrun.test -- false alarm:
$ diff before after
66c66
< drwxr-xr-x 2 cwilson Administ 0 Apr 20 2007 bin
---
> drwxr-xr-x 2 cwilson Administ 0 Apr 20 20:29 bin
Probably need another 'sleep 1' somewhere, but that's outside the scope
of this patch.
___________________________________________________________
ChangeLog:
2007-04-20 Charles Wilson <address@hidden>
* ltmain.m4sh (func_emit_libtool_wrapper_script): add
code block to handle cases when wrapper script is in $objdir.
(func_emit_libtool_cwrapperexe_source): replace DEBUG() macro
with namespace-safe LTWRAPPER_DEBUGPRINTF(). Call
func_emit_libtool_wrapper_script() with appropriate filters to
embed script text in C char* static variable.
(f_e_l_c_s: main): add new option -ltdumpscript, parse argv[]
for it, and take appropriate action. Call chase_symlinks()
on argv[0], in case this.exe was launched via one. Use chased
value to determine full absolute pathname of wrapper script, in
$objdir. Unconditionally write script out to this pathname and
set permission bits.
(f_e_l_c_s: main) [mingw]: DOS-ize $SHELL before populating
newargv[0]. Ensure newargv[1] (wrapper script absolute path)
uses only '/', not '\'. Make sure to call execv() with DOS-ized
$SHELL.
(f_e_l_c_s: make_executable): new function
(f_e_l_c_s: chase_symlinks): new function (no-op if !S_ISLNK)
--
Chuck
Index: libltdl/config/ltmain.m4sh
===================================================================
RCS file: /cvsroot/libtool/libtool/libltdl/config/ltmain.m4sh,v
retrieving revision 1.72
diff -u -r1.72 ltmain.m4sh
--- libltdl/config/ltmain.m4sh 2007-04-19 19:54:53.500000000 -0400
+++ libltdl/config/ltmain.m4sh 2007-04-20 03:20:46.281250000 -0400
@@ -2301,6 +2301,20 @@
file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
done
+ # cygwin/mingw cwrapper will rewrite this line:
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
+ if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+ # special case for '.'
+ if test \"\$thisdir\" = \".\"; then
+ thisdir=\`pwd\`
+ fi
+ # remove .libs from thisdir
+ case \"\$thisdir\" in
+ *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e
's%[\\\\/][^\\\\/]*$%%'\` ;;
+ $objdir ) thisdir=. ;;
+ esac
+ fi
+
# Try to get the absolute directory name.
absdir=\`cd \"\$thisdir\" && pwd\`
test -n \"\$absdir\" && thisdir=\"\$absdir\"
@@ -2424,7 +2438,7 @@
This wrapper executable should never be moved out of the build directory.
If it is, it will not operate correctly.
- Currently, it simply execs the wrapper *script* "/bin/sh $output",
+ Currently, it simply execs the wrapper *script* "$SHELL $output",
but could eventually absorb all of the scripts functionality and
exec $objdir/$outputname directly.
*/
@@ -2438,6 +2452,7 @@
#include <assert.h>
#include <string.h>
#include <ctype.h>
+#include <errno.h>
#include <sys/stat.h>
#if defined(PATH_MAX)
@@ -2482,12 +2497,11 @@
if (stale) { free ((void *) stale); stale = 0; } \
} while (0)
-/* -DDEBUG is fairly common in CFLAGS. */
-#undef DEBUG
+#undef LTWRAPPER_DEBUGPRINTF
#if defined DEBUGWRAPPER
-# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__)
+# define LTWRAPPER_DEBUGPRINTF(format, ...) fprintf(stderr, format,
__VA_ARGS__)
#else
-# define DEBUG(format, ...)
+# define LTWRAPPER_DEBUGPRINTF(format, ...)
#endif
const char *program_name = NULL;
@@ -2496,41 +2510,156 @@
char * xstrdup (const char *string);
const char * base_name (const char *name);
char * find_executable(const char *wrapper);
+char * chase_symlinks(const char *pathspec);
+int make_executable(const char *path);
int check_executable(const char *path);
char * strendzap(char *str, const char *pat);
void lt_fatal (const char *message, ...);
+static const char* script_text =
+EOF
+
+ func_emit_libtool_wrapper_script |\
+ $SED -e 's/\([\\"]\)/\\\1/g' |\
+ $SED -e 's/\(WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\)=.*/\1=yes/' |\
+ $SED -e 's/^/"/' -e 's/$/\\n"/'
+ $ECHO ";"
+
+ cat <<EOF
int
main (int argc, char *argv[])
{
char **newargz;
+ char *tmp_pathspec;
+ char *actual_cwrapper_path;
+ char *shwrapper_name;
+ FILE *shwrapperFILE;
+
+ const char* dumpscript_opt = "-ltdumpscript";
+ size_t dumpscript_len = strlen(dumpscript_opt);
int i;
program_name = (char *) xstrdup (base_name (argv[0]));
- DEBUG("(main) argv[0] : %s\n",argv[0]);
- DEBUG("(main) program_name : %s\n",program_name);
+ LTWRAPPER_DEBUGPRINTF("(main) argv[0] : %s\n",argv[0]);
+ LTWRAPPER_DEBUGPRINTF("(main) program_name : %s\n",program_name);
+
+ /* very simple arg parsing; don't want to rely on getopt */
+ for (i=1; i<argc; i++)
+ {
+ if (strncmp(argv[i], dumpscript_opt, dumpscript_len) == 0)
+ {
+ printf("%s", script_text);
+ return 0;
+ }
+ }
+
newargz = XMALLOC(char *, argc+2);
EOF
- cat <<EOF
+ case $host_os in
+ mingw*)
+ # such a shame msys has no cygpath-like program...
+ lt_mingwSHELL_prog=`basename $SHELL`;
+ lt_mingwSHELL_prog_noEXE=`$ECHO "X${lt_mingwSHELL_prog}" |
$Xsed -e 's%.exe$%%'`
+ if test -n "$lt_mingwSHELL_prog_noEXE" ; then
+ lt_mingwSHELL_progEXE="${lt_mingwSHELL_prog_noEXE}.exe"
+ else
+ # best guess
+ lt_mingwSHELL_progEXE="sh.exe"
+ fi
+
+ lt_mingwSHELL_dir=`dirname $SHELL`;
+ lt_mingwSHELL_wdir=`cd $lt_mingwSHELL_dir && pwd -W`
+ if test -z "$lt_mingwSHELL_wdir"; then
+ # best guess
+ lt_mingwSHELL_wdir=`cd /bin && pwd -W`
+ fi
+ lt_mingwSHELL_mdir=`$ECHO "X${lt_mingwSHELL_wdir}" | $Xsed -e
's%\\\\%/%g'`
+ lt_mingwSHELL="$lt_mingwSHELL_mdir/$lt_mingwSHELL_progEXE"
+
+ cat <<EOF
+ newargz[0] = (char *) xstrdup("$lt_mingwSHELL");
+EOF
+ ;;
+ *)
+ cat <<EOF
newargz[0] = (char *) xstrdup("$SHELL");
EOF
+ ;;
+ esac
cat <<"EOF"
- newargz[1] = find_executable(argv[0]);
- if (newargz[1] == NULL)
+ tmp_pathspec = find_executable (argv[0]);
+ if (tmp_pathspec == NULL)
lt_fatal("Couldn't find %s", argv[0]);
- DEBUG("(main) found exe at : %s\n",newargz[1]);
- /* we know the script has the same name, without the .exe */
- /* so make sure newargz[1] doesn't end in .exe */
- strendzap(newargz[1],".exe");
+ LTWRAPPER_DEBUGPRINTF("(main) found exe (before symlink chase) at :
%s\n",tmp_pathspec);
+
+ actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+ LTWRAPPER_DEBUGPRINTF("(main) found exe (after symlink chase) at :
%s\n",actual_cwrapper_path);
+ XFREE(tmp_pathspec);
+
+ shwrapper_name = (char *) xstrdup (base_name (actual_cwrapper_path));
+ strendzap( actual_cwrapper_path, shwrapper_name );
+
+ /* shwrapper_name transforms */
+ strendzap(shwrapper_name,".exe");
+ tmp_pathspec = XMALLOC( char, strlen ( shwrapper_name ) +
+ strlen ( "_ltshwrapper" ) + 1 );
+ strcpy ( tmp_pathspec, shwrapper_name );
+ strcat ( tmp_pathspec, "_ltshwrapper" );
+ XFREE( shwrapper_name );
+ shwrapper_name = tmp_pathspec;
+ tmp_pathspec = 0;
+ LTWRAPPER_DEBUGPRINTF("(main) libtool shell wrapper name:
%s\n",shwrapper_name);
+EOF
+
+ cat <<EOF
+ newargz[1] = XMALLOC( char, strlen ( actual_cwrapper_path ) +
+ strlen ( "$objdir" ) + 1 +
+ strlen ( shwrapper_name ) + 1 );
+ strcpy ( newargz[1], actual_cwrapper_path );
+ strcat ( newargz[1], "$objdir" );
+ strcat ( newargz[1], "/" );
+ strcat ( newargz[1], shwrapper_name );
+EOF
+
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ {
+ char* p = newargz[1];
+ while(*p!='\0') {
+ if (*p == '\\') {
+ *p = '/';
+ }
+ p++;
+ }
+ }
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+ XFREE( shwrapper_name );
+ XFREE( actual_cwrapper_path );
+
+ if ( (shwrapperFILE = fopen (newargz[1], "wb")) == 0 )
+ {
+ lt_fatal("Could not open %s for writing", newargz[1]);
+ }
+ fprintf (shwrapperFILE, "%s", script_text);
+ fclose (shwrapperFILE);
+
+ make_executable( newargz[1] );
+
for (i = 1; i < argc; i++)
newargz[i+1] = xstrdup(argv[i]);
newargz[argc+1] = NULL;
for (i=0; i<argc+1; i++)
{
- DEBUG("(main) newargz[%d] : %s\n",i,newargz[i]);
+ LTWRAPPER_DEBUGPRINTF("(main) newargz[%d] : %s\n",i,newargz[i]);
;
}
@@ -2539,7 +2668,7 @@
case $host_os in
mingw*)
cat <<EOF
- execv("$SHELL",(char const **)newargz);
+ execv("$lt_mingwSHELL",(const char * const *)newargz);
EOF
;;
*)
@@ -2592,7 +2721,7 @@
{
struct stat st;
- DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") :
"NULL!");
+ LTWRAPPER_DEBUGPRINTF("(check_executable) : %s\n", path ? (*path ? path :
"EMPTY!") : "NULL!");
if ((!path) || (!*path))
return 0;
@@ -2612,8 +2741,37 @@
return 0;
}
+int
+make_executable(const char * path)
+{
+ int rval = 0;
+ struct stat st;
+
+ /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */
+ int S_XFLAGS =
+#if defined (S_IXOTH)
+ S_IXOTH ||
+#endif
+#if defined (S_IXGRP)
+ S_IXGRP ||
+#endif
+ S_IXUSR;
+
+ LTWRAPPER_DEBUGPRINTF("(make_executable) : %s\n", path ? (*path ? path :
"EMPTY!") : "NULL!");
+ if ((!path) || (!*path))
+ return 0;
+
+ if (stat (path, &st) >= 0)
+ {
+ rval = chmod ( path, st.st_mode | S_XFLAGS );
+ }
+ return rval;
+}
+
/* Searches for the full path of the wrapper. Returns
- newly allocated full path name if found, NULL otherwise */
+ newly allocated full path name if found, NULL otherwise
+ Does not chase symlinks, even on platforms that support them.
+*/
char *
find_executable (const char* wrapper)
{
@@ -2625,7 +2783,7 @@
int tmp_len;
char* concat_name;
- DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!")
: "NULL!");
+ LTWRAPPER_DEBUGPRINTF("(find_executable) : %s\n", wrapper ? (*wrapper ?
wrapper : "EMPTY!") : "NULL!");
if ((wrapper == NULL) || (*wrapper == '\0'))
return NULL;
@@ -2715,6 +2873,62 @@
}
char *
+chase_symlinks(const char *pathspec)
+{
+#ifndef S_ISLNK
+ return xstrdup ( pathspec );
+#else
+ char buf[LT_PATHMAX];
+ struct stat s;
+ int rv = 0;
+ char* tmp_pathspec = xstrdup (pathspec);
+ char* p;
+ int has_symlinks = 0;
+ while (strlen(tmp_pathspec) && !has_symlinks)
+ {
+ LTWRAPPER_DEBUGPRINTF("checking path component for symlinks: %s\n",
tmp_pathspec);
+ if (lstat (tmp_pathspec, &s) == 0)
+ {
+ if (S_ISLNK(s.st_mode) != 0)
+ {
+ has_symlinks = 1;
+ break;
+ }
+
+ /* search backwards for last DIR_SEPARATOR */
+ p = tmp_pathspec + strlen(tmp_pathspec) - 1;
+ while ( (p > tmp_pathspec) && (! IS_DIR_SEPARATOR(*p)) )
+ p--;
+ if ( (p == tmp_pathspec) && (! IS_DIR_SEPARATOR(*p)) )
+ {
+ /* no more DIR_SEPARATORS left */
+ break;
+ }
+ *p = '\0';
+ }
+ else
+ {
+ char* errstr = strerror(errno);
+ lt_fatal("Error accessing file %s (%s)", tmp_pathspec, errstr);
+ }
+ }
+ XFREE(tmp_pathspec);
+
+ if (!has_symlinks)
+ {
+ return xstrdup ( pathspec );
+ }
+
+ tmp_pathspec = realpath ( pathspec, buf );
+ if (tmp_pathspec == 0)
+ {
+ lt_fatal("Could not follow symlinks for %s", pathspec);
+ }
+ return xstrdup ( tmp_pathspec );
+#endif
+}
+
+char *
strendzap(char *str, const char *pat)
{
size_t len, patlen;
- [cygwin] cwrapper emits wrapper script,
Charles Wilson <=
- Re: [cygwin] cwrapper emits wrapper script, Ralf Wildenhues, 2007/04/23
- Re: [cygwin] cwrapper emits wrapper script, Charles Wilson, 2007/04/23
- Re: [cygwin] cwrapper emits wrapper script, Charles Wilson, 2007/04/24
- Re: [cygwin] cwrapper emits wrapper script, Ralf Wildenhues, 2007/04/25
- Re: [cygwin] cwrapper emits wrapper script, libtool, 2007/04/25
- Re: [cygwin] cwrapper emits wrapper script, Ralf Wildenhues, 2007/04/26
Re: [cygwin] cwrapper emits wrapper script, Charles Wilson, 2007/04/27