summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/toolchain.in38
-rw-r--r--docs/overview.txt49
-rw-r--r--scripts/build/internals.sh22
-rw-r--r--scripts/wrapper.c128
4 files changed, 233 insertions, 4 deletions
diff --git a/config/toolchain.in b/config/toolchain.in
index ffa4f3e..0aae112 100644
--- a/config/toolchain.in
+++ b/config/toolchain.in
@@ -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
diff --git a/docs/overview.txt b/docs/overview.txt
index 740ac0a..1176352 100644
--- a/docs/overview.txt
+++ b/docs/overview.txt
@@ -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).
+
_______________________
/
diff --git a/scripts/build/internals.sh b/scripts/build/internals.sh
index a920c50..cf869a1 100644
--- a/scripts/build/internals.sh
+++ b/scripts/build/internals.sh
@@ -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
diff --git a/scripts/wrapper.c b/scripts/wrapper.c
new file mode 100644
index 0000000..dbbcdd9
--- /dev/null
+++ b/scripts/wrapper.c
@@ -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;
+}