mirror of
https://github.com/crosstool-ng/crosstool-ng.git
synced 2024-12-19 04:47:52 +00:00
Merge the C wrapper.
This commit is contained in:
commit
b7b6314a81
@ -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
|
||||
|
@ -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).
|
||||
|
||||
|
||||
_______________________
|
||||
/
|
||||
|
@ -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
128
scripts/wrapper.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user