source: trunk/emx/src/emxomf/emxomfld.c@ 2997

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

Applied the -Zsym patch from Yuri.

  • Property cvs2svn:cvs-rev set to 1.42
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 65.9 KB
Line 
1/* emxomfld.c -- Provide an ld-like interface to the IBM and M$ linkers
2 Copyright (c) 1992-1998 Eberhard Mattes
3 Copyright (c) 2003 InnoTek Systemberatung GmbH
4 Copyright (c) 2003-2004 Knut St. Osmundsen
5
6This file is part of emxomld.
7
8emxomfld is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2, or (at your option)
11any later version.
12
13emxomfld is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with emxomfld; see the file COPYING. If not, write to
20the Free Software Foundation, 59 Temple Place - Suite 330,
21Boston, MA 02111-1307, USA. */
22
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <alloca.h>
27#include <errno.h>
28#include <string.h>
29#include <process.h>
30#include <io.h>
31#include <fcntl.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <sys/utime.h>
35#include <sys/moddef.h>
36#include <getopt.h>
37#include <alloca.h>
38#include <sys/omflib.h>
39#include "defs.h"
40#include "weakld.h"
41
42#define FALSE 0
43#define TRUE 1
44
45/* A member of a linked list of strings such as file names. */
46typedef struct name_list
47{
48 struct name_list *next;
49 unsigned flags;
50 char *name;
51} name_list;
52
53
54/* Whether or not linker tracing is enabled. */
55static int opt_t;
56
57/* Whether or not to include .dll in the shared library searching. */
58static int opt_dll_search;
59
60/* The output file name, specified by the -o option. */
61static const char *output_fname = NULL;
62
63/* The map file name (output), set by the -Zmap option. */
64static const char *map_fname = NULL;
65static int map_flag = FALSE;
66
67/* The sym file output flag, set by the -Zsym option. */
68static int sym_flag = FALSE;
69
70/* The module definition file name (input), set if a file matching
71 *.def is given on the command line. */
72static const char *def_fname = NULL;
73
74/* The binary resource file name (input), set if a file matching *.res
75 is given on the command line. */
76static const char *res_fname = NULL;
77
78/* Base address of the excecutable file, specified by the -T
79 option. */
80static const char *base = NULL;
81
82/* List of directories searched for libraries. Each -L option adds a
83 directory to this list. add_libdirs is used to add another entry
84 at the end of the list. */
85static name_list *libdirs = NULL;
86static name_list **add_libdirs = &libdirs;
87
88/* List of object files. Each file given on the command line which
89 does not match *.def, *.lib and *.res is added to this list.
90 add_obj_fnames is used to add another entry at the end of the
91 list. */
92static name_list *obj_fnames = NULL;
93static name_list **add_obj_fnames = &obj_fnames;
94
95/* List of library files. Each file matching *.lib given on the
96 command line is added to this list. The -l option also adds an
97 entry to this list. add_lib_fnames is used to add another entry at
98 the end of the list.
99 The flags member indicates library search method. If set search for
100 static lib, if clear search for shared lib before search for static lib. */
101static name_list *lib_fnames = NULL;
102static name_list **add_lib_fnames = &lib_fnames;
103
104/* List of linker options. Linker options can be specified with the
105 -O option. add_options is used to add another entry at the end of
106 the list. */
107static name_list *options = NULL;
108static name_list **add_options = &options;
109
110/* The command line passed to the linker. */
111static char command_line[260];
112
113/* The current length of the command line. */
114static int line_len;
115
116/* Non-zero if arguments go into the response file instead of
117 command_line. */
118static int response_flag;
119
120/* The name of the response file. */
121static char response_fname[L_tmpnam] = "";
122
123/* The response file. */
124static FILE *response_file = NULL;
125
126/* Force the use of a response file from the next put_arg(). */
127static int force_response_file = FALSE;
128
129/* Weak alias object file. */
130static char weakobj_fname[_MAX_PATH + 1];
131
132/* Weak definition file (modified def_fname). */
133static char weakdef_fname[_MAX_PATH + 1];
134
135/* list of converted libraries and objects which must be removed upon exit. */
136static name_list *conv_list = NULL;
137
138/* Non-zero if debugging information is to be omitted. Set by the -s
139 and -S options. */
140static int strip_symbols = FALSE;
141
142/* Non-zero if emxomfld should create an .exe file and touch the
143 output file. Set by the -Zexe option. */
144static int exe_flag = FALSE;
145
146/* Non-zero when creating a dynamic link library. Set by the -Zdll
147 option. */
148static int dll_flag = FALSE;
149
150/* The stack size, specified by the -Zstack option, in Kbyte. If the
151 -Zstack option is not used, this variable defaults to 1024 to match
152 the defaults of emxbind. */
153static long stack_size = 1024;
154
155/* The name of the linker to use. By default, ilink is used. This
156 can be overridden with the EMXOMFLD_LINKER environment variable. */
157static const char *linker_name = "wlink.exe";
158
159/* The type of linker to use. By default we assume it's VAC365 or later
160 version of ilink. This can be overridden with the EMXOMFLD_TYPE env.
161 var. using any of the values WLINK, VAC365, VAC308 and LINK386. */
162static const char *linker_type = "WLINK";
163
164/* Non-zero if emxomfld should automatically convert a.out objects and
165 archives to the OMF equivalents during linking. */
166static int autoconvert_flag = 1;
167
168
169/* Prototypes. */
170
171static void usage (void) NORETURN2;
172extern void *xmalloc (size_t n);
173extern void *xrealloc (void *ptr, size_t n);
174extern char *xstrdup (const char *s);
175static void add_name_list (name_list ***add, const char *src, unsigned flags);
176static void conv_path (char *name);
177static void put_arg (const char *src, int path, int quotable);
178static void put_args (const name_list *list, int paths);
179static void make_env (void);
180static void cleanup (void);
181static void arg_init (int rsp);
182static void arg_end (void);
183int main (int argc, char *argv[]);
184
185/* To avoid including os2.h... */
186#ifndef _System
187#define _System
188#endif
189extern int _System DosCopy (char *, char *, int);
190
191/* Allocate N bytes of memory. Quit on failure. This function is
192 used like malloc(), but we don't have to check the return value. */
193
194void *xmalloc (size_t n)
195{
196 void *p;
197
198 p = malloc (n);
199 if (p == NULL && n)
200 {
201 fprintf (stderr, "emxomfld: out of memory\n");
202 exit (2);
203 }
204 return p;
205}
206
207
208/* Change the allocation of PTR to N bytes. Quit on failure. This
209 function is used like realloc(), but we don't have to check the
210 return value. */
211
212void *xrealloc (void *ptr, size_t n)
213{
214 void *p;
215
216 p = realloc (ptr, n);
217 if (p == NULL && n)
218 {
219 fprintf (stderr, "emxomfld: out of memory\n");
220 exit (2);
221 }
222 return p;
223}
224
225
226
227/* Create a duplicate of the string S on the heap. Quit on failure.
228 This function is used like strdup(), but we don't have to check the
229 return value. */
230
231char *xstrdup (const char *s)
232{
233 char *p;
234 int cch = strlen (s) + 1;
235
236 p = xmalloc (cch);
237 memcpy (p, s, cch);
238 return p;
239}
240
241
242/* Add the name SRC to a list. ADD is a pointer to the pointer of the
243 end of the list. We duplicate the string before adding it to the
244 list. */
245
246static void add_name_list (name_list ***add, const char *src, unsigned flags)
247{
248 name_list *node;
249
250 node = xmalloc (sizeof (name_list));
251 node->next = NULL;
252 node->name = xstrdup (src);
253 node->flags = flags;
254 *(*add) = node;
255 (*add) = &node->next;
256}
257
258/* Opens a response file. */
259
260static void open_response_file(void)
261{
262 int fd;
263
264 if (response_file)
265 return;
266
267 /* Complain if we are not allowed to use a response
268 file. */
269
270 if (!response_flag)
271 {
272 fprintf (stderr, "emxomfld: command line too long\n");
273 exit (2);
274 }
275
276 /* Choose a unique file name and create the response
277 file. */
278
279 strcpy (response_fname, "ldXXXXXX");
280 fd = mkstemp (response_fname);
281 if (fd < 0)
282 {
283 perror ("emxomfld");
284 exit (2);
285 }
286 close(fd);
287 response_file = fopen (response_fname, "wt");
288 if (response_file == NULL)
289 {
290 perror ("emxomfld");
291 exit (2);
292 }
293
294 /* Add the name of the response file to the command
295 line. */
296
297 command_line[line_len++] = ' ';
298 command_line[line_len++] = '@';
299 strcpy (command_line+line_len, response_fname);
300 if (!stricmp (linker_type, "WLINK"))
301 strcat (command_line, ".");
302
303 if (force_response_file)
304 force_response_file = FALSE;
305}
306
307/* Replace forward slashes `/' in NAME with backslashes `\'. The linkers
308 requires backslashes in path names. */
309
310static void conv_path (char *name)
311{
312 char *p;
313
314 for (p = name; *p != 0; ++p)
315 if (*p == '/')
316 *p = '\\';
317}
318
319
320/* Add the argument SRC to the command line or to the response file.
321 If PATH is non-zero, SRC is a path name and slashes are to be
322 replaced by backslashes. If the command line gets too long, a
323 response file is created.
324 If quotable is non-zero SRC will be quoted. This is required for
325 supporting files names which includes '+' and spaces. */
326
327static void put_arg (const char *src, int path, int quotable)
328{
329 int len, max_len;
330 char *tmp;
331
332 if (src != NULL)
333 {
334
335 /* Instead of a comma, we write a newline to the response
336 file. */
337
338 if (response_file != NULL && strcmp (src, ",") == 0)
339 {
340 fputc ('\n', response_file);
341 line_len = 0;
342 return;
343 }
344
345 /* Make a local copy of SRC to be able to modify it. Then,
346 translate forward slashes to backslashes if PATH is
347 non-zero. */
348
349 len = strlen (src);
350 tmp = alloca (len + (quotable ? 3 : 1));
351 if (path)
352 {
353 /* needs quoting? */
354 if (quotable)
355 {
356 *tmp = '"';
357 strcpy (tmp+1, src);
358 tmp[++len] = '"';
359 tmp[++len] = '\0';
360 }
361 else
362 strcpy (tmp, src);
363 conv_path (tmp);
364 }
365 else
366 strcpy (tmp, src);
367
368
369 /* Check if we've reached the maximum line length. If the
370 maximum command line length is exceeded, create a response
371 file and write the remaining arguments to that file instead
372 of putting them on the command line. */
373
374 max_len = (response_file == NULL ? 110 : 52);
375 if ( line_len + len + 1 > max_len
376 || (force_response_file && !response_file))
377 {
378
379 /* If SRC is a single comma or a single semicolon, copy it
380 to the output, ignoring the maximum line length. This is
381 to meet the IBM/M$ linker command syntax. The maximum line
382 length allows for enough commas and semicolons added this
383 way. */
384
385 if ((*tmp == ',' || *tmp == ';') && tmp[1] == 0)
386 {
387 if (response_file == NULL)
388 {
389 command_line[line_len+0] = *tmp;
390 command_line[line_len+1] = 0;
391 }
392 else
393 fputc (*tmp, response_file);
394 ++line_len;
395 return;
396 }
397
398 /* If a response file has not yet been opened, open it. */
399
400 if (response_file == NULL)
401 open_response_file();
402 else if (line_len != 0)
403 {
404
405 /* Start a new line in the response file. */
406
407 fputs (" +\n", response_file);
408 }
409 line_len = 0;
410 }
411
412 /* Separate command line arguments by spaces (unless the
413 argument to be added starts with a delimiter. */
414
415 if (line_len != 0 && *src != ',' && *src != ';')
416 {
417 if (response_file == NULL)
418 command_line[line_len++] = ' ';
419 else
420 fputc (' ', response_file);
421 }
422
423 /* Finally write the argument to the command line or to the
424 response file and adjust the current line length. */
425
426 if (response_file == NULL)
427 strcpy (command_line + line_len, tmp);
428 else
429 fputs (tmp, response_file);
430 line_len += len;
431 }
432}
433
434
435/* Put a list of arguments onto the command line or into the response
436 file. If PATHS is non-zero, the arguments are path names and
437 slashes are to be replaced by backslashes. */
438
439static void put_args (const name_list *list, int paths)
440{
441 while (list != NULL)
442 {
443 put_arg (list->name, paths, paths);
444 list = list->next;
445 }
446}
447
448
449/* Build the environment for the IBM/M$ Linkers: define the LIB
450 environment variable. */
451
452static void make_env (void)
453{
454 static char tmp[4096];
455 char *p;
456 int len;
457 const name_list *list;
458
459 /* Create a string for putenv(). */
460
461 strcpy (tmp, "LIB=");
462 len = strlen (tmp);
463
464 /* Add the library directories to LIB, using `;' as separator. */
465
466 for (list = libdirs; list != NULL; list = list->next)
467 {
468 if (list != libdirs && tmp[len-1] != ';')
469 tmp[len++] = ';';
470 strcpy (tmp+len, list->name);
471 conv_path (tmp+len);
472 len += strlen (list->name);
473 }
474
475 /* Append to the end the previous definition of LIB. */
476
477 p = getenv ("LIB");
478 if (p != NULL)
479 {
480 if (tmp[len-1] != ';')
481 tmp[len++] = ';';
482 strcpy (tmp+len, p);
483 }
484
485
486 /* Put the new value of LIB into the environment. */
487
488 putenv (tmp);
489
490 if (opt_t)
491 fprintf(stderr, "*** %s\n", tmp);
492}
493
494/**
495 * Checks if the stream phFile is an OMF library.
496 *
497 * @returns 1 if OMF library.
498 * @returns 0 if not OMF library.
499 * @param phFile Filestream to check.
500 */
501static int check_omf_library(FILE *phFile)
502{
503#pragma pack(1)
504 struct
505 {
506 byte rec_type;
507 word rec_len;
508 dword dict_offset;
509 word dict_blocks;
510 byte flags;
511 } libhdr;
512#pragma pack()
513
514 if ( fread(&libhdr, 1, sizeof(libhdr), phFile) == sizeof (libhdr)
515 && !fseek(phFile, 0, SEEK_SET)
516 && libhdr.rec_type == LIBHDR
517 && libhdr.flags <= 1 /* ASSUME only first bit is used... */
518 )
519 {
520 int page_size = libhdr.rec_len + 3;
521 if (page_size >= 16
522 && page_size <= 32768
523 && !(page_size & (page_size - 1)) != 0)
524 return 1;
525 }
526 return 0;
527}
528
529
530/**
531 * Checks if the stream phFile is an OMF object or library.
532 *
533 * @returns 1 if OMF.
534 * @returns 0 if not OMF.
535 * @param phFile Filestream to check.
536 */
537static int check_omf(FILE *phFile)
538{
539#pragma pack(1)
540 struct
541 {
542 byte rec_type;
543 word rec_len;
544 } omfhdr;
545#pragma pack()
546 if ( fread(&omfhdr, 1, sizeof(omfhdr), phFile) == sizeof (omfhdr)
547 && omfhdr.rec_type == THEADR
548 && omfhdr.rec_len >= sizeof(omfhdr)
549 && !fseek(phFile, 0, SEEK_SET)
550 )
551 return 1;
552
553 return !fseek(phFile, 0, SEEK_SET)
554 && check_omf_library(phFile);
555}
556
557
558/**
559 * Checks if the stream phFile is an LX DLL.
560 *
561 * @returns 1 if LX DLL.
562 * @returns 0 if not LX DLL.
563 * @param phFile File stream to check.
564 */
565static int check_lx_dll(FILE *phFile)
566{
567 unsigned long ul;
568 char achMagic[2];
569
570 if ( fseek(phFile, 0, SEEK_SET)
571 || fread(&achMagic, 1, 2, phFile) != 2)
572 goto thats_not_it;
573
574 if (!memcmp(achMagic, "MZ", 2))
575 {
576 if ( fseek(phFile, 0x3c, SEEK_SET)
577 || fread(&ul, 1, 4, phFile) != 4 /* offset of the 'new' header */
578 || ul < 0x40
579 || ul >= 0x10000000 /* 512MB stubs sure */
580 || fseek(phFile, ul, SEEK_SET)
581 || fread(&achMagic, 1, 2, phFile) != 2)
582 goto thats_not_it;
583 }
584
585 if ( memcmp(achMagic, "LX", 2)
586 || fseek(phFile, 14, SEEK_CUR)
587 || fread(&ul, 1, 4, phFile) != 4) /*e32_mflags*/
588 goto thats_not_it;
589
590#define E32MODDLL 0x08000L
591#define E32MODPROTDLL 0x18000L
592#define E32MODMASK 0x38000L
593 if ( (ul & E32MODMASK) != E32MODDLL
594 && (ul & E32MODMASK) != E32MODPROTDLL)
595 goto thats_not_it;
596
597 /* it's a LX DLL! */
598 fseek(phFile, 0, SEEK_SET);
599 return 1;
600
601
602thats_not_it:
603 fseek(phFile, 0, SEEK_SET);
604 return 0;
605}
606
607
608/**
609 * Generates an unique temporary file.
610 *
611 * @returns 0 on success.
612 * @returns -1 on failure.
613 * @param pszFile Where to put the filename.
614 * @param pszPrefix Prefix.
615 * @param pszSuffix Suffix.
616 * @param pszLooklike Filename which name is to be incorporated into the temp filename.
617 * @remark The code is nicked from the weak linker.
618 */
619static int make_tempfile(char *pszFile, const char *pszPrefix, const char *pszSuffix, const char *pszLooklike)
620{
621 struct stat s;
622 unsigned c = 0;
623 char szLooklike[32];
624 pid_t pid = getpid();
625 const char * pszTmp = getenv("TMP");
626 if (!pszTmp) pszTmp = getenv("TMPDIR");
627 if (!pszTmp) pszTmp = getenv("TEMP");
628 if (!pszTmp) pszTmp = ".";
629 if (pszLooklike)
630 {
631 int cch;
632 char *psz = (char*)pszLooklike; /* we're nice fellows. */
633 while ((psz = strpbrk(psz, ":/\\")) != NULL)
634 pszLooklike = ++psz;
635 cch = strlen(pszLooklike);
636 if (cch + 3 > sizeof(szLooklike))
637 cch = sizeof(szLooklike) - 3;
638 szLooklike[0] = '_';
639 memcpy(&szLooklike[1], pszLooklike, cch);
640 szLooklike[cch + 1] = '_';
641 szLooklike[cch + 2] = '\0';
642 pszLooklike = psz = &szLooklike[0];
643 while ((psz = strpbrk(psz, ".@%^&#()")) != NULL)
644 *psz++ = '_';
645 }
646 else
647 pszLooklike = "";
648
649 do
650 {
651 struct timeval tv = {0,0};
652 if (c++ >= 200)
653 return -1;
654 gettimeofday(&tv, NULL);
655 sprintf(pszFile, "%s\\%s%s%x%lx%d%lx%s", pszTmp, pszPrefix, pszLooklike, pid, tv.tv_sec, c, tv.tv_usec, pszSuffix);
656 } while (!stat(pszFile, &s));
657
658 return 0;
659}
660
661
662/**
663 * Converts the file indicated by phFile & pszFilename to omf closing
664 * phFile and updating pszFilename with the new (temporary filename).
665 *
666 * @returns Pointer to an filestream for the converted file and pszFilename
667 * containing the name of the converted file.
668 * @returns exit the program
669 * @param phFile Filestream of the file to convert. (close this)
670 * @param pszFilename Name of the file to convert on entry.
671 * Name of the converted file on return.
672 */
673static FILE *aout_to_omf(FILE *pf, char *pszFilename, int fLibrary)
674{
675 int rc;
676 char * pszNewFile;
677 name_list *pName;
678
679 fclose(pf); /* don't need this! */
680
681 if (opt_t)
682 fprintf(stderr, "emxomfld: info: converting %s %s to OMF.\n",
683 fLibrary ? "lib" : "obj", pszFilename);
684
685 /*
686 * Make temporary file.
687 */
688 pName = xmalloc(sizeof(name_list));
689 pName->name = pszNewFile = xmalloc(_MAX_PATH);
690 if (make_tempfile(pszNewFile, "ldconv", fLibrary ? ".lib" : ".obj", pszFilename))
691 {
692 free(pszNewFile);
693 return NULL;
694 }
695
696 /*
697 * Do the conversion.
698 */
699 rc = spawnlp(P_WAIT, "emxomf.exe", "emxomf.exe", "-o", pszNewFile, pszFilename, NULL);
700 if (!rc)
701 {
702 /* open the file */
703 pf = fopen(pszNewFile, "rb");
704 if (pf)
705 {
706 /* add to auto delete list for removal on exit(). */
707 pName->next = conv_list;
708 conv_list = pName;
709
710 strcpy(pszFilename, pszNewFile);
711
712 if (opt_t)
713 fprintf(stderr, "emxomfld: info: convert result '%s'.\n",
714 pszFilename);
715 return pf;
716 }
717 remove(pszNewFile);
718 }
719 free(pszNewFile);
720 free(pName);
721
722 fprintf(stderr, "emxomfld: a.out to omf conversion failed for '%s'.\n",
723 pszFilename);
724 exit(1);
725 return NULL;
726}
727
728
729/**
730 * Converts the file indicated by phFile & pszFilename to omf closing
731 * phFile and updating pszFilename with the new (temporary filename).
732 *
733 * @returns Pointer to an filestream for the converted file and pszFilename
734 * containing the name of the converted file.
735 * @returns exit the program
736 * @param phFile Filestream of the file to convert. (close this)
737 * @param pszFilename Name of the file to convert on entry.
738 * Name of the converted file on return.
739 */
740static FILE *lx_to_omf(FILE *pf, char *pszFilename)
741{
742 int rc;
743 char * pszNewFile;
744 name_list *pName;
745
746 fclose(pf); /* don't need this! */
747
748 if (opt_t)
749 fprintf(stderr, "emxomfld: info: converting %s %s to an OMF import lib.\n",
750 "lib", pszFilename);
751
752 /*
753 * Make temporary file.
754 */
755 pName = xmalloc(sizeof(name_list));
756 pName->name = pszNewFile = xmalloc(_MAX_PATH);
757 if (make_tempfile(pszNewFile, "ldconv", ".lib", pszFilename))
758 {
759 free(pszNewFile);
760 return NULL;
761 }
762
763 /*
764 * Do the conversion.
765 */
766 rc = spawnlp(P_WAIT, "emximp.exe", "emximp.exe", "-o", pszNewFile, pszFilename, NULL);
767 if (!rc)
768 {
769 /* open the file */
770 pf = fopen(pszNewFile, "rb");
771 if (pf)
772 {
773 /* add to auto delete list for removal on exit(). */
774 pName->next = conv_list;
775 conv_list = pName;
776
777 strcpy(pszFilename, pszNewFile);
778
779 if (opt_t)
780 fprintf(stderr, "emxomfld: info: convert result '%s'.\n",
781 pszFilename);
782 return pf;
783 }
784 remove(pszNewFile);
785 }
786 free(pszNewFile);
787 free(pName);
788
789 fprintf(stderr, "emxomfld: lx dll to omf conversion failed for '%s'.\n",
790 pszFilename);
791 exit(2);
792 return NULL;
793}
794
795
796/**
797 * Finds the full path of a OMF object file and opens the file.
798 *
799 * This function may perform conversion from a.out to omf if that feature
800 * is enabled.
801 *
802 * We choose to be UNIX compatible her, and not search the LIB env.var.
803 * for unqualified objects. Nor will we add any suffixes to the name
804 * if it's witout any extension.
805 *
806 * @returns Pointer to a file stream for the object file to use in the link.
807 * @returns NULL on failure with pszFullname containing a copy of
808 * pszName (or something like that).
809 * @param pszFullname Where to store the name of the file to be used
810 * in the linking (and which stream is returned).
811 * @param pszName Object name given to on the linker commandline.
812 */
813static FILE *find_obj(char *pszFullname, const char *pszName)
814{
815 FILE *phFile;
816 char *psz;
817
818 /*
819 * Make abspath with slashes the desired way and such.
820 */
821 if (!_realrealpath(pszName, pszFullname, _MAX_PATH + 1))
822 {
823 printf("emxomfld: _abspath failed on '%s'!!!\n", pszName);
824 exit(1);
825 }
826
827 psz = pszFullname;
828 while ((psz = strchr(psz, '/')) != NULL)
829 *psz++ = '\\';
830
831 /*
832 * Try open the file.
833 */
834 phFile = fopen(pszFullname, "rb");
835 if (!phFile)
836 return NULL;
837
838 /*
839 * If autoconversion check if such is needed.
840 */
841 if ( autoconvert_flag
842 && !check_omf(phFile))
843 phFile = aout_to_omf(phFile, pszFullname, FALSE);
844
845 return phFile;
846}
847
848
849
850/* Finds the full path of a library file and opens the file.
851 *
852 * This function may perform conversion from a.out to omf if that feature
853 * is enabled.
854 *
855 * The function assumes that LIB has been updated with all the search paths
856 * specified on the commandline.
857 *
858 * Library names with no extension are given extensions after the rules
859 * indicated by the IS_SHARED parameter. If IS_SHARED is set then libraries
860 * with suffixes indicating shared libraries will be looked for before
861 * libraries with suffixes indicated static libraries. The list is as
862 * follows for set IS_SHARED:
863 * 1. _dll.lib
864 * 2. .lib
865 * 3. .dll (optional)
866 * 4. _s.lib
867 *
868 * If IS_SHARED is clear:
869 * 1. _s.lib
870 * 2. .lib
871 *
872 * Library names with no path is searched for in the semicolon separated list
873 * of paths the env.var. LIB contains. For each directory in LIB we'll start
874 * by see if it contains a 'lib' prefixed file, if not found we'll check for
875 * the unprefixed filename. If we're appending suffixes too, we'll loop thru
876 * all the possible suffixes for each directory before advancing to the next,
877 * having the prefixing as the inner most loop.
878 *
879 * @returns Pointer to a file stream for the library file to use in the link.
880 * @returns NULL on failure with pszFullname containing a copy of
881 * pszName (or something like that).
882 * @param pszFullname Where to store the name of the file to be used
883 * in the linking (and which stream is returned).
884 * @param pszName Library name given to on the linker commandline.
885 */
886static FILE *find_lib(char *pszFullname, const char *pszName, int fShared)
887{
888 /* Suffix list for shared linking. */
889 static const char *apszSharedSuff[] = { "_dll.lib", "_dll.a", ".lib", ".a", "_s.lib", "_s.a", NULL };
890 /* Suffix list for shared linking with .dll. */
891 static const char *apszSharedDllSuff[] = { "_dll.lib", "_dll.a", ".lib", ".a", ".dll", "_s.lib", "_s.a", NULL };
892 /* Suffix list for static linking. */
893 static const char *apszStaticSuff[] = { "_s.lib", "_s.a", ".lib", ".a", NULL };
894 /* Suffix list for names with extension. */
895 static const char *apszExtensionSuff[] = { "", NULL };
896 /* Prefix list for names with path. */
897 static const char *apszWithPathPref[] = { "", NULL };
898 /* Prefix list for names with no path. */
899 static const char *apszWithoutPathPref[]= { "lib", "", NULL };
900 int fPath; /* set if the library name have a path. */
901 int fExt; /* set if the library name have an extension. */
902 const char **papszSuffs; /* Pointer to the suffix list. */
903 const char **papszPrefs; /* Pointer to the prefix list. */
904 const char *pszLibPath; /* The path we're searching. */
905 size_t cchCurPath; /* Size of the current path. */
906 size_t cchName = strlen(pszName);
907 const char *psz;
908
909 /*
910 * Check if the file name has a path.
911 * (If it has, we won't check the LIB directories.)
912 * Choose the prefix list accordingly.
913 */
914 fPath = (strpbrk(pszName, ":/\\") != NULL);
915 papszPrefs = fPath ? apszWithPathPref : apszWithoutPathPref;
916
917 /*
918 * Check if the file has a real extension.
919 * Real extension means, .lib, .dll or .a. It also implies something
920 * before the dot.
921 * Choose the suffix list accordingly.
922 */
923 fExt = ( (cchName > 4 && !stricmp(pszName + cchName - 4, ".lib"))
924 || (cchName > 4 && !stricmp(pszName + cchName - 4, ".dll"))
925 || (cchName > 2 && !stricmp(pszName + cchName - 2, ".a")) );
926
927 if (!fExt)
928 {
929 if (fShared)
930 papszSuffs = opt_dll_search ? &apszSharedDllSuff[0] : &apszSharedSuff[0];
931 else
932 papszSuffs = &apszStaticSuff[0];
933 }
934 else
935 papszSuffs = apszExtensionSuff;
936
937 /*
938 * Loop 1: LIB (with a fake .\ as the first iteration)
939 * (Looping on pszLibPath, with preinitiated cchCurPath & pszFullname.)
940 */
941 cchCurPath = 0;
942 if (!fPath)
943 {
944 cchCurPath = 2;
945 memcpy(pszFullname, ".\\", 2);
946 }
947 pszLibPath = getenv("LIB");
948 do
949 {
950 /*
951 * Loop2: Suffixes.
952 */
953 int iSuff;
954 for (iSuff = 0; papszSuffs[iSuff]; iSuff++)
955 {
956 /*
957 * Loop3: Prefixes.
958 */
959 int iPref;
960 for (iPref = 0; papszPrefs[iPref]; iPref++)
961 {
962 FILE *phFile;
963 int cch = strlen(papszPrefs[iPref]);
964
965 /*
966 * Construct name.
967 */
968 memcpy(&pszFullname[cchCurPath], papszPrefs[iPref], cch);
969 cch = cchCurPath + cch;
970 memcpy(&pszFullname[cch], pszName, cchName);
971 cch += cchName;
972 strcpy(&pszFullname[cch], papszSuffs[iSuff]);
973
974 /*
975 * Open and if necessary convert it.
976 */
977 phFile = fopen(pszFullname, "rb");
978 if (phFile)
979 {
980 char *pszTmp;
981 if (autoconvert_flag)
982 {
983 if (check_lx_dll(phFile))
984 phFile = lx_to_omf(phFile, pszFullname);
985 else if (!check_omf(phFile))
986 phFile = aout_to_omf(phFile, pszFullname, TRUE);
987 }
988
989 /* Get the real native path. */
990 pszTmp = _realrealpath(pszFullname, NULL, 0);
991 if (pszTmp)
992 {
993 strcpy(pszFullname, pszTmp);
994 free(pszTmp);
995 }
996
997 /* Replace forward slashes with backslashes (link386). */
998 while ((pszFullname = strchr(pszFullname, '/')) != NULL)
999 *pszFullname++ = '\\';
1000 return phFile;
1001 }
1002 } /* next prefix */
1003 } /* next suffix */
1004
1005 /*
1006 * If a path was specified or no LIB we're done now.
1007 */
1008 if (fPath || !pszLibPath)
1009 break;
1010
1011 /*
1012 * Next LIB part.
1013 */
1014 for (;;)
1015 {
1016 psz = strchr(pszLibPath, ';');
1017 if (!psz)
1018 psz = strchr(pszLibPath, '\0');
1019 cchCurPath = psz - pszLibPath;
1020 if (cchCurPath)
1021 {
1022 memcpy(pszFullname, pszLibPath, cchCurPath);
1023 pszLibPath = psz + (*psz == ';');
1024 /* Append last slash if it is not there */
1025 if ( pszFullname[cchCurPath - 1] != '/'
1026 && pszFullname[cchCurPath - 1] != '\\')
1027 pszFullname[cchCurPath++] = '\\';
1028 break;
1029 }
1030 if (!*psz)
1031 break;
1032 pszLibPath = psz + 1;
1033 }
1034 } while (cchCurPath);
1035
1036 /* failure */
1037 return NULL;
1038}
1039
1040
1041/* Weak prelinking for Method 2 Weak support. */
1042
1043static void weak_prelink ()
1044{
1045 int rc = 0;
1046 name_list * pOpt;
1047 PWLD pwld;
1048 unsigned fFlags = 0;
1049
1050 /* look for ilinker options. */
1051 if (opt_t)
1052 fFlags |= WLDC_VERBOSE;
1053 if (!stricmp(linker_type, "LINK386"))
1054 fFlags |= WLDC_LINKER_LINK386;
1055 else if (!stricmp(linker_type, "WLINK"))
1056 fFlags |= WLDC_LINKER_WLINK;
1057
1058 for (pOpt = options; pOpt; pOpt = pOpt->next)
1059 if ( !strnicmp(pOpt->name, "/NOE", 4)
1060 || !strnicmp(pOpt->name, "-NOE", 4))
1061 fFlags |= WLDC_NO_EXTENDED_DICTIONARY_SEARCH;
1062 else
1063 if ( !strnicmp(pOpt->name, "/INC", 4)
1064 || !strnicmp(pOpt->name, "-INC", 4))
1065 fFlags = fFlags; /* Ignore for now. */
1066 else
1067 if ( !strnicmp(pOpt->name, "/IG", 3)
1068 || !strnicmp(pOpt->name, "-IG", 3))
1069 fFlags |= WLDC_CASE_INSENSITIVE;
1070 else
1071 if ( !strnicmp(pOpt->name, "/I", 2)
1072 || !strnicmp(pOpt->name, "-I", 2))
1073 fFlags = fFlags; /* Ignore - require opt_t. */
1074 else
1075 if ( !strnicmp(pOpt->name, "/NOIN", 5)
1076 || !strnicmp(pOpt->name, "-NOIN", 5))
1077 fFlags &= ~WLDC_VERBOSE;
1078 else
1079 if ( !strnicmp(pOpt->name, "/NOI", 4)
1080 || !strnicmp(pOpt->name, "/NOI", 4))
1081 fFlags &= ~WLDC_CASE_INSENSITIVE;
1082
1083 /* create the linker and to the linking. */
1084 if (opt_t)
1085 fprintf(stderr, "*** Invoking weak prelinker with flags %x.\n", fFlags);
1086 pwld = WLDCreate (fFlags);
1087 if (pwld)
1088 {
1089 name_list * pcur;
1090 FILE *phfile;
1091 char szname[_MAX_PATH + 1];
1092
1093 /* definition file if any */
1094 if (def_fname && def_fname[0])
1095 {
1096 phfile = fopen (def_fname, "r");
1097 rc = WLDAddDefFile (pwld, phfile, def_fname);
1098 }
1099
1100 /* objects */
1101 for (pcur = obj_fnames; !rc && pcur; pcur = pcur->next)
1102 {
1103 phfile = find_obj (szname, pcur->name);
1104 rc = WLDAddObject (pwld, phfile, szname);
1105 }
1106
1107 /* libraries */
1108 for (pcur = lib_fnames; !rc && pcur; pcur = pcur->next)
1109 {
1110 phfile = find_lib (szname, pcur->name, !pcur->flags);
1111 rc = WLDAddLibrary (pwld, phfile, szname);
1112 free(pcur->name);
1113 pcur->name = xstrdup(szname);
1114 }
1115
1116 /* complete pass 1 */
1117 if (!rc)
1118 {
1119 rc = WLDPass1 (pwld);
1120 /* ignore unresolved externals for now. */
1121 if (rc == 42)
1122 {
1123 rc = 0;
1124 fprintf(stderr, "Ignoring unresolved externals reported from weak prelinker.\n");
1125 }
1126 }
1127
1128 /* generate weak aliases. */
1129 if (!rc)
1130 rc = WLDGenerateWeakAliases (pwld, weakobj_fname, weakdef_fname);
1131 if (!rc && weakobj_fname[0])
1132 {
1133 char *pszTmp = _realrealpath(weakobj_fname, NULL, 0);
1134 if (pszTmp)
1135 {
1136 strcpy(weakobj_fname, pszTmp);
1137 free(pszTmp);
1138 }
1139 add_name_list (&add_obj_fnames, weakobj_fname, 0);
1140 }
1141 if (!rc && weakdef_fname[0])
1142 {
1143 char *pszTmp = _realrealpath(weakdef_fname, NULL, 0);
1144 if (pszTmp)
1145 {
1146 strcpy(weakdef_fname, pszTmp);
1147 free(pszTmp);
1148 }
1149 def_fname = weakdef_fname;
1150 }
1151
1152 /* cleanup the linker */
1153 WLDDestroy (pwld);
1154
1155 /* last words */
1156 if (rc)
1157 {
1158 fprintf (stderr, "emxomfld: weak prelinker failed. (rc=%d)\n", rc);
1159 rc = 8;
1160 }
1161 }
1162 else
1163 {
1164 fprintf (stderr, "emxomfld: failed to create weak prelinker.\n");
1165 rc = 8;
1166 }
1167
1168 /* die on error. */
1169 if (rc)
1170 exit(rc);
1171
1172 /* verbose */
1173 if (opt_t)
1174 fprintf(stderr, "*** Weak prelinker done\n");
1175}
1176
1177
1178/* Start a new set of command line arguments. If RSP is non-zero, we
1179 are allowed to use a response file. */
1180
1181static void arg_init (int rsp)
1182{
1183 if (response_fname[0] != '\0')
1184 {
1185 remove (response_fname);
1186 response_fname[0] = '\0';
1187 }
1188 command_line[0] = '\0';
1189 line_len = 0;
1190 response_flag = rsp;
1191 force_response_file = FALSE;
1192}
1193
1194
1195/* Call this after adding all the command line arguments. If a
1196 response file has been created, add a newline and close it. */
1197
1198static void arg_end (void)
1199{
1200 if (response_file != NULL)
1201 {
1202 fputc ('\n', response_file);
1203 if (fflush (response_file) != 0 || fclose (response_file) != 0)
1204 {
1205 perror ("emxomfld");
1206 exit (2);
1207 }
1208 response_file = NULL;
1209 }
1210}
1211
1212/* Generates a definition file for a dll which doesn't have one. */
1213static void gen_deffile(void)
1214{
1215 char * psz;
1216 name_list *pName;
1217
1218 /*
1219 * Make temporary file.
1220 */
1221 pName = (name_list *)xmalloc(sizeof(*pName));
1222 pName->name = psz = xmalloc(_MAX_PATH);
1223 if (!make_tempfile(psz, "lddef", ".def", NULL))
1224 {
1225 FILE *pFile = fopen(psz, "w");
1226 if (pFile)
1227 {
1228 const char *pszName = _getname(output_fname);
1229 size_t cchName = strlen(pszName);
1230 if (cchName > 4 && !stricmp(pszName + cchName - 4, ".dll"))
1231 cchName -= 4;
1232 fprintf(pFile,
1233 ";; Autogenerated by emxomfld\n"
1234 "LIBRARY %.*s INITINSTANCE TERMINSTANCE\n"
1235 "DATA MULTIPLE\n"
1236 "CODE SHARED\n"
1237 "\n",
1238 cchName, pszName);
1239 fclose(pFile);
1240 def_fname = psz;
1241 if (opt_t)
1242 fprintf(stderr,
1243 "--- Generated def-file %s:\n"
1244 ";; Autogenerated by emxomfld\n"
1245 "LIBRARY %.*s INITINSTANCE TERMINSTANCE\n"
1246 "DATA MULTIPLE NONSHARED\n"
1247 "CODE SINGLE SHARED\n"
1248 "---- End of generated def-file.\n",
1249 psz, cchName, pszName);
1250
1251 /* add to auto delete list for removal on exit(). */
1252 pName->next = conv_list;
1253 conv_list = pName;
1254 return;
1255 }
1256 }
1257 free(psz);
1258 free(pName);
1259}
1260
1261/* converts a def file statement to watcom responsfile lingo. */
1262
1263static int def_2_watcom(struct _md *md, const _md_stmt *stmt, _md_token token, void *arg)
1264{
1265 switch (token)
1266 {
1267 case _MD_BASE:
1268 fprintf (response_file, "OPTION OFFSET=%#lx\n", stmt->base.addr);
1269 break;
1270
1271 case _MD_CODE:
1272 break;
1273
1274 case _MD_DATA:
1275 break;
1276
1277 case _MD_DESCRIPTION:
1278 fprintf (response_file, "OPTION DESCRIPTION '%s'\n", stmt->descr.string);
1279 break;
1280
1281 case _MD_EXETYPE:
1282 break;
1283
1284 case _MD_EXPORTS:
1285 fprintf (response_file, "EXPORT '%s'", stmt->export.entryname);
1286 if (stmt->export.flags & _MDEP_ORDINAL)
1287 fprintf (response_file, ".%d", stmt->export.ordinal);
1288 if (stmt->export.internalname[0])
1289 fprintf (response_file, "='%s'", stmt->export.internalname);
1290 if (stmt->export.flags & _MDEP_RESIDENTNAME)
1291 fprintf (response_file, " RESIDENT");
1292 /** @todo _MDEP_NONAME */
1293 fprintf (response_file, "\n");
1294
1295 /* reference the internal name. */
1296 if (stmt->export.internalname[0])
1297 fprintf (response_file, "REFERENCE '%s'\n", stmt->export.internalname);
1298 break;
1299
1300 case _MD_HEAPSIZE:
1301 fprintf (response_file, "OPTION HEAPSIZE=%#lx\n", stmt->heapsize.size);
1302 break;
1303
1304 case _MD_IMPORTS:
1305 fprintf (response_file, "IMPORT '%s' '%s'", stmt->import.internalname,
1306 stmt->import.modulename);
1307 if (stmt->import.flags & _MDEP_ORDINAL)
1308 fprintf (response_file, ".%d", stmt->import.ordinal);
1309 else if (stmt->import.internalname[0])
1310 fprintf (response_file, ".'%s'", stmt->import.entryname);
1311 fprintf (response_file, "\n");
1312 break;
1313
1314 case _MD_LIBRARY:
1315 if (stmt->library.name[0])
1316 fprintf (response_file, "OPTION MODNAME='%s'\n", stmt->library.name);
1317 break;
1318
1319 case _MD_NAME:
1320 if (stmt->name.name[0])
1321 fprintf (response_file, "OPTION MODNAME='%s'\n", stmt->name.name);
1322 break;
1323
1324 case _MD_OLD:
1325 fprintf (response_file, "OPTION OLDLIBRARY='%s'\n", stmt->old.name);
1326 break;
1327
1328 case _MD_PROTMODE:
1329 fprintf (response_file, "OPTION PROTMODE\n");
1330 break;
1331
1332 case _MD_REALMODE:
1333 fprintf (response_file, "OPTION PROTMODE\n");
1334 break;
1335
1336 case _MD_SEGMENTS:
1337 fprintf (stderr, "emxomfld: ignoring SEGMENTS directive in .def-file\n");
1338 break;
1339
1340 case _MD_STACKSIZE:
1341 fprintf (response_file, "OPTION STACK=%#lx\n", stmt->stacksize.size);
1342 break;
1343
1344 case _MD_STUB:
1345 if (!stmt->stub.none)
1346 fprintf (response_file, "OPTION STUB='%s'\n", stmt->stub.name);
1347 else
1348 fprintf (stderr, "emxomfld: warning: \"STUB NONE\" is not supported by wlink. ignoring\n");
1349 break;
1350
1351 case _MD_VIRTUAL:
1352 case _MD_PHYSICAL:
1353 break;
1354
1355 case _MD_parseerror:
1356 fprintf (stderr, "emxomfld: %s (line %ld of %s)",
1357 _md_errmsg (stmt->error.code), _md_get_linenumber (md), def_fname);
1358 exit (2);
1359 break;
1360
1361 default:
1362 abort ();
1363 }
1364 return 0;
1365}
1366
1367/* -t output. We dump the commandline and responsefile. */
1368static void show_spawn(const char *pszwhat)
1369{
1370 if (!opt_t)
1371 return;
1372 fprintf(stderr, "*** Invoking %s\n %s\n", pszwhat, command_line);
1373 if (response_fname[0])
1374 { /* display the responsfile content. */
1375 char sz[4096];
1376 FILE *phfile = fopen(response_fname, "r");
1377 fprintf(stderr, "--- Response file %s:\n", response_fname);
1378 sz[0] = '\0';
1379 while (fgets(sz, sizeof(sz), phfile))
1380 fprintf(stderr, "%s", sz);
1381 fclose(phfile);
1382 if (sz[strlen(sz) - 1] != '\n')
1383 fprintf(stderr, "\n");
1384 fprintf(stderr, "--- End of Response File\n");
1385 }
1386}
1387
1388
1389/* Execute commandline and returns the result.
1390 pszwhat is used for opt_t trace information. */
1391
1392static int emxomfld_spawn(char *pszcmd, const char *pszwhat)
1393{
1394 int argi;
1395 char ** argv;
1396 char * psz;
1397 int rc;
1398
1399 if (opt_t)
1400 show_spawn(pszwhat);
1401
1402 /* construct spawnvp() argument array */
1403 argi = 0;
1404 argv = NULL;
1405 psz = pszcmd;
1406 while (psz && *psz)
1407 {
1408 char *psz2 = psz;
1409
1410 /* skip blanks. */
1411 while (*psz2 == '\t' || *psz2 == ' ')
1412 psz2++;
1413
1414 /* find end of argument taking in account in arg quoting. */
1415 while (*psz2 && *psz2 != '\t' && *psz2 != ' ')
1416 {
1417 if (*psz2 == '"' || *psz2 == '\'')
1418 {
1419 char chQuote = *psz2++;
1420 while (*psz2 && *psz2 != chQuote)
1421 psz2++;
1422 }
1423 psz2++;
1424 }
1425
1426 /* terminate and set psz2 to point to next */
1427 if (*psz2)
1428 *psz2++ = '\0';
1429
1430 /* add argument to argument vector. */
1431 if (!(argi % 32))
1432 argv = xrealloc(argv, sizeof(argv[0]) * (argi + 32 + 1));
1433 argv[argi++] = psz;
1434
1435 /* next */
1436 psz = psz2;
1437 }
1438 argv[argi] = NULL;
1439
1440 /* Spawn process. */
1441 rc = spawnvp(P_WAIT, argv[0], argv);
1442 if (opt_t)
1443 fprintf(stderr, "*** Return from %s is %d\n", pszwhat, rc);
1444
1445 free(argv);
1446 return rc;
1447}
1448
1449
1450/* Cleanup by closing (if open) and deleting (if pressent) the
1451 response file. This function is used with atexit(). */
1452
1453static void cleanup (void)
1454{
1455 if (response_file != NULL)
1456 {
1457 fclose (response_file);
1458 response_file = NULL;
1459 }
1460 if (opt_t <= 1)
1461 {
1462 if (response_fname[0] != '\0')
1463 {
1464 remove (response_fname);
1465 response_fname[0] = '\0';
1466 }
1467 if (weakobj_fname[0] != '\0')
1468 {
1469 remove (weakobj_fname);
1470 weakobj_fname[0] = '\0';
1471 }
1472 if (weakdef_fname[0] != '\0')
1473 {
1474 remove (weakdef_fname);
1475 weakdef_fname[0] = '\0';
1476 }
1477 for (; conv_list; conv_list = conv_list->next)
1478 remove (conv_list->name);
1479 }
1480}
1481
1482/* Tell the user how to run this program. */
1483
1484static void usage (void)
1485{
1486 fputs ("emxomfld " VERSION INNOTEK_VERSION "\n"
1487 "Copyright (c) 1992-1996 by Eberhard Mattes\n"
1488 "Copyright (c) 2003 by InnoTek Systemberatung GmbH\n"
1489 "Copyright (c) 2003-2006 by Knut St. Osmundsen\n"
1490 "\n", stderr);
1491 fputs ("Usage: emxomfld -o <file> [-l <lib>] [-L <libdir>] [-T <base>] [-igtsS]\n"
1492 " [-Zexe] [-Zdll] [-Zsym] [-Zstack <size>] [-Zmap[=<map_file>]]\n"
1493 " [-Z[no-]autoconv] [-Zdll-search] [-O <option>] [-static]\n"
1494 " [-non_shared] [-Bstatic] [-dn] [call_shared] [-Bshared]\n"
1495 " [-dy] <file>...\n"
1496 "\n", stderr);
1497 fputs ("Options:\n"
1498 " -Zno-autoconv / -Zautoconv:\n"
1499 " Turns off/on the automatic conversion of a.out libs and objs.\n"
1500 " default: -Zautoconv\n"
1501 " -Bstatic, -non_shared, -dn, -static:\n"
1502 " Link with static libraries.\n"
1503 " The search order is then changed to: lib<name>_s.lib, <name>_s.lib,\n"
1504 " lib<name>.lib, <name>.lib\n", stderr);
1505 fputs (" -Bshared, -call_shared, -dy:\n"
1506 " Link with shared libraries. This is default.\n"
1507 " The search order is then changed to: lib<name>_dll.lib, <name>_dll.lib,\n"
1508 " lib<name>.lib, <name>.lib, <name>.dll, lib<name>_s.lib, <name>_s.lib.\n"
1509 " -Zdll-search:\n"
1510 " Enables dlls as valid libraries from shared linking. (default disabled)\n",
1511 stderr);
1512 fputs (" -Zsym:"
1513 " Invoke mapsym.cmd on the mapfile to produce a .sym file. Requires -Zmap.\n"
1514 "\n", stderr);
1515 fputs ("Environment variables:\n"
1516 " EMXOMFLD_TYPE:\n"
1517 " The type of linker we're using. Values: WLINK, VAC365, VAC308, LINK386.\n"
1518 " WLINK wlink.exe from Open Watcom v1.5 or later.\n"
1519 " VAC365 ilink.exe from IBM C and C++ Compilers for OS/2 v3.6 or later.\n"
1520 " VAC308 ilink.exe from Visual Age for C++ v3.08.\n"
1521 " LINK386 link386 form OS/2 install or DDK.\n", stderr);
1522 fputs (" EMXOMFLD_LINKER:\n"
1523 " Name of the linker to use and optionally extra parameters. Spaces in the\n"
1524 " linker name or path is not supported. Quotes are not supported either.\n"
1525 "The default values for these two variables are WLINK and wlink.exe.\n", stderr);
1526 exit (1);
1527}
1528
1529
1530
1531static struct option longopts[] =
1532{
1533#define OPT_LIBS_STATIC 0x1000
1534 {"Bstatic", 0, 0, OPT_LIBS_STATIC},
1535 {"non_shared", 0, 0, OPT_LIBS_STATIC},
1536 {"dn", 0, 0, OPT_LIBS_STATIC},
1537 {"static", 0, 0, OPT_LIBS_STATIC},
1538#define OPT_LIBS_SHARED 0x1001
1539 {"Bshared", 0, 0, OPT_LIBS_SHARED},
1540 {"call_shared", 0, 0, OPT_LIBS_SHARED},
1541 {"dy", 0, 0, OPT_LIBS_SHARED},
1542#define OPT_ZEXE 0x1002
1543 {"Zexe", 0, 0, OPT_ZEXE}, /* Create .exe file, touch `output file' */
1544#define OPT_ZDLL 0x1003
1545 {"Zdll", 0, 0, OPT_ZDLL}, /* Create .dll file, touch `output file' */
1546#define OPT_ZSTACK 0x1004
1547 {"Zstack", 1, 0, OPT_ZSTACK}, /* Set stack size */
1548#define OPT_ZMAP 0x1005
1549 {"Zmap", 2, 0, OPT_ZMAP}, /* Create .map file */
1550 {"Zmap=", 1, 0, OPT_ZMAP},
1551#define OPT_ZAUTOCONV 0x1006
1552 {"Zautoconv",0, 0, OPT_ZAUTOCONV},
1553#define OPT_ZNO_AUTOCONV 0x1007
1554 {"Zno-autoconv",0, 0, OPT_ZNO_AUTOCONV},
1555#define OPT_ZDLL_SEARCH 0x1008
1556 {"Zdll-search",0, 0, OPT_ZDLL_SEARCH},
1557#define OPT_ZSYM 0x1009
1558 {"Zsym",0, 0, OPT_ZSYM},
1559/* {"e", 1, 0, 'e'}, entry point */
1560 {"i", 0, 0, 'i'},
1561 {"o", 1, 0, 'o'},
1562 {"O", 1, 0, 'O'},
1563/* {"u", 1, 0, 'u'}, reference symbol */
1564 {"s", 0, 0, 's'},
1565 {"S", 0, 0, 'S'},
1566 {"t", 0, 0, 't'},
1567 {"T", 1, 0, 'T'},
1568 {"v", 0, 0, 'v'},
1569 {"x", 0, 0, 'x'},
1570 {"X", 0, 0, 'X'},
1571 {NULL, 0, 0, 0}
1572};
1573
1574/* Main function of emxomf. Parse the command line and call the IBM/M$
1575 linker (and optionally RC). */
1576
1577int main (int argc, char *argv[])
1578{
1579 struct stat s;
1580 int c, rc, files;
1581 const char *ext;
1582 char tmp[512], *t;
1583 char execname[512];
1584 name_list *pcur;
1585 int opt_libs_static = 0;
1586 int longind;
1587
1588 /* Get options from response files (@filename) and wildcard (*.o) on the command. */
1589
1590 _response (&argc, &argv);
1591 _wildcard (&argc, &argv);
1592
1593 /* Close and delete the response file on exit. */
1594
1595 atexit (cleanup);
1596
1597 /* Prepare parsing of the command line. */
1598
1599 files = 0;
1600 opterr = FALSE;
1601 /*optmode = GETOPT_KEEP; */
1602 if (argc < 2)
1603 usage ();
1604
1605 /* Parse the command line options and other arguments. */
1606 while ((c = getopt_long_only (argc, argv, "-l:y:L:", longopts, &longind)) != EOF)
1607 {
1608 if (c == 0)
1609 c = longopts[longind].val;
1610 switch (c)
1611 {
1612 case 1: /* Non-option argument */
1613
1614 /* Extract the extension to see what to do with this
1615 argument. */
1616
1617 ext = _getext (optarg);
1618
1619 if (ext == NULL)
1620 {
1621 /* GCC's temporary files don't have an extension. Add a
1622 dot to the end of the name to prevent the linker from
1623 adding `.obj'. */
1624
1625 sprintf (tmp, "%s.", optarg);
1626 add_name_list (&add_obj_fnames, tmp, 0);
1627 }
1628
1629 /* If it's a .def file, use it as module definition file
1630 (input). */
1631
1632 else if (stricmp (ext, ".def") == 0)
1633 {
1634 if (def_fname != NULL)
1635 {
1636 fprintf (stderr,
1637 "emxomfld: multiple module definition files\n");
1638 return 1;
1639 }
1640 def_fname = _realrealpath(optarg, NULL, 0);
1641 if (!def_fname)
1642 def_fname = optarg;
1643 }
1644
1645 /* If it's a .res file, use it as binary resource file
1646 (input). */
1647
1648 else if (stricmp (ext, ".res") == 0)
1649 {
1650 if (res_fname != NULL)
1651 {
1652 fprintf (stderr,
1653 "emxomfld: multiple binary resource files\n");
1654 return 1;
1655 }
1656 res_fname = _realrealpath(optarg, NULL, 0);
1657 if (!def_fname)
1658 res_fname = optarg;
1659 }
1660
1661 /* If it's a .lib file, use it as library file. We also
1662 accept .a files for those who use OMF files disguised as
1663 a.out files (to simplify their make files). */
1664
1665 else if (stricmp (ext, ".lib") == 0 || stricmp (ext, ".a") == 0 || stricmp (ext, ".dll") == 0)
1666 add_name_list (&add_lib_fnames, optarg, opt_libs_static);
1667
1668 /* Otherwise, assume it's an object file. */
1669
1670 else
1671 add_name_list (&add_obj_fnames, optarg, 0);
1672 ++files;
1673 break;
1674
1675 case 't':
1676 case 'i': /* Trace the linking process, sending /INFO to the IBM/M$ linker. */
1677 opt_t++;
1678 break;
1679
1680 case 'l': /* Add library */
1681 add_name_list (&add_lib_fnames, optarg, opt_libs_static);
1682 break;
1683
1684 case 'o': /* Set output file name */
1685 output_fname = optarg;
1686 break;
1687
1688 case 'L': /* Add library directory */
1689 add_name_list (&add_libdirs, optarg, 0);
1690 break;
1691
1692 case 'T': /* Set base address */
1693 base = optarg;
1694 break;
1695
1696 case 's': /* Strip all symbols */
1697 case 'S': /* Strip debugging symbols */
1698 strip_symbols = TRUE;
1699 break;
1700
1701 case 'x': /* Discard all local symbols */
1702 case 'X': /* Discard local symbols starting with L */
1703 break;
1704
1705 case 'v': /* For compatibility */
1706 break;
1707
1708 case 'O': /* Specify Linker option */
1709 add_name_list (&add_options, optarg, 0);
1710 break;
1711
1712 case OPT_ZDLL:
1713 dll_flag = TRUE;
1714 break;
1715
1716 case OPT_ZEXE:
1717 exe_flag = TRUE;
1718 break;
1719
1720 case OPT_ZMAP:
1721 map_flag = TRUE;
1722 if (optarg)
1723 {
1724 if (map_fname != NULL)
1725 {
1726 fprintf (stderr, "emxomfld: multiple map files files\n");
1727 return 1;
1728 }
1729 map_fname = optarg;
1730 }
1731 break;
1732
1733 case OPT_ZSTACK:
1734 if (!optarg)
1735 return 1;
1736 errno = 0;
1737 stack_size = strtol (optarg, &t, 0);
1738 if (errno != 0 || *t != 0 || t == optarg)
1739 return 1;
1740 break;
1741
1742 case OPT_ZAUTOCONV:
1743 autoconvert_flag = 1;
1744 break;
1745 case OPT_ZNO_AUTOCONV:
1746 autoconvert_flag = 0;
1747 break;
1748
1749 case OPT_ZDLL_SEARCH:
1750 opt_dll_search = 1;
1751 break;
1752
1753 case OPT_ZSYM:
1754 sym_flag = TRUE;
1755 break;
1756
1757 case OPT_LIBS_STATIC:
1758 opt_libs_static = 1;
1759 break;
1760 case OPT_LIBS_SHARED:
1761 opt_libs_static = 0;
1762 break;
1763
1764 case '?':
1765 default:
1766 if (optind > 1)
1767 fprintf (stderr, "emxomfld: invalid option (%s)\n", argv[optind - 1]);
1768 else
1769 usage ();
1770 return 1;
1771 }
1772 }
1773 /* Set default value for output file. */
1774
1775 if (output_fname == NULL)
1776 {
1777 fprintf (stderr,
1778 "emxomfld: no output file, creating $$$.exe or $$$.dll\n");
1779 output_fname = "$$$";
1780 }
1781
1782 /* Check if there are any input files. */
1783
1784 if (files == 0)
1785 {
1786 fprintf (stderr, "emxomfld: no input files\n");
1787 return 1;
1788 }
1789
1790 /* Check that -Zmap was specified with -Zsym. */
1791
1792 if (sym_flag && !map_flag)
1793 {
1794 fprintf (stderr, "emxomfld: -Zsym without -Zmap.\n");
1795 return 1;
1796 }
1797
1798 /* Remove the output file if -Zexe is given. */
1799
1800 if (exe_flag)
1801 remove (output_fname);
1802
1803 /* If neither -Zmap nor -Zmap=file is used, pass "nul" to the linker in
1804 the map file field. If -Zmap is used, construct the name of the
1805 .map file. If -Zmap=file is used, use `file' as the name of the
1806 .map file. */
1807
1808 if (!map_flag)
1809 map_fname = "nul";
1810 else if (map_fname == NULL)
1811 {
1812 int cch = strlen (output_fname) + 1;
1813 t = xmalloc (cch + 4);
1814 memcpy (t, output_fname, cch);
1815 _remext (t);
1816 strcat (t, ".map");
1817 map_fname = t;
1818 }
1819
1820 /* Build the environment for the linker. */
1821
1822 make_env ();
1823
1824 /* EMXOMFLD_TYPE contains VAC365, VAC308 or LINK386 if set. If non of these
1825 we assume VAC365.
1826 EMXOMFLD_LINKER contains the linker name and perhaps extra arguments. If
1827 not set we'll use the default linker, ilink. */
1828
1829 t = getenv ("EMXOMFLD_TYPE");
1830 if ( t
1831 && stricmp(t, "WLINK")
1832 && stricmp(t, "VAC365")
1833 && stricmp(t, "VAC308")
1834 && stricmp(t, "LINK386")
1835 )
1836 fprintf (stderr, "emxomfld: warning: '%s' is an invalid value for EMXOMFLD_TYPE.\n", t);
1837 else if (t)
1838 linker_type = t;
1839
1840 t = getenv ("EMXOMFLD_LINKER");
1841 if (t)
1842 linker_name = t;
1843 if (opt_t)
1844 fprintf(stderr, "*** Linker : %s\n"
1845 "*** Linker type: %s\n", linker_name, linker_type);
1846
1847 /* apply object & library hacks */
1848 for (pcur = obj_fnames, rc = 0; !rc && pcur; pcur = pcur->next)
1849 {
1850 char szname[_MAX_PATH + 1];
1851 FILE *phfile = find_obj (szname, pcur->name);
1852 if (!phfile)
1853 continue;
1854 free (pcur->name);
1855 pcur->name = xstrdup(szname);
1856 fclose(phfile);
1857 }
1858
1859 for (pcur = lib_fnames, rc = 0; !rc && pcur; pcur = pcur->next)
1860 {
1861 char szname[_MAX_PATH + 1];
1862 FILE *phfile = find_lib (szname, pcur->name, !pcur->flags);
1863 if (!phfile)
1864 continue;
1865 free (pcur->name);
1866 pcur->name = xstrdup(szname);
1867 fclose(phfile);
1868 }
1869
1870 /* generate .def-file for dlls. */
1871
1872 if (!def_fname && dll_flag)
1873 gen_deffile();
1874
1875 /* Do the weak prelinking. Important that this is done after make_env(). */
1876
1877 weak_prelink ();
1878
1879 /* Start building the linker command line. We can use a response
1880 file if the command line gets too long. */
1881
1882 arg_init (TRUE);
1883
1884 /* issue commandline */
1885 put_arg (linker_name, TRUE, FALSE);
1886
1887 if (stricmp (linker_type, "WLINK"))
1888 {
1889 /*
1890 For VAC365 and VAC308 the default options are:
1891
1892 /NOFR[EEFORMAT] Use /NOFREEFORMAT to allow a LINK386-compatible
1893 command line syntax, in which different types of file
1894 are grouped and separated by commas.
1895
1896 /DBGPACK If !strip_symbols then we'll add this option, which
1897 will cause type tables to be merged into one global
1898 table and so eliminating a lot of duplicate info.
1899
1900 For VAC365 additional default option is:
1901
1902 /STUB:<emxomfld-path>\os2stub.bin
1903 Causes this MZ stub to be used when linking the
1904 executables instead of the default on for the linker.
1905
1906 For LINK386 the default options are:
1907
1908 /BATCH Run in batch mode (disable prompting, don't
1909 echo response file)
1910
1911 The default options for all linkers are:
1912
1913 /NOLOGO Don't display sign-on banner
1914
1915 /NOEXTDICTIONARY Don't use extended dictionary (redefining
1916 library symbols is quite common)
1917
1918 /NOIGNORECASE Make symbols case-sensitive
1919
1920 /PACKCODE Group neighboring code segments (this is the
1921 default unless the SEGMENTS module definition
1922 statement is used for a segment of class
1923 'CODE'). Not grouping neighboring code
1924 segments would break sets
1925
1926 For non DLLs targets:
1927
1928 /BASE:0x10000 Base the executable an so removing extra fixups.
1929
1930 */
1931
1932 /* the next part depends on the linker type. */
1933 if (!stricmp (linker_type, "LINK386"))
1934 put_arg ("/bat", FALSE, FALSE);
1935 else /* vac3xx: */
1936 {
1937 put_arg ("/nofree", FALSE, FALSE);
1938 if (!strip_symbols)
1939 put_arg ("/db", FALSE, FALSE);
1940 if (map_flag)
1941 put_arg ("/map", FALSE, FALSE);
1942 }
1943 put_arg ("/nol", FALSE, FALSE);
1944 put_arg ("/noe", FALSE, FALSE);
1945 put_arg ("/noi", FALSE, FALSE);
1946 put_arg ("/packc", FALSE, FALSE);
1947
1948
1949 /* VAC365: check if we have os2stub.bin.
1950 We must to this after the above stuff else /nol might end up in the
1951 response file and we'll get the component output. */
1952
1953 if (!stricmp (linker_type, "VAC365"))
1954 {
1955 /* gklayout show that the linker isn't capable of determining a
1956 decent value for this parameter. 32MB makes gklayout link. */
1957 put_arg ("/ocache:0x02000000", FALSE, FALSE);
1958
1959 _execname (&execname[0], sizeof(execname));
1960 strcpy (_getname (&execname[0]), "os2stub.bin");
1961 if (!stat (execname, &s))
1962 {
1963 sprintf (tmp, "/STUB:%s", &execname[0]);
1964 put_arg (tmp, FALSE, FALSE);
1965 }
1966 }
1967
1968 /* Add the /INFORMATION option if the -i or -t option was given. This is
1969 for debugging. */
1970
1971 if (opt_t)
1972 put_arg ("/i", FALSE, FALSE);
1973
1974 /* Add the /DEBUG option if the -s option was not given. Without
1975 this, the linker throws away debugging information. */
1976
1977 if (!strip_symbols)
1978 put_arg ("/de", FALSE, FALSE);
1979
1980 /* Add the /BASE:n option to set the base address. This specifies
1981 the preferred load address of object 1. The base address being
1982 used is 0x10000 unless a DLL is generated or the -T option was
1983 given. -Tno can be used to suppress the /BASE:n option. */
1984
1985 if (base == NULL && !dll_flag)
1986 {
1987 struct _md *md;
1988
1989 if (def_fname != NULL)
1990 {
1991 int token;
1992 md = _md_open (def_fname);
1993 if (md == NULL)
1994 {
1995 fprintf (stderr, "emxomfld: cannot open `%s'\n", def_fname);
1996 exit (2);
1997 }
1998 token = _md_next_token (md);
1999 if (token == _MD_LIBRARY || token == _MD_PHYSICAL || token == _MD_VIRTUAL)
2000 dll_flag = TRUE;
2001 _md_close (md);
2002 }
2003 }
2004 if (base == NULL && !dll_flag)
2005 base = "0x10000";
2006 if (base != NULL && stricmp (base, "no") != 0)
2007 {
2008 sprintf (tmp, "/bas:%s", base);
2009 put_arg (tmp, FALSE, FALSE);
2010 }
2011
2012 /* Add the /STACK:n option if the -Zstack option was given. */
2013
2014 if (!dll_flag)
2015 {
2016 sprintf (tmp, "/st:0x%lx", stack_size * 1024);
2017 put_arg (tmp, FALSE, FALSE);
2018 }
2019
2020 /* Add the linker options specified with -O. */
2021
2022 put_args (options, FALSE);
2023
2024 /* Put the object file names onto the command line. */
2025
2026 force_response_file = TRUE; /* link386 workaround. */
2027 put_args (obj_fnames, TRUE);
2028 put_arg (",", FALSE, FALSE);
2029
2030 /* Put the output file name onto the command line. */
2031
2032 put_arg (output_fname, TRUE, TRUE);
2033 put_arg (",", FALSE, FALSE);
2034
2035 /* Put the map file name onto the command line. */
2036
2037 put_arg (map_fname, TRUE, TRUE);
2038 put_arg (",", FALSE, FALSE);
2039
2040 /* Put the library file names onto the command line. */
2041
2042 put_args (lib_fnames, TRUE);
2043 put_arg (",", FALSE, FALSE);
2044
2045 /* Put the name of the module definition file onto the command line. */
2046
2047 put_arg (def_fname, TRUE, TRUE);
2048 put_arg (";", FALSE, FALSE);
2049
2050 /* Call Linker and abort on failure. */
2051 }
2052 else /* wlink */
2053 {
2054 open_response_file ();
2055
2056 /* figure out what format options we're gonna use */
2057
2058 if (!def_fname && !dll_flag)
2059 fprintf (response_file, "FORMAT OS2 LX PMCompatible\n");
2060 else if (!def_fname && dll_flag)
2061 fprintf (response_file, "FORMAT OS2 LX DLL INITINSTANCE TERMINSTANCE\n");
2062 else
2063 {
2064 int token;
2065 struct _md *pMd = _md_open (def_fname);
2066 if (!pMd)
2067 {
2068 fprintf (stderr, "emxomfld: cannot open `%s'\n", def_fname);
2069 exit (2);
2070 }
2071 token = _md_next_token (pMd);
2072 if (token == _MD_LIBRARY || token == _MD_PHYSICAL || token == _MD_VIRTUAL)
2073 dll_flag = TRUE;
2074 if (dll_flag)
2075 {
2076 int fInitInstance = 1;
2077 int fTermInstance = 1;
2078 for (;;)
2079 {
2080 switch (_md_next_token (pMd))
2081 {
2082 case _MD_INITINSTANCE: fInitInstance = 1; continue;
2083 case _MD_INITGLOBAL: fInitInstance = 0; continue;
2084 case _MD_TERMINSTANCE: fTermInstance = 1; continue;
2085 case _MD_TERMGLOBAL: fTermInstance = 0; continue;
2086 default: break;
2087 }
2088 break;
2089 }
2090 fprintf (response_file, "FORMAT OS2 LX DLL %s %s\n",
2091 fInitInstance ? "INITINSTANCE" : "INITGLOBAL",
2092 fTermInstance ? "TERMINSTANCE" : "TERMGLOBAL");
2093 }
2094 else
2095 switch (_md_next_token (pMd))
2096 {
2097 case _MD_WINDOWAPI:
2098 fprintf (response_file, "FORMAT OS2 LX PM\n");
2099 break;
2100 default:
2101 case _MD_WINDOWCOMPAT:
2102 fprintf (response_file, "FORMAT OS2 LX PMCompatible\n");
2103 break;
2104 case _MD_NOTWINDOWCOMPAT:
2105 fprintf (response_file, "FORMAT OS2 LX FullScreen\n");
2106 break;
2107 }
2108 _md_close (pMd);
2109 }
2110
2111 /* output files */
2112
2113 fprintf (response_file, "NAME '%s'\n", output_fname);
2114
2115 if (map_flag && map_fname)
2116 fprintf (response_file, "OPTION MAP='%s'\n", map_fname);
2117 else if (map_flag)
2118 fprintf (response_file, "OPTION MAP\n");
2119
2120 /* standard stuff */
2121
2122 if (!strip_symbols)
2123 fprintf (response_file, "DEBUG HLL\n");
2124 fprintf (response_file, "OPTION QUIET\n");
2125 fprintf (response_file, "OPTION OSNAME='OS/2 EMX'\n");
2126 fprintf (response_file, "OPTION CASEEXACT\n");
2127 if (!dll_flag)
2128 fprintf (response_file, "OPTION STACK=%#lx\n", stack_size * 1024);
2129 if (!dll_flag && !base)
2130 base = "0x10000";
2131 if (base)
2132 fprintf (response_file, "OPTION OFFSET=%s\n", base);
2133
2134 /* the stub */
2135
2136 _execname(&execname[0], sizeof(execname));
2137 strcpy (_getname (&execname[0]), "os2stub.bin");
2138 if (!stat (execname, &s))
2139 fprintf (response_file, "OPTION STUB='%s'\n", execname);
2140
2141 /* Add the /INFORMATION option if the -i or -t option was given. This is
2142 for debugging. */
2143
2144// if (opt_t)
2145// put_arg ("/i", FALSE, FALSE);
2146
2147 /* Add the linker options specified with -O. */
2148
2149 for (pcur = options; pcur; pcur = pcur->next)
2150 fprintf (response_file, "%s\n", pcur->name);
2151
2152 /* Put the object file names onto the command line. */
2153
2154 for (pcur = obj_fnames; pcur; pcur = pcur->next)
2155 fprintf (response_file, "FILE '%s'\n", pcur->name);
2156
2157 /* Put the library file names onto the command line. */
2158
2159 for (pcur = lib_fnames; pcur; pcur = pcur->next)
2160 fprintf (response_file, "LIBRARY '%s'\n", pcur->name);
2161
2162 /* Translate the essentials of the module definition file into wlink lingo. */
2163 if (def_fname)
2164 {
2165 struct _md *pMd = _md_open (def_fname);
2166 if (!pMd)
2167 {
2168 fprintf (stderr, "emxomfld: cannot open `%s'\n", def_fname);
2169 exit (2);
2170 }
2171 _md_next_token (pMd);
2172 _md_parse (pMd, def_2_watcom, NULL);
2173 _md_close (pMd);
2174 }
2175 }
2176
2177 /* End the arguments and run the linker. */
2178
2179 arg_end ();
2180
2181 rc = emxomfld_spawn (command_line, "Linker");
2182 if (rc == 4 && !strnicmp(linker_type, "VAC3", 4)) /* Ignore iLink warnings. */
2183 rc = 0;
2184 if (rc < 0)
2185 {
2186 perror (linker_name);
2187 exit (2);
2188 }
2189
2190 /* Run RC if Linker completed successfully and a binary resource
2191 file was given on the command line. */
2192
2193 if (rc == 0 && res_fname != NULL)
2194 {
2195 arg_init (TRUE);
2196 put_arg ("rc.exe", TRUE, FALSE);
2197 put_arg ("-n", FALSE, FALSE);
2198 put_arg (res_fname, TRUE, FALSE);
2199 put_arg (output_fname, TRUE, FALSE);
2200 arg_end ();
2201 rc = emxomfld_spawn (command_line, "Resource Linker");
2202 if (rc < 0)
2203 {
2204 perror ("emxomfld: rc");
2205 exit (2);
2206 }
2207 }
2208
2209 /* If both Linker and RC completed successfully and the -Zexe option
2210 was given, touch the output file (without .exe) to keep `make'
2211 happy. */
2212
2213 if (rc == 0 && exe_flag)
2214 {
2215 /* find target and source filenames. */
2216 t = xstrdup (output_fname);
2217 _remext (t);
2218 _execname (&execname[0], sizeof(execname));
2219 strcpy (_getname(&execname[0]), "ldstub.bin");
2220
2221 /* Copy stub into file */
2222 if (opt_t)
2223 fprintf (stderr, "*** copy %s to %s (-Zexe)", execname, t);
2224 DosCopy (&execname[0], t, 4);
2225
2226 /* Now touch it */
2227 if (utime (t, NULL))
2228 {
2229 perror ("emxomfld");
2230 exit (2);
2231 }
2232 free (t);
2233 }
2234
2235 /* Run mapsym if requested and linking succeeded. */
2236 if (rc == 0 && sym_flag)
2237 {
2238 char* cwd = getcwd (NULL, 0);
2239 char map_fname_fullpath[_MAX_PATH];
2240 char drive[_MAX_PATH];
2241 char dir[_MAX_DIR];
2242
2243 /* get absolute path of map file and change CWD to map file directory. */
2244 _fullpath (map_fname_fullpath, map_fname, sizeof (map_fname_fullpath));
2245 _splitpath (map_fname_fullpath, drive, dir, NULL, NULL);
2246 strcat (drive, dir);
2247 if (chdir (drive))
2248 {
2249 perror ("chdir failed");
2250 exit (2);
2251 }
2252
2253 /* Invoke mapsym.cmd writing the .sym file to current directory. */
2254 arg_init (TRUE);
2255 if (getenv ("COMSPEC"))
2256 put_arg (getenv ("COMSPEC"), TRUE, FALSE);
2257 else
2258 put_arg ("cmd.exe", TRUE, FALSE);
2259 put_arg ("/c", FALSE, FALSE);
2260 put_arg ("mapsym.cmd", TRUE, FALSE);
2261 if (!stricmp (linker_type, "WLINK"))
2262 put_arg ("watcom", TRUE, FALSE);
2263 else if (!stricmp (linker_type, "LINK386"))
2264 put_arg ("link386", TRUE, FALSE);
2265 else
2266 put_arg ("vac3xx", TRUE, FALSE);
2267 put_arg (map_fname_fullpath, TRUE, FALSE);
2268 arg_end ();
2269 rc = emxomfld_spawn (command_line, "Mapsym");
2270 if (rc < 0)
2271 {
2272 perror ("emxomfld: mapsym");
2273 exit (2);
2274 }
2275
2276 /* Restore the working directory */
2277 if (chdir (cwd))
2278 {
2279 perror ("chdir failed");
2280 exit (2);
2281 }
2282 }
2283
2284 /* Return the return code of Linker or RC. */
2285
2286 return rc;
2287}
2288
Note: See TracBrowser for help on using the repository browser.