Merge the C wrapper.

This commit is contained in:
Yann E. MORIN" 2009-08-30 00:35:58 +02:00
commit b7b6314a81
4 changed files with 233 additions and 4 deletions

View File

@ -296,4 +296,42 @@ config TARGET_SUFFIX
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

View File

@ -24,6 +24,8 @@ Running crosstool-NG
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 @@ If you go the hacker's way, then the usage is a bit different, although very
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 @@ in parallel (there is not much to gain). When speaking of // jobs, we are
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).
_______________________
/

View File

@ -46,9 +46,25 @@ do_finish() {
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

128
scripts/wrapper.c Normal file
View File

@ -0,0 +1,128 @@
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
/* 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;
}