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