home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Source / GNU / gcc / cp / g++.c < prev    next >
C/C++ Source or Header  |  1996-02-07  |  13KB  |  585 lines

  1. /* G++ preliminary semantic processing for the compiler driver.
  2.    Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
  3.    Contributed by Brendan Kehoe (brendan@cygnus.com).
  4.  
  5. This file is part of GNU CC.
  6.  
  7. GNU CC is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11.  
  12. GNU CC is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU CC; see the file COPYING.  If not, write to
  19. the Free Software Foundation, 59 Temple Place - Suite 330,
  20. Boston, MA 02111-1307, USA.  */
  21.  
  22. /* This program is a wrapper to the main `gcc' driver.  For GNU C++,
  23.    we need to do two special things: a) append `-lg++' in situations
  24.    where it's appropriate, to link in libg++, and b) add `-xc++'..`-xnone'
  25.    around file arguments named `foo.c' or `foo.i'.  So, we do all of
  26.    this semantic processing then just exec gcc with the new argument
  27.    list.
  28.  
  29.    We used to do all of this in a small shell script, but many users
  30.    found the performance of this as a shell script to be unacceptable.
  31.    In situations where your PATH has a lot of NFS-mounted directories,
  32.    using a script that runs sed and other things would be a nasty
  33.    performance hit.  With this program, we never search the PATH at all.  */
  34.  
  35. #include "config.h"
  36. #ifdef __STDC__
  37. #include <stdarg.h>
  38. #else
  39. #include <varargs.h>
  40. #endif
  41. #include <stdio.h>
  42. #include <sys/types.h>
  43. #ifndef _WIN32
  44. #include <sys/file.h>   /* May get R_OK, etc. on some systems.  */
  45. #else
  46. #include <process.h>
  47. #endif
  48. #include <errno.h>
  49.  
  50. /* Defined to the name of the compiler; if using a cross compiler, the
  51.    Makefile should compile this file with the proper name
  52.    (e.g., "i386-aout-gcc").  */
  53. #ifndef GCC_NAME
  54. #define GCC_NAME "gcc"
  55. #endif
  56.  
  57. /* This bit is set if we saw a `-xfoo' language specification.  */
  58. #define LANGSPEC    (1<<1)
  59. /* This bit is set if they did `-lm' or `-lmath'.  */
  60. #define MATHLIB        (1<<2)
  61.  
  62. #ifndef MATH_LIBRARY
  63. #define MATH_LIBRARY "-lm"
  64. #endif
  65.  
  66. /* On MSDOS, write temp files in current dir
  67.    because there's no place else we can expect to use.  */
  68. #ifdef __MSDOS__
  69. #ifndef P_tmpdir
  70. #define P_tmpdir "."
  71. #endif
  72. #ifndef R_OK
  73. #define R_OK 4
  74. #define W_OK 2
  75. #define X_OK 1
  76. #endif
  77. #endif
  78.  
  79. #ifndef VPROTO
  80. #ifdef __STDC__
  81. #define PVPROTO(ARGS)        ARGS
  82. #define VPROTO(ARGS)        ARGS
  83. #define VA_START(va_list,var)    va_start(va_list,var)
  84. #else
  85. #define PVPROTO(ARGS)        ()
  86. #define VPROTO(ARGS)        (va_alist) va_dcl
  87. #define VA_START(va_list,var)    va_start(va_list)
  88. #endif
  89. #endif
  90.  
  91. #ifndef errno
  92. extern int errno;
  93. #endif
  94.  
  95. extern int sys_nerr;
  96. #ifndef HAVE_STRERROR
  97. #if defined(bsd4_4)
  98. extern const char *const sys_errlist[];
  99. #else
  100. #ifndef _WIN32
  101. extern char *sys_errlist[];
  102. #endif
  103. #endif
  104. #else
  105. extern char *strerror();
  106. #endif
  107.  
  108. /* Name with which this program was invoked.  */
  109. static char *programname;
  110.  
  111. char *
  112. my_strerror(e)
  113.      int e;
  114. {
  115.  
  116. #ifdef HAVE_STRERROR
  117.   return strerror(e);
  118.  
  119. #else
  120.  
  121.   static char buffer[30];
  122.   if (!e)
  123.     return "";
  124.  
  125.   if (e > 0 && e < sys_nerr)
  126.     return sys_errlist[e];
  127.  
  128.   sprintf (buffer, "Unknown error %d", e);
  129.   return buffer;
  130. #endif
  131. }
  132.  
  133. #ifdef HAVE_VPRINTF
  134. /* Output an error message and exit */
  135.  
  136. static void
  137. fatal VPROTO((char *format, ...))
  138. {
  139. #ifndef __STDC__
  140.   char *format;
  141. #endif
  142.   va_list ap;
  143.  
  144.   VA_START (ap, format);
  145.  
  146. #ifndef __STDC__
  147.   format = va_arg (ap, char*);
  148. #endif
  149.  
  150.   fprintf (stderr, "%s: ", programname);
  151.   vfprintf (stderr, format, ap);
  152.   va_end (ap);
  153.   fprintf (stderr, "\n");
  154. #if 0
  155.   /* XXX Not needed for g++ driver.  */
  156.   delete_temp_files ();
  157. #endif
  158.   exit (1);
  159. }
  160.  
  161. static void
  162. error VPROTO((char *format, ...))
  163. {
  164. #ifndef __STDC__
  165.   char *format;
  166. #endif
  167.   va_list ap;
  168.  
  169.   VA_START (ap, format);
  170.  
  171. #ifndef __STDC__
  172.   format = va_arg (ap, char*);
  173. #endif
  174.  
  175.   fprintf (stderr, "%s: ", programname);
  176.   vfprintf (stderr, format, ap);
  177.   va_end (ap);
  178.  
  179.   fprintf (stderr, "\n");
  180. }
  181.  
  182. #else /* not HAVE_VPRINTF */
  183.  
  184. static void
  185. error (msg, arg1, arg2)
  186.      char *msg, *arg1, *arg2;
  187. {
  188.   fprintf (stderr, "%s: ", programname);
  189.   fprintf (stderr, msg, arg1, arg2);
  190.   fprintf (stderr, "\n");
  191. }
  192.  
  193. static void
  194. fatal (msg, arg1, arg2)
  195.      char *msg, *arg1, *arg2;
  196. {
  197.   error (msg, arg1, arg2);
  198. #if 0
  199.   /* XXX Not needed for g++ driver.  */
  200.   delete_temp_files ();
  201. #endif
  202.   exit (1);
  203. }
  204.  
  205. #endif /* not HAVE_VPRINTF */
  206.  
  207. /* More 'friendly' abort that prints the line and file.
  208.    config.h can #define abort fancy_abort if you like that sort of thing.  */
  209.  
  210. void
  211. fancy_abort ()
  212. {
  213.   fatal ("Internal g++ abort.");
  214. }
  215.  
  216. char *
  217. xmalloc (size)
  218.      unsigned size;
  219. {
  220.   register char *value = (char *) malloc (size);
  221.   if (value == 0)
  222.     fatal ("virtual memory exhausted");
  223.   return value;
  224. }
  225.  
  226. /* Return a newly-allocated string whose contents concatenate those
  227.    of s1, s2, s3.  */
  228. static char *
  229. concat (s1, s2, s3)
  230.      char *s1, *s2, *s3;
  231. {
  232.   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  233.   char *result = xmalloc (len1 + len2 + len3 + 1);
  234.  
  235.   strcpy (result, s1);
  236.   strcpy (result + len1, s2);
  237.   strcpy (result + len1 + len2, s3);
  238.   *(result + len1 + len2 + len3) = 0;
  239.  
  240.   return result;
  241. }
  242.  
  243. static void
  244. pfatal_with_name (name)
  245.      char *name;
  246. {
  247.   fatal (concat ("%s: ", my_strerror (errno), ""), name);
  248. }
  249.  
  250. #ifdef __MSDOS__
  251. /* This is the common prefix we use to make temp file names.  */
  252. char *temp_filename;
  253.  
  254. /* Length of the prefix.  */
  255. int temp_filename_length;
  256.  
  257. /* Compute a string to use as the base of all temporary file names.  */
  258. static char *
  259. choose_temp_base_try (try, base)
  260. char *try;
  261. char *base;
  262. {
  263.   char *rv;
  264.   if (base)
  265.     rv = base;
  266.   else if (try == (char *)0)
  267.     rv = 0;
  268.   else if (access (try, R_OK | W_OK) != 0)
  269.     rv = 0;
  270.   else
  271.     rv = try;
  272.   return rv;
  273. }
  274.  
  275. static void
  276. choose_temp_base ()
  277. {
  278.   char *base = 0;
  279.   int len;
  280.  
  281.   base = choose_temp_base_try (getenv ("TMPDIR"), base);
  282.   base = choose_temp_base_try (getenv ("TMP"), base);
  283.   base = choose_temp_base_try (getenv ("TEMP"), base);
  284.  
  285. #ifdef P_tmpdir
  286.   base = choose_temp_base_try (P_tmpdir, base);
  287. #endif
  288.  
  289.   base = choose_temp_base_try ("/usr/tmp", base);
  290.   base = choose_temp_base_try ("/tmp", base);
  291.  
  292.   /* If all else fails, use the current directory! */  
  293.   if (base == (char *)0)
  294.     base = "./";
  295.  
  296.   len = strlen (base);
  297.   temp_filename = xmalloc (len + sizeof("/ccXXXXXX"));
  298.   strcpy (temp_filename, base);
  299.   if (len > 0 && temp_filename[len-1] != '/')
  300.     temp_filename[len++] = '/';
  301.   strcpy (temp_filename + len, "ccXXXXXX");
  302.  
  303.   mktemp (temp_filename);
  304.   temp_filename_length = strlen (temp_filename);
  305.   if (temp_filename_length == 0)
  306.     abort ();
  307. }
  308.  
  309. static void
  310. perror_exec (name)
  311.      char *name;
  312. {
  313.   char *s;
  314.  
  315.   if (errno < sys_nerr)
  316.     s = concat ("installation problem, cannot exec %s: ",
  317.         my_strerror( errno ), "");
  318.   else
  319.     s = "installation problem, cannot exec %s";
  320.   error (s, name);
  321. }
  322.  
  323. /* This is almost exactly what's in gcc.c:pexecute for MSDOS.  */
  324. void
  325. run_dos (program, argv)
  326.      char *program;
  327.      char *argv[];
  328. {
  329.   char *scmd, *rf;
  330.   FILE *argfile;
  331.   int i;
  332.  
  333.   choose_temp_base (); /* not in gcc.c */
  334.  
  335.   scmd = (char *) malloc (strlen (program) + strlen (temp_filename) + 10);
  336.   rf = scmd + strlen (program) + 6;
  337.   sprintf (scmd, "%s.exe @%s.gp", program, temp_filename);
  338.  
  339.   argfile = fopen (rf, "w");
  340.   if (argfile == 0)
  341.     pfatal_with_name (rf);
  342.  
  343.   for (i=1; argv[i]; i++)
  344.     {
  345.       char *cp;
  346.       for (cp = argv[i]; *cp; cp++)
  347.     {
  348.       if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
  349.         fputc ('\\', argfile);
  350.       fputc (*cp, argfile);
  351.     }
  352.       fputc ('\n', argfile);
  353.     }
  354.   fclose (argfile);
  355.  
  356.   i = system (scmd);
  357.  
  358.   remove (rf);
  359.   
  360.   if (i == -1)
  361.     perror_exec (program);
  362. }
  363. #endif /* __MSDOS__ */
  364.  
  365. int
  366. main (argc, argv)
  367.      int argc;
  368.      char **argv;
  369. {
  370.   register int i, j = 0;
  371.   register char *p;
  372.   int verbose = 0;
  373.  
  374.   /* This will be 0 if we encounter a situation where we should not
  375.      link in libstdc++, or 2 if we should link in libg++ as well.  */
  376.   int library = 1;
  377.  
  378.   /* Used to track options that take arguments, so we don't go wrapping
  379.      those with -xc++/-xnone.  */
  380.   char *quote = NULL;
  381.  
  382.   /* The new argument list will be contained in this.  */
  383.   char **arglist;
  384.  
  385.   /* The name of the compiler we will want to run---by default, it
  386.      will be the definition of `GCC_NAME', e.g., `gcc'.  */
  387.   char *gcc = GCC_NAME;
  388.  
  389.   /* Non-zero if we saw a `-xfoo' language specification on the
  390.      command line.  Used to avoid adding our own -xc++ if the user
  391.      already gave a language for the file.  */
  392.   int saw_speclang = 0;
  393.  
  394.   /* Non-zero if we saw `-lm' or `-lmath' on the command line.  */
  395.   char *saw_math = 0;
  396.  
  397.   /* The number of arguments being added to what's in argv, other than
  398.      libraries.  We use this to track the number of times we've inserted
  399.      -xc++/-xnone.  */
  400.   int added = 0;
  401.  
  402.   /* An array used to flag each argument that needs a bit set for
  403.      LANGSPEC or MATHLIB.  */
  404.   int *args;
  405.  
  406.   p = argv[0] + strlen (argv[0]);
  407.  
  408.   /* If we're called as g++ (or i386-aout-g++), link in libg++ as well.  */
  409.  
  410.   if (strcmp (p - 3, "g++") == 0)
  411.     {
  412.       library = 2;
  413.     }
  414.  
  415.   while (p != argv[0] && p[-1] != '/')
  416.     --p;
  417.   programname = p;
  418.  
  419.   if (argc == 1)
  420.     fatal ("No input files specified.\n");
  421.  
  422. #ifndef __MSDOS__
  423.   /* We do a little magic to find out where the main gcc executable
  424.      is.  If they ran us as /usr/local/bin/g++, then we will look
  425.      for /usr/local/bin/gcc; similarly, if they just ran us as `g++',
  426.      we'll just look for `gcc'.  */
  427.   if (p != argv[0])
  428.     {
  429.       *--p = '\0';
  430.       gcc = (char *) malloc ((strlen (argv[0]) + 1 + strlen (GCC_NAME) + 1)
  431.                  * sizeof (char));
  432.       sprintf (gcc, "%s/%s", argv[0], GCC_NAME);
  433.     }
  434. #endif
  435.  
  436.   args = (int *) malloc (argc * sizeof (int));
  437.   bzero ((char *) args, argc * sizeof (int));
  438.  
  439.   for (i = 1; i < argc; i++)
  440.     {
  441.       /* If the previous option took an argument, we swallow it here.  */
  442.       if (quote)
  443.     {
  444.       quote = NULL;
  445.       continue;
  446.     }
  447.  
  448.       if (argv[i][0] == '\0' || argv[i][1] == '\0')
  449.     continue;
  450.  
  451.       if (argv[i][0] == '-')
  452.     {
  453.       if (library != 0 && strcmp (argv[i], "-nostdlib") == 0)
  454.         {
  455.           library = 0;
  456.         }
  457.       else if (strcmp (argv[i], "-lm") == 0
  458.            || strcmp (argv[i], "-lmath") == 0)
  459.         args[i] |= MATHLIB;
  460.       else if (strcmp (argv[i], "-v") == 0)
  461.         {
  462.           verbose = 1;
  463.           if (argc == 2)
  464.         {
  465.           /* If they only gave us `-v', don't try to link
  466.              in libg++.  */ 
  467.           library = 0;
  468.         }
  469.         }
  470.       else if (strncmp (argv[i], "-x", 2) == 0)
  471.         saw_speclang = 1;
  472.       else if (((argv[i][2] == '\0'
  473.              && (char *)strchr ("bBVDUoeTuIYmLiA", argv[i][1]) != NULL)
  474.             || strcmp (argv[i], "-Tdata") == 0))
  475.         quote = argv[i];
  476.       else if (library != 0 && ((argv[i][2] == '\0'
  477.              && (char *) strchr ("cSEM", argv[i][1]) != NULL)
  478.             || strcmp (argv[i], "-MM") == 0))
  479.         {
  480.           /* Don't specify libraries if we won't link, since that would
  481.          cause a warning.  */
  482.           library = 0;
  483.         }
  484.       else
  485.         /* Pass other options through.  */
  486.         continue;
  487.     }
  488.       else
  489.     {
  490.       int len; 
  491.  
  492.       if (saw_speclang)
  493.         {
  494.           saw_speclang = 0;
  495.           continue;
  496.         }
  497.  
  498.       /* If the filename ends in .c or .i, put options around it.
  499.          But not if a specified -x option is currently active.  */
  500.       len = strlen (argv[i]);
  501.       if (len > 2
  502.           && (argv[i][len - 1] == 'c' || argv[i][len - 1] == 'i')
  503.           && argv[i][len - 2] == '.')
  504.         {
  505.           args[i] |= LANGSPEC;
  506.           added += 2;
  507.         }
  508.     }
  509.     }
  510.  
  511.   if (quote)
  512.     fatal ("argument to `%s' missing\n", quote);
  513.  
  514.   if (added || library)
  515.     {
  516.       arglist = (char **) malloc ((argc + added + 4) * sizeof (char *));
  517.  
  518.       for (i = 1, j = 1; i < argc; i++, j++)
  519.     {
  520.       arglist[j] = argv[i];
  521.  
  522.       /* Make sure -lg++ is before the math library, since libg++
  523.          itself uses those math routines.  */
  524.       if (!saw_math && (args[i] & MATHLIB) && library)
  525.         {
  526.           --j;
  527.           saw_math = argv[i];
  528.         }
  529.  
  530.       /* Wrap foo.c and foo.i files in a language specification to
  531.          force the gcc compiler driver to run cc1plus on them.  */
  532.       if (args[i] & LANGSPEC)
  533.         {
  534.           int len = strlen (argv[i]);
  535.           if (argv[i][len - 1] == 'i')
  536.         arglist[j++] = "-xc++-cpp-output";
  537.           else
  538.         arglist[j++] = "-xc++";
  539.           arglist[j++] = argv[i];
  540.           arglist[j] = "-xnone";
  541.         }
  542.     }
  543.  
  544.       /* Add `-lg++' if we haven't already done so.  */
  545.       if (library == 2)
  546.     arglist[j++] = "-lg++";
  547.       if (library)
  548.     arglist[j++] = "-lstdc++";
  549.       if (saw_math)
  550.     arglist[j++] = saw_math;
  551.       else if (library)
  552.     arglist[j++] = MATH_LIBRARY;
  553.  
  554.       arglist[j] = NULL;
  555.     }
  556.   else
  557.     /* No need to copy 'em all.  */
  558.     arglist = argv;
  559.  
  560.   arglist[0] = gcc;
  561.  
  562.   if (verbose)
  563.     {
  564.       if (j == 0)
  565.     j = argc;
  566.  
  567.       for (i = 0; i < j; i++)
  568.     fprintf (stderr, " %s", arglist[i]);
  569.       fprintf (stderr, "\n");
  570.     }
  571. #if !defined(OS2) && !defined (_WIN32)
  572. #ifdef __MSDOS__
  573.   run_dos (gcc, arglist);
  574. #else /* !__MSDOS__ */
  575.   if (execvp (gcc, arglist) < 0)
  576.     pfatal_with_name (gcc);
  577. #endif /* __MSDOS__ */
  578. #else /* OS2 or _WIN32 */
  579.   if (spawnvp (1, gcc, arglist) < 0)
  580.     pfatal_with_name (gcc);
  581. #endif
  582.  
  583.   return 0;
  584. }
  585.