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

Last change on this file since 2689 was 2689, checked in by bird, 19 years ago

#89: Experimental support for wlink (the watcom linker).

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