From: Andreas Jaeger Date: Sat, 12 May 2001 15:44:22 +0000 (+0000) Subject: Initial submit X-Git-Tag: binary-mlb~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=92e49ffbe18ea47ce376851e25d8ba99932c04aa;p=thirdparty%2Flibtool.git Initial submit --- diff --git a/exe/ltmain.c b/exe/ltmain.c new file mode 100644 index 000000000..211791102 --- /dev/null +++ b/exe/ltmain.c @@ -0,0 +1,462 @@ +/* ltmain.c - C implementation of GNU Libtool + * + * Copyright (C) 1998-2000 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + * As a special exception to the GNU General Public License, if you + * distribute this file as part of a program that contains a + * configuration script generated by Autoconf, you may include it under + * the same distribution terms that you use for the rest of that program. + */ + +#include /* printf */ +#include /* exit */ +#include +#include +#include +#include +#include + +#include "ltopts.h" +#include "ltstr.h" +#include "ltconfig.x" + + +tSCC zFatalConfig[] = +"Fatal configuration error.\n\ +ltmain: not configured to build any kind of library\n\ +See the docs for more information.\n"; + +tSCC zBadOpt[] = "%s ERROR: option `--%s' invalid in this context\n"; +tSCC zBadMode[] = "%s ERROR: could not infer mode\n"; +tSCC zUnkn[] = "** UNKNOWN **"; +char zShell[ 256 ]; + +static const char* pz_cmd_name = (char*)NULL; +int scriptStatus = EXIT_SUCCESS; +int signalReceived = 0; + + +/* + * Handle SIGPIPE and SIGSEGV by telling emitScript() to call close. + */ + void +handleSignal( int signo ) +{ + signalReceived = signo; +} + + +/* + * Close script is called either right after a signal is handled above, + * or when we have finished writing to a popen-ed shell. If we get + * a signal on writes to stdout (rather than a popen-ed shell), then + * this routine will be called, too. However, it will choke. If that + * is a problem, then check `fp' for being stdout. + */ + void +closeScript( FILE* fp ) +{ + int scriptStatus = pclose( fp ); + + if (scriptStatus == -1) { + fprintf( stderr, "%s EXIT FAILURE: pclose returned %d (%s)\n", + ltmainOptions.pzProgName, errno, strerror( errno )); + scriptStatus = EXIT_FAILURE; + return; + } + + if (! WIFEXITED( scriptStatus )) { + fprintf( stderr, "%s EXIT FAILURE: %s did not exit - code %x\n", + ltmainOptions.pzProgName, pz_cmd_name, scriptStatus ); + scriptStatus = EXIT_FAILURE; + return; + } + + scriptStatus = WEXITSTATUS(scriptStatus); + if (scriptStatus != 0) { + fprintf( stderr, "%s BAD EXIT: %s exited %d\n", + ltmainOptions.pzProgName, pz_cmd_name, scriptStatus ); + return; + } + + switch (signalReceived) { + case 0: /* no signal received */ + case SIGPIPE: + /* + * SIGPIPE just means the script exited before we could + * write out everything. This is terribly ugly, but correct. Ick. + */ + scriptStatus = EXIT_SUCCESS; + break; + + default: + fprintf( stderr, "%s WRONG SIGNAL: %d\n", + ltmainOptions.pzProgName, signalReceived ); + scriptStatus = EXIT_FAILURE; + } +} + +/* + * The usage text varies a bit, depending on operational mode. + * Therefore, catch the usage call, do the variation and then + * finish up with the library routine. + */ + void +modalUsage( pOpts, exitCode ) + tOptions* pOpts; + int exitCode; +{ + tSCC zFmt[] = "%s --mode=%s"; + char z[ 256 ]; + + if (HAVE_OPT( MODE )) { + sprintf( z, zFmt, pOpts->pzProgName, + pOpts->pOptDesc[ OPT_VALUE_MODE ].pz_Name ); + pOpts->pzProgName = z; + pOpts->pzExplain = apz_mode_explain[ OPT_VALUE_MODE ]; + } + + optionUsage( pOpts, exitCode ); +} + + + void +validateMode( argct, argvec ) + int argct; + char** argvec; +{ + char* pzCmd = *argvec; + char* pzEnd = pzCmd + strlen( pzCmd ); + + if (HAVE_OPT( MODE )) + return; + + /* + * IF we don't even have two letters in our command, + * THEN we won't try to figure out what the command is supposed to be. + * Tandem's C compiler fails this test, however. + */ + if ((pzEnd - pzCmd) < 2) + return; + + do { + if ( ((pzEnd[-2] == 'c') && (pzEnd[-1] == 'c')) + || ((pzEnd[-2] == '+') && (pzEnd[-1] == '+')) + || (strncmp( pzCmd, "gcc", 3 ) == 0) + || (strstr( pzCmd, "-gcc" ) != (char*)NULL) ) + break; + + if ( (strcmp( pzEnd-2, "db" ) == 0) + || (strcmp( pzEnd-3, "dbx" ) == 0) + || (strcmp( pzEnd-6, "strace" ) == 0) + || (strcmp( pzEnd-5, "truss" ) == 0) ) { + SET_OPT_MODE( "execute" ); + return; + } + + if ( ((pzEnd[-2] == 'c') && (pzEnd[-1] == 'p')) + || ((pzEnd[-2] == 'm') && (pzEnd[-1] == 'v')) + || (strstr( pzCmd, "install" ) != (char*)NULL) ) { + SET_OPT_MODE( "install" ); + return; + } + + return; + } while (0); + + while (--argct > 0) { + if (strcmp( *++argvec, "-c" ) == 0) { + SET_OPT_MODE( "compile" ); + return; + } + } + + SET_OPT_MODE( "link" ); +} + + + void +emitShellQuoted( pzArg, outFp ) + tCC* pzArg; + FILE* outFp; +{ + for (;;) { + char ch = *(pzArg++); + switch (ch) { + case '\0': + return; + + case '\'': + fputs( "'\\'", outFp ); + while (*pzArg == '\'') { + fputs( "\\'", outFp ); + pzArg++; + } + /* FALLTHROUGH */ + + default: + fputc( ch, outFp ); + } + } +} + + + void +emitShellArg( pzArg, outFp ) + tCC* pzArg; + FILE* outFp; +{ + tSCC zMetas[] = "<>{}()[]|&^#~*;?$`'\"\\ \t\v\f\r\n"; + + if (strpbrk( pzArg, zMetas ) == (char*)NULL) { + fputs( pzArg, outFp ); + return; + } + + if (strchr( pzArg, '\'' ) == (char*)NULL) { + fprintf( outFp, "'%s'", pzArg ); + return; + } + + fputc( '\'', outFp ); + emitShellQuoted( pzArg, outFp ); + fputc( '\'', outFp ); +} + + + void +emitScript( argc, argv ) + int argc; + char** argv; +{ + tSCC zDbgFmt[] = "set -x\n"; + tSCC zQuiet[] = "run=\nshow=%s\n"; + tSCC zDynFmt[] = "build_libtool_libs=%s\n"; + tSCC zStatic[] = "build_old_libs=%s\n"; + tSCC zModeName[] = "modename='%s: %s'\n"; + tSCC zMode[] = "mode='%s'\n"; + tSCC zCmdName[] = "nonopt='%s'\nset --"; + tSCC zDlOpt[] = "execute_dlfiles='"; + + /* + * When we emit our script, we want the interpreter to invoke *US* + * if echo does not work right. + */ + tSCC zChkEcho[] = +"\n\nif test \"X`($echo '\\t') 2>/dev/null`\" = 'X\\t'\n\ +then :\n\ +else echo='%s --echo --' ; fi\n"; + + FILE* fp = HAVE_OPT( DRY_RUN ) ? stdout : popen( pz_shell, "w" ); + if (fp == (FILE*)NULL) { + tSCC zErr[] = "%s error: fs error %d (%s) on popen( \"%s\",\"w\")\n"; + fprintf( stderr, zErr, ltmainOptions.pzProgPath, errno, + strerror( errno ), pz_shell ); + exit( EXIT_FAILURE ); + } + +# define CKSERV if (signalReceived != 0) { \ + closeScript( fp ); if (scriptStatus == 0) scriptStatus = EXIT_FAILURE; \ + return; } + +# define CLOSEOK if (signalReceived != 0) { closeScript( fp ); return; } + + /* + * Emit the default configuration set up at program configuration time + */ + fputs( z_ltconfig, fp ); + CKSERV; + fputs( apz_mode_cmd[ 0 ], fp ); + CKSERV; + fprintf( fp, zChkEcho, ltmainOptions.pzProgPath ); + CKSERV; + + fprintf( fp, zQuiet, HAVE_OPT( QUIET ) ? ":" : "\"$echo\"" ); + CKSERV; + + /* + * IF we have DYNAMIC or STATIC, then we override the configured + * values. We emitted the configured values with `z_ltconfig'. + */ + if (HAVE_OPT( DYNAMIC )) + fprintf( fp, zDynFmt, ENABLED_OPT( DYNAMIC ) ? "yes" : "no" ); + if (HAVE_OPT( STATIC )) + fprintf( fp, zStatic, ENABLED_OPT( STATIC ) ? "yes" : "no" ); + + if (HAVE_OPT( DEBUG )) { + fprintf( stderr, "%s: enabling shell trace mode\n", + ltmainOptions.pzProgName ); + fputs( zDbgFmt, fp ); + } + CKSERV; + + if (HAVE_OPT( DLOPEN )) { + int ct = STACKCT_OPT( DLOPEN ); + char** al = STACKLST_OPT( DLOPEN ); + fputs( zDlOpt, fp ); + for (;;) { + emitShellQuoted( *(al++), fp ); + if (--ct <= 0) + break; + fputc( ' ', fp ); /* between each value only */ + } + fputs( "'\n", fp ); + } + CKSERV; + + /* + * Insert our modal stuff and one shell option processing dinkleberry + * that one of the command scripts depends upon. + */ + fprintf( fp, zModeName, ltmainOptions.pzProgName, + ltmainOptions.pOptDesc[ WHICH_OPT_COMPILE ].pz_Name ); + CKSERV; + fprintf( fp, zMode, ltmainOptions.pzProgName ); + CKSERV; + + /* + * Emit the real command. The original shell script shifts off the + * command name before it realizes what it has done. We emulate + * that behavior by setting `nonopt' to the command name and inserting + * the remaining arguments as arguments via `set -- $@'. + */ + fprintf( fp, zCmdName, argv[0] ); + CKSERV; + + while (--argc > 0) { + fputc( ' ', fp ); + emitShellArg( *(++argv), fp ); + CKSERV; + } + + fputc( '\n', fp ); + fflush( fp ); + CKSERV; + + /* + * Up to now, we are just initializing variables. Here, we write + * a large chunk of text to the pipe and the shell may exit before + * we are done. If that happens, we get a SIGPIPE. The `CLOSEOK' + * macro will detect that, call closeScript() and return so as to + * avoid segfaults and more SIGPIPEs. + */ + fputs( apz_mode_cmd[ WHICH_OPT_COMPILE ], fp ); + CLOSEOK; + + fputc( '\n', fp ); + CLOSEOK; + + fflush( fp ); + + if (fp != stdout) + closeScript( fp ); +} + + + int +main( argc, argv ) + int argc; + char** argv; +{ + pzHost = getenv( "host" ); + if (pzHost == (char*)NULL) + pzHost = zUnkn; + + /* + * Process the options, removing them from the arg list. + * Make sure the resulting state is sane. + */ + { + int ct = optionProcess( <mainOptions, argc, argv ); + argc -= ct; + argv += ct; + if (! HAVE_OPT( MODE )) + validateMode( argc, argv ); + } + + switch (OPT_VALUE_MODE) { + case MODE_EXECUTE: + case MODE_CLEAN: + case MODE_FINISH: + case MODE_INSTALL: + case MODE_UNINSTALL: + /* + * Options prohibited for all states except link & compile + */ + if (HAVE_OPT( OUTPUT_FILE )) { + fprintf( stderr, zBadOpt, ltmainOptions.pzProgName, "output-file" ); + USAGE( EXIT_FAILURE ); + /* NOTREACHED */ + } + if (HAVE_OPT( STATIC )) { + fprintf( stderr, zBadOpt, ltmainOptions.pzProgName, "static" ); + USAGE( EXIT_FAILURE ); + /* NOTREACHED */ + } + if (HAVE_OPT( DYNAMIC )) { + fprintf( stderr, zBadOpt, ltmainOptions.pzProgName, "dynamic" ); + USAGE( EXIT_FAILURE ); + /* NOTREACHED */ + } + + /* + * dlopen is allowed for execute, but nothing else. So, for + * other modes, fall through and check for DLOPEN. + */ + if (OPT_VALUE_MODE == MODE_EXECUTE) + break; + /* FALLTHROUGH */ + + case MODE_LINK: + case MODE_COMPILE: + if (HAVE_OPT( DLOPEN )) { + fprintf( stderr, zBadOpt, ltmainOptions.pzProgName, "dlopen" ); + USAGE( EXIT_FAILURE ); + /* NOTREACHED */ + } + break; + + case MODE_ECHO: + /* + * We ignore all conflicts for echo mode + */ + for (;;) { + fputs( *(argv++), stdout ); + if (--argc <= 0) + break; + fputc( ' ', stdout ); + } + + fputc( '\n', stdout ); + return EXIT_SUCCESS; + + default: + fprintf( stderr, zBadMode, ltmainOptions.pzProgName ); + USAGE( EXIT_FAILURE ); + /* NOTREACHED */ + } + + pz_cmd_name = argv[0]; + signal( SIGPIPE, handleSignal ); + signal( SIGBUS, handleSignal ); + signal( SIGSEGV, handleSignal ); + + emitScript( argc, argv ); + + return scriptStatus; +}