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

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

#89: more wlink stuff. ; Fixed the exp=int .def errors in weakld.

  • Property cvs2svn:cvs-rev set to 1.42
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 63.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/* 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 else if (!stricmp(linker_type, "WLINK"))
1053 fFlags |= WLDC_LINKER_WLINK;
1054
1055 for (pOpt = options; pOpt; pOpt = pOpt->next)
1056 if ( !strnicmp(pOpt->name, "/NOE", 4)
1057 || !strnicmp(pOpt->name, "-NOE", 4))
1058 fFlags |= WLDC_NO_EXTENDED_DICTIONARY_SEARCH;
1059 else
1060 if ( !strnicmp(pOpt->name, "/INC", 4)
1061 || !strnicmp(pOpt->name, "-INC", 4))
1062 fFlags = fFlags; /* Ignore for now. */
1063 else
1064 if ( !strnicmp(pOpt->name, "/IG", 3)
1065 || !strnicmp(pOpt->name, "-IG", 3))
1066 fFlags |= WLDC_CASE_INSENSITIVE;
1067 else
1068 if ( !strnicmp(pOpt->name, "/I", 2)
1069 || !strnicmp(pOpt->name, "-I", 2))
1070 fFlags = fFlags; /* Ignore - require opt_t. */
1071 else
1072 if ( !strnicmp(pOpt->name, "/NOIN", 5)
1073 || !strnicmp(pOpt->name, "-NOIN", 5))
1074 fFlags &= ~WLDC_VERBOSE;
1075 else
1076 if ( !strnicmp(pOpt->name, "/NOI", 4)
1077 || !strnicmp(pOpt->name, "/NOI", 4))
1078 fFlags &= ~WLDC_CASE_INSENSITIVE;
1079
1080 /* create the linker and to the linking. */
1081 if (opt_t)
1082 fprintf(stderr, "*** Invoking weak prelinker with flags %x.\n", fFlags);
1083 pwld = WLDCreate (fFlags);
1084 if (pwld)
1085 {
1086 name_list * pcur;
1087 FILE *phfile;
1088 char szname[_MAX_PATH + 1];
1089
1090 /* definition file if any */
1091 if (def_fname && def_fname[0])
1092 {
1093 phfile = fopen (def_fname, "r");
1094 rc = WLDAddDefFile (pwld, phfile, def_fname);
1095 }
1096
1097 /* objects */
1098 for (pcur = obj_fnames; !rc && pcur; pcur = pcur->next)
1099 {
1100 phfile = find_obj (szname, pcur->name);
1101 rc = WLDAddObject (pwld, phfile, szname);
1102 }
1103
1104 /* libraries */
1105 for (pcur = lib_fnames; !rc && pcur; pcur = pcur->next)
1106 {
1107 phfile = find_lib (szname, pcur->name, !pcur->flags);
1108 rc = WLDAddLibrary (pwld, phfile, szname);
1109 free(pcur->name);
1110 pcur->name = xstrdup(szname);
1111 }
1112
1113 /* complete pass 1 */
1114 if (!rc)
1115 {
1116 rc = WLDPass1 (pwld);
1117 /* ignore unresolved externals for now. */
1118 if (rc == 42)
1119 {
1120 rc = 0;
1121 fprintf(stderr, "Ignoring unresolved externals reported from weak prelinker.\n");
1122 }
1123 }
1124
1125 /* generate weak aliases. */
1126 if (!rc)
1127 rc = WLDGenerateWeakAliases (pwld, weakobj_fname, weakdef_fname);
1128 if (!rc && weakobj_fname[0])
1129 {
1130 char *pszTmp = _realrealpath(weakobj_fname, NULL, 0);
1131 if (pszTmp)
1132 {
1133 strcpy(weakobj_fname, pszTmp);
1134 free(pszTmp);
1135 }
1136 add_name_list (&add_obj_fnames, weakobj_fname, 0);
1137 }
1138 if (!rc && weakdef_fname[0])
1139 {
1140 char *pszTmp = _realrealpath(weakdef_fname, NULL, 0);
1141 if (pszTmp)
1142 {
1143 strcpy(weakdef_fname, pszTmp);
1144 free(pszTmp);
1145 }
1146 def_fname = weakdef_fname;
1147 }
1148
1149 /* cleanup the linker */
1150 WLDDestroy (pwld);
1151
1152 /* last words */
1153 if (rc)
1154 fprintf (stderr, "emxomfld: weak prelinker failed. (rc=%d)\n", rc);
1155 }
1156 else
1157 {
1158 rc = 8;
1159 fprintf (stderr, "emxomfld: failed to create weak prelinker.\n");
1160 }
1161
1162 /* die on error. */
1163 if (rc)
1164 exit(rc);
1165
1166 /* verbose */
1167 if (opt_t)
1168 fprintf(stderr, "*** Weak prelinker done\n");
1169}
1170
1171
1172/* Start a new set of command line arguments. If RSP is non-zero, we
1173 are allowed to use a response file. */
1174
1175static void arg_init (int rsp)
1176{
1177 if (response_fname[0] != '\0')
1178 {
1179 remove (response_fname);
1180 response_fname[0] = '\0';
1181 }
1182 command_line[0] = '\0';
1183 line_len = 0;
1184 response_flag = rsp;
1185 force_response_file = FALSE;
1186}
1187
1188
1189/* Call this after adding all the command line arguments. If a
1190 response file has been created, add a newline and close it. */
1191
1192static void arg_end (void)
1193{
1194 if (response_file != NULL)
1195 {
1196 fputc ('\n', response_file);
1197 if (fflush (response_file) != 0 || fclose (response_file) != 0)
1198 {
1199 perror ("emxomfld");
1200 exit (2);
1201 }
1202 response_file = NULL;
1203 }
1204}
1205
1206/* Generates a definition file for a dll which doesn't have one. */
1207static void gen_deffile(void)
1208{
1209 char * psz;
1210 name_list *pName;
1211
1212 /*
1213 * Make temporary file.
1214 */
1215 pName = (name_list *)xmalloc(sizeof(*pName));
1216 pName->name = psz = xmalloc(_MAX_PATH);
1217 if (!make_tempfile(psz, "lddef", ".def", NULL))
1218 {
1219 FILE *pFile = fopen(psz, "w");
1220 if (pFile)
1221 {
1222 const char *pszName = _getname(output_fname);
1223 size_t cchName = strlen(pszName);
1224 if (cchName > 4 && !stricmp(pszName + cchName - 4, ".dll"))
1225 cchName -= 4;
1226 fprintf(pFile,
1227 ";; Autogenerated by emxomfld\n"
1228 "LIBRARY %.*s INITINSTANCE TERMINSTANCE\n"
1229 "DATA MULTIPLE\n"
1230 "CODE SHARED\n"
1231 "\n",
1232 cchName, pszName);
1233 fclose(pFile);
1234 def_fname = psz;
1235 if (opt_t)
1236 fprintf(stderr,
1237 "--- Generated def-file %s:\n"
1238 ";; Autogenerated by emxomfld\n"
1239 "LIBRARY %.*s INITINSTANCE TERMINSTANCE\n"
1240 "DATA MULTIPLE NONSHARED\n"
1241 "CODE SINGLE SHARED\n"
1242 "---- End of generated def-file.\n",
1243 psz, cchName, pszName);
1244
1245 /* add to auto delete list for removal on exit(). */
1246 pName->next = conv_list;
1247 conv_list = pName;
1248 return;
1249 }
1250 }
1251 free(psz);
1252 free(pName);
1253}
1254
1255/* converts a def file statement to watcom responsfile lingo. */
1256
1257static def_2_watcom(struct _md *md, const _md_stmt *stmt, _md_token token, void *arg)
1258{
1259 switch (token)
1260 {
1261 case _MD_BASE:
1262 fprintf (response_file, "OPTION OFFSET=%#lx\n", stmt->base.addr);
1263 break;
1264
1265 case _MD_CODE:
1266 break;
1267
1268 case _MD_DATA:
1269 break;
1270
1271 case _MD_DESCRIPTION:
1272 fprintf (response_file, "OPTION DESCRIPTION '%s'\n", stmt->descr.string);
1273 break;
1274
1275 case _MD_EXETYPE:
1276 break;
1277
1278 case _MD_EXPORTS:
1279 fprintf (response_file, "EXPORT '%s'", stmt->export.entryname);
1280 if (stmt->export.flags & _MDEP_ORDINAL)
1281 fprintf (response_file, ".%d", stmt->export.ordinal);
1282 if (stmt->export.internalname[0])
1283 fprintf (response_file, "='%s'", stmt->export.internalname);
1284 if (stmt->export.flags & _MDEP_RESIDENTNAME)
1285 fprintf (response_file, " RESIDENT", stmt->export.internalname);
1286 /** @todo _MDEP_NONAME */
1287 fprintf (response_file, "\n");
1288 break;
1289
1290 case _MD_HEAPSIZE:
1291 fprintf (response_file, "OPTION HEAPSIZE=%#lx\n", stmt->heapsize.size);
1292 break;
1293
1294 case _MD_IMPORTS:
1295 fprintf (response_file, "IMPORT '%s' '%s'", stmt->import.entryname,
1296 stmt->import.modulename);
1297 if (stmt->import.flags & _MDEP_ORDINAL)
1298 fprintf (response_file, ".%d", stmt->import.ordinal);
1299 else if (stmt->import.internalname[0])
1300 fprintf (response_file, ".'%s'", stmt->import.internalname);
1301 fprintf (response_file, "\n");
1302 break;
1303
1304 case _MD_LIBRARY:
1305 if (stmt->library.name[0])
1306 fprintf (response_file, "OPTION MODNAME='%s'\n", stmt->library.name);
1307 break;
1308
1309 case _MD_NAME:
1310 if (stmt->name.name[0])
1311 fprintf (response_file, "OPTION MODNAME='%s'\n", stmt->name.name);
1312 break;
1313
1314 case _MD_OLD:
1315 fprintf (response_file, "OPTION OLDLIBRARY='%s'\n", stmt->old.name);
1316 break;
1317
1318 case _MD_PROTMODE:
1319 fprintf (response_file, "OPTION PROTMODE\n");
1320 break;
1321
1322 case _MD_REALMODE:
1323 fprintf (response_file, "OPTION PROTMODE\n");
1324 break;
1325
1326 case _MD_SEGMENTS:
1327 fprintf (stderr, "emxomfld: ignoring SEGMENTS directive in .def-file\n");
1328 break;
1329
1330 case _MD_STACKSIZE:
1331 fprintf (response_file, "OPTION STACK=%#ld\n", stmt->stacksize.size);
1332 break;
1333
1334 case _MD_STUB:
1335 fprintf (response_file, "OPTION STUB='%s'\n", stmt->stub.name);
1336 break;
1337
1338 case _MD_VIRTUAL:
1339 case _MD_PHYSICAL:
1340 break;
1341
1342 case _MD_parseerror:
1343 fprintf (stderr, "emxomfld: %s (line %ld of %s)",
1344 _md_errmsg (stmt->error.code), _md_get_linenumber (md), def_fname);
1345 exit (2);
1346 break;
1347
1348 default:
1349 abort ();
1350 }
1351 return 0;
1352}
1353
1354/* -t output. We dump the commandline and responsefile. */
1355static void show_spawn(const char *pszwhat)
1356{
1357 if (!opt_t)
1358 return;
1359 fprintf(stderr, "*** Invoking %s\n %s\n", pszwhat, command_line);
1360 if (response_fname[0])
1361 { /* display the responsfile content. */
1362 char sz[4096];
1363 FILE *phfile = fopen(response_fname, "r");
1364 fprintf(stderr, "--- Response file %s:\n", response_fname);
1365 sz[0] = '\0';
1366 while (fgets(sz, sizeof(sz), phfile))
1367 fprintf(stderr, "%s", sz);
1368 fclose(phfile);
1369 if (sz[strlen(sz) - 1] != '\n')
1370 fprintf(stderr, "\n");
1371 fprintf(stderr, "--- End of Response File\n");
1372 }
1373}
1374
1375
1376/* Execute commandline and returns the result.
1377 pszwhat is used for opt_t trace information. */
1378
1379static int emxomfld_spawn(char *pszcmd, const char *pszwhat)
1380{
1381 int argi;
1382 char ** argv;
1383 char * psz;
1384 int rc;
1385
1386 if (opt_t)
1387 show_spawn(pszwhat);
1388
1389 /* construct spawnvp() argument array */
1390 argi = 0;
1391 argv = NULL;
1392 psz = pszcmd;
1393 while (psz && *psz)
1394 {
1395 char *psz2 = psz;
1396
1397 /* skip blanks. */
1398 while (*psz2 == '\t' || *psz2 == ' ')
1399 psz2++;
1400
1401 /* find end of argument taking in account in arg quoting. */
1402 while (*psz2 && *psz2 != '\t' && *psz2 != ' ')
1403 {
1404 if (*psz2 == '"' || *psz2 == '\'')
1405 {
1406 char chQuote = *psz2++;
1407 while (*psz2 && *psz2 != chQuote)
1408 psz2++;
1409 }
1410 psz2++;
1411 }
1412
1413 /* terminate and set psz2 to point to next */
1414 if (*psz2)
1415 *psz2++ = '\0';
1416
1417 /* add argument to argument vector. */
1418 if (!(argi % 32))
1419 argv = xrealloc(argv, sizeof(argv[0]) * (argi + 32 + 1));
1420 argv[argi++] = psz;
1421
1422 /* next */
1423 psz = psz2;
1424 }
1425 argv[argi] = NULL;
1426
1427 /* Spawn process. */
1428 rc = spawnvp(P_WAIT, argv[0], argv);
1429 if (opt_t)
1430 fprintf(stderr, "*** Return from %s is %d\n", pszwhat, rc);
1431
1432 free(argv);
1433 return rc;
1434}
1435
1436
1437/* Cleanup by closing (if open) and deleting (if pressent) the
1438 response file. This function is used with atexit(). */
1439
1440static void cleanup (void)
1441{
1442 if (response_file != NULL)
1443 {
1444 fclose (response_file);
1445 response_file = NULL;
1446 }
1447 if (opt_t <= 1)
1448 {
1449 if (response_fname[0] != '\0')
1450 {
1451 remove (response_fname);
1452 response_fname[0] = '\0';
1453 }
1454 if (weakobj_fname[0] != '\0')
1455 {
1456 remove (weakobj_fname);
1457 weakobj_fname[0] = '\0';
1458 }
1459 if (weakdef_fname[0] != '\0')
1460 {
1461 remove (weakdef_fname);
1462 weakdef_fname[0] = '\0';
1463 }
1464 for (; conv_list; conv_list = conv_list->next)
1465 remove (conv_list->name);
1466 }
1467}
1468
1469/* Tell the user how to run this program. */
1470
1471static void usage (void)
1472{
1473 fputs ("emxomfld " VERSION INNOTEK_VERSION "\n"
1474 "Copyright (c) 1992-1996 by Eberhard Mattes\n"
1475 "Copyright (c) 2003 by InnoTek Systemberatung GmbH\n"
1476 "Copyright (c) 2003-2006 by Knut St. Osmundsen\n"
1477 "\n", stderr);
1478 fputs ("Usage: emxomfld -o <file> [-l <lib>] [-L <libdir>] [-T <base>] [-igtsS]\n"
1479 " [-Zexe] [-Zdll] [-Zstack <size>] [-Zmap[=<map_file>]]\n"
1480 " [-Z[no-]autoconv] [-Zdll-search] [-O <option>] [-static]\n"
1481 " [-non_shared] [-Bstatic] [-dn] [call_shared] [-Bshared]\n"
1482 " [-dy] <file>...\n"
1483 "\n", stderr);
1484 fputs ("Options:\n"
1485 " -Zno-autoconv / -Zautoconv:\n"
1486 " Turns off/on the automatic conversion of a.out libs and objs.\n"
1487 " default: -Zautoconv\n"
1488 " -Bstatic, -non_shared, -dn, -static:\n"
1489 " Link with static libraries.\n"
1490 " The search order is then changed to: lib<name>_s.lib, <name>_s.lib,\n"
1491 " lib<name>.lib, <name>.lib\n", stderr);
1492 fputs (" -Bshared, -call_shared, -dy:\n"
1493 " Link with shared libraries. This is default.\n"
1494 " The search order is then changed to: lib<name>_dll.lib, <name>_dll.lib,\n"
1495 " lib<name>.lib, <name>.lib, <name>.dll, lib<name>_s.lib, <name>_s.lib.\n"
1496 " -Zdll-search:\n"
1497 " Enables dlls as valid libraries from shared linking. (default disabled)\n"
1498 "\n", stderr);
1499 fputs ("Environment variables:\n"
1500 " EMXOMFLD_TYPE:\n"
1501 " The type of linker we're using. Values: VAC365, VAC308, LINK386, WLINK.\n"
1502 " VAC365 ilink.exe from IBM C and C++ Compilers for OS/2 v3.6 or later.\n"
1503 " VAC308 ilink.exe from Visual Age for C++ v3.08.\n"
1504 " LINK386 link386 form OS/2 install or DDK.\n"
1505 " WLINK wlink.exe from Open Watcom v1.4 or later. (experimental)\n", stderr);
1506 fputs (" EMXOMFLD_LINKER:\n"
1507 " Name of the linker to use and optionally extra parameters. Spaces in the\n"
1508 " linker name or path is not supported. Quotes are not supported either.\n"
1509 "The default values for these two variables are VAC365 and ilink.exe.\n", stderr);
1510 exit (1);
1511}
1512
1513
1514
1515static struct option longopts[] =
1516{
1517#define OPT_LIBS_STATIC 0x1000
1518 {"Bstatic", 0, 0, OPT_LIBS_STATIC},
1519 {"non_shared", 0, 0, OPT_LIBS_STATIC},
1520 {"dn", 0, 0, OPT_LIBS_STATIC},
1521 {"static", 0, 0, OPT_LIBS_STATIC},
1522#define OPT_LIBS_SHARED 0x1001
1523 {"Bshared", 0, 0, OPT_LIBS_SHARED},
1524 {"call_shared", 0, 0, OPT_LIBS_SHARED},
1525 {"dy", 0, 0, OPT_LIBS_SHARED},
1526#define OPT_ZEXE 0x1002
1527 {"Zexe", 0, 0, OPT_ZEXE}, /* Create .exe file, touch `output file' */
1528#define OPT_ZDLL 0x1003
1529 {"Zdll", 0, 0, OPT_ZDLL}, /* Create .dll file, touch `output file' */
1530#define OPT_ZSTACK 0x1004
1531 {"Zstack", 1, 0, OPT_ZSTACK}, /* Set stack size */
1532#define OPT_ZMAP 0x1005
1533 {"Zmap", 2, 0, OPT_ZMAP}, /* Create .map file */
1534 {"Zmap=", 1, 0, OPT_ZMAP},
1535#define OPT_ZAUTOCONV 0x1006
1536 {"Zautoconv",0, 0, OPT_ZAUTOCONV},
1537#define OPT_ZNO_AUTOCONV 0x1007
1538 {"Zno-autoconv",0, 0, OPT_ZNO_AUTOCONV},
1539#define OPT_ZDLL_SEARCH 0x1008
1540 {"Zdll-search",0, 0, OPT_ZDLL_SEARCH},
1541/* {"e", 1, 0, 'e'}, entry point */
1542 {"i", 0, 0, 'i'},
1543 {"o", 1, 0, 'o'},
1544 {"O", 1, 0, 'O'},
1545/* {"u", 1, 0, 'u'}, reference symbol */
1546 {"s", 0, 0, 's'},
1547 {"S", 0, 0, 'S'},
1548 {"t", 0, 0, 't'},
1549 {"T", 1, 0, 'T'},
1550 {"v", 0, 0, 'v'},
1551 {"x", 0, 0, 'x'},
1552 {"X", 0, 0, 'X'},
1553 {NULL, 0, 0, 0}
1554};
1555
1556/* Main function of emxomf. Parse the command line and call the IBM/M$
1557 linker (and optionally RC). */
1558
1559int main (int argc, char *argv[])
1560{
1561 struct stat s;
1562 int c, rc, files;
1563 const char *ext;
1564 char tmp[512], *t;
1565 char execname[512];
1566 name_list *pcur;
1567 int opt_libs_static = 0;
1568 int longind;
1569
1570 /* Get options from response files (@filename) and wildcard (*.o) on the command. */
1571
1572 _response (&argc, &argv);
1573 _wildcard (&argc, &argv);
1574
1575 /* Close and delete the response file on exit. */
1576
1577 atexit (cleanup);
1578
1579 /* Prepare parsing of the command line. */
1580
1581 files = 0;
1582 opterr = FALSE;
1583 /*optmode = GETOPT_KEEP; */
1584 if (argc < 2)
1585 usage ();
1586
1587 /* Parse the command line options and other arguments. */
1588 while ((c = getopt_long_only (argc, argv, "-l:y:L:", longopts, &longind)) != EOF)
1589 {
1590 if (c == 0)
1591 c = longopts[longind].val;
1592 switch (c)
1593 {
1594 case 1: /* Non-option argument */
1595
1596 /* Extract the extension to see what to do with this
1597 argument. */
1598
1599 ext = _getext (optarg);
1600
1601 if (ext == NULL)
1602 {
1603 /* GCC's temporary files don't have an extension. Add a
1604 dot to the end of the name to prevent the linker from
1605 adding `.obj'. */
1606
1607 sprintf (tmp, "%s.", optarg);
1608 add_name_list (&add_obj_fnames, tmp, 0);
1609 }
1610
1611 /* If it's a .def file, use it as module definition file
1612 (input). */
1613
1614 else if (stricmp (ext, ".def") == 0)
1615 {
1616 if (def_fname != NULL)
1617 {
1618 fprintf (stderr,
1619 "emxomfld: multiple module definition files\n");
1620 return 1;
1621 }
1622 def_fname = _realrealpath(optarg, NULL, 0);
1623 if (!def_fname)
1624 def_fname = optarg;
1625 }
1626
1627 /* If it's a .res file, use it as binary resource file
1628 (input). */
1629
1630 else if (stricmp (ext, ".res") == 0)
1631 {
1632 if (res_fname != NULL)
1633 {
1634 fprintf (stderr,
1635 "emxomfld: multiple binary resource files\n");
1636 return 1;
1637 }
1638 res_fname = _realrealpath(optarg, NULL, 0);
1639 if (!def_fname)
1640 res_fname = optarg;
1641 }
1642
1643 /* If it's a .lib file, use it as library file. We also
1644 accept .a files for those who use OMF files disguised as
1645 a.out files (to simplify their make files). */
1646
1647 else if (stricmp (ext, ".lib") == 0 || stricmp (ext, ".a") == 0 || stricmp (ext, ".dll") == 0)
1648 add_name_list (&add_lib_fnames, optarg, opt_libs_static);
1649
1650 /* Otherwise, assume it's an object file. */
1651
1652 else
1653 add_name_list (&add_obj_fnames, optarg, 0);
1654 ++files;
1655 break;
1656
1657 case 't':
1658 case 'i': /* Trace the linking process, sending /INFO to the IBM/M$ linker. */
1659 opt_t++;
1660 break;
1661
1662 case 'l': /* Add library */
1663 add_name_list (&add_lib_fnames, optarg, opt_libs_static);
1664 break;
1665
1666 case 'o': /* Set output file name */
1667 output_fname = optarg;
1668 break;
1669
1670 case 'L': /* Add library directory */
1671 add_name_list (&add_libdirs, optarg, 0);
1672 break;
1673
1674 case 'T': /* Set base address */
1675 base = optarg;
1676 break;
1677
1678 case 's': /* Strip all symbols */
1679 case 'S': /* Strip debugging symbols */
1680 strip_symbols = TRUE;
1681 break;
1682
1683 case 'x': /* Discard all local symbols */
1684 case 'X': /* Discard local symbols starting with L */
1685 break;
1686
1687 case 'v': /* For compatibility */
1688 break;
1689
1690 case 'O': /* Specify Linker option */
1691 add_name_list (&add_options, optarg, 0);
1692 break;
1693
1694 case OPT_ZDLL:
1695 dll_flag = TRUE;
1696 break;
1697
1698 case OPT_ZEXE:
1699 exe_flag = TRUE;
1700 break;
1701
1702 case OPT_ZMAP:
1703 map_flag = TRUE;
1704 if (optarg)
1705 {
1706 if (map_fname != NULL)
1707 {
1708 fprintf (stderr, "emxomfld: multiple map files files\n");
1709 return 1;
1710 }
1711 map_fname = optarg;
1712 }
1713 break;
1714
1715 case OPT_ZSTACK:
1716 if (!optarg)
1717 return 1;
1718 errno = 0;
1719 stack_size = strtol (optarg, &t, 0);
1720 if (errno != 0 || *t != 0 || t == optarg)
1721 return 1;
1722 break;
1723
1724 case OPT_ZAUTOCONV:
1725 autoconvert_flag = 1;
1726 break;
1727 case OPT_ZNO_AUTOCONV:
1728 autoconvert_flag = 0;
1729 break;
1730
1731 case OPT_ZDLL_SEARCH:
1732 opt_dll_search = 1;
1733 break;
1734
1735 case OPT_LIBS_STATIC:
1736 opt_libs_static = 1;
1737 break;
1738 case OPT_LIBS_SHARED:
1739 opt_libs_static = 0;
1740 break;
1741
1742 case '?':
1743 default:
1744 if (optind > 1)
1745 fprintf (stderr, "emxomfld: invalid option (%s)\n", argv[optind - 1]);
1746 else
1747 usage ();
1748 return 1;
1749 }
1750 }
1751 /* Set default value for output file. */
1752
1753 if (output_fname == NULL)
1754 {
1755 fprintf (stderr,
1756 "emxomfld: no output file, creating $$$.exe or $$$.dll\n");
1757 output_fname = "$$$";
1758 }
1759
1760 /* Check if there are any input files. */
1761
1762 if (files == 0)
1763 {
1764 fprintf (stderr, "emxomfld: no input files\n");
1765 return 1;
1766 }
1767
1768 /* Remove the output file if -Zexe is given. */
1769
1770 if (exe_flag)
1771 remove (output_fname);
1772
1773 /* If neither -Zmap nor -Zmap=file is used, pass "nul" to the linker in
1774 the map file field. If -Zmap is used, construct the name of the
1775 .map file. If -Zmap=file is used, use `file' as the name of the
1776 .map file. */
1777
1778 if (!map_flag)
1779 map_fname = "nul";
1780 else if (map_fname == NULL)
1781 {
1782 int cch = strlen (output_fname) + 1;
1783 t = xmalloc (cch + 4);
1784 memcpy (t, output_fname, cch);
1785 _remext (t);
1786 strcat (t, ".map");
1787 map_fname = t;
1788 }
1789
1790 /* Build the environment for the linker. */
1791
1792 make_env ();
1793
1794 /* EMXOMFLD_TYPE contains VAC365, VAC308 or LINK386 if set. If non of these
1795 we assume VAC365.
1796 EMXOMFLD_LINKER contains the linker name and perhaps extra arguments. If
1797 not set we'll use the default linker, ilink. */
1798
1799 t = getenv ("EMXOMFLD_TYPE");
1800 if ( t
1801 && stricmp(t, "VAC365")
1802 && stricmp(t, "VAC308")
1803 && stricmp(t, "LINK386")
1804 && stricmp(t, "WLINK")
1805 )
1806 fprintf (stderr, "emxomfld: warning: '%s' is an invalid value for EMXOMFLD_TYPE.\n", t);
1807 else if (t)
1808 linker_type = t;
1809
1810 t = getenv ("EMXOMFLD_LINKER");
1811 if (t)
1812 linker_name = t;
1813 if (opt_t)
1814 fprintf(stderr, "*** Linker : %s\n"
1815 "*** Linker type: %s\n", linker_name, linker_type);
1816
1817 /* apply object & library hacks */
1818 for (pcur = obj_fnames, rc = 0; !rc && pcur; pcur = pcur->next)
1819 {
1820 char szname[_MAX_PATH + 1];
1821 FILE *phfile = find_obj (szname, pcur->name);
1822 if (!phfile)
1823 continue;
1824 free (pcur->name);
1825 pcur->name = xstrdup(szname);
1826 fclose(phfile);
1827 }
1828
1829 for (pcur = lib_fnames, rc = 0; !rc && pcur; pcur = pcur->next)
1830 {
1831 char szname[_MAX_PATH + 1];
1832 FILE *phfile = find_lib (szname, pcur->name, !pcur->flags);
1833 if (!phfile)
1834 continue;
1835 free (pcur->name);
1836 pcur->name = xstrdup(szname);
1837 fclose(phfile);
1838 }
1839
1840 /* generate .def-file for dlls. */
1841
1842 if (!def_fname && dll_flag)
1843 gen_deffile();
1844
1845 /* Do the weak prelinking. Important that this is done after make_env(). */
1846
1847 weak_prelink ();
1848
1849 /* Start building the linker command line. We can use a response
1850 file if the command line gets too long. */
1851
1852 arg_init (TRUE);
1853
1854 /* issue commandline */
1855 put_arg (linker_name, TRUE, FALSE);
1856
1857 if (stricmp (linker_type, "WLINK"))
1858 {
1859 /*
1860 For VAC365 and VAC308 the default options is:
1861
1862 /NOFR[EEFORMAT] Use /NOFREEFORMAT to allow a LINK386-compatible
1863 command line syntax, in which different types of file
1864 are grouped and separated by commas.
1865
1866 /DBGPACK If !strip_symbols then we'll add this option, which
1867 will cause type tables to be merged into one global
1868 table and so eliminating a lot of duplicate info.
1869
1870 For VAC365 additional default option is:
1871
1872 /STUB:<emxomfld-path>\os2stub.bin
1873 Causes this MZ stub to be used when linking the
1874 executables instead of the default on for the linker.
1875
1876 For LINK386 the default options is:
1877
1878 /BATCH Run in batch mode (disable prompting, don't
1879 echo response file)
1880
1881 The default options for all linkers are:
1882
1883 /NOLOGO Don't display sign-on banner
1884
1885 /NOEXTDICTIONARY Don't use extended dictionary (redefining
1886 library symbols is quite common)
1887
1888 /NOIGNORECASE Make symbols case-sensitive
1889
1890 /PACKCODE Group neighboring code segments (this is the
1891 default unless the SEGMENTS module definition
1892 statement is used for a segment of class
1893 'CODE'). Not grouping neighboring code
1894 segments would break sets
1895
1896 For non DLLs targets:
1897
1898 /BASE:0x10000 Base the executable an so removing extra fixups.
1899
1900 */
1901
1902 /* the next part depends on the linker type. */
1903 if (!stricmp (linker_type, "LINK386"))
1904 put_arg ("/bat", FALSE, FALSE);
1905 else /* vac3xx: */
1906 {
1907 put_arg ("/nofree", FALSE, FALSE);
1908 if (!strip_symbols)
1909 put_arg ("/db", FALSE, FALSE);
1910 if (map_flag)
1911 put_arg ("/map", FALSE, FALSE);
1912 }
1913 put_arg ("/nol", FALSE, FALSE);
1914 put_arg ("/noe", FALSE, FALSE);
1915 put_arg ("/noi", FALSE, FALSE);
1916 put_arg ("/packc", FALSE, FALSE);
1917
1918
1919 /* VAC365: check if we have os2stub.bin.
1920 We must to this after the above stuff else /nol might end up in the
1921 response file and we'll get the component output. */
1922
1923 if (!stricmp (linker_type, "VAC365"))
1924 {
1925 /* gklayout show that the linker isn't capable of determining a
1926 decent value for this parameter. 32MB makes gklayout link. */
1927 put_arg ("/ocache:0x02000000", FALSE, FALSE);
1928
1929 _execname (&execname[0], sizeof(execname));
1930 strcpy (_getname (&execname[0]), "os2stub.bin");
1931 if (!stat (execname, &s))
1932 {
1933 sprintf (tmp, "/STUB:%s", &execname[0]);
1934 put_arg (tmp, FALSE, FALSE);
1935 }
1936 }
1937
1938 /* Add the /INFORMATION option if the -i or -t option was given. This is
1939 for debugging. */
1940
1941 if (opt_t)
1942 put_arg ("/i", FALSE, FALSE);
1943
1944 /* Add the /DEBUG option if the -s option was not given. Without
1945 this, the linker throws away debugging information. */
1946
1947 if (!strip_symbols)
1948 put_arg ("/de", FALSE, FALSE);
1949
1950 /* Add the /BASE:n option to set the base address. This specifies
1951 the preferred load address of object 1. The base address being
1952 used is 0x10000 unless a DLL is generated or the -T option was
1953 given. -Tno can be used to suppress the /BASE:n option. */
1954
1955 if (base == NULL && !dll_flag)
1956 {
1957 struct _md *md;
1958
1959 if (def_fname != NULL)
1960 {
1961 int token;
1962 md = _md_open (def_fname);
1963 if (md == NULL)
1964 {
1965 fprintf (stderr, "emxomfld: cannot open `%s'\n", def_fname);
1966 exit (2);
1967 }
1968 token = _md_next_token (md);
1969 if (token == _MD_LIBRARY || token == _MD_PHYSICAL || token == _MD_VIRTUAL)
1970 dll_flag = TRUE;
1971 _md_close (md);
1972 }
1973 }
1974 if (base == NULL && !dll_flag)
1975 base = "0x10000";
1976 if (base != NULL && stricmp (base, "no") != 0)
1977 {
1978 sprintf (tmp, "/bas:%s", base);
1979 put_arg (tmp, FALSE, FALSE);
1980 }
1981
1982 /* Add the /STACK:n option if the -Zstack option was given. */
1983
1984 if (!dll_flag)
1985 {
1986 sprintf (tmp, "/st:0x%lx", stack_size * 1024);
1987 put_arg (tmp, FALSE, FALSE);
1988 }
1989
1990 /* Add the linker options specified with -O. */
1991
1992 put_args (options, FALSE);
1993
1994 /* Put the object file names onto the command line. */
1995
1996 force_response_file = TRUE; /* link386 workaround. */
1997 put_args (obj_fnames, TRUE);
1998 put_arg (",", FALSE, FALSE);
1999
2000 /* Put the output file name onto the command line. */
2001
2002 put_arg (output_fname, TRUE, TRUE);
2003 put_arg (",", FALSE, FALSE);
2004
2005 /* Put the map file name onto the command line. */
2006
2007 put_arg (map_fname, TRUE, TRUE);
2008 put_arg (",", FALSE, FALSE);
2009
2010 /* Put the library file names onto the command line. */
2011
2012 put_args (lib_fnames, TRUE);
2013 put_arg (",", FALSE, FALSE);
2014
2015 /* Put the name of the module definition file onto the command line. */
2016
2017 put_arg (def_fname, TRUE, TRUE);
2018 put_arg (";", FALSE, FALSE);
2019
2020 /* Call Linker and abort on failure. */
2021 }
2022 else /* wlink */
2023 {
2024 open_response_file ();
2025
2026 /* figure out what format options we're gonna use */
2027
2028 if (!def_fname && !dll_flag)
2029 fprintf (response_file, "FORMAT OS2 LX PMCompatible\n");
2030 else if (!def_fname && dll_flag)
2031 fprintf (response_file, "FORMAT OS2 LX DLL INITINSTANCE TERMINSTANCE\n");
2032 else
2033 {
2034 int token;
2035 struct _md *pMd = _md_open (def_fname);
2036 if (!pMd)
2037 {
2038 fprintf (stderr, "emxomfld: cannot open `%s'\n", def_fname);
2039 exit (2);
2040 }
2041 token = _md_next_token (pMd);
2042 if (token == _MD_LIBRARY || token == _MD_PHYSICAL || token == _MD_VIRTUAL)
2043 dll_flag = TRUE;
2044 if (dll_flag)
2045 {
2046 int fInitInstance = 1;
2047 int fTermInstance = 1;
2048 for (;;)
2049 {
2050 switch (_md_next_token (pMd))
2051 {
2052 case _MD_INITINSTANCE: fInitInstance = 1; continue;
2053 case _MD_INITGLOBAL: fInitInstance = 0; continue;
2054 case _MD_TERMINSTANCE: fTermInstance = 1; continue;
2055 case _MD_TERMGLOBAL: fTermInstance = 0; continue;
2056 default: break;
2057 }
2058 break;
2059 }
2060 fprintf (response_file, "FORMAT OS2 LX DLL %s %s\n",
2061 fInitInstance ? "INITINSTANCE" : "INITGLOBAL",
2062 fTermInstance ? "TERMINSTANCE" : "TERMGLOBAL");
2063 }
2064 else
2065 switch (_md_next_token (pMd))
2066 {
2067 case _MD_WINDOWAPI:
2068 fprintf (response_file, "FORMAT OS2 LX PM\n");
2069 break;
2070 default:
2071 case _MD_WINDOWCOMPAT:
2072 fprintf (response_file, "FORMAT OS2 LX PMCompatible\n");
2073 break;
2074 case _MD_NOTWINDOWCOMPAT:
2075 fprintf (response_file, "FORMAT OS2 LX FullScreen\n");
2076 break;
2077 }
2078 _md_close (pMd);
2079 }
2080
2081 /* output files */
2082
2083 fprintf (response_file, "NAME '%s'\n", output_fname);
2084
2085 if (map_flag && map_fname)
2086 fprintf (response_file, "OPTION MAP='%s'\n", map_fname);
2087 else if (map_flag)
2088 fprintf (response_file, "OPTION MAP\n", map_fname);
2089
2090 /* standard stuff */
2091
2092 if (!strip_symbols)
2093 fprintf (response_file, "DEBUG HLL\n");
2094 fprintf (response_file, "OPTION QUIET\n");
2095 fprintf (response_file, "OPTION OSNAME='OS/2 EMX'\n");
2096 fprintf (response_file, "OPTION CASEEXACT\n");
2097 if (!dll_flag)
2098 fprintf (response_file, "OPTION STACK=%#lx\n", stack_size * 1024);
2099 if (!dll_flag && !base)
2100 base = "0x10000";
2101 if (base)
2102 fprintf (response_file, "OPTION OFFSET=%s\n", base);
2103
2104 /* the stub */
2105
2106 _execname(&execname[0], sizeof(execname));
2107 strcpy (_getname (&execname[0]), "os2stub.bin");
2108 if (!stat (execname, &s))
2109 fprintf (response_file, "OPTION STUB='%s'\n", execname);
2110
2111 /* Add the /INFORMATION option if the -i or -t option was given. This is
2112 for debugging. */
2113
2114// if (opt_t)
2115// put_arg ("/i", FALSE, FALSE);
2116
2117 /* Add the linker options specified with -O. */
2118
2119 for (pcur = options; pcur; pcur = pcur->next)
2120 fprintf (response_file, "%s\n", pcur->name);
2121
2122 /* Put the object file names onto the command line. */
2123
2124 for (pcur = obj_fnames; pcur; pcur = pcur->next)
2125 fprintf (response_file, "FILE '%s'\n", pcur->name);
2126
2127 /* Put the library file names onto the command line. */
2128
2129 for (pcur = lib_fnames; pcur; pcur = pcur->next)
2130 fprintf (response_file, "LIBRARY '%s'\n", pcur->name);
2131
2132 /* Translate the essentials of the module definition file into wlink lingo. */
2133 if (def_fname)
2134 {
2135 _md_token token;
2136 struct _md *pMd = _md_open (def_fname);
2137 if (!pMd)
2138 {
2139 fprintf (stderr, "emxomfld: cannot open `%s'\n", def_fname);
2140 exit (2);
2141 }
2142 _md_next_token (pMd);
2143 _md_parse (pMd, def_2_watcom, NULL);
2144 _md_close (pMd);
2145 }
2146 }
2147
2148 /* End the arguments and run the linker. */
2149
2150 arg_end ();
2151
2152 rc = emxomfld_spawn (command_line, "Linker");
2153 if (rc == 4 && !strnicmp(linker_type, "VAC3", 4)) /* Ignore iLink warnings. */
2154 rc = 0;
2155 if (rc < 0)
2156 {
2157 perror (linker_name);
2158 exit (2);
2159 }
2160
2161 /* Run RC if Linker completed successfully and a binary resource
2162 file was given on the command line. */
2163
2164 if (rc == 0 && res_fname != NULL)
2165 {
2166 arg_init (TRUE);
2167 put_arg ("rc.exe", TRUE, FALSE);
2168 put_arg ("-n", FALSE, FALSE);
2169 put_arg (res_fname, TRUE, FALSE);
2170 put_arg (output_fname, TRUE, FALSE);
2171 arg_end ();
2172 rc = emxomfld_spawn (command_line, "Resource Linker");
2173 if (rc < 0)
2174 {
2175 perror ("emxomfld: rc");
2176 exit (2);
2177 }
2178 }
2179
2180 /* If both Linker and RC completed successfully and the -Zexe option
2181 was given, touch the output file (without .exe) to keep `make'
2182 happy. */
2183
2184 if (rc == 0 && exe_flag)
2185 {
2186 /* find target and source filenames. */
2187 t = xstrdup (output_fname);
2188 _remext (t);
2189 _execname(&execname[0], sizeof(execname));
2190 strcpy(_getname(&execname[0]), "ldstub.bin");
2191
2192 /* Copy stub into file */
2193 if (opt_t)
2194 fprintf(stderr, "*** copy %s to %s (-Zexe)", execname, t);
2195 DosCopy(&execname[0], t, 4);
2196
2197 /* Now touch it */
2198 if (utime(t, NULL))
2199 {
2200 perror ("emxomfld");
2201 exit (2);
2202 }
2203 free (t);
2204 }
2205
2206 /* Return the return code of Linker or RC. */
2207
2208 return rc;
2209}
Note: See TracBrowser for help on using the repository browser.