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

Last change on this file since 2673 was 2673, checked in by bird, 19 years ago
  • *:

o Synced over changed from 0.6.1 bugfixing.

  • emxbind:

o #38: Fixed truncation bug writing to the LX nametable. (Yuri)
o #38: Imports and exports are limited to 255 not 127 chars. (Yuri)
o #28: Use DLL name from the .def file when present.

  • emxomf:

o #70: Demangle symbol names in debug info. (thanks to Yuri)

  • emxomfld:

o #55: delete the response file when reinit the args.
o #46: specify .map file extension to the linker.
o #34: Removed all the silliness trying to deal with truncated symbols.
o Don't display usage() on failure, just the error message.
o #20: use mkstemp + close instead of mktemp for the response file.

  • ld:

o #20: use make_temp_file instead of mktemp. This involved including

libiberty.h which required some adjustments of duplicate code to work.

o #27: Applied fix from Yuri.

  • libmoddef:

o Allow '.' and '@' in LIBRARY/NAME names.

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