--- /dev/null
+/* 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 <stdio.h> /* printf */
+#include <stdlib.h> /* exit */
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#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;
+}