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

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

Make an attempt at converting common ilink/link386 options to wlink lingo to make migration smoother.

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