source: vendor/emx/current/src/emxomf/emxomfld.c

Last change on this file was 18, checked in by bird, 23 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 21.4 KB
Line 
1/* emxomfld.c -- Provide an ld-like interface to LINK386
2 Copyright (c) 1992-1998 Eberhard Mattes
3
4This file is part of emxomld.
5
6emxomfld is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11emxomfld is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with emxomfld; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, 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. */
41typedef 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. */
49static const char *output_fname = NULL;
50
51/* The map file name (output), set by the -Zmap option. */
52static const char *map_fname = NULL;
53static 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. */
57static 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. */
61static const char *res_fname = NULL;
62
63/* Base address of the excecutable file, specified by the -T
64 option. */
65static 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. */
70static name_list *libdirs = NULL;
71static 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. */
77static name_list *obj_fnames = NULL;
78static 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. */
84static name_list *lib_fnames = NULL;
85static 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. */
90static name_list *options = NULL;
91static name_list **add_options = &options;
92
93/* The command line passed to LINK386. */
94static char command_line[260];
95
96/* The current length of the command line. */
97static int line_len;
98
99/* Non-zero if arguments go into the response file instead of
100 command_line. */
101static int response_flag;
102
103/* The name of the response file. */
104static char response_fname[L_tmpnam] = "";
105
106/* The response file. */
107static FILE *response_file = NULL;
108
109/* Non-zero if debugging information is to be omitted. Set by the -s
110 and -S options. */
111static 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. */
115static int exe_flag = FALSE;
116
117/* Non-zero when creating a dynamic link library. Set by the -Zdll
118 option. */
119static 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. */
123static 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. */
127static const char *linker_name = "link386";
128
129/* Prototypes. */
130
131static void usage (void) NORETURN2;
132static void *xmalloc (size_t n);
133static char *xstrdup (const char *s);
134static void add_name_list (name_list ***add, const char *src);
135static void conv_path (char *name);
136static void put_arg (const char *src, int path);
137static void put_args (const name_list *list, int paths);
138static void make_env (void);
139static void cleanup (void);
140static void arg_init (int rsp);
141static void arg_end (void);
142int main (int argc, char *argv[]);
143
144
145/* Tell the user how to run this program. */
146
147static 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
162static 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
180static 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
194static 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
209static 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
224static 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
354static 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
367static 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
410static 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
421static 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
439static 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
457int 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}
Note: See TracBrowser for help on using the repository browser.