]> git.ipfire.org Git - thirdparty/libtool.git/commitdiff
Initial submit
authorAndreas Jaeger <aj@suse.de>
Sat, 12 May 2001 15:44:22 +0000 (15:44 +0000)
committerBruce Korb <bkorb@gnu.org>
Sat, 12 May 2001 15:44:22 +0000 (15:44 +0000)
exe/ltmain.c [new file with mode: 0644]

diff --git a/exe/ltmain.c b/exe/ltmain.c
new file mode 100644 (file)
index 0000000..2117911
--- /dev/null
@@ -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 <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( &ltmainOptions, 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;
+}