# HG changeset patch # User "Yann E. MORIN" # Date 1251585358 -7200 # Node ID 0bcc7afb5d421135314e554a874b4794cbcce00e # Parent bb70615043cb8ac79d4502c31c80732077b3081d# Parent 0dce3a3986a16a203cb00c3a63526b416bee39c7 Merge the C wrapper. diff -r bb70615043cb -r 0bcc7afb5d42 config/toolchain.in --- a/config/toolchain.in Fri Aug 28 12:09:04 2009 +0200 +++ b/config/toolchain.in Sun Aug 30 00:35:58 2009 +0200 @@ -296,4 +296,42 @@ endif # CROSS_NATIVE || CANADIAN +# Kept as a separate if block, even if it could go into the above block, +# because it seems better. No real reason, only that it seems right... +if CANADIAN + +comment "Host specifics" + +choice + bool + prompt "| Install tools wrapper as:" + default TOOLS_WRAPPER_SHELL + +config TOOLS_WRAPPER_SCRIPT + bool + prompt "shell script" + help + If your host has a shell, then you should say 'Y' here, to use + a (very very simple) shell script as wrapper. + + See docs/overview.txt, section "Tools wrapper". + +config TOOLS_WRAPPER_EXEC + bool + prompt "executable" + help + If your host lacks a shell, then you should say 'Y' here, to use + an executable. + + See docs/overview.txt, section "Tools wrapper". + +endchoice + +config TOOLS_WRAPPER + string + default "script" if TOOLS_WRAPPER_SCRIPT + default "exec" if TOOLS_WRAPPER_EXEC + +endif # CROSS_NATIVE || CANADIAN + endmenu diff -r bb70615043cb -r 0bcc7afb5d42 docs/overview.txt --- a/docs/overview.txt Fri Aug 28 12:09:04 2009 +0200 +++ b/docs/overview.txt Sun Aug 30 00:35:58 2009 +0200 @@ -24,6 +24,8 @@ Stopping and restarting a build Testing all toolchains at once Overriding the number of // jobs + Note on // jobs + Tools wrapper Using the toolchain Toolchain types Internals @@ -145,7 +147,6 @@ simple: ./configure --local make - make install Now, *do not* remove crosstool-NG sources. They are needed to run crosstool-NG! Stay in the directory holding the sources, and run: @@ -382,6 +383,52 @@ refering to the number of // jobs when making the *components*. That is, we speak of the number of // jobs used to build gcc, glibc, and so on... +Tools wrapper | +--------------+ + +Starting with gcc-4.3 come two new dependencies: GMP and MPFR. With gcc-4.4, +come three new ones: GMP, PPL and CLooG/ppl. These are libraries that enable +advanced features to gcc. Additionally, some of the libraries can be used by +binutils and gdb. Unfortunately, not all systems on which crosstool-NG runs +have all of those libraries. And for those that do, the versions of those +libraries may be older than the version required by gcc. + +This is why crosstool-NG builds its own set of libraries as part of the +toolchain. + +The libraries are built as shared libraries, because building them as static +libraries has some short-comings. This poses no problem at build time, as +crosstool-NG correctly points gcc (and binutiols and gdb) to the correct +place where our own version of the libraries are installed. But it poses +a problem when gcc et al. are run: the place where the libraries are is most +probably not known to the host dynamic linker. Still worse, if the host system +has its own versions, then ld.so would load the wrong library! + +So we have to force the dynamic linker to load the correct version. We do this +by using the LD_LIBRARY_PATH variable, that informs the dynamic linker where +to look for shared libraries prior to searching its standard places. But we +can't impose that burden on all the system (because it'd be a nightmare to +configure, and because two tolchains on the same system may use different +versions of the libraries); so we have to do it on a per-toolchain basis. + +So we rename all binaries of the toolchain (by adding a dot '.' as their first +character), and add a small program, the so-called "tools wrapper", that +correctly sets LD_LIBRARY_PATH prior to running the real tool. + +First, the wrapper was written as a POSIX-compliant shell script. That shell +script is very simple, if not trivial, and works great. The only drawback is +that it does not work on host systems that lack a shell, for example the +MingW32 environment. To solve the issue, the wrapper has been re-written in C, +and compiled at build time. This C wrapper is much more complex than the shell +script, and although it sems to be working, it's been only lightly tested. +Some of the expected short-comings with this C wrapper are; + - multi-byte file names may not be handled correctly + - it's really big for what it does + +So, the default wrapper installed with your toolchain is the shell script. +If you know that your system is missing a shell, then you shall use the C +wrapper (and report back whether it works, or does not work, for you). + _______________________ / diff -r bb70615043cb -r 0bcc7afb5d42 scripts/build/internals.sh --- a/scripts/build/internals.sh Fri Aug 28 12:09:04 2009 +0200 +++ b/scripts/build/internals.sh Sun Aug 30 00:35:58 2009 +0200 @@ -46,9 +46,25 @@ CT_DoLog EXTRA "Installing toolchain wrappers" CT_Pushd "${CT_PREFIX_DIR}/bin" - # Copy the wrapper - CT_DoExecLog DEBUG install -m 0755 "${CT_LIB_DIR}/scripts/wrapper.in" \ - ".${CT_TARGET}-wrapper" + # Install the wrapper + case "${CT_TOOLS_WRAPPER}" in + script) + CT_DoExecLog DEBUG install \ + -m 0755 \ + "${CT_LIB_DIR}/scripts/wrapper.in" \ + ".${CT_TARGET}-wrapper" + ;; + exec) + _t="-s" + if [ "${CT_DEBUG_CT}" = "y" ]; then + _t="" # If debugging crosstool-NG, don't strip the wrapper + fi + CT_DoExecLog "${HOST_CC}" \ + -Wall -Wextra -Wunreachable-code -Werror \ + -O3 -static ${_t} \ + -o ".${CT_TARGET}-wrapper" + ;; + esac # Replace every tools with the wrapper # Do it unconditionally, even for those tools that happen to be shell diff -r bb70615043cb -r 0bcc7afb5d42 scripts/wrapper.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/wrapper.c Sun Aug 30 00:35:58 2009 +0200 @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Needed for execve */ +extern char **environ; + +int main( int argc, + char** argv ) +{ + char *fullname; /* 'fullname' is used to store the absolute path to the + tool being executed; it serves as a base to compute + the realname of that tool, and the directory holding + our runtime libraries */ + char *realname; /* 'realname' is the real name of the tool, that is what + the wrapper is currently impersonating */ + char *basedir; /* 'libdir' contains our runtime libraries */ + + char *lastslash; /* Temporary variables now */ + char *ldlibpath; + size_t len; + int execve_ret; + + /* In case we have a relative or absolute pathname (ie. contains a slash), + * then realpath wll work. But if the tool was found in the PATH, realpath + * won't work, and we'll have to search ourselves. + * This if{}else{} block allocates memory for fullname. */ + if( strchr( argv[0], '/' ) ) { + fullname = (char*) malloc( PATH_MAX * sizeof(char) ); + if( ! realpath( argv[0], fullname ) ) { + perror( "tool wrapper" ); + exit( 1 ); + } + } else { + char *path; + char *mypath; + char *colon; + char *testname; + struct stat st; + + fullname = NULL; + colon = mypath = path = strdup( getenv( "PATH" ) ); + while( colon ) { + colon = strchr( mypath, ':' ); + if( colon ) { + *colon = '\0'; + } + testname = strdup( mypath ); + testname = (char*) realloc( testname, strlen( testname ) + + strlen( argv[0] ) + + 2 * sizeof(char) ); + memset( testname + strlen( testname ), + 0, + strlen( argv[0] ) + 2 * sizeof(char) ); + strcat( testname, "/" ); + strcat( testname, argv[0] ); + if( stat( testname, &st ) == 0 ) { + /* OK, exists. Is it a regular file, or a + * symlink, which the current user may execute? */ + if( S_ISREG( st.st_mode ) && ! access( testname, X_OK || R_OK ) ) { + fullname = strdup( testname ); + break; + } + } + free( testname ); + mypath = colon + 1; + } + free( path ); + if( ! fullname ) { + fprintf( stderr, "tool wrapper: %s: command not found\n", argv[0] ); + exit( 1 ); + } + } + + /* Duplicate my own name to add the 'dot' to tool name */ + realname = strdup( fullname ); + realname = (char*) realloc( realname, strlen( realname) + 2 * sizeof(char) ); + realname[ strlen( realname ) + 1 ] = '\0'; + + /* Add the dot after the last '/' */ + lastslash = strrchr( realname, '/' ); + memmove( lastslash + 1, lastslash, strlen( lastslash ) ); + *( lastslash + 1 ) = '.'; + + /* Compute the basedir of the tool */ + basedir = strdup( fullname ); + lastslash = strrchr( basedir, '/' ); + *lastslash = '\0'; + lastslash = strrchr( basedir, '/' ); + *lastslash = '\0'; + + /* Append '/lib' */ + len = strlen( basedir ); + basedir = (char*) realloc( basedir, len + 5 ); + *( basedir + len ) = '\0'; + strcat( basedir, "/lib" ); + + /* Now add the directory with our runtime libraries to the + front of the library search path, LD_LIBRARY_PATH */ + ldlibpath = getenv( "LD_LIBRARY_PATH" ); + if( ldlibpath ) { + basedir = (char*) realloc( basedir, strlen( basedir ) + + strlen( ldlibpath ) + + 2 * sizeof(char) ); + strcat( basedir, ":" ); + strcat( basedir, ldlibpath ); + } + + if( setenv( "LD_LIBRARY_PATH", basedir, 1 ) ) { + errno = ENOMEM; + perror( "tool wrapper" ); + exit( 1 ); + } + + /* Execute the real tool, now */ + execve_ret = execve( realname, argv, environ ); + + /* In case something went wrong above, print a + diagnostic message, and exit with error code 1 */ + perror( "tool wrapper" ); + return 1; +}