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

Last change on this file since 2446 was 2300, checked in by bird, 20 years ago

Default stack size set to 1MB.
The old defaults were 8MB (emxbind) and 8KB (emxomfld).

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