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

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

Ignore PACKData and NOPACKData in wlink mode.

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