home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Source / GNU / gcc / config / winnt / ld.c < prev    next >
C/C++ Source or Header  |  1997-02-11  |  25KB  |  1,044 lines

  1. /* Call Windows NT 3.x linker.
  2.    Copyright (C) 1994 Free Software Foundation, Inc.
  3.    Contributed by Douglas B. Rupp (drupp@cs.washington.edu).
  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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. #include "config.h"
  22. #include <stdio.h>
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <process.h>
  28. #include <stdarg.h>
  29. #if 0
  30. #include <varargs.h>
  31. #endif
  32. #include <fcntl.h>
  33. #if defined (_WIN32) && defined (NEXT_PDO)
  34. #include <signal.h>
  35. #endif /* defined (_WIN32) && defined (NEXT_PDO) */
  36.  
  37. #ifdef __GNUC__
  38. #define spawnvp _spawnvp
  39. #define stat _stat
  40. #define strdup _strdup
  41. #endif __GNUC__
  42.  
  43. static char *progname = NULL;
  44.  
  45. /* These can be set by command line arguments */
  46. char *linker_path = 0;
  47. int verbose = 0;
  48.  
  49. int link_arg_max = -1;
  50. char **link_args = (char **) 0;
  51. int link_arg_index = -1;
  52.  
  53. int lib_arg_max = -1;
  54. char **lib_args = (char **)0;
  55. int lib_arg_index = -1;
  56.  
  57. char *search_dirs = 0;
  58.  
  59. #if defined (_WIN32) && defined (NEXT_PDO)
  60. char *standard_framework_dirs[] = {
  61.     "/LocalLibraray/Frameworks/", 
  62.     "/NextLibrary/Frameworks/",
  63.     NULL
  64. };
  65.  
  66. char **framework_dirs = NULL;
  67. unsigned long nframework_dirs = 0;
  68.  
  69. char **framework_names = NULL;
  70. unsigned long nframework_names = 0;
  71.  
  72. static void cleanup (int);
  73. #endif /* defined (_WIN32) && defined (NEXT_PDO) */
  74.  
  75. static int is_regular_file (char *name);
  76.  
  77. static void
  78. addarg (str)
  79.      char *str;
  80. {
  81.   int i;
  82.  
  83.   if (++link_arg_index >= link_arg_max)
  84.     {
  85.       char **new_link_args
  86.     = (char **) calloc (link_arg_max + 1000, sizeof (char *));
  87.  
  88.       for (i = 0; i <= link_arg_max; i++)
  89.     new_link_args [i] = link_args [i];
  90.  
  91.       if (link_args)
  92.     free (link_args);
  93.  
  94.       link_arg_max += 1000;
  95.       link_args = new_link_args;
  96.     }
  97.  
  98.   link_args [link_arg_index] = str;
  99. }
  100.  
  101. /*
  102.  * libargs() is called when when are running "link.exe /LIB" and takes the
  103.  * arguments in link_args and removed the arguments that cause warnings.
  104.  * The new arguments are left in lib_args with lib_arg_index and lib_arg_max
  105.  * set as link_arg_index and link_arg_max are set.
  106.  */
  107. static void
  108. libargs (void)
  109. {
  110.   int i, j;
  111.   char *p;
  112.  
  113.   lib_arg_max = link_arg_max;
  114.   lib_args = calloc (lib_arg_max, sizeof (char *));
  115.  
  116.   for (i = 0; i <= link_arg_index; i++)
  117.     {
  118.       if (link_args [i] != NULL)
  119.     {
  120.       if (strncmp(link_args [i], "-align", strlen("-align")) != 0 &&
  121.           strncmp(link_args [i], "/BASE",  strlen("/BASE"))  != 0 &&
  122.           strncmp(link_args [i], "-debug", strlen("-debug")) != 0)
  123.         {
  124.         lib_args [++lib_arg_index] = link_args [i];
  125.         }
  126.     }
  127.       else
  128.     {
  129.       lib_args [++lib_arg_index] = link_args [i];
  130.       break;
  131.     }
  132.     }
  133. }
  134.  
  135. static char *
  136. locate_file (file_name, path_val)
  137.      char *file_name;
  138.      char *path_val;
  139. {
  140.   char buf [1000];
  141.   int file_len = strlen (file_name);
  142.   char *end_path = path_val + strlen (path_val);
  143.   char *ptr;
  144.  
  145.   /* Handle absolute pathnames */
  146.   if (file_name [0] == '/' || file_name [0] == DIR_SEPARATOR
  147.       || isalpha (file_name [0]) && file_name [1] == ':')
  148.     {
  149.       strncpy (buf, file_name, sizeof buf);
  150.       buf[sizeof buf - 1] = '\0';
  151.       if (is_regular_file (buf))
  152.     return strdup (buf);
  153.       else
  154.     return 0;
  155.   }
  156.  
  157.   if (! path_val)
  158.     return 0;
  159.  
  160.   for (;;)
  161.     {
  162.       for (; *path_val == PATH_SEPARATOR ; path_val++)
  163.     ;
  164.       if (! *path_val)
  165.     return 0;
  166.  
  167.       for (ptr = buf; *path_val && *path_val != PATH_SEPARATOR; )
  168.     *ptr++ = *path_val++;
  169.  
  170.       ptr--;
  171.       if (*ptr != '/' && *ptr != DIR_SEPARATOR)
  172.     *++ptr = DIR_SEPARATOR;
  173.  
  174.       strcpy (++ptr, file_name);
  175.  
  176.       if (is_regular_file (buf))
  177.     return strdup (buf);
  178.     }
  179.  
  180.   return 0;
  181. }
  182.  
  183. static char *
  184. expand_lib (name)
  185.      char *name;
  186. {
  187.   char *lib, *lib_path;
  188.  
  189.   lib = malloc (strlen (name) + 6);
  190.   strcpy (lib, "lib");
  191.   strcat (lib, name);
  192.   strcat (lib, ".a");
  193.  
  194.  
  195.   lib_path = locate_file (lib, search_dirs);
  196.   if (!lib_path)
  197.     {
  198. #if defined (_WIN32) && defined (NEXT_PDO)
  199.       char *lib2;
  200.       lib2 = (char *) malloc (strlen (name) + 5);
  201.       strcpy (lib2, name);
  202.       strcat (lib2, ".lib");
  203.       lib_path = locate_file (lib2, search_dirs);
  204.       if (!lib_path)
  205.     {
  206.       fprintf (stderr, "%s: couldn't locate library: %s or %s\n", progname,
  207.            lib, lib2);
  208.       free (lib2);
  209.       cleanup (0);
  210.       exit (FATAL_EXIT_CODE);
  211.     }
  212.       free (lib2);
  213. #else
  214.       fprintf (stderr, "%s: couldn't locate library: %s\n", progname, lib);
  215.       cleanup (0);
  216.       exit (-1);
  217. #endif /* _WIN32 */
  218.     }
  219.  
  220.   return lib_path;
  221.  
  222.  
  223.  
  224. }
  225.  
  226. static int
  227. is_regular_file (name)
  228.      char *name;
  229. {
  230.   int ret;
  231.   struct _stat statbuf;
  232.  
  233.   ret = stat(name, &statbuf);
  234.   return !ret && S_ISREG (statbuf.st_mode);
  235. }
  236.  
  237. static int
  238. is_directory (name)
  239.      char *name;
  240. {
  241.   int ret;
  242.   struct _stat statbuf;
  243.  
  244.   ret = stat(name, &statbuf);
  245.   return !ret && S_ISDIR (statbuf.st_mode);
  246. }
  247.  
  248. static void
  249. process_args (p_argc, argv)
  250.      int *p_argc;
  251.      char *argv[];
  252. {
  253.   int i, j;
  254.  
  255.   for (i = 1; i < *p_argc; i++)
  256.     {
  257.       /* -v turns on verbose option here and is passed on to gcc */
  258.       if (! strcmp (argv [i], "-v"))
  259.     verbose = 1;
  260.     }
  261. }
  262.  
  263.  
  264.  
  265.  
  266. /*
  267.  * search_for_framework() takes name and tries to open a file with that name
  268.  * in the -F search directories and in the standard framework directories.  If
  269.  * it is sucessful it returns a pointer to the file name indirectly through
  270.  * file_name and the open file descriptor indirectly through fd.
  271.  */
  272. static
  273. void
  274. search_for_framework(
  275. char *name,
  276. char **file_name,
  277. int *fd)
  278. {
  279.     unsigned long i;
  280.     char *p;
  281.  
  282.     *fd = -1;
  283.     *file_name = NULL;
  284.     for(i = 0; i < nframework_dirs ; i++){
  285.         *file_name = (char*)malloc (strlen(framework_dirs[i]) + strlen(name) + 6);
  286.         // First try with a .lib on it
  287.         sprintf (*file_name, "%s%s%s.lib", framework_dirs[i], "/", name);
  288.         if((*fd = open(*file_name, O_RDONLY, 0)) != -1)
  289.         {
  290.             close(*fd);
  291.             break;
  292.         }
  293.         // Then try with nothing.
  294.         sprintf (*file_name, "%s%s%s.", framework_dirs[i], "/", name);
  295.         if((*fd = open(*file_name, O_RDONLY, 0)) != -1)
  296.         {
  297.             close(*fd);
  298.             break;
  299.         }
  300.         free(*file_name);
  301.         *file_name = NULL;
  302.     }
  303.     if(*fd == -1){
  304.         for(i = 0; standard_framework_dirs[i] != NULL ; i++){
  305.         *file_name = (char*)malloc (strlen(standard_framework_dirs[i]) + strlen(name) + 5);
  306.         // First try with a .lib on it
  307.         sprintf (*file_name, "%s%s.lib", standard_framework_dirs[i], name);
  308.         if((*fd = open(*file_name, O_RDONLY, 0)) != -1)
  309.         {
  310.             close(*fd);
  311.             break;
  312.         }
  313.         // Then try with nothing.
  314.         sprintf (*file_name, "%s%s.", standard_framework_dirs[i], name);
  315.         if((*fd = open(*file_name, O_RDONLY, 0)) != -1)
  316.         {
  317.             close(*fd);
  318.             break;
  319.         }
  320.         free(*file_name);
  321.         *file_name = NULL;
  322.         }
  323.     }
  324.     if(*file_name != NULL){
  325.         for(p = *file_name; *p != '\0'; p++)
  326.         if(*p == '/')
  327.             *p = '\\';
  328.     }
  329. }
  330.  
  331.  
  332. #if defined (_WIN32) && defined (NEXT_PDO)
  333. /*
  334.  * The names of temporary @ files to expand -filelists argument with ,dirname
  335.  * options into and count of them (needed to clean them up).
  336.  */
  337. static char **tmp_at_filenames = NULL;
  338. static int ntmp_at_filenames = 0;
  339.  
  340. static
  341. void
  342. cleanup(
  343. int sig)
  344. {
  345.   int i;
  346.  
  347.     for(i = 0; i < ntmp_at_filenames; i++)
  348.         (void)remove(tmp_at_filenames[i]);
  349. }
  350.  
  351. /*
  352.  * add_to_tmp_at_file() takes a pointer to the string which is the -filelist
  353.  * argument.  This argument may look like "listfile,dirname" where listfile is
  354.  * the name of a file containing object file names one to a line and dirname is
  355.  * an optional directory name to be prepend to each object file name.  This
  356.  * routine writes the object file names (with the dirname) into a temporary
  357.  * file.  The temporary file name with an @ symbol prepened to is then returned
  358.  * so it can be added to argument list to link as @tmpfile.
  359.  */
  360. static
  361. char *
  362. add_to_tmp_at_file(
  363. char *filelist_arg)
  364. {
  365.     char *comma, *dirname, *tmppath, filename[FILENAME_MAX + 2], *p;
  366.     int dirsize, filesize;
  367.     int offset;
  368.     FILE *stream, *tmp_at_file;
  369.     char *tmp_at_filename;
  370.  
  371.     dirsize = 0;
  372.     comma = strrchr(filelist_arg, ',');
  373.     if(comma != NULL){
  374.         *comma = '\0';
  375.         dirname = comma + 1;
  376.         dirsize = strlen(dirname);
  377.         if(dirsize + 2 > FILENAME_MAX){
  378.         *comma = ',';
  379.         fprintf(stderr, "%s: directory name too long for -filelist "
  380.             "argument: %s\n", progname, filelist_arg);
  381.         cleanup(0);
  382.         exit(FATAL_EXIT_CODE);
  383.         } 
  384.         strcpy(filename, dirname);
  385.         if(filename[dirsize] != '/' ||
  386.            filename[dirsize] != DIR_SEPARATOR){
  387.            filename[dirsize] = DIR_SEPARATOR;
  388.            filename[++dirsize] = '\0';
  389.            
  390.         }
  391.     }
  392.  
  393.     stream = fopen(filelist_arg, "r");
  394.     if(stream == NULL){
  395.         fprintf(stderr, "%s: can't open -filelist argument: %s\n",
  396.             progname, filelist_arg);
  397.         cleanup(0);
  398.         exit(FATAL_EXIT_CODE);
  399.     }
  400.  
  401.     if(comma != NULL)
  402.         *comma = ',';
  403.  
  404.     tmp_at_filename = (char *)malloc(L_tmpnam + 1);
  405.     tmp_at_filename[0] = '@';
  406.     tmpnam(tmp_at_filename+1);
  407.     tmp_at_file = fopen(tmp_at_filename+1, "w");
  408.     if(tmp_at_file == NULL){
  409.         fprintf(stderr, "%s: can't create temporary file: %s to expand "
  410.             "-filelist %s argument\n", progname, tmp_at_filename+1,
  411.             filelist_arg);
  412.         cleanup(0);
  413.         exit(FATAL_EXIT_CODE);
  414.     }
  415.  
  416.     tmp_at_filenames = (char **)realloc(tmp_at_filenames,
  417.                     sizeof(char *) * (ntmp_at_filenames+1));
  418.     tmp_at_filenames[ntmp_at_filenames++] = tmp_at_filename+1;
  419.  
  420.     while(fgets(filename+dirsize, FILENAME_MAX+2-dirsize, stream) != NULL){
  421.         filesize = strlen(filename);
  422.         if(filesize > FILENAME_MAX &&
  423.           (filesize != FILENAME_MAX+1 || filename[filesize-1] != '\n')){
  424.         fprintf(stderr, "%s: file name constructed from -filelist %s "
  425.             "argument too long (%s)\n", progname, filelist_arg,
  426.             filename);
  427.         cleanup(0);
  428.         exit(FATAL_EXIT_CODE);
  429.         }
  430.         for(p = filename; *p != '\0'; p++)
  431.         if(*p == '/')
  432.             *p = DIR_SEPARATOR;
  433.         if(fputs(filename, tmp_at_file) == EOF){
  434.         fprintf(stderr, "%s: can't write to temporary file: %s to "
  435.             "expand -filelist %s argument\n", progname,
  436.             tmp_at_filename+1,
  437.             filelist_arg);
  438.         cleanup(0);
  439.         exit(FATAL_EXIT_CODE);
  440.         }
  441.     }
  442.  
  443.     if(fclose (tmp_at_file) == EOF){
  444.         fprintf(stderr, "%s: can't close temporary file: %s to expand "
  445.             "-filelist %s argument\n", progname, tmp_at_filename+1,
  446.             filelist_arg);
  447.         cleanup(0);
  448.         exit(FATAL_EXIT_CODE);
  449.     }
  450.     return(tmp_at_filename);
  451. }
  452. #endif /* defined (_WIN32) && defined (NEXT_PDO) */
  453.  
  454. enum tristate {
  455.     DEFAULT,
  456.     ON,
  457.     OFF
  458. };
  459.  
  460. /*
  461.  * set_gvalue() takes a pointer to a -g flag and a pointer into that flag
  462.  * where the number part would start and the pointer to the corresponding
  463.  * gvalue.  It parses out the number part and sets the gvalue.  If there is no
  464.  * number the default value is 2.  It prints an error and exits for invalid
  465.  * arguments or a previously conflicting flag.
  466.  */
  467. static
  468. void
  469. set_gvalue(
  470. char *gflag,
  471. char *number_string,
  472. enum tristate *gvalue)
  473. {
  474.     unsigned int number;
  475.     char *endp;
  476.  
  477.     if(*number_string == '\0'){
  478.         number = 2;
  479.     }
  480.     else{
  481.         number = strtoul(number_string, &endp, 10);
  482.         if(*endp != '\0'){
  483.         fprintf(stderr, "%s: invalid %s argument\n", progname, gflag);
  484.         cleanup(0);
  485.         exit(FATAL_EXIT_CODE);
  486.         }
  487.     }
  488.     if(*gvalue == DEFAULT){
  489.         if(number == 0)
  490.         *gvalue = OFF;
  491.         else
  492.         *gvalue = ON;
  493.     }
  494.     else{
  495.         if((*gvalue == ON && number == 0) ||
  496.            (*gvalue == OFF && number != 0)){
  497.         fprintf(stderr, "%s: conflicting -g[gdb,codeview,stab][number] "
  498.             "arguments specified\n", progname);
  499.         cleanup(0);
  500.         exit(FATAL_EXIT_CODE);
  501.         }
  502.     }
  503. }
  504.  
  505.  
  506. main (argc, argv)
  507.      int argc;
  508.      char *argv[];
  509. {
  510.   int i;
  511.   int done_an_ali = 0;
  512.   int file_name_index;
  513.   enum tristate gdb = DEFAULT, codeview = DEFAULT;
  514.   int debug_flags_specified = 0;
  515.   int undefined_flag = 0; /* records the value of the -undefined switch */
  516.   char *pathval = getenv ("PATH");
  517.   char *spawn_args [5];
  518.   char *tmppathval = malloc (strlen (pathval) + 3);
  519.  
  520. #if defined (_WIN32) && defined (NEXT_PDO)
  521.   char *next_root = getenv( "NEXT_ROOT" );
  522.   int lib_seen = 0;
  523.   int dll_seen = 0;
  524.   int dll_arg_index = -1;
  525.   int out_arg_index = -1;
  526.   int def_arg_index = -1;
  527.  
  528.   (void)signal(SIGINT, cleanup);
  529.   (void)signal(SIGTERM, cleanup);
  530.  
  531.   if (next_root && *next_root)
  532.     {
  533.       if (next_root[strlen(next_root)-1] == '/')
  534.     next_root[strlen(next_root)-1] = '\0';
  535.       for (i = 0; standard_framework_dirs[i]; i++)
  536.     {
  537.       char* new_fname =
  538.         (char *) malloc (strlen (next_root)
  539.                  + strlen (standard_framework_dirs[i]) + 1);
  540.       sprintf (new_fname, "%s%s", next_root, standard_framework_dirs[i]);
  541.       if (new_fname && *new_fname)
  542.         standard_framework_dirs[i] = new_fname;
  543.     }
  544.     }
  545. #endif
  546.  
  547.   progname = argv[0];
  548.  
  549.   /* Set up the search dirs variable */
  550.   search_dirs = (char*)malloc( strlen( getenv ("LIB") ) + 1 );
  551.   strcpy( search_dirs, getenv ("LIB") );
  552.   strcat( search_dirs, "\0" );
  553.  
  554.   strcpy (tmppathval, ".;");
  555.   pathval = strcat (tmppathval, pathval);
  556.  
  557.   process_args (&argc , argv);
  558.  
  559.   linker_path = locate_file ("link32.exe", pathval);
  560.   if (!linker_path)
  561.     {
  562.       linker_path = locate_file ("link.exe", pathval);
  563.       if (!linker_path)
  564.     {
  565.       fprintf (stderr, "%s: couldn't locate link32 or link\n", progname);
  566.       cleanup(0);
  567.       exit (FATAL_EXIT_CODE);
  568.     }
  569.     }
  570.  
  571.   addarg (linker_path);
  572.  
  573. #if defined (_WIN32) && defined (NEXT_PDO)
  574.   /*
  575.    * To make sure we don't alter the position of object files (including
  576.    * libraries and frameworks) we must make two passes through the argument
  577.    * list.  On the first pass we build up the list of -L's and -F's.
  578.    */
  579.   for (i = 1; i < argc; i++)
  580.     {
  581.       int arg_len = strlen (argv [i]);
  582.  
  583.       if (arg_len > 2 && !strncmp (argv [i], "-L", 2))
  584.     {
  585.       char *nbuff, *sdbuff;
  586.       int j, new_len, search_dirs_len;
  587.  
  588.       new_len = strlen (&argv[i][2]);
  589.       search_dirs_len = strlen (search_dirs);
  590.  
  591.       nbuff = malloc (new_len + 1);
  592.       strcpy (nbuff, &argv[i][2]);
  593.  
  594.       for (j = 0; j < new_len; j++)
  595.         if (nbuff[j] == '/')
  596.           nbuff[j] = DIR_SEPARATOR;
  597.  
  598.       sdbuff = malloc (search_dirs_len + new_len + 2);
  599.       strcpy (sdbuff, search_dirs);
  600.       sdbuff[search_dirs_len] = PATH_SEPARATOR;
  601.       sdbuff[search_dirs_len+1] = 0;
  602.       strcat (sdbuff, nbuff);
  603.  
  604.       if (search_dirs)
  605.         free (search_dirs);
  606.  
  607.       search_dirs = sdbuff;
  608.     }
  609.       else if (!strncmp (argv [i], "-F", 2))
  610.     {
  611.       if (argv[i][2] == '\0')
  612.         {
  613.           fprintf (stderr, "%s: error: -F: directory name missing\n",
  614.                progname);
  615.           cleanup (0);
  616.           exit (FATAL_EXIT_CODE);
  617.         }
  618.   
  619.       framework_dirs = (char**)realloc (framework_dirs,
  620.                (nframework_dirs + 1) * sizeof (char*));
  621.       framework_dirs[nframework_dirs++] = &(argv[i][2]);
  622.       if (!is_directory (&(argv[i][2])))
  623.         {
  624.           fprintf (stderr, "%s: warning: -F: directory name (%s) does not "
  625.                "exist\n", progname, &(argv[i][2]));
  626.         }
  627.     }
  628.       else if (arg_len >= 2 && !strncmp (argv [i], "-g", 2))
  629.         {
  630.       /*
  631.        * The possible -g flags are as follows:
  632.        *
  633.        * -ggdb[number]
  634.        * -gcodeview[number]
  635.        * -gstabs[number] (treated the same as -ggdb)
  636.        * -g[number] (treated the same as -ggdb)
  637.        *
  638.        * If no number is present it value is 2.  For this implementation
  639.        * the values of [number] fall into two classes zero (turn it off)
  640.        * and non-zero (turn it on).  By default gdb is on and codeview is
  641.        * off.  set_value() handles errors in [number] and if a value is
  642.        * specified as both on and off.
  643.        */
  644.       if (arg_len > 2)
  645.         {
  646.           if (!strncmp (argv[i]+2, "gdb", 3))
  647.         set_gvalue(argv[i], argv[i]+5, &gdb);
  648.           else if (!strncmp (argv[i]+2, "codeview", 8))
  649.         set_gvalue(argv[i], argv[i]+10, &codeview);
  650.           else if (!strncmp (argv[i]+2, "stab", 4))
  651.         set_gvalue(argv[i], argv[i]+6, &gdb);
  652.           else
  653.         set_gvalue(argv[i], argv[i]+2, &gdb);
  654.         }
  655.       else
  656.         set_gvalue(argv[i], argv[i]+2, &gdb);
  657.     }
  658.       else if (arg_len >= 5 && !strncmp (argv [i], "-debug", 6))
  659.     {
  660.       /*
  661.        * If any -debug or -debugtype flags are specified then we will
  662.        * honor them and never add any of our own for -g flags.
  663.        */
  664.       debug_flags_specified = 1;
  665.     }
  666.       else if (!strcmp (argv [i], "-o") ||
  667.            !strcmp (argv [i], "-framework") ||
  668.            !strcmp (argv [i], "-undefined") ||
  669.            !strcmp (argv [i], "-image_base") ||
  670.            !strcmp (argv [i], "-filelist"))
  671.     {
  672.       if (i + 1 >= argc)
  673.         {
  674.           fprintf (stderr, "%s: error: %s: argument missing\n", progname,
  675.                argv [i]);
  676.           cleanup (0);
  677.           exit (FATAL_EXIT_CODE);
  678.         }
  679.       i++;
  680.     }
  681.       else if (!strcmp (argv [i], "-lib") ||
  682.            !strcmp (argv [i], "/LIB"))
  683.     {
  684.       lib_seen = 1;
  685.     }
  686.       else if (!strcmp (argv [i], "-dll") ||
  687.            !strcmp (argv [i], "/DLL"))
  688.     {
  689.       dll_seen = 1;
  690.     }
  691.       else if (!strncmp (argv [i], "-def:", strlen("-def:")) ||
  692.                !strncmp (argv [i], "-DEF:", strlen("-DEF:")))
  693.     {
  694.       def_arg_index = link_arg_index;
  695.     }
  696.     }
  697.  
  698.   /* This must the the first argument if seen */
  699.   if (lib_seen == 1)
  700.     {
  701.       addarg ("/LIB");
  702.       dll_seen = 0;
  703.     }
  704.   else if (dll_seen && def_arg_index != -1)
  705.     {
  706.       addarg ("/LIB");
  707.       dll_arg_index = link_arg_index;
  708.     }
  709.  
  710. #endif /* defined (_WIN32) && defined (NEXT_PDO) */
  711.  
  712.   for (i = 1; i < argc; i++)
  713.     {
  714.       int arg_len = strlen (argv [i]);
  715.  
  716.       if (!strcmp (argv [i], "-o"))
  717.     {
  718.       char *buff, *ptr;
  719.       int out_len;
  720.  
  721.       i++;
  722.       out_len = strlen (argv[i]) + 10;
  723.       buff = malloc (out_len);
  724.       strcpy (buff, "-out:");
  725.       strcat (buff, argv[i]);
  726.       ptr = strstr (buff, ".exe");
  727.       if( ptr == NULL )
  728.           ptr = strstr( buff, ".dll" );
  729.       if (ptr == NULL || strlen (ptr) != 4)
  730.         strcat (buff, ".exe");
  731.       addarg (buff);
  732. #if defined (_WIN32) && defined (NEXT_PDO)
  733.       if (dll_seen && def_arg_index != -1)
  734.         {
  735.           if (ptr != NULL && strcmp(ptr, ".dll") == 0)
  736.         {
  737.           strcpy(ptr, ".lib");
  738.           out_arg_index = link_arg_index;
  739.         }
  740.           else
  741.         {
  742.           link_args[dll_arg_index] = "/DLL";
  743.           dll_seen = 0;
  744.         }
  745.         }
  746. #endif /* defined (_WIN32) && defined (NEXT_PDO) */
  747.     }
  748.       else if (arg_len >= 2 && !strncmp (argv [i], "-g", 2))
  749.         {
  750.       /* Picked up this argument in the first pass */
  751.         }
  752.       else if (arg_len > 2 && !strncmp (argv [i], "-L", 2))
  753.     {
  754.       /* Picked up this argument in the first pass */
  755.     }
  756.       else if (arg_len > 2 && !strncmp (argv [i], "-l", 2))
  757.     {
  758.       addarg (expand_lib (&argv[i][2]));
  759.     }
  760. #if defined (_WIN32) && defined (NEXT_PDO)
  761.       else if (!strncmp (argv [i], "-def:", strlen("-def:")) ||
  762.                !strncmp (argv [i], "-DEF:", strlen("-DEF:")))
  763.     {
  764.       addarg (argv [i]);
  765.       def_arg_index = link_arg_index;
  766.     }
  767.       else if (!strcmp (argv [i], "-lib") ||
  768.            !strcmp (argv [i], "/LIB"))
  769.     {
  770.       /* Picked up this argument in the first pass */
  771.     }
  772.       else if (!strcmp (argv [i], "-dll") ||
  773.            !strcmp (argv [i], "/DLL"))
  774.     {
  775.       /* Picked up this argument in the first pass,
  776.          but pass it on through if we didn't encounter a -def */
  777.       if (def_arg_index == -1)
  778.         addarg (argv [i]);
  779.     }
  780.       else if (!strcmp (argv [i], "-image_base"))
  781.     {
  782.       char *p;
  783.  
  784.         i++;
  785.         p = (char*)malloc (strlen(argv[i]) + 7);
  786.         strcpy (p, "/BASE:");
  787.         strcat (p, argv[i]);
  788.         addarg (p);
  789.     }
  790.       else if (!strcmp (argv [i], "-framework"))
  791.     {
  792.       char *type;
  793.       char *p;
  794.       char *file_name;
  795.       int count;
  796.       int fd = -1;            // not used, only for return value;
  797.  
  798.       i++;
  799.       fd = -1;
  800.       type = strrchr(argv[i], ',');
  801.       if (type != NULL && type[1] != '\0')
  802.         {
  803.           *type = '\0';
  804.           type++;
  805.           p = (char*)malloc ((strlen(argv[i])*2) + 11 + strlen(type) + 2);
  806.           sprintf (p, "%s%s%s%s", argv[i], ".framework/", argv[i], type);
  807.           search_for_framework(p, &file_name, &fd);
  808.           if (fd == -1)
  809.         {
  810.           fprintf(stderr, "%s: can't locate framework link library for:"
  811.               " -framework %s,%s using suffix %s\n", progname,
  812.               argv[i], type, type);
  813.         }
  814.           else
  815.         addarg (file_name);
  816.         }
  817.       else
  818.         type = NULL;
  819.       if (fd == -1)
  820.         {
  821.           p = (char*)malloc ((strlen(argv[i])*2) + 11 + 2);
  822.           sprintf (p, "%s%s%s", argv[i], ".framework/", argv[i]);
  823.           search_for_framework (p, &file_name, &fd);
  824.         }
  825.       if (fd == -1)
  826.         {
  827.           if (type != NULL)
  828.         {
  829.           fprintf (stderr, "%s: can't locate framework link library "
  830.                "for: -framework %s,%s\n", progname, argv[i], type);
  831.           cleanup (0);
  832.           exit(FATAL_EXIT_CODE);
  833.         }
  834.           else
  835.         {
  836.           fprintf (stderr, "%s: can't locate framework link library "
  837.                "for: -framework %s\n", progname, argv[i]);
  838.           cleanup (0);
  839.           exit(FATAL_EXIT_CODE);
  840.         }
  841.         }
  842.       else
  843.         addarg (file_name);
  844.     }
  845.       else if (!strncmp (argv [i], "-F", 2))
  846.     {
  847.       /* Picked up this argument in the first pass */
  848.     }
  849.       else if (!strcmp (argv[i], "-undefined"))
  850.     {
  851.       if (++i >= argc)
  852.         {
  853.           fprintf (stderr, "%s: error: Argument to -undefined missing\n",
  854.                progname);
  855.           cleanup (0);
  856.           exit (FATAL_EXIT_CODE);
  857.         }
  858.       if (!strcmp (argv[i], "warning") || !strcmp (argv[i], "suppress"))
  859.         {
  860.           if (!undefined_flag)
  861.         {
  862.           undefined_flag = 1;
  863.           addarg ("-force:unresolved");
  864.         }
  865.           else if (undefined_flag != 1)
  866.         {
  867.           fprintf (stderr, "%s: error: Multiple conflicting -undefined "
  868.                "flags\n", progname);
  869.           cleanup (0);
  870.           exit (FATAL_EXIT_CODE);
  871.         }
  872.         }
  873.       else if (!strcmp (argv[i], "error"))
  874.         {
  875.           if (undefined_flag > 0)
  876.         {
  877.           fprintf (stderr, "%s: error: Multiple conflicting -undefined "
  878.                "flags\n", progname);
  879.           cleanup (0);
  880.           exit (FATAL_EXIT_CODE);
  881.         }
  882.           undefined_flag = -1;
  883.         }
  884.       else
  885.         {
  886.           fprintf (stderr, "%s: error: unrecognized option \"-undefined "
  887.                "%s\"\n", progname, argv[i]);
  888.           cleanup (0);
  889.           exit (FATAL_EXIT_CODE);
  890.         }
  891.     }
  892.       else if (!strcmp (argv[i], "-filelist"))
  893.     {
  894.       if (++i >= argc)
  895.         {
  896.           fprintf (stderr, "%s: error: Argument to -filelist missing\n",
  897.                progname);
  898.           cleanup (0);
  899.           exit (FATAL_EXIT_CODE);
  900.         }
  901.       if (strrchr(argv[i], ',') == NULL)
  902.         {
  903.         char *at_arg = (char *) malloc (strlen (argv[i]) + 2);
  904.         strcpy (at_arg, "@");
  905.         strcat (at_arg, argv[i]);
  906.         addarg (at_arg);
  907.         }
  908.       else
  909.         {
  910.         addarg (add_to_tmp_at_file (argv [i]));
  911.         }
  912.     }
  913. #endif
  914.     else if (!strcmp (argv [i], "-v")) 
  915.       ;
  916.     else
  917.       addarg (argv [i]);
  918.     }
  919.  
  920.   if (debug_flags_specified == 0)
  921.     {
  922.     if (gdb == DEFAULT)
  923.       gdb = ON;
  924.     if (codeview == DEFAULT)
  925.       codeview = OFF;
  926.     if (gdb == ON)
  927.       {
  928.         if (codeview == ON)
  929.           {
  930.         addarg ("-debug");
  931.         addarg ("-debugtype:both");
  932.         addarg ("-pdb:none");
  933.           }
  934.         else
  935.           {
  936.         addarg ("-debug");
  937.         addarg ("-debugtype:coff");
  938.           }
  939.       }
  940.     else
  941.       {
  942.         if (codeview == ON)
  943.           {
  944.         addarg ("-debug");
  945.         addarg ("-debugtype:both");
  946.         addarg ("-pdb:none");
  947.           }
  948.         else
  949.           {
  950.         ; /* no flags */
  951.           }
  952.       }
  953.     }
  954.  
  955.   addarg (NULL);
  956.  
  957. #if defined (_WIN32) && defined (NEXT_PDO)
  958.       if (dll_seen && def_arg_index != -1)
  959.     libargs();
  960. #endif /* defined (_WIN32) && defined (NEXT_PDO) */
  961.  
  962.   if (verbose)
  963.     {
  964.       int i;
  965. #if defined (_WIN32) && defined (NEXT_PDO)
  966.       if (dll_seen && def_arg_index != -1)
  967.     {
  968.       for (i = 0; i < lib_arg_index; i++)
  969.         printf ("%s ", lib_args [i]);
  970.       putchar ('\n');
  971.     }
  972.       else
  973. #endif /* defined (_WIN32) && defined (NEXT_PDO) */
  974.       for (i = 0; i < link_arg_index; i++)
  975.     printf ("%s ", link_args [i]);
  976.       putchar ('\n');
  977.     }
  978.  
  979. #if defined (_WIN32) && defined (NEXT_PDO)
  980.   if (dll_seen && def_arg_index != -1)
  981.     {
  982.       if (spawnvp (P_WAIT, linker_path, (const char * const *)lib_args) != 0)
  983.         {
  984.       cleanup(0);
  985.       exit (FATAL_EXIT_CODE);
  986.         }
  987.     }
  988.   else
  989. #endif /* defined (_WIN32) && defined (NEXT_PDO) */
  990.  
  991.   if (spawnvp (P_WAIT, linker_path, (const char * const *)link_args) != 0)
  992.     {
  993. //    fprintf (stderr, "%s: error executing %s\n", progname, link_args[0]);
  994. #if defined (_WIN32) && defined (NEXT_PDO)
  995.       cleanup(0);
  996.       exit (FATAL_EXIT_CODE);
  997. #else
  998.       exit (-1);
  999. #endif /* defined (_WIN32) && defined (NEXT_PDO) */
  1000.     }
  1001.  
  1002. #if defined (_WIN32) && defined (NEXT_PDO)
  1003.   if (dll_seen && def_arg_index != -1)
  1004.     {
  1005.       char *buff, *ptr;
  1006.       int out_len;
  1007.  
  1008.       link_args[dll_arg_index] = "/DLL";
  1009.  
  1010.       ptr = strstr (link_args[out_arg_index], ".lib");
  1011.       strcpy (ptr, ".dll");
  1012.  
  1013.       out_len = strlen (link_args[out_arg_index]);
  1014.       buff = malloc (out_len);
  1015.       strcpy (buff, link_args[out_arg_index] + strlen ("-out:"));
  1016.       ptr = strstr (buff, ".dll" );
  1017.       strcpy (ptr, ".exp");
  1018.       if (def_arg_index != -1)
  1019.     link_args[def_arg_index] = buff;
  1020.       else
  1021.     addarg (buff);
  1022.  
  1023.     if (verbose)
  1024.       {
  1025.     int i;
  1026.  
  1027.     for (i = 0; i < link_arg_index; i++)
  1028.       printf ("%s ", link_args [i]);
  1029.     putchar ('\n');
  1030.       }
  1031.  
  1032.     if (spawnvp (P_WAIT, linker_path, (const char * const *)link_args) != 0)
  1033.       {
  1034.     fprintf (stderr, "%s: error executing %s\n", progname, link_args[0]);
  1035.     cleanup(0);
  1036.     exit (FATAL_EXIT_CODE);
  1037.       }
  1038.     }
  1039.   cleanup(0);
  1040. #endif /* defined (_WIN32) && defined (NEXT_PDO) */
  1041.  
  1042.   exit (0);
  1043. }
  1044.