Merge the C wrapper.
author"Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Aug 30 00:35:58 2009 +0200 (2009-08-30)
changeset 14940bcc7afb5d42
parent 1490 bb70615043cb
parent 1493 0dce3a3986a1
child 1495 2542421e3321
Merge the C wrapper.
     1.1 --- a/config/toolchain.in	Fri Aug 28 12:09:04 2009 +0200
     1.2 +++ b/config/toolchain.in	Sun Aug 30 00:35:58 2009 +0200
     1.3 @@ -296,4 +296,42 @@
     1.4  
     1.5  endif # CROSS_NATIVE || CANADIAN
     1.6  
     1.7 +# Kept as a separate if block, even if it could go into the above block,
     1.8 +# because it seems better. No real reason, only that it seems right...
     1.9 +if CANADIAN
    1.10 +
    1.11 +comment "Host specifics"
    1.12 +
    1.13 +choice
    1.14 +    bool
    1.15 +    prompt "|  Install tools wrapper as:"
    1.16 +    default TOOLS_WRAPPER_SHELL
    1.17 +
    1.18 +config TOOLS_WRAPPER_SCRIPT
    1.19 +    bool
    1.20 +    prompt "shell script"
    1.21 +    help
    1.22 +      If your host has a shell, then you should say 'Y' here, to use
    1.23 +      a (very very simple) shell script as wrapper.
    1.24 +      
    1.25 +      See docs/overview.txt, section "Tools wrapper".
    1.26 +
    1.27 +config TOOLS_WRAPPER_EXEC
    1.28 +    bool
    1.29 +    prompt "executable"
    1.30 +    help
    1.31 +      If your host lacks a shell, then you should say 'Y' here, to use
    1.32 +      an executable.
    1.33 +      
    1.34 +      See docs/overview.txt, section "Tools wrapper".
    1.35 +
    1.36 +endchoice
    1.37 +
    1.38 +config TOOLS_WRAPPER
    1.39 +    string
    1.40 +    default "script" if TOOLS_WRAPPER_SCRIPT
    1.41 +    default "exec"   if TOOLS_WRAPPER_EXEC
    1.42 +
    1.43 +endif # CROSS_NATIVE || CANADIAN
    1.44 +
    1.45  endmenu
     2.1 --- a/docs/overview.txt	Fri Aug 28 12:09:04 2009 +0200
     2.2 +++ b/docs/overview.txt	Sun Aug 30 00:35:58 2009 +0200
     2.3 @@ -24,6 +24,8 @@
     2.4    Stopping and restarting a build
     2.5    Testing all toolchains at once
     2.6    Overriding the number of // jobs
     2.7 +  Note on // jobs
     2.8 +  Tools wrapper
     2.9  Using the toolchain
    2.10  Toolchain types
    2.11  Internals
    2.12 @@ -145,7 +147,6 @@
    2.13  simple:
    2.14    ./configure --local
    2.15    make
    2.16 -  make install
    2.17  
    2.18  Now, *do not* remove crosstool-NG sources. They are needed to run crosstool-NG!
    2.19  Stay in the directory holding the sources, and run:
    2.20 @@ -382,6 +383,52 @@
    2.21  refering to the number of // jobs when making the *components*. That is, we
    2.22  speak of the number of // jobs used to build gcc, glibc, and so on...
    2.23  
    2.24 +Tools wrapper |
    2.25 +--------------+
    2.26 +
    2.27 +Starting with gcc-4.3 come two new dependencies: GMP and MPFR. With gcc-4.4,
    2.28 +come three new ones: GMP, PPL and CLooG/ppl. These are libraries that enable
    2.29 +advanced features to gcc. Additionally, some of the libraries can be used by
    2.30 +binutils and gdb. Unfortunately, not all systems on which crosstool-NG runs
    2.31 +have all of those libraries. And for those that do, the versions of those
    2.32 +libraries may be older than the version required by gcc.
    2.33 +
    2.34 +This is why crosstool-NG builds its own set of libraries as part of the
    2.35 +toolchain.
    2.36 +
    2.37 +The libraries are built as shared libraries, because building them as static
    2.38 +libraries has some short-comings. This poses no problem at build time, as
    2.39 +crosstool-NG correctly points gcc (and binutiols and gdb) to the correct
    2.40 +place where our own version of the libraries are installed. But it poses
    2.41 +a problem when gcc et al. are run: the place where the libraries are is most
    2.42 +probably not known to the host dynamic linker. Still worse, if the host system
    2.43 +has its own versions, then ld.so would load the wrong library!
    2.44 +
    2.45 +So we have to force the dynamic linker to load the correct version. We do this
    2.46 +by using the LD_LIBRARY_PATH variable, that informs the dynamic linker where
    2.47 +to look for shared libraries prior to searching its standard places. But we
    2.48 +can't impose that burden on all the system (because it'd be a nightmare to
    2.49 +configure, and because two tolchains on the same system may use different
    2.50 +versions of the libraries); so we have to do it on a per-toolchain basis.
    2.51 +
    2.52 +So we rename all binaries of the toolchain (by adding a dot '.' as their first
    2.53 +character), and add a small program, the so-called "tools wrapper", that
    2.54 +correctly sets LD_LIBRARY_PATH prior to running the real tool.
    2.55 +
    2.56 +First, the wrapper was written as a POSIX-compliant shell script. That shell
    2.57 +script is very simple, if not trivial, and works great. The only drawback is
    2.58 +that it does not work on host systems that lack a shell, for example the
    2.59 +MingW32 environment. To solve the issue, the wrapper has been re-written in C,
    2.60 +and compiled at build time. This C wrapper is much more complex than the shell
    2.61 +script, and although it sems to be working, it's been only lightly tested.
    2.62 +Some of the expected short-comings with this C wrapper are;
    2.63 + - multi-byte file names may not be handled correctly
    2.64 + - it's really big for what it does
    2.65 +
    2.66 +So, the default wrapper installed with your toolchain is the shell script.
    2.67 +If you know that your system is missing a shell, then you shall use the C
    2.68 +wrapper (and report back whether it works, or does not work, for you).
    2.69 +
    2.70  
    2.71  _______________________
    2.72                        /
     3.1 --- a/scripts/build/internals.sh	Fri Aug 28 12:09:04 2009 +0200
     3.2 +++ b/scripts/build/internals.sh	Sun Aug 30 00:35:58 2009 +0200
     3.3 @@ -46,9 +46,25 @@
     3.4          CT_DoLog EXTRA "Installing toolchain wrappers"
     3.5          CT_Pushd "${CT_PREFIX_DIR}/bin"
     3.6  
     3.7 -        # Copy the wrapper
     3.8 -        CT_DoExecLog DEBUG install -m 0755 "${CT_LIB_DIR}/scripts/wrapper.in"   \
     3.9 -                                           ".${CT_TARGET}-wrapper"
    3.10 +        # Install the wrapper
    3.11 +        case "${CT_TOOLS_WRAPPER}" in
    3.12 +            script)
    3.13 +                CT_DoExecLog DEBUG install                              \
    3.14 +                                   -m 0755                              \
    3.15 +                                   "${CT_LIB_DIR}/scripts/wrapper.in"   \
    3.16 +                                   ".${CT_TARGET}-wrapper"
    3.17 +                ;;
    3.18 +            exec)
    3.19 +                _t="-s"
    3.20 +                if [ "${CT_DEBUG_CT}" = "y" ]; then
    3.21 +                  _t="" # If debugging crosstool-NG, don't strip the wrapper
    3.22 +                fi
    3.23 +                CT_DoExecLog "${HOST_CC}"                               \
    3.24 +                             -Wall -Wextra -Wunreachable-code -Werror   \
    3.25 +                             -O3 -static ${_t}                          \
    3.26 +                             -o ".${CT_TARGET}-wrapper"
    3.27 +                ;;
    3.28 +        esac
    3.29  
    3.30          # Replace every tools with the wrapper
    3.31          # Do it unconditionally, even for those tools that happen to be shell
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/scripts/wrapper.c	Sun Aug 30 00:35:58 2009 +0200
     4.3 @@ -0,0 +1,128 @@
     4.4 +#include <limits.h>
     4.5 +#include <stdlib.h>
     4.6 +#include <stdio.h>
     4.7 +#include <string.h>
     4.8 +#include <sys/types.h>
     4.9 +#include <sys/stat.h>
    4.10 +#include <unistd.h>
    4.11 +#include <errno.h>
    4.12 +
    4.13 +
    4.14 +/* Needed for execve */
    4.15 +extern char **environ;
    4.16 +
    4.17 +int main( int argc,
    4.18 +          char** argv )
    4.19 +{
    4.20 +  char *fullname;   /* 'fullname' is used to store the absolute path to the
    4.21 +                       tool being executed; it serves as a base to compute
    4.22 +                       the realname of that tool, and the directory holding
    4.23 +                       our runtime libraries */
    4.24 +  char *realname;   /* 'realname' is the real name of the tool, that is what
    4.25 +                       the wrapper is currently impersonating */
    4.26 +  char *basedir;    /* 'libdir' contains our runtime libraries */
    4.27 +
    4.28 +  char *lastslash;  /* Temporary variables now */
    4.29 +  char *ldlibpath;
    4.30 +  size_t len;
    4.31 +  int execve_ret;
    4.32 +
    4.33 +  /* In case we have a relative or absolute pathname (ie. contains a slash),
    4.34 +   * then realpath wll work. But if the tool was found in the PATH, realpath
    4.35 +   * won't work, and we'll have to search ourselves.
    4.36 +   * This if{}else{} block allocates memory for fullname. */
    4.37 +  if( strchr( argv[0], '/' ) ) {
    4.38 +    fullname = (char*) malloc( PATH_MAX * sizeof(char) );
    4.39 +    if( ! realpath( argv[0], fullname ) ) {
    4.40 +      perror( "tool wrapper" );
    4.41 +      exit( 1 );
    4.42 +    }
    4.43 +  } else {
    4.44 +    char *path;
    4.45 +    char *mypath;
    4.46 +    char *colon;
    4.47 +    char *testname;
    4.48 +    struct stat st;
    4.49 +
    4.50 +    fullname = NULL;
    4.51 +    colon = mypath = path = strdup( getenv( "PATH" ) );
    4.52 +    while( colon ) {
    4.53 +      colon = strchr( mypath, ':' );
    4.54 +      if( colon ) {
    4.55 +        *colon = '\0';
    4.56 +      }
    4.57 +      testname = strdup( mypath );
    4.58 +      testname = (char*) realloc( testname,   strlen( testname )
    4.59 +                                            + strlen( argv[0] )
    4.60 +                                            + 2 * sizeof(char) );
    4.61 +      memset( testname + strlen( testname ),
    4.62 +              0,
    4.63 +              strlen( argv[0] ) + 2 * sizeof(char) );
    4.64 +      strcat( testname, "/" );
    4.65 +      strcat( testname, argv[0] );
    4.66 +      if( stat( testname, &st ) == 0 ) {
    4.67 +        /* OK, exists. Is it a regular file, or a
    4.68 +         * symlink, which the current user may execute? */
    4.69 +        if( S_ISREG( st.st_mode ) && ! access( testname, X_OK || R_OK ) ) {
    4.70 +          fullname = strdup( testname );
    4.71 +          break;
    4.72 +        }
    4.73 +      }
    4.74 +      free( testname );
    4.75 +      mypath = colon + 1;
    4.76 +    }
    4.77 +    free( path );
    4.78 +    if( ! fullname ) {
    4.79 +      fprintf( stderr, "tool wrapper: %s: command not found\n", argv[0] );
    4.80 +      exit( 1 );
    4.81 +    }
    4.82 +  }
    4.83 +
    4.84 +  /* Duplicate my own name to add the 'dot' to tool name */
    4.85 +  realname = strdup( fullname );
    4.86 +  realname = (char*) realloc( realname, strlen( realname) + 2 * sizeof(char) );
    4.87 +  realname[ strlen( realname ) + 1 ] = '\0';
    4.88 +
    4.89 +  /* Add the dot after the last '/' */
    4.90 +  lastslash = strrchr( realname, '/' );
    4.91 +  memmove( lastslash + 1, lastslash, strlen( lastslash ) );
    4.92 +  *( lastslash + 1 ) = '.';
    4.93 +
    4.94 +  /* Compute the basedir of the tool */
    4.95 +  basedir = strdup( fullname );
    4.96 +  lastslash = strrchr( basedir, '/' );
    4.97 +  *lastslash = '\0';
    4.98 +  lastslash = strrchr( basedir, '/' );
    4.99 +  *lastslash = '\0';
   4.100 +
   4.101 +  /* Append '/lib' */
   4.102 +  len = strlen( basedir );
   4.103 +  basedir = (char*) realloc( basedir, len + 5 );
   4.104 +  *( basedir + len ) = '\0';
   4.105 +  strcat( basedir, "/lib" );
   4.106 +
   4.107 +  /* Now add the directory with our runtime libraries to the
   4.108 +     front of the library search path, LD_LIBRARY_PATH */
   4.109 +  ldlibpath = getenv( "LD_LIBRARY_PATH" );
   4.110 +  if( ldlibpath ) {
   4.111 +    basedir = (char*) realloc( basedir,   strlen( basedir )
   4.112 +                                        + strlen( ldlibpath )
   4.113 +                                        + 2 * sizeof(char) );
   4.114 +    strcat( basedir, ":" );
   4.115 +    strcat( basedir, ldlibpath );
   4.116 +  }
   4.117 +
   4.118 +  if( setenv( "LD_LIBRARY_PATH", basedir, 1 ) ) {
   4.119 +    errno = ENOMEM;
   4.120 +    perror( "tool wrapper" );
   4.121 +    exit( 1 );
   4.122 +  }
   4.123 +
   4.124 +  /* Execute the real tool, now */
   4.125 +  execve_ret = execve( realname, argv, environ );
   4.126 +
   4.127 +  /* In case something went wrong above, print a
   4.128 +     diagnostic message, and exit with error code 1 */
   4.129 +  perror( "tool wrapper" );
   4.130 +  return 1;
   4.131 +}