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

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

do _realrealpath on the TMPDIR before using it. Fixes #179.

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