1 /*  Part of SWI-Prolog
2 
3     Author:        Jan Wielemaker
4     E-mail:        J.Wielemaker@vu.nl
5     WWW:           http://www.swi-prolog.org
6     Copyright (c)  2010-2019, University of Amsterdam
7                               VU University Amsterdam
8     All rights reserved.
9 
10     Redistribution and use in source and binary forms, with or without
11     modification, are permitted provided that the following conditions
12     are met:
13 
14     1. Redistributions of source code must retain the above copyright
15        notice, this list of conditions and the following disclaimer.
16 
17     2. Redistributions in binary form must reproduce the above copyright
18        notice, this list of conditions and the following disclaimer in
19        the documentation and/or other materials provided with the
20        distribution.
21 
22     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26     COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33     POSSIBILITY OF SUCH DAMAGE.
34 */
35 
36 /*
37   Preprocessor symbols that may be defined during the compilation
38   of this file:
39 
40   #ifdef __WINDOWS__
41     This file (swipl-ld.c) is being compiled by a Windows compiler
42     (either MSC or gcc/MinGW).  The resulting swipl-ld* executable
43     will thus run under Windows.
44   #endif
45 
46   #ifdef HOST_TOOLCHAIN_MSC
47     The generated swipl-ld* executable will use the Microsoft C/C++
48     compiler to produce shared objects and executables.
49   #endif
50 
51   #ifdef HOST_TOOLCHAIN_MINGW
52     The generated swipl-ld* executable will use the MinGW compilers
53     to produce shared objects and executables.
54   #endif
55 
56   #ifdef HOST_OS_WINDOWS
57     The generated swipl-ld* executable will produce shared objects
58     and executable that will run under Windows.
59   #endif
60  */
61 
62 #ifndef __WINDOWS__
63 #if defined(_MSC_VER) || defined(__MINGW32__)
64 #define __WINDOWS__ 1
65 #endif
66 #endif
67 
68 #define UNQUOTED_PREFIX "\1"
69 
70 #include "config.h"
71 #include "parms.h"
72 
73 #ifdef __WINDOWS__
74 #include <process.h>
75 #include <io.h>
76 
77 #ifdef _MSC_VER
78 #define HOST_TOOLCHAIN_MSC
79 
80 #define popen _popen
81 #define pclose _pclose
82 #pragma warning(disable : 4996)	/* deprecate open() etc */
83 
84 #if SIZEOF_VOIDP == 4
85 typedef long ssize_t;
86 #else
87 typedef long long ssize_t;
88 #endif
89 
90 #define O_WRONLY _O_WRONLY
91 #define O_RDONLY _O_RDONLY
92 #define O_CREAT _O_CREAT
93 #define O_TRUNC _O_TRUNC
94 #define O_BINARY _O_BINARY
95 #else  /*_MSC_VER*/
96 #define HOST_TOOLCHAIN_MINGW
97 #endif /*_MSC_VER*/
98 
99 #define HOST_OS_WINDOWS 1
100 #define DEF_PROG_PL "swipl.exe"
101 #define PROG_OUT "a.exe"
102 #else
103 #define DEF_PROG_PL "swipl"
104 #define PROG_OUT "a.out"
105 #endif
106 
107 #ifndef PROG_PL
108 #define PROG_PL DEF_PROG_PL
109 #endif
110 
111 #if defined(HOST_TOOLCHAIN_MSC)
112 
113 #define PROG_CC "cl.exe /MD"
114 #define PROG_CXX "cl.exe /MD /GX"
115 /* PROG_CPP is defined in config.h: we need to redefine it. */
116 #undef PROG_CPP
117 #define PROG_CPP "cl.exe -P"
118 
119 #define PROG_LD "link.exe"
120 /* SO_LD is defined in config.h: we need to redefine it. */
121 #undef SO_LD
122 #define SO_LD "link.exe"
123 
124 #define EXT_OBJ "obj"
125 
126 #define LIB_PL_DEBUG "swiplD.lib"
127 #define OPT_DEBUG "/DEBUG"
128 
129 #elif defined(HOST_TOOLCHAIN_MINGW)
130 
131 #define PROG_CC    "gcc.exe"
132 #define PROG_CXX   "g++.exe"
133 #define PROG_LD    PROG_CC
134 #define EXT_OBJ    "obj"
135 #define OPT_DEBUG  "-g"
136 #define SO_LDFLAGS "-shared"
137 #undef SO_LD
138 #define SO_LD	   PROG_LD
139 
140 #else /*Native*/
141 
142 #define PROG_CC C_CC
143 #ifdef C_CXX
144 #define PROG_CXX C_CXX
145 #else
146 #define PROG_CXX C_CC " -x c++"
147 #endif
148 /* PROG_CPP is defined in config.h */
149 
150 #define PROG_LD C_CC
151 
152 /* SO_LD is defined in config.h. */
153 #ifndef PROG_LD
154 #define PROG_LD C_CC
155 #endif
156 #ifndef SO_LD
157 #define SO_LD PROG_LD
158 #endif
159 
160 #define EXT_OBJ "o"
161 #define OPT_DEBUG "-g"
162 
163 #ifndef SO_LDFLAGS
164 #define SO_LDFLAGS "-shared"
165 #endif
166 
167 #ifndef SO_pic
168 #define SO_pic "-fPIC"
169 #endif
170 
171 #endif /*Toolchain selection*/
172 
173 
174 #include <stdio.h>
175 #include <stdlib.h>
176 #ifdef HAVE_MALLOC_H
177 #include <malloc.h>
178 #else
179 #ifdef HAVE_SYS_MALLOC_H
180 #include <sys/malloc.h>
181 #endif
182 #endif
183 #include <ctype.h>
184 #ifdef HAVE_UNISTD_H
185 #include <unistd.h>
186 #endif
187 #ifdef HAVE_SYS_TYPES_H
188 #include <sys/types.h>
189 #endif
190 #ifdef HAVE_SYS_STAT_H
191 #include <sys/stat.h>
192 #endif
193 #include <fcntl.h>
194 #include <errno.h>
195 #include <string.h>
196 #include <signal.h>
197 
198 #ifndef TRUE
199 #define TRUE 1
200 #define FALSE 0
201 #endif
202 
203 #ifndef O_BINARY
204 #define O_BINARY 0
205 #endif
206 
207 #ifndef MAXPATHLEN
208 #define MAXPATHLEN 1024
209 #endif
210 
211 #define CPBUFSIZE 8192
212 
213 #ifndef streq
214 #define streq(s, q)     (strcmp((s), (q)) == 0)
215 #endif
216 #define strprefix(s, p) (strncmp((s), (p), strlen(p)) == 0)
217 #if defined(__WINDOWS__)
218 #define strfeq(s, q)	(stricmp((s), (q)) == 0)
219 #else
220 #define strfeq(s, q)	streq(s, q)
221 #endif
222 #undef oserror				/* Irix name-clash */
223 #define oserror xoserror
224 #undef strdup
225 #define strdup plld_strdup
226 #undef strndup
227 #define strndup plld_strndup
228 #ifdef DMALLOC
229 #undef xmalloc
230 #undef xrealloc
231 #undef xfree
232 #endif
233 #define xmalloc plld_xmalloc
234 #define xrealloc plld_xrealloc
235 #define xfree plld_xfree
236 #define CTOI(c) ((c)&0xff)
237 
238 typedef struct
239 { char **list;
240   int  size;
241 } arglist;
242 
243 					/* prefix strings with ^A to signal */
244 					/* it must be passed unquoted */
245 #define UNQUOTED	UNQUOTED_PREFIX[0]
246 
247 
248 static arglist tmpfiles;		/* list of temporary files */
249 
250 static arglist ofiles;			/* object files */
251 static arglist cfiles;			/* C input files */
252 static arglist cppfiles;		/* C++ input files */
253 static arglist plfiles;			/* Prolog files */
254 static arglist qlfiles;			/* Prolog Quick Load Files */
255 
256 static arglist coptions;		/* CC options */
257 static arglist cppoptions;		/* C++ options */
258 static arglist ldoptions;		/* LD options */
259 static arglist ploptions;		/* PL options for saved state */
260 
261 static arglist libs;			/* (C) libraries */
262 static arglist lastlibs;		/* libs that must be at the end */
263 static arglist libdirs;			/* -L library directories */
264 static arglist includedirs;		/* -I include directories */
265 
266 static char *pllib;			/* -lswipl, swipl.lib, ... */
267 static char *pllibs = "";		/* Requirements to link to pllib */
268 static char *pllibdir;
269 
270 static char *pl;			/* Prolog executable */
271 static char *cc;			/* CC executable */
272 static char *cxx;			/* C++ executable */
273 static char *ld;			/* The Linker */
274 static char *plld;			/* Thats me! */
275 
276 static char *plbase;			/* Prolog home */
277 static char *plarch;			/* Prolog architecture id */
278 static char *plexe;			/* Path to the executable */
279 
280 static char *plgoal;			/* -g goal */
281 static char *pltoplevel;		/* -t goal */
282 static char *plinitfile;		/* -f file */
283 static char *plclass;			/* -class <class> */
284 static char *plsysinit;			/* -F file */
285 
286 static char *ctmp;			/* base executable */
287 static char *pltmp;			/* base saved state */
288 static char *out;			/* final output */
289 static int  opt_o=FALSE;		/* -o out given */
290 static int  opt_E=FALSE;		/* -E given */
291 
292 static int build_defaults = FALSE;	/* don't ask Prolog for parameters*/
293 
294 static int nostate = TRUE;		/* do not make a state */
295 static int nolink = FALSE;		/* do not link */
296 static int nolibswipl = FALSE;		/* do not link with -lswipl */
297 static int shared = FALSE;		/* -shared: make a shared-object/DLL */
298 static char *soext = SO_EXT;		/* extension of shared object */
299 static int embed_shared = FALSE;	/* -dll/-embed-shared: embed Prolog */
300 					/* in a DLL/.so file */
301 static int verbose = TRUE;		/* verbose operation */
302 static int fake = FALSE;		/* don't really do anything */
303 static int show_version = FALSE;	/* --version */
304 
305 static void	removeTempFiles();
306 static void	parseOptions(int argc, char **argv);
307 static void	linkSharedObject();
308 
309 		 /*******************************
310 		 *	       ERROR		*
311 		 *******************************/
312 
313 static char *
oserror()314 oserror()
315 {
316 #ifdef HAVE_STRERROR
317   return strerror(errno);
318 #else
319   extern int sys_nerr;
320   extern char *sys_errlist[];
321   extern int errno;
322 
323   if ( errno < sys_nerr )
324     return sys_errlist[errno];
325 
326   return "Unknown error";
327 #endif
328 }
329 
330 
331 static int
error(int status)332 error(int status)
333 { removeTempFiles();
334 
335   fprintf(stderr, "*** %s exit status %d\n", plld, status);
336 
337   exit(status);
338   return 1;				/* not reached */
339 }
340 
341 
342 static void
caught_signal(int sig)343 caught_signal(int sig)
344 { error(sig);
345 }
346 
347 
348 		 /*******************************
349 		 *	       MALLOC		*
350 		 *******************************/
351 
352 static void
xfree(void * mem)353 xfree(void *mem)
354 { if ( mem )
355     free(mem);
356 }
357 
358 
359 void *
xmalloc(size_t bytes)360 xmalloc(size_t bytes)
361 { void *mem;
362 
363   if ( !bytes )
364     return NULL;
365   if ( (mem = malloc(bytes)))
366     return mem;
367 
368   fprintf(stderr, "%s: not enough memory\n", plld);
369   error(1);
370   return NULL;
371 }
372 
373 
374 void *
xrealloc(void * old,size_t bytes)375 xrealloc(void *old, size_t bytes)
376 { void *mem;
377 
378   if ( !bytes )
379   { xfree(old);
380     return NULL;
381   }
382   if ( !old )
383   { if ( (mem = malloc(bytes)))
384       return mem;
385   } else
386   { if ( (mem = realloc(old, bytes)))
387       return mem;
388   }
389 
390   fprintf(stderr, "%s: not enough memory\n", plld);
391   error(1);
392   return NULL;
393 }
394 
395 
396 
397 		 /*******************************
398 		 *	TEXT MANIPULATION	*
399 		 *******************************/
400 
401 static char *
strdup(const char * in)402 strdup(const char *in)
403 { return strcpy(xmalloc(strlen(in)+1), in);
404 }
405 
406 
407 static char *
strndup(const char * in,size_t len)408 strndup(const char *in, size_t len)
409 { char *r = xmalloc(len+1);
410 
411   r[len] = '\0';
412 
413   return memcpy(r, in, len);
414 }
415 
416 
417 void
appendArgList(arglist * list,const char * arg)418 appendArgList(arglist *list, const char *arg)
419 { if ( arg[0] )
420   { if ( list->size == 0 )
421     { list->list = xmalloc(sizeof(char*) * (list->size+2));
422     } else
423     { list->list = xrealloc(list->list, sizeof(char*) * (list->size+2));
424     }
425 
426     list->list[list->size++] = strdup(arg);
427     list->list[list->size]   = NULL;
428   }
429 }
430 
431 
432 void
prependArgList(arglist * list,const char * arg)433 prependArgList(arglist *list, const char *arg)
434 { int n;
435 
436   if ( list->size == 0 )
437   { list->list = xmalloc(sizeof(char*) * (list->size+2));
438   } else
439   { list->list = xrealloc(list->list, sizeof(char*) * (list->size+2));
440   }
441   for(n=++list->size; n>0; n--)
442     list->list[n] = list->list[n-1];
443 
444   list->list[0] = strdup(arg);
445 }
446 
447 
448 void
concatArgList(arglist * to,const char * prefix,arglist * from)449 concatArgList(arglist *to, const char *prefix, arglist *from)
450 { int n;
451 
452   for(n=0; n<from->size; n++)
453   { char buf[1024];
454 
455     buf[0] = UNQUOTED;
456     if ( strchr(from->list[n], ' ') )
457       sprintf(buf+1, "%s\"%s\"", prefix, from->list[n]);
458     else
459       sprintf(buf+1, "%s%s", prefix, from->list[n]);
460     appendArgList(to, buf);
461   }
462 }
463 
464 
465 static int
breakargs(const char * line,char ** argv)466 breakargs(const char *line, char **argv)
467 { int argc = 0;
468 
469   while(*line)
470   { while(*line && isspace(CTOI(*line)))
471       line++;
472 
473     if ( *line == '"' )			/* Windows-95 quoted arguments */
474     { const char *start = line+1;
475       const char *end = start;
476 
477       while( *end && *end != '"' )
478 	end++;
479       if ( *end == '"' )
480       { argv[argc++] = strndup(start, end-start);
481 	line = end+1;
482 	continue;
483       }
484     }
485 
486     if ( *line )
487     { const char *start = line;
488 
489       while(*line && !isspace(CTOI(*line)))
490 	line++;
491       argv[argc++] = strndup(start, line-start);
492     }
493   }
494   argv[argc] = NULL;			/* add trailing NULL pointer to argv */
495 
496   return argc;
497 }
498 
499 
500 
501 void
addOptionString(const char * s)502 addOptionString(const char *s)
503 { char *argv[256];
504   int argc = breakargs(s, argv);
505 
506   parseOptions(argc, argv);
507 }
508 
509 
510 void
appendOptions(arglist * args,const char * from)511 appendOptions(arglist *args, const char *from)
512 { int sep = *from++;
513   const char *f;
514   char tmp[1024];
515 
516   while(*from)
517   { f = from;
518     while(*from && *from != sep)
519       from++;
520     if ( from > f )
521     { strncpy(tmp, f, from-f);
522       tmp[from-f] = '\0';
523       appendArgList(args, tmp);
524     }
525     if ( *from == sep )
526       from++;
527   }
528 }
529 
530 
531 void
ensureOption(arglist * args,const char * opt)532 ensureOption(arglist *args, const char *opt)
533 { int n;
534 
535   for(n=0; n<args->size; n++)
536   { if ( streq(args->list[n], opt) )
537       return;
538   }
539 
540   appendArgList(args, opt);
541 }
542 
543 
544 arglist *
copyArgList(arglist * in)545 copyArgList(arglist *in)
546 { arglist *out = xmalloc(sizeof(arglist));
547   int n;
548 
549   out->size = in->size;
550   out->list = xmalloc(sizeof(char *) * (in->size + 1));
551   for(n=0; n<in->size; n++)
552     out->list[n] = strdup(in->list[n]);
553   out->list[n] = NULL;
554 
555   return out;
556 }
557 
558 void
freeArgList(arglist * l)559 freeArgList(arglist *l)
560 { int n;
561 
562   for(n=0; n<l->size; n++)
563     xfree(l->list[n]);
564 
565   xfree(l);
566 }
567 
568 
569 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
570 If the filename has an extension, replace it, otherwise add the given
571 extension.
572 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
573 
574 char *
replaceExtension(const char * base,const char * ext,char * buf)575 replaceExtension(const char *base, const char *ext, char *buf)
576 { char *e = NULL, *q = buf;
577   const char *s = base;
578 
579   for( ; *s; s++, q++ )
580   { *q = *s;
581     if ( *q == '.' )
582       e = q;
583     else if ( *q == '/' || *q == '\\' )
584       e = NULL;
585   }
586   *q = '\0';
587 
588   if ( e )
589   { e++;
590   } else
591   { e = q;				/* q points at '\0' */
592     *e++ = '.';
593   }
594 
595   strcpy(e, ext);
596 
597   return buf;
598 }
599 
600 
601 
602 		 /*******************************
603 		 *	   OPTION DEFS		*
604 		 *******************************/
605 
606 typedef struct
607 { char *extension;
608   arglist*list;
609 } extdef;
610 
611 static extdef extdefs[] =
612 { { EXT_OBJ,	&ofiles },
613 #if defined(HOST_TOOLCHAIN_MSC)
614   { "lib",	&libs },
615 #else
616   { "a",	&libs },
617 #endif
618   { "c",	&cfiles },
619   { "cpp",	&cppfiles },
620   { "cxx",	&cppfiles },
621   { "cc",	&cppfiles },
622 #ifndef __WINDOWS__
623   { "C",	&cppfiles },
624 #endif
625   { "pl",	&plfiles },
626   { "qlf",	&qlfiles },
627   { NULL,	NULL }
628 };
629 
630 const char *
file_name_extension(const char * in)631 file_name_extension(const char *in)
632 { const char *ext = NULL;
633 
634   for( ; *in; in++)
635   { if ( *in == '.' )
636       ext = in+1;
637     else if ( *in == '/' || *in == '\\' )
638       ext = NULL;
639   }
640 
641   return ext;
642 }
643 
644 
645 int
dispatchFile(const char * name)646 dispatchFile(const char *name)
647 { const char *ext;
648 
649   if ( (ext = file_name_extension(name)) )
650   { extdef *d = extdefs;
651 
652     for( ; d->extension; d++ )
653     { if ( strfeq(d->extension, ext) )
654       { if ( d->list == &plfiles || d->list == &qlfiles )
655 	  nostate = FALSE;
656 	appendArgList(d->list, name);
657 	return TRUE;
658       }
659     }
660     if ( soext && strfeq(soext, ext) )
661     { if ( d->list == &plfiles || d->list == &qlfiles )
662 	nostate = FALSE;
663       appendArgList(&libs, name);
664       return TRUE;
665     }
666   }
667 
668   return FALSE;
669 }
670 
671 
672 		 /*******************************
673 		 *	  OPTION PARSING	*
674 		 *******************************/
675 
676 static void
usage()677 usage()
678 { fprintf(stderr,
679 	  "SWI-Prolog linker utility\n"
680 	  "swipl-ld comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
681 	  "and you are welcome to redistribute it under certain conditions.\n"
682 	  "Please visit http://www.swi-prolog.org for details.\n\n"
683 	  "usage: %s -help\n"
684 	  "       %s [options] inputfile ...\n"
685 	  "       %s -shared -o out inputfile ...\n"
686 #if defined(HOST_OS_WINDOWS)
687 	  "       %s -dll -o out inputfile ...\n"
688 #endif
689 	  "\n"
690 	  "options:\n"
691 	  "       -o out           define output file\n"
692 	  "\n"
693 	  "       -v               verbose\n"
694 	  "       -f               fake (do not run any commands)\n"
695 	  "       -g               Compile/link for debugging\n"
696 	  "       --version        for GCC: run gcc --version\n"
697 	  "\n"
698 	  "       -pl prolog       Prolog to use\n"
699 	  "       -ld linker       link editor to use\n"
700           "       -cc compiler     compiler for C source files\n"
701 	  "       -c++ compiler    compiler for C++ source files\n"
702 	  "\n"
703 	  "       -c               only compile C/C++ files, do not link\n"
704 	  "       -S               emit assembler, do not link\n"
705 	  "       -E               only run preprocessor, do not link\n"
706           "       -build-defaults  use default parameters, don't ask Prolog\n"
707 	  "       -nostate         just relink the kernel\n"
708 	  "       -state           add a Prolog saved state\n"
709 	  "       -nolibswipl      do not link with -lswipl\n"
710 	  "       -shared          create target for load_foreign_library/2\n"
711 	  "       -embed-shared    embed Prolog in a shared object/DLL\n"
712 #if defined(HOST_OS_WINDOWS)
713 	  "       -dll             synonym for -embed-shared\n"
714 #endif
715 	  "       -fpic            compile small position-independent code\n"
716 	  "       -fPIC            compile large position-independent code\n"
717 	  "\n"
718 	  "       -pl-options,...  Add options for Prolog\n"
719 	  "       -ld-options,...  Add options for linker\n"
720 	  "       -cc-options,...  Add options for C/C++-compiler\n"
721 	  "       -F base          Load	swi(base.rc)"
722 	  "\n"
723 	  "       -goal goal       (Prolog) entry point\n"
724 	  "       -toplevel goal   (Prolog) abort toplevel goal\n"
725 	  "       -initfile file   (Prolog) profile file to load\n"
726 	  "       -class class     {runtime,kernel,development}\n"
727 	  "\n"
728 	  "       -O*              Optimization passed to compiler\n"
729 	  "       -Wl,*            Options passed to linker\n"
730 	  "       -W*              Warning options passed to compiler\n"
731 	  "\n"
732 	  "       -Dmacro          Define macro (C/C++)\n"
733 	  "       -Umacro          Undefine macro (C/C++)\n"
734 	  "       -Iincludedir     Include directory (C/C++)\n"
735 	  "       -Llibdir         Library directory (C/C++ link)\n"
736 	  "       -llib            library (C/C++)\n",
737 	plld,
738         plld,
739 #if defined(HOST_OS_WINDOWS)
740         plld,
741 #endif
742         plld);
743 
744   exit(1);
745 }
746 
747 
748 static void
parseOptions(int argc,char ** argv)749 parseOptions(int argc, char **argv)
750 { for( ; argc > 0; argc--, argv++ )
751   { char *opt = argv[0];
752 
753     if ( dispatchFile(opt) )
754       continue;
755 
756     if ( streq(opt, "-help") )			/* -help */
757     { usage();
758     } else if ( streq(opt, "-v") )		/* -v */
759     { verbose++;
760     } else if ( streq(opt, "--version") )	/* --version */
761     { appendArgList(&coptions, opt);
762       appendArgList(&cppoptions, opt);
763       show_version = TRUE;
764     } else if ( streq(opt, "-f") )		/* -f */
765     { fake++;
766     } else if ( streq(opt, "-c") )		/* -c */
767     { nolink++;
768     } else if ( streq(opt, "-S") )		/* -S */
769     { nolink++;
770       appendArgList(&coptions, opt);
771       appendArgList(&cppoptions, opt);
772     } else if ( streq(opt, "-E") )		/* -E */
773     { nolink++;
774       opt_E = TRUE;
775       appendArgList(&coptions, opt);
776       appendArgList(&cppoptions, opt);
777     } else if ( streq(opt, "-g") )		/* -g */
778     { appendArgList(&coptions, OPT_DEBUG);
779       appendArgList(&cppoptions, OPT_DEBUG);
780 #if defined(HOST_TOOLCHAIN_MSC)			/* MSVC DEBUG OPTIONS */
781       appendArgList(&coptions, "/ZI");
782       appendArgList(&coptions, "/Od");
783       appendArgList(&cppoptions, "/ZI");
784       appendArgList(&cppoptions, "/Od");
785 #endif
786       appendArgList(&ldoptions, OPT_DEBUG);
787 #ifdef LIB_PL_DEBUG
788       pllib = LIB_PL_DEBUG;
789 #endif
790     } else if ( strprefix(opt, "-pg") )		/* -pg* */
791     { appendArgList(&coptions, opt);
792       appendArgList(&cppoptions, opt);
793     } else if ( streq(opt, "-g3") )		/* -g3 */
794     { appendArgList(&coptions, opt);
795       appendArgList(&cppoptions, opt);
796     } else if ( strprefix(opt, "gdwarf-") )	/* -gdwarf-* */
797     { appendArgList(&coptions, opt);
798       appendArgList(&cppoptions, opt);
799     } else if ( strprefix(opt, "-O") )		/* -O* */
800     { appendArgList(&coptions, opt);
801       appendArgList(&cppoptions, opt);
802     } else if ( strprefix(opt, "-Wl,") )	/* -Wl,* */
803     { appendArgList(&ldoptions, opt);
804     } else if ( strprefix(opt, "-W") )		/* -W* */
805     { appendArgList(&coptions, opt);
806       appendArgList(&cppoptions, opt);
807     } else if ( streq(opt, "-build-defaults") )	/* -build-defaults */
808     { build_defaults = TRUE;
809     } else if ( streq(opt, "-nostate") )	/* -nostate */
810     { nostate = TRUE;
811     } else if ( streq(opt, "-state") )		/* -state */
812     { nostate = FALSE;
813     } else if ( streq(opt, "-nolibswipl") )	/* -nolibswipl */
814     { nolibswipl = TRUE;
815     } else if ( streq(opt, "-dll") ||		/* -dll */
816 		streq(opt, "-embed-shared") )   /* -embed-shared */
817     { embed_shared = TRUE;
818 #if defined(HOST_TOOLCHAIN_MSC)
819       appendArgList(&ldoptions, "/DLL");
820 #else
821 #ifdef SO_pic
822       appendArgList(&coptions, SO_pic);
823       appendArgList(&cppoptions, SO_pic);
824 #endif
825 #endif
826     } else if ( streq(opt, "-shared") )		/* -shared */
827     { shared = TRUE;
828       nostate = TRUE;
829 #ifdef SO_pic
830       appendArgList(&coptions, SO_pic);
831       appendArgList(&cppoptions, SO_pic);
832 #endif
833     } else if ( streq(opt, "-SHARED") )		/* -SHARED */
834     { shared = TRUE;
835       nostate = TRUE;
836 #ifdef SO_PIC
837       appendArgList(&coptions, SO_PIC);
838       appendArgList(&cppoptions, SO_PIC);
839 #else
840 #ifdef SO_pic
841       appendArgList(&coptions, SO_pic);
842       appendArgList(&cppoptions, SO_pic);
843 #endif
844 #endif
845     } else if ( streq(opt, "-fpic") )		/* -fpic */
846     {
847 #ifdef SO_pic
848       appendArgList(&coptions, SO_pic);
849       appendArgList(&cppoptions, SO_pic);
850 #endif
851     } else if ( streq(opt, "-fPIC") )		/* -fPIC */
852     {
853 #ifdef SO_PIC
854       appendArgList(&coptions, SO_PIC);
855       appendArgList(&cppoptions, SO_PIC);
856 #endif
857     } else if ( streq(opt, "-o") )		/* -o out */
858     { if ( argc > 1 )
859       { out = argv[1];
860 	opt_o = TRUE;
861 	argc--, argv++;
862       } else
863 	usage();
864     } else if ( streq(opt, "-goal") )		/* -goal goal */
865     { if ( argc > 1 )
866       { plgoal = argv[1];
867 	argc--, argv++;
868       } else
869 	usage();
870     } else if ( streq(opt, "-toplevel") )	/* -toplevel goal */
871     { if ( argc > 1 )
872       { pltoplevel = argv[1];
873 	argc--, argv++;
874       } else
875 	usage();
876     } else if ( streq(opt, "-initfile") )	/* -initfile goal */
877     { if ( argc > 1 )
878       { plinitfile = argv[1];
879 	argc--, argv++;
880       } else
881 	usage();
882     } else if ( streq(opt, "-F") )		/* -F base */
883     { if ( argc > 1 )
884       { plsysinit = argv[1];
885 	argc--, argv++;
886       } else
887 	usage();
888     } else if ( streq(opt, "-class") )		/* -class runtime,kernel,
889 							  development */
890     { if ( argc > 1 )
891       { plclass = argv[1];
892 	if ( !streq(plclass, "runtime") &&
893 	     !streq(plclass, "kernel") &&
894 	     !streq(plclass, "development")
895 	   )
896 	  usage();
897 	argc--, argv++;
898       } else
899 	usage();
900     } else if ( streq(opt, "-pl") )		/* -pl prolog */
901     { if ( argc > 1 )
902       { pl = argv[1];
903 	argc--, argv++;
904       } else
905 	usage();
906     } else if ( streq(opt, "-cc") )		/* -cc compiler */
907     { if ( argc > 1 )
908       { cc = argv[1];
909 	argc--, argv++;
910       } else
911 	usage();
912     } else if ( streq(opt, "-c++") )		/* -c++ compiler */
913     { if ( argc > 1 )
914       { cxx = argv[1];
915 	argc--, argv++;
916       } else
917 	usage();
918     } else if ( streq(opt, "-ld") )		/* -ld linker */
919     { if ( argc > 1 )
920       { ld = argv[1];
921 	argc--, argv++;
922       } else
923 	usage();
924     } else if ( strprefix(opt, "-cc-options") )
925     { appendOptions(&coptions, opt+strlen("-cc-options"));
926       appendOptions(&cppoptions, opt+strlen("-cc-options"));
927     } else if ( strprefix(opt, "-ld-options") )
928     { appendOptions(&ldoptions, opt+strlen("-ld-options"));
929     } else if ( strprefix(opt, "-pl-options") )
930     { appendOptions(&ploptions, opt+strlen("-pl-options"));
931     } else if ( strprefix(opt, "-I") )		/* -I<include> */
932     { appendArgList(&includedirs, &opt[2]);
933     } else if ( strprefix(opt, "-D") )		/* -D<def> */
934     { appendArgList(&coptions, opt);
935       appendArgList(&cppoptions, opt);
936     } else if ( strprefix(opt, "-U") )		/* -U<def> */
937     { appendArgList(&coptions, opt);
938       appendArgList(&cppoptions, opt);
939     } else if ( strprefix(opt, "-L") )		/* -L<libdir> */
940     { appendArgList(&libdirs, &opt[2]);
941     } else if ( streq(opt, "-lccmalloc") )	/* -lccmalloc */
942     { appendArgList(&lastlibs, opt);
943     } else if ( strprefix(opt, "-l") )		/* -l<lib> */
944     { appendArgList(&libs, opt);
945     }
946   }
947 }
948 
949 
950 static void
defaultProgram(char ** store,char * def)951 defaultProgram(char **store, char *def)
952 { if ( !*store )
953     *store = strdup(def);
954 }
955 
956 
957 static void
defaultPath(char ** store,char * def)958 defaultPath(char **store, char *def)
959 { if ( !*store )
960   { char *s, *e;
961 
962     s = strdup(def);
963     e = s + strlen(s);
964     while(e>s+1 && e[-1] == '/')	/* strip terminating /'s */
965       e--;
966     *e = '\0';
967 
968     *store = s;
969   }
970 }
971 
972 
973 static void
tmpPath(char ** store,const char * base)974 tmpPath(char **store, const char *base)
975 { if ( !*store )
976   { char tmp[MAXPATHLEN];
977 
978     sprintf(tmp, "%s%d", base, (int)getpid());
979     *store = strdup(tmp);
980   }
981 }
982 
983 
984 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
985 Setup the -L option as well as the runpath for the target executable.
986 FIXME: Can we get how to do this from cmake?
987 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
988 
989 static void
setLibDir(const char * libdir)990 setLibDir(const char *libdir)
991 { pllibdir = strdup(libdir);
992   appendArgList(&libdirs, libdir);
993 
994 #ifndef __WINDOWS__
995   char tmp[MAXPATHLEN+16];
996 #ifdef __APPLE__
997   snprintf(tmp, sizeof(tmp), "-Wl,-rpath,%s", libdir);
998 #else
999   snprintf(tmp, sizeof(tmp), "-Wl,-rpath=%s", libdir);
1000 #endif
1001   appendArgList(&ldoptions, tmp);
1002 #endif
1003 }
1004 
1005 
1006 static void
fillDefaultOptions()1007 fillDefaultOptions()
1008 { char tmp[1024];
1009   char *defcxx = PROG_CXX;
1010 
1011   defaultProgram(&cc,  PROG_CC);
1012   if ( streq(cc, "gcc") )			/* TBD: MINGW */
1013     defcxx = "g++";
1014   defaultProgram(&cxx, defcxx);
1015 
1016   if ( !ld )				/* not specified */
1017   { ld = (shared ? SO_LD : PROG_LD);
1018 
1019     if ( cppfiles.size > 0 && streq(ld, cc) )
1020       ld = cxx;
1021   }
1022 
1023 #if defined(HOST_TOOLCHAIN_MSC)
1024   if ( strcmp(LIB_PL_DEBUG,pllib) == 0 )
1025     ensureOption(&coptions, "/MDd");
1026   else ensureOption(&coptions, "/MD");
1027   ensureOption(&coptions, "/D__WINDOWS__");
1028   ensureOption(&coptions, "/nologo");
1029   ensureOption(&ldoptions, "/nologo");
1030 #endif
1031 
1032   tmpPath(&ctmp,   "ctmp-");
1033   tmpPath(&pltmp,  "pltmp-");
1034 #if defined(__CYGWIN__)
1035 /* Compile generates .exe files on Cygwin */
1036   replaceExtension(ctmp, "exe", tmp);
1037   free(ctmp);
1038   ctmp = strdup(tmp);
1039 #endif
1040 #if defined(HOST_OS_WINDOWS)
1041 /* Saved states have the .exe extension under Windows */
1042   replaceExtension(pltmp, "exe", tmp);
1043   free(pltmp);
1044   pltmp = strdup(tmp);
1045 #endif
1046   if ( shared && !out && !nolink )
1047   { fprintf(stderr, "%s: \"-o out\" required for linking shared object\n", plld);
1048     exit(1);
1049   }
1050 #if defined(HOST_OS_WINDOWS)
1051   if ( out && !nolink )
1052   { replaceExtension(out, shared || embed_shared ? "dll" : "exe", tmp);
1053     out = strdup(tmp);
1054   }
1055 #endif
1056   defaultPath(&out, PROG_OUT);
1057 
1058   defaultProgram(&plgoal,     "version");
1059   defaultProgram(&pltoplevel, "prolog");
1060   defaultProgram(&plinitfile, "none");
1061   defaultProgram(&plsysinit,  "none");
1062 
1063   if ( !pllibdir )
1064   {
1065 #ifdef __WINDOWS__
1066     sprintf(tmp, "%s/lib", plbase);
1067 #else
1068     sprintf(tmp, "%s/lib/%s", plbase, plarch);
1069 #endif
1070     prependArgList(&libdirs, tmp);
1071   }
1072   sprintf(tmp, "%s/include", plbase);
1073   prependArgList(&includedirs, tmp);
1074 }
1075 
1076 		 /*******************************
1077 		 *	   PROLOG OPTIONS	*
1078 		 *******************************/
1079 static void
getPrologOptions()1080 getPrologOptions()
1081 { FILE *fd;
1082   char cmd[512];
1083 
1084   sprintf(cmd, "%s --dump-runtime-variables", pl);
1085   if ( verbose )
1086     printf("\teval `%s`\n", cmd);
1087 
1088   if ( (fd = popen(cmd, "r")) )
1089   { char buf[1024];
1090 
1091     while( fgets(buf, sizeof(buf), fd) )
1092     { char name[100];
1093       char value[1024];
1094       char *v;
1095 
1096       if ( sscanf(buf, "%[^=]=%[^;\n]", name, value) == 2 )
1097       { v = value;
1098 	if ( *v == '"' )
1099 	{ char *e = ++v;
1100 
1101 	  while(*e && *e != '"')
1102 	    e++;
1103 	  while(e>v && isspace(CTOI(e[-1])))
1104 	    e--;
1105 	  *e = '\0';
1106 	}
1107 	if ( streq(name, "CC") )
1108 	  defaultProgram(&cc, v);
1109 	else if ( streq(name, "PLBASE") )
1110 	  defaultPath(&plbase, v);
1111 	else if ( streq(name, "PLARCH") )
1112 	  defaultPath(&plarch, v);
1113 	else if ( streq(name, "PLLIBS") )	/* Always required. */
1114 	  pllibs = strdup(v);
1115 	else if ( streq(name, "PLLIBDIR") )
1116 	  setLibDir(v);
1117 	else if ( streq(name, "PLLIB") )
1118 	  defaultProgram(&pllib, v);
1119 	else if ( streq(name, "PLLDFLAGS") )
1120 	  appendArgList(&ldoptions, v);
1121 	else if ( streq(name, "PLCFLAGS") )
1122 	{ appendArgList(&coptions, v);
1123 	  appendArgList(&cppoptions, v);
1124 	}
1125 	else if ( streq(name, "PLSOEXT") )
1126 	  soext = strdup(v);
1127 	else if ( streq(name, "PLTHREADS") && streq(v, "yes") )
1128 	{ ensureOption(&coptions, "-D_REENTRANT");
1129 	  ensureOption(&cppoptions, "-D_REENTRANT");
1130 #ifdef _THREAD_SAFE			/* FreeBSD */
1131           ensureOption(&coptions, "-D_THREAD_SAFE");
1132 	  ensureOption(&cppoptions, "-D_THREAD_SAFE");
1133 #endif
1134 	} else
1135 	  continue;
1136 
1137 	if ( verbose )
1138 	  fprintf(stderr, "\t\t%s=\"%s\"\n", name, v);
1139       }	else
1140       { fprintf(stderr, "Unparsed Prolog option: %s\n", buf);
1141       }
1142     }
1143 
1144     pclose(fd);
1145 
1146 #if defined(__WINDOWS__) && defined(HOST_OS_WINDOWS)
1147     sprintf(buf, "%s/bin/%s", plbase, PROG_PL);
1148 #else
1149     sprintf(buf, "%s/bin/%s/%s", plbase, plarch, PROG_PL);
1150 #endif
1151     defaultPath(&plexe, buf);
1152   } else
1153   { fprintf(stderr, "%s: failed to run %s: %s", plld, cmd, oserror());
1154     error(1);
1155   }
1156 }
1157 
1158 		 /*******************************
1159 		 *	     CALLING		*
1160 		 *******************************/
1161 
1162 char *
shell_quote(char * to,const char * arg)1163 shell_quote(char *to, const char *arg)
1164 { static const char needq[] = "#!|<>*?$'\"";
1165   const char *s;
1166   int needquote = FALSE;
1167 
1168   if ( arg[0] == UNQUOTED )
1169   { arg++;				/* skip the not-quote marker */
1170   } else
1171   { for(s=arg; *s; s++)
1172     { if ( strchr(needq, *s) )
1173       { needquote = TRUE;
1174 	break;
1175       }
1176     }
1177   }
1178 
1179   if ( needquote )
1180   { *to++ = '"';
1181     for(s=arg; *s; s++)
1182     { if ( *s == '"'
1183 #ifdef HOST_OS_WINDOWS			/* $ is no special in Windows shell */
1184 	   || *s == '$'			/* and % needs to appear around the var */
1185 #endif
1186 	 )
1187 	*to++ = '\\';
1188       *to++ = *s;
1189     }
1190     *to++ = '"';
1191     *to = '\0';
1192 
1193     return to;
1194   }
1195 
1196   strcpy(to, arg);
1197 
1198   return to+strlen(to);
1199 }
1200 
1201 
1202 
1203 static void
callprog(const char * ld,arglist * args)1204 callprog(const char *ld, arglist *args)
1205 { char cmd[10240];
1206   char *e = cmd;
1207   int n, status;
1208 
1209   strcpy(e, ld);
1210   e = &e[strlen(e)];
1211   for(n=0; n<args->size; n++)
1212   { *e++ = ' ';
1213     e = shell_quote(e, args->list[n]);
1214   }
1215 
1216   if ( verbose )
1217     printf("\t%s\n", cmd);
1218 
1219   if ( !fake )
1220   { if ( (status=system(cmd)) != 0 )
1221     { fprintf(stderr, "%s returned code %d\n", ld, status);
1222       error(1);
1223     }
1224   }
1225 }
1226 
1227 
1228 		 /*******************************
1229 		 *	    PROCESSING		*
1230 		 *******************************/
1231 
1232 static void
compileFile(const char * compiler,arglist * options,const char * cfile)1233 compileFile(const char *compiler, arglist *options, const char *cfile)
1234 { char ofile[MAXPATHLEN];
1235   char *ext;
1236   arglist *args = copyArgList(options);
1237 
1238   if ( opt_o && nolink )
1239   { strcpy(ofile, out);
1240   } else
1241   { strcpy(ofile, cfile);
1242     if ( (ext = (char *)file_name_extension(ofile)) )
1243       strcpy(ext, EXT_OBJ);
1244   }
1245 
1246   if ( !opt_E )
1247     prependArgList(args, "-c");
1248 #if defined(HOST_OS_WINDOWS)
1249   appendArgList(args, "-D__WINDOWS__");
1250   appendArgList(args, "-D_WINDOWS");
1251 #endif
1252   appendArgList(args, "-D__SWI_PROLOG__");
1253   if ( !shared )
1254     appendArgList(args, "-D__SWI_EMBEDDED__");
1255   concatArgList(args, "-I", &includedirs);
1256 
1257   if ( opt_o || !opt_E )
1258   { appendArgList(args, "-o");
1259     appendArgList(args, ofile);
1260   }
1261   appendArgList(args, cfile);
1262 
1263   callprog(compiler, args);
1264   appendArgList(&ofiles, ofile);
1265   if ( !nolink )
1266     appendArgList(&tmpfiles, ofile);
1267   freeArgList(args);
1268 }
1269 
1270 
1271 void
compileObjectFiles()1272 compileObjectFiles()
1273 { int n;
1274 
1275   for(n=0; n<cfiles.size; n++)
1276     compileFile(cc, &coptions, cfiles.list[n]);
1277   for(n=0; n<cppfiles.size; n++)
1278     compileFile(cxx, &cppoptions, cppfiles.list[n]);
1279 }
1280 
1281 #if defined(HOST_TOOLCHAIN_MSC)
1282 char *
os_path(char * out,const char * in)1283 os_path(char *out, const char *in)
1284 { for(; *in; in++)
1285   { if ( *in == '/' )
1286       *out++ = '\\';
1287     else
1288       *out++ = *in;
1289   }
1290   *out = '\0';
1291 
1292   return out;
1293 }
1294 
1295 void
exportlibdirs()1296 exportlibdirs()
1297 { char tmp[10240];
1298   char *s, *e;
1299   int n;
1300 
1301   strcpy(tmp, "LIB=");
1302   e = tmp + strlen(tmp);
1303 
1304   for(n=0; n<libdirs.size; n++)
1305   { e = os_path(e, libdirs.list[n]);
1306     *e++ = ';';
1307   }
1308   if ( (s = getenv("LIB")) )
1309     strcpy(e, s);
1310 
1311   if ( verbose )
1312     printf("\t%s\n", tmp);
1313 
1314   putenv(strdup(tmp));
1315 }
1316 #endif
1317 
1318 void
linkBaseExecutable()1319 linkBaseExecutable()
1320 { char *cout = out;
1321 
1322 #if !defined(HOST_OS_WINDOWS)			/* bit of a hack ... */
1323   if ( embed_shared )
1324   { linkSharedObject();
1325     return;
1326   }
1327 #endif
1328 
1329 #if defined(HOST_TOOLCHAIN_MSC)
1330 { char tmp[MAXPATHLEN];
1331   sprintf(tmp, "/out:%s", cout);
1332   prependArgList(&ldoptions, tmp);
1333 }
1334   concatArgList(&ldoptions, "", &ofiles);	/* object files */
1335   exportlibdirs();
1336   if ( !nolibswipl )
1337   { appendArgList(&ldoptions, pllib);		/* -lswipl */
1338     addOptionString(pllibs);
1339   }
1340   concatArgList(&ldoptions, "", &libs);		/* libraries */
1341   concatArgList(&ldoptions, "", &lastlibs);	/* libraries */
1342 #else /* !defined(HOST_TOOLCHAIN_MSC) */
1343   prependArgList(&ldoptions, cout);
1344   prependArgList(&ldoptions, "-o");		/* -o ctmp */
1345   concatArgList(&ldoptions, "", &ofiles);	/* object files */
1346   concatArgList(&ldoptions, "-L", &libdirs);    /* library directories */
1347   if ( !nolibswipl )
1348   { appendArgList(&ldoptions, pllib);		/* -lswipl */
1349     addOptionString(pllibs);
1350   }
1351   concatArgList(&ldoptions, "", &libs);		/* libraries */
1352   concatArgList(&ldoptions, "", &lastlibs);	/* libraries */
1353 #endif /* !defined(HOST_TOOLCHAIN_MSC) */
1354 
1355   if ( !nostate )
1356   {
1357 #if defined(HOST_TOOLCHAIN_MSC)
1358     if ( !embed_shared )
1359     { char buf[MAXPATHLEN];
1360       appendArgList(&tmpfiles, replaceExtension(cout, "exp", buf));
1361       appendArgList(&tmpfiles, replaceExtension(cout, "lib", buf));
1362     }
1363 #endif
1364   }
1365 
1366   callprog(ld, &ldoptions);
1367 }
1368 
1369 
1370 void
linkSharedObject()1371 linkSharedObject()
1372 { char soname[MAXPATHLEN];
1373   char *soout;
1374 
1375   if ( !soext )
1376     soext = SO_EXT;
1377 
1378   if ( file_name_extension(out) )
1379   { soout = out;
1380   } else
1381   { soout = replaceExtension(out, soext, soname);
1382   }
1383 
1384 #if defined(HOST_TOOLCHAIN_MSC)
1385   prependArgList(&ldoptions, "/dll");
1386 { char tmp[MAXPATHLEN];
1387   sprintf(tmp, "/out:%s", soout);
1388   prependArgList(&ldoptions, tmp);
1389 }
1390   concatArgList(&ldoptions, "", &ofiles);	/* object files */
1391   exportlibdirs();
1392   if ( !nolibswipl )
1393   { appendArgList(&ldoptions, pllib);		/* swipl.lib */
1394     addOptionString(pllibs);
1395   }
1396   concatArgList(&ldoptions, "", &libs);		/* libraries */
1397   concatArgList(&ldoptions, "", &lastlibs);	/* libraries */
1398 #else /* !defined(HOST_TOOLCHAIN_MSC) */
1399 #ifdef __CYGWIN__
1400   prependArgList(&ldoptions, SO_LDFLAGS);
1401   prependArgList(&ldoptions, soout);
1402   prependArgList(&ldoptions, "-o");		/* -o ctmp */
1403   concatArgList(&ldoptions, "", &ofiles);	/* object files */
1404   if ( !nolibswipl )
1405   { appendArgList(&ldoptions, pllib);		/* -lswipl */
1406     addOptionString(pllibs);
1407   }
1408   concatArgList(&ldoptions, "-L", &libdirs);    /* library directories */
1409   concatArgList(&ldoptions, "", &libs);		/* libraries */
1410   concatArgList(&ldoptions, "", &lastlibs);	/* libraries */
1411 #else /*__CYGWIN__*/
1412 #ifdef SO_FORMAT_LDFLAGS			/* must specify output too */
1413   { char tmp[MAXPATHLEN];
1414     tmp[0] = UNQUOTED;
1415     sprintf(&tmp[1], SO_FORMAT_LDFLAGS);
1416     prependArgList(&ldoptions, tmp);
1417   }
1418 #else
1419   prependArgList(&ldoptions, SO_LDFLAGS);
1420   prependArgList(&ldoptions, soout);
1421   prependArgList(&ldoptions, "-o");		/* -o ctmp */
1422 #endif /*SO_FORMAT_LDFLAGS*/
1423   concatArgList(&ldoptions, "", &ofiles);	/* object files */
1424   concatArgList(&ldoptions, "-L", &libdirs);    /* library directories */
1425   concatArgList(&ldoptions, "", &libs);		/* libraries */
1426 #ifdef O_SHARED_KERNEL
1427   if ( !nolibswipl )
1428 #endif
1429   { appendArgList(&ldoptions, pllib);		/* -lswipl */
1430   }
1431   concatArgList(&ldoptions, "", &lastlibs);	/* libraries */
1432 #ifdef __BEOS__
1433   appendArgList(&ldoptions, plexe);		/* last is executable */
1434 #endif
1435 #endif /*__CYGWIN__*/
1436 #endif /* !defined(HOST_TOOLCHAIN_MSC) */
1437 
1438   callprog(ld, &ldoptions);
1439 }
1440 
1441 
1442 static void
quoted_name(const char * name,char * plname)1443 quoted_name(const char *name, char *plname)
1444 { int needquote = TRUE;
1445 
1446   if ( islower(CTOI(name[0])) )
1447   { const char *s = name+1;
1448 
1449     for( ; *s && (isalnum(CTOI(*s)) || *s == '_'); s++)
1450       ;
1451     if ( *s == '\0' )
1452       needquote = FALSE;
1453   }
1454 
1455   if ( !needquote )
1456     strcpy(plname, name);
1457   else
1458   { char *o = plname;
1459 
1460     *o++ = '\'';
1461     for( ; *name; name++)
1462     { if ( *name == '\'' )
1463 	*o++ = *name;
1464       *o++ = *name;
1465     }
1466     *o++ = '\'';
1467     *o = '\0';
1468   }
1469 }
1470 
1471 
1472 char *
put_pl_option(char * to,const char * name,const char * value)1473 put_pl_option(char *to, const char* name, const char *value)
1474 { strcpy(to, name);
1475   to += strlen(to);
1476   *to++ = '=';
1477   quoted_name(value, to);
1478   to += strlen(to);
1479 
1480   return to;
1481 }
1482 
1483 
1484 void
createSavedState()1485 createSavedState()
1486 { char buf[1024];
1487   char *e;
1488   int n;
1489 
1490   strcpy(buf, "consult([");
1491   e = buf + strlen(buf);
1492   for(n=0; n<plfiles.size; n++)
1493   { if ( n > 0 )
1494       *e++ = ',';
1495     quoted_name(plfiles.list[n], e);
1496     e += strlen(e);
1497   }
1498   for(n=0; n<qlfiles.size; n++)
1499   { if ( n > 0 )
1500       *e++ = ',';
1501     quoted_name(qlfiles.list[n], e);
1502     e += strlen(e);
1503   }
1504   strcpy(e, "]),qsave_program(");
1505   e += strlen(e);
1506   quoted_name(pltmp, e);
1507   e += strlen(e);
1508   strcpy(e, ",[");
1509   e += strlen(e);
1510   e = put_pl_option(e, "goal",     plgoal);
1511   *e++ = ',';
1512   e = put_pl_option(e, "toplevel", pltoplevel);
1513   *e++ = ',';
1514   e = put_pl_option(e, "init_file", plinitfile);
1515   if ( plclass )
1516   { *e++ = ',';
1517     e = put_pl_option(e, "class", plclass);
1518   }
1519   strcpy(e, "])");
1520   e += strlen(e);
1521 
1522   appendArgList(&ploptions, "-f");
1523   appendArgList(&ploptions, "none");
1524   appendArgList(&ploptions, "-F");
1525   appendArgList(&ploptions, plsysinit);
1526   appendArgList(&ploptions, "-g");
1527   appendArgList(&ploptions, "true");
1528   appendArgList(&ploptions, "-t");
1529   appendArgList(&ploptions, buf);
1530   appendArgList(&tmpfiles, pltmp);
1531 
1532   callprog(pl, &ploptions);
1533 }
1534 
1535 
1536 static void
copy_fd(int i,int o)1537 copy_fd(int i, int o)
1538 { char buf[CPBUFSIZE];
1539   ssize_t n;
1540 
1541   while( (n=read(i, buf, sizeof(buf))) > 0 )
1542   { while( n > 0 )
1543     { ssize_t n2;
1544 
1545       if ( (n2 = write(o, buf, n)) > 0 )
1546       { n -= n2;
1547       } else
1548       { fprintf(stderr, "%s: write failed: %s\n", plld, oserror());
1549 	error(1);
1550       }
1551     }
1552   }
1553 
1554   if ( n < 0 )
1555   { fprintf(stderr, "%s: read failed: %s\n", plld, oserror());
1556     error(1);
1557   }
1558 }
1559 
1560 
1561 #if defined(HOST_TOOLCHAIN_MSC)
1562 void
saveExportLib()1563 saveExportLib()
1564 { char ibuf[MAXPATHLEN];
1565   char obuf[MAXPATHLEN];
1566   char *ilib, *olib;
1567 
1568   ilib = replaceExtension(ctmp, "lib", ibuf);
1569   olib = replaceExtension(out, "lib", obuf);
1570 
1571   if ( verbose )
1572   { printf("\tren \"%s\" \"%s\"\n", ilib, olib);
1573   }
1574 
1575   if ( !fake )
1576   { if ( rename(ilib, olib) != 0 )
1577     { fprintf(stderr, "Could not rename export lib %s to %s: %s\n",
1578 	      ilib, olib, oserror());
1579       error(1);
1580     }
1581   }
1582 }
1583 #endif /* defined(HOST_TOOLCHAIN_MSC) */
1584 
1585 
1586 void
createOutput()1587 createOutput()
1588 { int ifd, ofd = -1;
1589 
1590   if ( verbose )
1591   {
1592 #if defined(HOST_TOOLCHAIN_MSC)
1593     printf("\tcopy /b %s+%s %s\n", out, pltmp, out);
1594 #else
1595     printf("\tcat %s >> %s\n", pltmp, out);
1596 #endif
1597   }
1598 
1599   if ( !fake )
1600   { if ( (ofd = open(out, O_WRONLY|O_BINARY, 0666)) < 0 )
1601     { fprintf(stderr, "Could not open %s: %s\n", out, oserror());
1602       error(1);
1603     }
1604     if ( lseek(ofd, 0, SEEK_END) == (off_t)-1 )
1605     { fprintf(stderr, "Could not seek to end of %s: %s\n", out, oserror());
1606       error(1);
1607     }
1608     if ( (ifd = open(pltmp, O_RDONLY|O_BINARY)) < 0 )
1609     { close(ofd);
1610       remove(out);
1611       fprintf(stderr, "Could not open %s: %s\n", pltmp, oserror());
1612       error(1);
1613     }
1614     copy_fd(ifd, ofd);
1615     close(ifd);
1616   }
1617 
1618 #ifdef HAVE_CHMOD
1619   { int mask = umask(0777);
1620 
1621     umask(mask);
1622 
1623     if ( verbose )
1624       printf("\tchmod %03o %s\n", 0777 & ~mask, out);
1625 
1626     if ( !fake )
1627     {
1628 #ifdef HAVE_FCHMOD
1629       if ( fchmod(ofd, 0777 & ~mask) != 0 )
1630 #else
1631       if ( chmod(out, 0777 & ~mask) != 0 )
1632 #endif
1633       { fprintf(stderr, "Could not make %s executable: %s\n", out, oserror());
1634 	error(1);
1635       }
1636     }
1637   }
1638 #endif
1639 
1640   if ( !fake )
1641     close(ofd);
1642 }
1643 
1644 
1645 static void
removeTempFiles()1646 removeTempFiles()
1647 { int n;
1648 
1649   for(n = 0; n < tmpfiles.size; n++)
1650   { if ( remove(tmpfiles.list[n]) == 0 )
1651     { if ( verbose )
1652 	printf("\trm %s\n", tmpfiles.list[n]);
1653     }
1654   }
1655 }
1656 
1657 		 /*******************************
1658 		 *	       SIGNALS		*
1659 		 *******************************/
1660 
1661 static void
catchSignals()1662 catchSignals()
1663 { signal(SIGINT,	caught_signal);
1664   signal(SIGSEGV,	caught_signal);
1665 }
1666 
1667 
1668 		 /*******************************
1669 		 *	       MAIN		*
1670 		 *******************************/
1671 
1672 int
main(int argc,char ** argv)1673 main(int argc, char **argv)
1674 { int special;
1675 
1676   plld = argv[0];
1677 
1678   argc--;
1679   argv++;
1680 
1681   catchSignals();
1682 
1683   if ( argc == 0 )
1684   { fprintf(stderr, "No input files.  Use %s -help.\n", plld);
1685     exit(0);
1686   }
1687 
1688   putenv("PLLD=true");			/* for subprograms */
1689 
1690   verbose = FALSE;
1691 
1692   if ( argc > 2 && streq(argv[0], "-pl") )
1693     special = 2;
1694   else
1695     special = 0;
1696 					  /* swipl-ld [-pl x] -v: verbose */
1697   if ( argc-special == 1 && streq(argv[special], "-v") )
1698   { arglist coptions;
1699     int i;
1700 
1701     memset(&coptions, 0, sizeof(coptions));
1702     for(i=special; i < argc; i++)
1703       appendArgList(&coptions, argv[i]);
1704 
1705     callprog(PROG_CC, &coptions);
1706 
1707     return 0;
1708   }
1709 
1710   parseOptions(argc, argv);
1711   defaultProgram(&pl, PROG_PL);
1712 
1713   if ( build_defaults )
1714   { nostate = TRUE;			/* not needed and Prolog won't run */
1715     defaultProgram(&cc, C_CC);
1716 #ifdef PLBASE
1717     defaultPath(&plbase, PLBASE);
1718 #else
1719     defaultPath(&plbase, PLHOME);
1720 #endif
1721     defaultPath(&plarch, PLARCH);
1722     defaultProgram(&pllib, C_PLLIB);
1723     addOptionString(C_LIBS);
1724     appendArgList(&ldoptions, C_LDFLAGS);
1725     appendArgList(&coptions, C_CFLAGS);
1726     appendArgList(&cppoptions, C_CFLAGS);
1727 #ifdef SO_EXT
1728     soext = strdup(SO_EXT);
1729 #endif
1730 #ifdef O_PLMT
1731     ensureOption(&coptions, "-D_REENTRANT");
1732     ensureOption(&cppoptions, "-D_REENTRANT");
1733 #ifdef _THREAD_SAFE			/* FreeBSD */
1734     ensureOption(&coptions, "-D_THREAD_SAFE");
1735     ensureOption(&cppoptions, "-D_THREAD_SAFE");
1736 #endif
1737 #endif
1738   } else
1739   { getPrologOptions();
1740   }
1741 
1742   fillDefaultOptions();
1743 
1744   if ( show_version )
1745   { callprog(cc, &coptions);
1746     exit(0);
1747   }
1748 
1749   compileObjectFiles();
1750 
1751   if ( !nolink )
1752   { if ( shared )
1753       linkSharedObject();
1754     else
1755     { linkBaseExecutable();
1756 
1757       if ( !nostate )
1758       { createSavedState();
1759 	createOutput();
1760       }
1761     }
1762   }
1763 
1764   removeTempFiles();
1765 
1766   return 0;
1767 }
1768 
1769 
1770