home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / emxtutor.zip / emxsrcd1.zip / emx / src / emxomf / emxomfld.c < prev    next >
C/C++ Source or Header  |  1998-12-19  |  23KB  |  820 lines

  1. /* emxomfld.c --  Provide an ld-like interface to LINK386
  2.    Copyright (c) 1992-1998 Eberhard Mattes
  3.  
  4. This file is part of emxomld.
  5.  
  6. emxomfld is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. emxomfld is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with emxomfld; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 59 Temple Place - Suite 330,
  19. Boston, MA 02111-1307, USA.  */
  20.  
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <process.h>
  26. #include <io.h>
  27. #include <fcntl.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #include <getopt.h>
  31. #include <errno.h>
  32. #include <sys/moddef.h>
  33. #include "defs.h"
  34.  
  35. #define VERSION "0.9d"
  36.  
  37. #define FALSE 0
  38. #define TRUE  1
  39.  
  40. /* A member of a linked list of strings such as file names. */
  41. typedef struct name_list
  42. {
  43.   struct name_list *next;
  44.   char *name;
  45. } name_list;
  46.  
  47.  
  48. /* The output file name, specified by the -o option.  */
  49. static const char *output_fname = NULL;
  50.  
  51. /* The map file name (output), set by the -Zmap option. */
  52. static const char *map_fname = NULL;
  53. static int map_flag = FALSE;
  54.  
  55. /* The module definition file name (input), set if a file matching
  56.    *.def is given on the command line. */
  57. static const char *def_fname = NULL;
  58.  
  59. /* The binary resource file name (input), set if a file matching *.res
  60.    is given on the command line. */
  61. static const char *res_fname = NULL;
  62.  
  63. /* Base address of the excecutable file, specified by the -T
  64.    option. */
  65. static const char *base = NULL;
  66.  
  67. /* List of directories searched for libraries.  Each -L option adds a
  68.    directory to this list.  add_libdirs is used to add another entry
  69.    at the end of the list. */
  70. static name_list *libdirs = NULL;
  71. static name_list **add_libdirs = &libdirs;
  72.  
  73. /* List of object files.  Each file given on the command line which
  74.    does not match *.def, *.lib and *.res is added to this list.
  75.    add_obj_fnames is used to add another entry at the end of the
  76.    list. */
  77. static name_list *obj_fnames = NULL;
  78. static name_list **add_obj_fnames = &obj_fnames;
  79.  
  80. /* List of library files.  Each file matching *.lib given on the
  81.    command line is added to this list.  The -l option also adds an
  82.    entry to this list. add_lib_fnames is used to add another entry at
  83.    the end of the list. */
  84. static name_list *lib_fnames = NULL;
  85. static name_list **add_lib_fnames = &lib_fnames;
  86.  
  87. /* List of LINK386 options.  LINK386 options can be specified with the
  88.    -O option.  add_options is used to add another entry at the end of
  89.    the list. */
  90. static name_list *options = NULL;
  91. static name_list **add_options = &options;
  92.  
  93. /* The command line passed to LINK386. */
  94. static char command_line[260];
  95.  
  96. /* The current length of the command line. */
  97. static int line_len;
  98.  
  99. /* Non-zero if arguments go into the response file instead of
  100.    command_line. */
  101. static int response_flag;
  102.  
  103. /* The name of the response file. */
  104. static char response_fname[L_tmpnam] = "";
  105.  
  106. /* The response file. */
  107. static FILE *response_file = NULL;
  108.  
  109. /* Non-zero if debugging information is to be omitted.  Set by the -s
  110.    and -S options. */
  111. static int strip_symbols = FALSE;
  112.  
  113. /* Non-zero if emxomfld should create an .exe file and touch the
  114.    output file.  Set by the -Zexe option. */
  115. static int exe_flag = FALSE;
  116.  
  117. /* Non-zero when creating a dynamic link library.  Set by the -Zdll
  118.    option. */
  119. static int dll_flag = FALSE;
  120.  
  121. /* The stack size, specified by the -Zstack option, in Kbyte.  If the
  122.    -Zstack option is not used, this variable is 0. */
  123. static long stack_size = 0;
  124.  
  125. /* The name of the linker to use.  By default, LINK386 is used.  This
  126.    can be overriden with the EMXOMFLD_LINKER environment variable. */
  127. static const char *linker_name = "link386";
  128.  
  129. /* Prototypes. */
  130.  
  131. static void usage (void) NORETURN2;
  132. static void *xmalloc (size_t n);
  133. static char *xstrdup (const char *s);
  134. static void add_name_list (name_list ***add, const char *src);
  135. static void conv_path (char *name);
  136. static void put_arg (const char *src, int path);
  137. static void put_args (const name_list *list, int paths);
  138. static void make_env (void);
  139. static void cleanup (void);
  140. static void arg_init (int rsp);
  141. static void arg_end (void);
  142. int main (int argc, char *argv[]);
  143.  
  144.  
  145. /* Tell the user how to run this program. */
  146.  
  147. static void usage (void)
  148. {
  149.   fprintf (stderr, "emxomfld " VERSION " -- "
  150.            "Copyright (c) 1992-1996 by Eberhard Mattes\n\n");
  151.   fprintf (stderr,
  152.            "Usage: emxomfld -o <file> [-l <lib>] [-L <libdir>] [-T <base>] [-sS]\n"
  153.            "                [-Zexe] [-Zdll] [-Zstack <size>] [-Zmap[=<map_file>]]\n"
  154.            "                [-O <option>] <file>...\n");
  155.   exit (1);
  156. }
  157.  
  158.  
  159. /* Allocate N bytes of memory.  Quit on failure.  This function is
  160.    used like malloc(), but we don't have to check the return value. */
  161.  
  162. static void *xmalloc (size_t n)
  163. {
  164.   void *p;
  165.   
  166.   p = malloc (n);
  167.   if (p == NULL)
  168.     {
  169.       fprintf (stderr, "emxomfld: out of memory\n");
  170.       exit (2);
  171.     }
  172.   return p;
  173. }
  174.  
  175.  
  176. /* Create a duplicate of the string S on the heap.  Quit on failure.
  177.    This function is used like strdup(), but we don't have to check the
  178.    return value. */
  179.  
  180. static char *xstrdup (const char *s)
  181. {
  182.   char *p;
  183.   
  184.   p = xmalloc (strlen (s) + 1);
  185.   strcpy (p, s);
  186.   return p;
  187. }
  188.  
  189.  
  190. /* Add the name SRC to a list.  ADD is a pointer to the pointer of the
  191.    end of the list.  We duplicate the string before adding it to the
  192.    list. */
  193.  
  194. static void add_name_list (name_list ***add, const char *src)
  195. {
  196.   name_list *new;
  197.  
  198.   new = xmalloc (sizeof (name_list));
  199.   new->next = NULL;
  200.   new->name = xstrdup (src);
  201.   *(*add) = new;
  202.   (*add) = &new->next;
  203. }
  204.  
  205.  
  206. /* Replace forward slashes `/' in NAME with backslashes `\'.  LINK386
  207.    needs backslashes in path names. */
  208.  
  209. static void conv_path (char *name)
  210. {
  211.   char *p;
  212.  
  213.   for (p = name; *p != 0; ++p)
  214.     if (*p == '/')
  215.       *p = '\\';
  216. }
  217.  
  218.  
  219. /* Add the argument SRC to the command line or to the response file.
  220.    If PATH is non-zero, SRC is a path name and slashes are to be
  221.    replaced by backslashes.  If the command line gets too long, a
  222.    response file is created. */
  223.  
  224. static void put_arg (const char *src, int path)
  225. {
  226.   int len, max_len;
  227.   char *tmp;
  228.  
  229.   if (src != NULL)
  230.     {
  231.  
  232.       /* Instead of a comma, we write a newline to the response
  233.          file. */
  234.  
  235.       if (response_file != NULL && strcmp (src, ",") == 0)
  236.         {
  237.           fputc ('\n', response_file);
  238.           line_len = 0;
  239.           return;
  240.         }
  241.  
  242.       /* Make a local copy of SRC to be able to modify it.  Then,
  243.          translate forward slashes to backslashes if PATH is
  244.          non-zero. */
  245.  
  246.       len = strlen (src);
  247.       tmp = alloca (len + 1);
  248.       strcpy (tmp, src);
  249.       if (path)
  250.         conv_path (tmp);
  251.  
  252.       /* Check if we've reached the maximum line length.  If the
  253.          maximum command line length is exceeded, create a response
  254.          file and write the remaining arguments to that file instead
  255.          of putting them on the command line. */
  256.  
  257.       max_len = (response_file == NULL ? 110 : 52);
  258.       if (line_len + len + 1 > max_len)
  259.         {
  260.  
  261.           /* If SRC is a single comma or a single semicolon, copy it
  262.              to the output, ignoring the maximum line length.  This is
  263.              to meet the LINK386 command syntax. The maximum line
  264.              length allows for enough commas and semicolons added this
  265.              way. */
  266.  
  267.           if ((*tmp == ',' || *tmp == ';') && tmp[1] == 0)
  268.             {
  269.               if (response_file == NULL)
  270.                 {
  271.                   command_line[line_len+0] = *tmp;
  272.                   command_line[line_len+1] = 0;
  273.                 }
  274.               else
  275.                 fputc (*tmp, response_file);
  276.               ++line_len;
  277.               return;
  278.             }
  279.  
  280.           /* If a response file has not yet been opened, open it. */
  281.  
  282.           if (response_file == NULL)
  283.             {
  284.  
  285.               /* Complain if we are not allowed to use a response
  286.                  file. */
  287.  
  288.               if (!response_flag)
  289.                 {
  290.                   fprintf (stderr, "emxomfld: command line too long\n");
  291.                   exit (2);
  292.                 }
  293.  
  294.               /* Choose a unique file name and create the response
  295.                  file. */
  296.  
  297.               strcpy (response_fname, "ldXXXXXX");
  298.               if (mktemp (response_fname) == NULL)
  299.                 {
  300.                   perror ("emxomfld");
  301.                   exit (2);
  302.                 }
  303.               response_file = fopen (response_fname, "wt");
  304.               if (response_file == NULL)
  305.                 {
  306.                   perror ("emxomfld");
  307.                   exit (2);
  308.                 }
  309.  
  310.               /* Add the name of the response file to the command
  311.                  line. */
  312.  
  313.               command_line[line_len++] = ' ';
  314.               command_line[line_len++] = '@';
  315.               strcpy (command_line+line_len, response_fname);
  316.             }
  317.           else if (line_len != 0)
  318.             {
  319.  
  320.               /* Start a new line in the response file. */
  321.  
  322.               fputs (" +\n", response_file);
  323.             }
  324.           line_len = 0;
  325.         }
  326.  
  327.       /* Separate command line arguments by spaces (unless the
  328.          argument to be added starts with a delimiter. */
  329.  
  330.       if (line_len != 0 && *src != ',' && *src != ';')
  331.         {
  332.           if (response_file == NULL)
  333.             command_line[line_len++] = ' ';
  334.           else
  335.             fputc (' ', response_file);
  336.         }
  337.  
  338.       /* Finally write the argument to the command line or to the
  339.          response file and adjust the current line length. */
  340.  
  341.       if (response_file == NULL)
  342.         strcpy (command_line + line_len, tmp);
  343.       else
  344.         fputs (tmp, response_file);
  345.       line_len += len;
  346.     }
  347. }
  348.  
  349.  
  350. /* Put a list of arguments onto the command line or into the response
  351.    file.  If PATHS is non-zero, the arguments are path names and
  352.    slashes are to be replaced by backslashes. */
  353.  
  354. static void put_args (const name_list *list, int paths)
  355. {
  356.   while (list != NULL)
  357.     {
  358.       put_arg (list->name, paths);
  359.       list = list->next;
  360.     }
  361. }
  362.  
  363.  
  364. /* Build the environment for LINK386: define the LIB environment
  365.    variable. */
  366.  
  367. static void make_env (void)
  368. {
  369.   static char tmp[4096];
  370.   char *p;
  371.   int len;
  372.   const name_list *list;
  373.  
  374.   /* Create a string for putenv(). */
  375.  
  376.   strcpy (tmp, "LIB=");
  377.   len = strlen (tmp);
  378.  
  379.   /* Add the library directories to LIB, using `;' as separator. */
  380.  
  381.   for (list = libdirs; list != NULL; list = list->next)
  382.     {
  383.       if (tmp[len-1] != ';')
  384.         tmp[len++] = ';';
  385.       strcpy (tmp+len, list->name);
  386.       conv_path (tmp+len);
  387.       len += strlen (list->name);
  388.     }
  389.  
  390.   /* Append to the end the previous definition of LIB. */
  391.  
  392.   p = getenv ("LIB");
  393.   if (p != NULL)
  394.     {
  395.       if (tmp[len-1] != ';')
  396.         tmp[len++] = ';';
  397.       strcpy (tmp+len, p);
  398.     }
  399.  
  400.  
  401.   /* Put the new value of LIB into the environment. */
  402.  
  403.   putenv (tmp);
  404. }
  405.  
  406.  
  407. /* Start a new set of command line arguments.  If RSP is non-zero, we
  408.    are allowed to use a response file. */
  409.  
  410. static void arg_init (int rsp)
  411. {
  412.   command_line[0] = 0;
  413.   line_len = 0;
  414.   response_flag = rsp;
  415. }
  416.  
  417.  
  418. /* Call this after adding all the command line arguments.  If a
  419.    response file has been created, add a newline and close it. */
  420.  
  421. static void arg_end (void)
  422. {
  423.   if (response_file != NULL)
  424.     {
  425.       fputc ('\n', response_file);
  426.       if (fflush (response_file) != 0 || fclose (response_file) != 0)
  427.         {
  428.           perror ("emxomfld");
  429.           exit (2);
  430.         }
  431.       response_file = NULL;
  432.     }
  433. }
  434.  
  435.  
  436. /* Cleanup by closing (if open) and deleting (if pressent) the
  437.    response file.  This function is used with atexit(). */
  438.  
  439. static void cleanup (void)
  440. {
  441.   if (response_file != NULL)
  442.     {
  443.       fclose (response_file);
  444.       response_file = NULL;
  445.     }
  446.   if (response_fname[0] != 0)
  447.     {
  448.       remove (response_fname);
  449.       response_fname[0] = 0;
  450.     }
  451. }
  452.  
  453.  
  454. /* Main function of emxomf.  Parse the command line and call LINK386
  455.    (and optionally RC). */
  456.  
  457. int main (int argc, char *argv[])
  458. {
  459.   int c, rc, files;
  460.   int opt_i;
  461.   const char *ext;
  462.   char tmp[512], *t;
  463.  
  464.   /* Close and delete the response file on exit. */
  465.  
  466.   atexit (cleanup);
  467.  
  468.   /* Prepare parsing of the command line. */
  469.  
  470.   opt_i = FALSE; files = 0;
  471.   opterr = FALSE; optmode = GETOPT_KEEP;
  472.   if (argc < 2)
  473.     usage ();
  474.  
  475.   /* Parse the command line options and other arguments. */
  476.  
  477.   while ((c = getopt (argc, argv, "o:O:il:vL:T:sSxXZ:")) != EOF)
  478.     switch (c)
  479.       {
  480.       case 'i':                 /* Use /INFORMATION option of LINK386 */
  481.         opt_i = TRUE;
  482.         break;
  483.  
  484.       case 'l':                 /* Add library */
  485.         add_name_list (&add_lib_fnames, optarg);
  486.         break;
  487.  
  488.       case 'o':                 /* Set output file name */
  489.         output_fname = optarg;
  490.         break;
  491.  
  492.       case 'L':                 /* Add library directory */
  493.         add_name_list (&add_libdirs, optarg);
  494.         break;
  495.  
  496.       case 'T':                 /* Set base address */
  497.         base = optarg;
  498.         break;
  499.  
  500.       case 's':                 /* Strip all symbols */
  501.       case 'S':                 /* Strip debugging symbols */
  502.         strip_symbols = TRUE;
  503.         break;
  504.  
  505.       case 'x':                 /* Discard all local symbols */
  506.       case 'X':                 /* Discard local symbols starting with L */
  507.         break;
  508.  
  509.       case 'v':                 /* For compatibility */
  510.         break;
  511.  
  512.       case 'O':                 /* Specify LINK386 option */
  513.         add_name_list (&add_options, optarg);
  514.         break;
  515.  
  516.       case 'Z':                 /* -Zdll, -Zexe, -Zmap, and -Zstack */
  517.         if (strcmp (optarg, "dll") == 0)
  518.           dll_flag = TRUE;
  519.         else if (strcmp (optarg, "exe") == 0)
  520.           exe_flag = TRUE;
  521.         else if (strcmp (optarg, "map") == 0)
  522.           map_flag = TRUE;
  523.         else if (strncmp (optarg, "map=", 4) == 0)
  524.           {
  525.             if (map_fname != NULL)
  526.               {
  527.                 fprintf (stderr, "emxomfld: multiple map files files\n");
  528.                 usage ();
  529.               }
  530.             map_fname = optarg + 4;
  531.             map_flag = TRUE;
  532.           }
  533.         else if (strcmp (optarg, "stack") == 0)
  534.           {
  535.             /* This makes assumptions on the internals of getopt(). */
  536.  
  537.             if (optind >= argc || argv[optind][0] == '-')
  538.               usage ();
  539.             errno = 0;
  540.             stack_size = strtol (argv[optind], &t, 0);
  541.             if (errno != 0 || *t != 0 || t == argv[optind])
  542.               usage ();
  543.             ++optind;
  544.           }
  545.         else
  546.           {
  547.             fprintf (stderr, "emxomfld: invalid option\n");
  548.             usage ();
  549.           }
  550.         break;
  551.  
  552.       case 0:                   /* Non-option argument */
  553.  
  554.         /* Extract the extension to see what to do with this
  555.            argument. */
  556.  
  557.         ext = _getext (optarg);
  558.  
  559.         if (ext == NULL)
  560.           {
  561.             /* GCC's temporary files don't have an extension.  Add a
  562.                dot to the end of the name to prevent LINK386 from
  563.                adding `.obj'. */
  564.  
  565.             sprintf (tmp, "%s.", optarg);
  566.             add_name_list (&add_obj_fnames, tmp);
  567.           }
  568.  
  569.         /* If it's a .def file, use it as module definition file
  570.            (input). */
  571.  
  572.         else if (stricmp (ext, ".def") == 0)
  573.           {
  574.             if (def_fname != NULL)
  575.               {
  576.                 fprintf (stderr,
  577.                          "emxomfld: multiple module definition files\n");
  578.                 usage ();
  579.               }
  580.             def_fname = optarg;
  581.           }
  582.  
  583.         /* If it's a .res file, use it as binary resource file
  584.            (input). */
  585.  
  586.         else if (stricmp (ext, ".res") == 0)
  587.           {
  588.             if (res_fname != NULL)
  589.               {
  590.                 fprintf (stderr,
  591.                          "emxomfld: multiple binary resource files\n");
  592.                 usage ();
  593.               }
  594.             res_fname = optarg;
  595.           }
  596.  
  597.         /* If it's a .lib file, use it as library file.  We also
  598.            accept .a files for those who use OMF files disguised as
  599.            a.out files (to simplify their make files). */
  600.  
  601.         else if (stricmp (ext, ".lib") == 0 || stricmp (ext, ".a") == 0)
  602.           add_name_list (&add_lib_fnames, optarg);
  603.  
  604.         /* Otherwise, assume it's an object file. */
  605.  
  606.         else
  607.           add_name_list (&add_obj_fnames, optarg);
  608.         ++files;
  609.         break;
  610.  
  611.       default:
  612.         fprintf (stderr, "emxomfld: invalid option\n");
  613.         usage ();
  614.       }
  615.  
  616.   /* Set default value for output file. */
  617.  
  618.   if (output_fname == NULL)
  619.     {
  620.       fprintf (stderr,
  621.                "emxomfld: no output file, creating $$$.exe or $$$.dll\n");
  622.       output_fname = "$$$";
  623.     }
  624.  
  625.   /* Check if there are any input files. */
  626.  
  627.   if (files == 0)
  628.     {
  629.       fprintf (stderr, "emxomfld: no input files\n");
  630.       usage ();
  631.     }
  632.  
  633.   /* Remove the output file if -Zexe is given. */
  634.  
  635.   if (exe_flag)
  636.     remove (output_fname);
  637.  
  638.   /* If neither -Zmap nor -Zmap=file is used, pass "nul" to LINK386 in
  639.      the map file field.  If -Zmap is used, construct the name of the
  640.      .map file.  If -Zmap=file is used, use `file' as the name of the
  641.      .map file. */
  642.  
  643.   if (!map_flag)
  644.     map_fname = "nul";
  645.   else if (map_fname == NULL)
  646.     {
  647.       t = xstrdup (output_fname);
  648.       _remext (t);
  649.       map_fname = t;
  650.     }
  651.  
  652.   t = getenv ("EMXOMFLD_LINKER");
  653.   if (t != NULL)
  654.     linker_name = t;
  655.  
  656.   /* Start building the LINK386 command line.  We can use a response
  657.      file if the command line gets too long. */
  658.  
  659.   arg_init (TRUE);
  660.  
  661.   /* Default options are:
  662.  
  663.      /BATCH             Run in batch mode (disable prompting, don't
  664.                         echo response file)
  665.  
  666.      /NOLOGO            Don't display sign-on banner
  667.  
  668.      /NOEXTDICTIONARY   Don't use extended dictionary (redefining
  669.                         library symbols is quite common)
  670.  
  671.      /NOIGNORECASE      Make symbols case-sensitive
  672.  
  673.      /PACKCODE          Group neighboring code segments (this is the
  674.                         default unless the SEGMENTS module definition
  675.                         statement is used for a segment of class
  676.                         'CODE').  Not grouping neighboring code
  677.                         segments would break sets */
  678.  
  679.   put_arg (linker_name, TRUE);
  680.   put_arg ("/bat", FALSE);
  681.   put_arg ("/nol", FALSE);
  682.   put_arg ("/noe", FALSE);
  683.   put_arg ("/noi", FALSE);
  684.   put_arg ("/packc", FALSE);
  685.  
  686.   /* Add the /INFORMATION option if the -i option was given.  This is
  687.      for debugging. */
  688.  
  689.   if (opt_i)
  690.     put_arg ("/i", FALSE);
  691.  
  692.   /* Add the /DEBUG option if the -s option was not given.  Without
  693.      this, LINK386 throws away debugging information. */
  694.  
  695.   if (!strip_symbols)
  696.     put_arg ("/de", FALSE);
  697.  
  698.   /* Add the /BASE:n option to set the base address.  This specifies
  699.      the preferred load address of object 1.  The base address being
  700.      used is 0x10000 unless a DLL is generated or the -T option was
  701.      given.  -Tno can be used to suppress the /BASE:n option. */
  702.  
  703.   if (base == NULL && !dll_flag)
  704.     {
  705.       struct _md *md;
  706.  
  707.       if (def_fname != NULL)
  708.         {
  709.           md = _md_open (def_fname);
  710.           if (md == NULL)
  711.             {
  712.               fprintf (stderr, "emxomfld: cannot open `%s'\n", def_fname);
  713.               exit (2);
  714.             }
  715.           if (_md_next_token (md) == _MD_LIBRARY)
  716.             dll_flag = TRUE;
  717.           _md_close (md);
  718.         }
  719.     }
  720.   if (base == NULL && !dll_flag)
  721.     base = "0x10000";
  722.   if (base != NULL && strcmp (base, "no") != 0)
  723.     {
  724.       sprintf (tmp, "/bas:%s", base);
  725.       put_arg (tmp, FALSE);
  726.     }
  727.  
  728.   /* Add the /STACK:n option if the -Zstack option was given. */
  729.  
  730.   if (stack_size != 0)
  731.     {
  732.       sprintf (tmp, "/st:0x%lx", stack_size * 1024);
  733.       put_arg (tmp, FALSE);
  734.     }
  735.  
  736.   /* Add the LINK386 options specified with -O. */
  737.  
  738.   put_args (options, FALSE);
  739.  
  740.   /* Put the object file names onto the command line. */
  741.  
  742.   put_args (obj_fnames, TRUE);
  743.   put_arg (",", FALSE);
  744.  
  745.   /* Put the output file name onto the command line. */
  746.  
  747.   put_arg (output_fname, TRUE);
  748.   put_arg (",", FALSE);
  749.  
  750.   /* Put the map file name onto the command line. */
  751.  
  752.   put_arg (map_fname, TRUE);
  753.   put_arg (",", FALSE);
  754.  
  755.   /* Put the library file names onto the command line. */
  756.  
  757.   put_args (lib_fnames, TRUE);
  758.   put_arg (",", FALSE);
  759.  
  760.   /* Put the name of the module definition file onto the command line. */
  761.  
  762.   put_arg (def_fname, TRUE);
  763.   put_arg (";", FALSE);
  764.   arg_end ();
  765.  
  766.   /* Build the environment for LINK386. */
  767.  
  768.   make_env ();
  769.  
  770.   /* Call LINK386 via CMD.EXE (what a waste -- but I'm lazy) and abort
  771.      on failure. */
  772.  
  773.   rc = system (command_line);
  774.   if (rc < 0)
  775.     {
  776.       perror (linker_name);
  777.       exit (2);
  778.     }
  779.  
  780.   /* Run RC if LINK386 completed successfully and a binary resource
  781.      file was given on the command line. */
  782.  
  783.   if (rc == 0 && res_fname != NULL)
  784.     {
  785.       arg_init (TRUE);
  786.       put_arg ("rc", TRUE);
  787.       put_arg (res_fname, TRUE);
  788.       put_arg (output_fname, TRUE);
  789.       arg_end ();
  790.       rc = system (command_line);
  791.       if (rc < 0)
  792.         {
  793.           perror ("emxomfld: rc");
  794.           exit (2);
  795.         }
  796.     }
  797.  
  798.   /* If both LINK386 and RC competed successfully and the -Zexe option
  799.      was given, touch the output file (without .exe) to keep `make'
  800.      happy. */
  801.  
  802.   if (rc == 0 && exe_flag)
  803.     {
  804.       int h;
  805.  
  806.       h = open (output_fname,
  807.                 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
  808.       if (h < 0)
  809.         {
  810.           perror ("emxomfld");
  811.           exit (2);
  812.         }
  813.       close (h);
  814.     }
  815.  
  816.   /* Return the return code of LINK386 (or RC). */
  817.  
  818.   return rc;
  819. }
  820.