home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / g77-0.5.15-src.tgz / tar.out / fsf / g77 / f / g77.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  15KB  |  614 lines

  1. /* G77 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), with significant
  4.    modifications for GNU Fortran by James Craig Burley (burley@gnu.ai.mit.edu).
  5.  
  6. This file is part of GNU Fortran.
  7.  
  8. GNU Fortran is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2, or (at your option)
  11. any later version.
  12.  
  13. GNU Fortran is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. GNU General Public License for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with GNU Fortran; see the file COPYING.  If not, write to
  20. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  21.  
  22. /* This program is a wrapper to the main `gcc' driver.  The generic
  23.    goal of this program is to be basically identical to gcc (in that
  24.    it faithfully passes all of the original arguments to gcc) but,
  25.    unless explicitly overridden by the user in certain ways, ensure
  26.    that the needs of the language supported by this wrapper are met.
  27.  
  28.    For GNU Fortran (g77), we do the following to the argument list
  29.    before passing it to `gcc':
  30.  
  31.    1.  Put `-xf77' or `-xf77-cpp-input' before each list of foo.f or foo.F
  32.        source files and put `-xnone' after that list, if necessary.
  33.        This shouldn't normally be necessary, but it is done in case
  34.        gcc.c normally treats .f/.F files as, say, to be compiled by f2c.
  35.  
  36.    2.  Make sure `-lf2c -lm' is at the end of the list.
  37.  
  38.    3.  Make sure each time `-lf2c' or `-lm' is seen, it forms
  39.        part of the series `-lf2c -lm'.
  40.  
  41.    #1 is not done if `-xfoo' is in effect (where foo is not "none").
  42.    #2 and #3 are not done if `-nostdlib' or any option that disables
  43.    the linking phase is present, or if `-xfoo' is in effect.  Note that
  44.    -v by itself disables linking.
  45.  
  46.    This program was originally made out of gcc/cp/g++.c, but the
  47.    way it builds the new argument list was rewritten so it is much
  48.    easier to maintain, improve the way it decides to add or not add
  49.    extra arguments, etc.  And several improvements were made in the
  50.    handling of arguments, primarily to make it more consistent with
  51.    `gcc' itself.  */
  52.  
  53. #include "config.j"
  54. #ifdef __STDC__
  55. #include <stdarg.h>
  56. #else
  57. #include <varargs.h>
  58. #endif
  59. #include <stdio.h>
  60. #include <sys/types.h>
  61. #include <sys/file.h>   /* May get R_OK, etc. on some systems.  */
  62.  
  63. /* Defined to the name of the compiler; if using a cross compiler, the
  64.    Makefile should compile this file with the proper name
  65.    (e.g., "i386-aout-gcc").  */
  66. #ifndef GCC_NAME
  67. #define GCC_NAME "gcc"
  68. #endif
  69.  
  70. /* On MSDOS, write temp files in current dir
  71.    because there's no place else we can expect to use.  */
  72. #ifdef __MSDOS__
  73. #ifndef P_tmpdir
  74. #define P_tmpdir "."
  75. #endif
  76. #ifndef R_OK
  77. #define R_OK 4
  78. #define W_OK 2
  79. #define X_OK 1
  80. #endif
  81. #endif
  82.  
  83. #ifndef VPROTO
  84. #ifdef __STDC__
  85. #define PVPROTO(ARGS)        ARGS
  86. #define VPROTO(ARGS)        ARGS
  87. #define VA_START(va_list,var)    va_start(va_list,var)
  88. #else
  89. #define PVPROTO(ARGS)        ()
  90. #define VPROTO(ARGS)        (va_alist) va_dcl
  91. #define VA_START(va_list,var)    va_start(va_list)
  92. #endif
  93. #endif
  94.  
  95. extern int errno, sys_nerr;
  96. #if defined(bsd4_4) || defined(__NetBSD__) || defined(__FreeBSD__)
  97. extern const char *const sys_errlist[];
  98. #else
  99. extern char *sys_errlist[];
  100. #endif
  101.  
  102. /* Name with which this program was invoked.  */
  103. static char *programname;
  104.  
  105. /* argc, argv from main().  */
  106. static int xargc;
  107. static char **xargv;
  108.  
  109. /* The new argument list will be contained in these, though if identical
  110.    to the original list, these will be == xargc, xargv.  */
  111. static int newargc;
  112. static char **newargv;
  113.  
  114. #ifdef HAVE_VPRINTF
  115. /* Output an error message and exit */
  116.  
  117. static void
  118. fatal VPROTO((char *format, ...))
  119. {
  120. #ifndef __STDC__
  121.   char *format;
  122. #endif
  123.   va_list ap;
  124.  
  125.   VA_START (ap, format);
  126.  
  127. #ifndef __STDC__
  128.   format = va_arg (ap, char*);
  129. #endif
  130.  
  131.   fprintf (stderr, "%s: ", programname);
  132.   vfprintf (stderr, format, ap);
  133.   va_end (ap);
  134.   fprintf (stderr, "\n");
  135. #if 0
  136.   /* XXX Not needed for g77 driver.  */
  137.   delete_temp_files ();
  138. #endif
  139.   exit (1);
  140. }
  141.  
  142. static void
  143. error VPROTO((char *format, ...))
  144. {
  145. #ifndef __STDC__
  146.   char *format;
  147. #endif
  148.   va_list ap;
  149.  
  150.   VA_START (ap, format);
  151.  
  152. #ifndef __STDC__
  153.   format = va_arg (ap, char*);
  154. #endif
  155.  
  156.   fprintf (stderr, "%s: ", programname);
  157.   vfprintf (stderr, format, ap);
  158.   va_end (ap);
  159.  
  160.   fprintf (stderr, "\n");
  161. }
  162.  
  163. #else /* not HAVE_VPRINTF */
  164.  
  165. static void
  166. error (msg, arg1, arg2)
  167.      char *msg, *arg1, *arg2;
  168. {
  169.   fprintf (stderr, "%s: ", programname);
  170.   fprintf (stderr, msg, arg1, arg2);
  171.   fprintf (stderr, "\n");
  172. }
  173.  
  174. static void
  175. fatal (msg, arg1, arg2)
  176.      char *msg, *arg1, *arg2;
  177. {
  178.   error (msg, arg1, arg2);
  179. #if 0
  180.   /* XXX Not needed for g77 driver.  */
  181.   delete_temp_files ();
  182. #endif
  183.   exit (1);
  184. }
  185.  
  186. #endif /* not HAVE_VPRINTF */
  187.  
  188. /* More 'friendly' abort that prints the line and file.
  189.    config.h can #define abort fancy_abort if you like that sort of thing.  */
  190.  
  191. void
  192. fancy_abort ()
  193. {
  194.   fatal ("Internal g77 abort.");
  195. }
  196.  
  197. char *
  198. xmalloc (size)
  199.      unsigned size;
  200. {
  201.   register char *value = (char *) malloc (size);
  202.   if (value == 0)
  203.     fatal ("virtual memory exhausted");
  204.   return value;
  205. }
  206.  
  207. /* Return a newly-allocated string whose contents concatenate those
  208.    of s1, s2, s3.  */
  209. static char *
  210. concat (s1, s2, s3)
  211.      char *s1, *s2, *s3;
  212. {
  213.   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  214.   char *result = xmalloc (len1 + len2 + len3 + 1);
  215.  
  216.   strcpy (result, s1);
  217.   strcpy (result + len1, s2);
  218.   strcpy (result + len1 + len2, s3);
  219.   *(result + len1 + len2 + len3) = 0;
  220.  
  221.   return result;
  222. }
  223.  
  224. static void
  225. pfatal_with_name (name)
  226.      char *name;
  227. {
  228.   char *s;
  229.  
  230.   if (errno < sys_nerr)
  231.     s = concat ("%s: ", sys_errlist[errno], "");
  232.   else
  233.     s = "cannot open %s";
  234.   fatal (s, name);
  235. }
  236.  
  237. #ifdef __MSDOS__
  238. /* This is the common prefix we use to make temp file names.  */
  239. char *temp_filename;
  240.  
  241. /* Length of the prefix.  */
  242. int temp_filename_length;
  243.  
  244. /* Compute a string to use as the base of all temporary file names.  */
  245. static char *
  246. choose_temp_base_try (try, base)
  247. char *try;
  248. char *base;
  249. {
  250.   char *rv;
  251.   if (base)
  252.     rv = base;
  253.   else if (try == (char *)0)
  254.     rv = 0;
  255.   else if (access (try, R_OK | W_OK) != 0)
  256.     rv = 0;
  257.   else
  258.     rv = try;
  259.   return rv;
  260. }
  261.  
  262. static void
  263. choose_temp_base ()
  264. {
  265.   char *base = 0;
  266.   int len;
  267.  
  268.   base = choose_temp_base_try (getenv ("TMPDIR"), base);
  269.   base = choose_temp_base_try (getenv ("TMP"), base);
  270.   base = choose_temp_base_try (getenv ("TEMP"), base);
  271.  
  272. #ifdef P_tmpdir
  273.   base = choose_temp_base_try (P_tmpdir, base);
  274. #endif
  275.  
  276.   base = choose_temp_base_try ("/usr/tmp", base);
  277.   base = choose_temp_base_try ("/tmp", base);
  278.  
  279.   /* If all else fails, use the current directory! */  
  280.   if (base == (char *)0)
  281.     base = "./";
  282.  
  283.   len = strlen (base);
  284.   temp_filename = xmalloc (len + sizeof("/ccXXXXXX"));
  285.   strcpy (temp_filename, base);
  286.   if (len > 0 && temp_filename[len-1] != '/')
  287.     temp_filename[len++] = '/';
  288.   strcpy (temp_filename + len, "ccXXXXXX");
  289.  
  290.   mktemp (temp_filename);
  291.   temp_filename_length = strlen (temp_filename);
  292.   if (temp_filename_length == 0)
  293.     abort ();
  294. }
  295.  
  296. static void
  297. perror_exec (name)
  298.      char *name;
  299. {
  300.   char *s;
  301.  
  302.   if (errno < sys_nerr)
  303.     s = concat ("installation problem, cannot exec %s: ",
  304.         sys_errlist[errno], "");
  305.   else
  306.     s = "installation problem, cannot exec %s";
  307.   error (s, name);
  308. }
  309.  
  310. /* This is almost exactly what's in gcc.c:pexecute for MSDOS.  */
  311. void
  312. run_dos (program, argv)
  313.      char *program;
  314.      char *argv[];
  315. {
  316.   char *scmd, *rf;
  317.   FILE *argfile;
  318.   int i;
  319.  
  320.   choose_temp_base (); /* not in gcc.c */
  321.  
  322.   scmd = (char *) malloc (strlen (program) + strlen (temp_filename) + 10);
  323.   rf = scmd + strlen (program) + 6;
  324.   sprintf (scmd, "%s.exe @%s.gp", program, temp_filename);
  325.  
  326.   argfile = fopen (rf, "w");
  327.   if (argfile == 0)
  328.     pfatal_with_name (rf);
  329.  
  330.   for (i=1; argv[i]; i++)
  331.     {
  332.       char *cp;
  333.       for (cp = argv[i]; *cp; cp++)
  334.     {
  335.       if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
  336.         fputc ('\\', argfile);
  337.       fputc (*cp, argfile);
  338.     }
  339.       fputc ('\n', argfile);
  340.     }
  341.   fclose (argfile);
  342.  
  343.   i = system (scmd);
  344.  
  345.   remove (rf);
  346.   
  347.   if (i == -1)
  348.     perror_exec (program);
  349. }
  350. #endif /* __MSDOS__ */
  351.  
  352. static void
  353. append_arg (arg)
  354.     char *arg;
  355. {
  356.   static int newargsize;
  357.  
  358. #if 0
  359.   fprintf (stderr, "`%s'\n", arg);
  360. #endif
  361.  
  362.   if ((newargv == xargv)
  363.       && (arg == xargv[newargc]))
  364.     {
  365.       ++newargc;
  366.       return;            /* Nothing new here. */
  367.     }
  368.  
  369.   if (newargv == xargv)
  370.     {                /* Make new arglist. */
  371.       int i;
  372.  
  373.       newargsize = xargc << 2;    /* Allow 4 output args for each 1 input. */
  374.       newargv = (char **) malloc (newargsize * sizeof (char *));
  375.  
  376.       /* Copy what has been done so far.  */
  377.       for (i = 0; i < newargc; ++i)
  378.     newargv[i] = xargv[i];
  379.     }
  380.  
  381.   if (newargc == newargsize)
  382.     fatal ("overflowed output arg list for `%s'", arg);
  383.   newargv[newargc++] = arg;
  384. }
  385.  
  386. int
  387. main (argc, argv)
  388.      int argc;
  389.      char **argv;
  390. {
  391.   register int i = 0;
  392.   register char *p;
  393.   int verbose = 0;
  394.  
  395.   /* This will be NULL if we encounter a situation where we should not
  396.      link in libf2c.  */
  397.   char *library = "-lf2c";
  398.  
  399.   /* The name of the compiler we will want to run---by default, it
  400.      will be the definition of `GCC_NAME', e.g., `gcc'.  */
  401.   char *gcc = GCC_NAME;
  402.  
  403.   /* 0 => -xnone in effect on input/output
  404.      1 => -xfoo in effect on input/output
  405.      2 => -xnone in effect on input, -xf77 on output
  406.      3 => -xnone in effect on input, -xf77-cpp-input on output.  */
  407.   int saw_speclang = 0;
  408.  
  409.   /* 0 => initial/reset state
  410.      1 => last arg was -l<library>
  411.      2 => last two args were -l<library> -lm.  */
  412.   int saw_library = 0;
  413.  
  414.   /* Initialize for append_arg().  */
  415.   xargc = argc;
  416.   newargv = xargv = argv;
  417.   newargc = 0;
  418.  
  419.   append_arg (argv[0]);
  420.  
  421.   p = argv[0] + strlen (argv[0]);
  422.   while (p != argv[0] && p[-1] != '/')
  423.     --p;
  424.   programname = p;
  425.  
  426.   if (argc == 1)
  427.     fatal ("No input files specified.\n");
  428.  
  429. #ifndef __MSDOS__
  430.   /* We do a little magic to find out where the main gcc executable
  431.      is.  If they ran us as /usr/local/bin/g77, then we will look
  432.      for /usr/local/bin/gcc; similarly, if they just ran us as `g77',
  433.      we'll just look for `gcc'.  */
  434.   if (p != argv[0])
  435.     {
  436.       *--p = '\0';
  437.       gcc = (char *) malloc ((strlen (argv[0]) + 1 + strlen (GCC_NAME) + 1)
  438.                  * sizeof (char));
  439.       sprintf (gcc, "%s/%s", argv[0], GCC_NAME);
  440.     }
  441. #endif
  442.  
  443.   /* If -nostdlib or a "turn-off-linking" option is anywhere in the
  444.      command line, don't do any library-option processing (except
  445.      relating to -x).  */
  446.  
  447.   for (i = 1; i < argc; i++)
  448.     {
  449.       if ((strcmp (argv[i], "-nostdlib") == 0)
  450.       || ((argv[i][2] == '\0'
  451.            && (char *) strchr ("cSEM", argv[i][1]) != NULL)
  452.           || strcmp (argv[i], "-MM") == 0))
  453.     /* Don't specify libraries after -nostdlib; or if we won't link,
  454.        since that would cause a warning.  */
  455.     library = NULL;
  456.       else if (strcmp (argv[i], "-v") == 0)
  457.     {
  458.       verbose = 1;
  459.       if (argc == 2)
  460.         /* If they only gave us `-v', don't try to link
  461.            in libf2c.  */ 
  462.         library = NULL;
  463.     }
  464.     }
  465.  
  466.   for (i = 1; i < argc; i++)
  467.     {
  468.       if (argv[i][0] == '\0')
  469.     append_arg (argv[i]);    /* Interesting.  Just append as is. */
  470.       else if ((argv[i][0] == '-') && (argv[i][1] != 'l'))
  471.     {            /* Not a filename or library. */
  472.       if (saw_library == 1)    /* -l<library>. */
  473.         append_arg ("-lm");
  474.       saw_library = 0;
  475.       append_arg (argv[i]);    /* Always append this arg first as is. */
  476.  
  477.       if (argv[i][1] == '\0')
  478.         ;            /* "-" == Standard input. */
  479.       else if (strncmp (argv[i], "-x", 2) == 0)
  480.         {            /* Track input language. */
  481.           char *lang;
  482.  
  483.           if ((argv[i][2] == '\0') && (argc == i + 1))
  484.         fatal ("argument to `-x' is missing");
  485.           if (argv[i][2] == '\0')
  486.         {
  487.           lang = argv[++i];
  488.           append_arg (lang);
  489.         }
  490.           else
  491.         lang = argv[i] + 2;
  492.           saw_speclang = (strcmp (lang, "none") != 0);
  493.         }
  494.       else if (((argv[i][2] == '\0'
  495.              && (char *)strchr ("bBVDUoeTuIYmLiA", argv[i][1]) != NULL)
  496.             || strcmp (argv[i], "-Tdata") == 0))
  497.         {            /* Skip over any args with arguments. */
  498.           if (argc == i + 1)
  499.         fatal ("argument to `%s' missing\n", argv[i]);
  500.           ++i;
  501.           append_arg (argv[i]);
  502.         }
  503.     }
  504.       else
  505.     {            /* A filename/library, not an option. */
  506.       int len;
  507.       int want_speclang;
  508.  
  509.       /* Here, always append the arg _after_ other stuff, possibly.  */
  510.  
  511.       if (saw_speclang == 1)
  512.         saw_library = 0;    /* -xfoo currently active. */
  513.       /* Put -xf77 and -xnone around list of filenames ending in
  514.          .F or .f, but don't include other filenames or libraries
  515.          in that list.  */
  516.       else if ((argv[i][0] != '-')    /* Not a library. */
  517.            && (len = strlen (argv[i])) > 2
  518.            && ((argv[i][len - 1] == 'F')
  519.                || (argv[i][len - 1] == 'f'))
  520.            && argv[i][len - 2] == '.')
  521.         {            /* filename.f or filename.F. */
  522.           if (saw_library == 1)    /* -l<library>. */
  523.         append_arg ("-lm");
  524.           saw_library = 0;
  525.           want_speclang = (argv[i][len - 1] == 'F') + 2;
  526.  
  527.           if (saw_speclang != want_speclang)
  528.         {
  529.           if (want_speclang == 2)
  530.             append_arg ("-xf77");
  531.           else
  532.             append_arg ("-xf77-cpp-input");
  533.           saw_speclang = want_speclang;
  534.         }
  535.         }
  536.       else
  537.         {            /* -lfoo or "alien" filename. */
  538.           if (saw_speclang)
  539.         append_arg ("-xnone");
  540.           saw_speclang = 0;
  541.  
  542.           if (strcmp (argv[i], "-lm") == 0
  543.           || strcmp (argv[i], "-lmath") == 0)
  544.         {
  545.           if (saw_library == 1)
  546.             saw_library = 2;    /* -l<library> -lm. */
  547.           else if (library)
  548.             {
  549.               append_arg (library);
  550.               saw_library = 2;    /* -l<library> -lm. */
  551.             }
  552.         }
  553.           else if ((library != NULL)
  554.                && (strcmp (argv[i], library) == 0))
  555.         saw_library = 1;    /* -l<library>. */
  556.           else
  557.         {        /* "Alien" library or filename. */
  558.           if (saw_library == 1)
  559.             append_arg ("-lm");
  560.           saw_library = 0;
  561.         }
  562.         }
  563.       append_arg (argv[i]);
  564.     }
  565.     }
  566.  
  567.   /* Add -lf2c -lm as necessary.  */
  568.  
  569.   if (library)
  570.     {                /* Doing a link and no -nostdlib. */
  571.       if (saw_speclang)
  572.     append_arg ("-xnone");
  573.       switch (saw_library)
  574.     {
  575.     case 0:
  576.       append_arg (library);
  577.     case 1:
  578.       append_arg ("-lm");
  579.     default:
  580.       break;
  581.     }
  582.     }
  583.  
  584.   append_arg (NULL);
  585.   --newargc;            /* Don't count null arg at end. */
  586.  
  587.   newargv[0] = gcc;        /* This is safe even if newargv == xargv. */
  588.  
  589.   if (verbose)
  590.     {
  591. #if 0
  592.       if (newargv == xargv)
  593.     fprintf (stderr, "[Original:]");
  594. #endif
  595.  
  596.       for (i = 0; i < newargc; i++)
  597.     fprintf (stderr, " %s", newargv[i]);
  598.       fprintf (stderr, "\n");
  599.     }
  600. #ifndef OS2
  601. #ifdef __MSDOS__
  602.   run_dos (gcc, newargv);
  603. #else /* !__MSDOS__ */
  604.   if (execvp (gcc, newargv) < 0)
  605.     pfatal_with_name (gcc);
  606. #endif /* __MSDOS__ */
  607. #else /* OS2 */
  608.   if (spawnvp (gcc, newargv) < 0)
  609.     pfatal_with_name (gcc);
  610. #endif
  611.  
  612.   return 0;
  613. }
  614.