comparison lib-src/ellcc.c @ 388:aabb7f5b1c81 r21-2-9

Import from CVS: tag r21-2-9
author cvs
date Mon, 13 Aug 2007 11:09:42 +0200
parents
children 74fd4e045ea6
comparison
equal deleted inserted replaced
387:f892a9d0bb8d 388:aabb7f5b1c81
1 /* ellcc.c - front-end for compiling Emacs modules
2 Copyright (C) 1998, 1999 J. Kean Johnston.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20
21 Author: J. Kean Johnston (jkj@sco.com).
22 Please mail bugs and suggestions to the XEmacs maintainer.
23 */
24
25 /*
26 Here's the scoop. We would really like this to be a shell script, but
27 the various Windows platforms dont have reliable scripting that suits
28 our needs. We dont want to reply on perl or some other such language
29 so we have to roll our own executable to act as a front-end for the
30 compiler.
31
32 This program is used to invoke the compiler, the linker and to generate
33 the module specific documentation and initialization code. We assume we
34 are in 'compile' mode unless we encounter an argument which tells us
35 that we're not. We take all arguments and pass them on directly to the
36 compiler, except for a few which are specific to this program:
37
38 --mode=VALUE This sets the program mode. VALUE can be one of
39 compile, link, init or verbose.
40 --mod-name=NAME Sets the module name to the string NAME.
41 --mod-title=TITLE Sets the module title to the string TITLE.
42 --mod-version=VER Sets the module version to the string VER.
43
44 The idea is that Makefiles will use ellcc as the compiler for making
45 dynamic Emacs modules, and life should be as simple as:
46
47 make CC=ellcc LD='ellcc --mode=link'
48
49 The only additional requirement is an entry in the Makefile to produce
50 the module initialization file, which will usually be something along
51 the lines of:
52
53 modinit.c: $(SRCS)
54 ellcc --mode=init --mod-name=\"$(MODNAME)\" \
55 --mod-title=\"$(MODTITLE)\" --mod-version=\"$(MODVERSION)\" \
56 -o $@ $(SRCS)
57
58 See the samples for more details.
59 */
60
61 #include <stdio.h>
62 #include <stdlib.h>
63
64 #ifdef MSDOS
65 # include <fcntl.h>
66 # include <sys/param.h>
67 # include <io.h>
68 # ifndef HAVE_CONFIG_H
69 # define DOS_NT
70 # include <sys/config.h>
71 # endif
72 #endif /* MSDOS */
73
74 #ifdef WINDOWSNT
75 # include <stdlib.h>
76 # include <fcntl.h>
77 # include <string.h>
78 # include <io.h>
79 # define MAXPATHLEN _MAX_PATH
80 # ifdef HAVE_CONFIG_H
81 # undef HAVE_NTGUI
82 # else
83 # define DOS_NT
84 # define HAVE_GETCWD
85 # endif /* not HAVE_CONFIG_H */
86 #endif /* WINDOWSNT */
87
88 #ifdef HAVE_CONFIG_H
89 # include <config.h>
90 /* On some systems, Emacs defines static as nothing for the sake
91 of unexec. We don't want that here since we don't use unexec. */
92 # undef static
93 #endif /* HAVE_CONFIG_H */
94
95 #if !defined (WINDOWSNT) && defined (STDC_HEADERS)
96 #include <stdlib.h>
97 #include <string.h>
98 #endif
99
100 #ifdef HAVE_UNISTD_H
101 # include <unistd.h>
102 #else
103 # ifdef HAVE_GETCWD
104 extern char *getcwd ();
105 # endif
106 #endif /* HAVE_UNISTD_H */
107
108 #include <stdio.h>
109 #include <ctype.h>
110 #include <errno.h>
111 #ifndef errno
112 extern int errno;
113 #endif
114 #include <sys/types.h>
115 #include <sys/stat.h>
116
117 #define EMODULES_GATHER_VERSION
118 #include "emodules.h"
119 #include "ellcc.h"
120
121 #if !defined (S_ISREG) && defined (S_IFREG)
122 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
123 #endif
124
125 /* Exit codes for success and failure. */
126 #ifdef VMS
127 # define GOOD 1
128 # define BAD 0
129 #else
130 # define GOOD 0
131 # define BAD 1
132 #endif
133
134 #define DEBUG
135
136 #ifndef HAVE_SHLIB
137 int
138 main()
139 {
140 fprintf (stderr, "Dynamic modules not supported on this platform\n");
141 return (BAD);
142 }
143 #else
144
145 /*
146 * Try to figure out the commands we need to use to create shared objects,
147 * and how to compile for PIC mode.
148 */
149
150 /*
151 * xnew, xrnew -- allocate, reallocate storage
152 *
153 * SYNOPSIS: Type *xnew (int n, Type);
154 * Type *xrnew (OldPointer, int n, Type);
155 */
156 #ifdef chkmalloc
157 # include "chkmalloc.h"
158 # define xnew(n,Type) ((Type *) trace_malloc (__FILE__, __LINE__, \
159 (n) * sizeof (Type)))
160 # define xrnew(op,n,Type) ((Type *) trace_realloc (__FILE__, __LINE__, \
161 (op), (n) * sizeof (Type)))
162 #else
163 # define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
164 # define xrnew(op,n,Type) ((Type *) xrealloc ((op), (n) * sizeof (Type)))
165 #endif
166 long *xmalloc (), *xrealloc ();
167 void fatal (), pfatal ();
168 char *ellcc_strchr (), *ellcc_strrchr ();
169 void add_to_argv ();
170 void do_compile_mode(), do_link_mode(), do_init_mode();
171
172 #define SSTR(S) ((S)?(S):"")
173
174 #define ELLCC_COMPILE_MODE 0
175 #define ELLCC_LINK_MODE 1
176 #define ELLCC_INIT_MODE 2
177
178 int ellcc_mode = ELLCC_COMPILE_MODE;
179 char *progname;
180 char *mod_name = (char *)0, *mod_version = (char *)0, *mod_title = (char *)0;
181 char *mod_output = (char *)0;
182 int verbose = 0;
183 char **exec_argv;
184 int exec_argc = 1, *exec_args;
185 int real_argc = 0;
186 int prog_argc;
187 char **prog_argv;
188
189 /*
190 * We allow the user to over-ride things in the environment
191 */
192 char *ellcc, *ellld, *ellcflags, *ellldflags, *ellpicflags, *elldllflags;
193 #define OVERENV(STR,EVAR,DFLT) \
194 STR = getenv(EVAR); \
195 if ((STR) == (char *)0) \
196 STR = DFLT
197
198 int
199 main (argc, argv)
200 int argc;
201 char *argv[];
202 {
203 char *tmp;
204 int i, done_mode = 0;
205
206 prog_argc = argc;
207 prog_argv = argv;
208
209 #if defined(MSDOS) || defined(WINDOWSNT)
210 tmp = ellcc_strrchr (argv[0], '\\');
211 if (tmp != (char *)0)
212 tmp++;
213 #elif !defined (VMS)
214 tmp = ellcc_strrchr (argv[0], '/');
215 if (tmp != (char *)0)
216 tmp++;
217 #else
218 tmp = argv[0];
219 #endif
220
221 if (tmp != (char *)0)
222 progname = tmp;
223 else
224 progname = argv[0];
225
226 tmp = &progname[strlen(progname)-2];
227 if (strcmp (tmp, "cc") == 0)
228 ellcc_mode = ELLCC_COMPILE_MODE;
229 else if (strcmp (tmp, "ld") == 0)
230 ellcc_mode = ELLCC_LINK_MODE;
231 else if (strcmp (tmp, "it") == 0)
232 ellcc_mode = ELLCC_INIT_MODE;
233
234 exec_argv = xnew(argc + 20, char *);
235 exec_args = xnew(argc, int);
236 for (i = 0; i < argc; i++)
237 exec_args[i] = -1;
238
239 if (argc < 2)
240 fatal ("too few arguments", (char *)0);
241
242 exec_args[0] = 0;
243
244 for (i = 1; i < argc; i++)
245 {
246 if (strncmp (argv[i], "--mode=", 7) == 0)
247 {
248 char *modeopt = argv[i] + 7;
249
250 if (done_mode && strcmp (modeopt, "verbose"))
251 fatal ("more than one mode specified");
252 if (strcmp (modeopt, "link") == 0)
253 {
254 done_mode++;
255 ellcc_mode = ELLCC_LINK_MODE;
256 }
257 else if (strcmp (modeopt, "compile") == 0)
258 {
259 done_mode++;
260 ellcc_mode = ELLCC_COMPILE_MODE;
261 }
262 else if (strcmp (modeopt, "init") == 0)
263 {
264 done_mode++;
265 ellcc_mode = ELLCC_INIT_MODE;
266 }
267 else if (strcmp (modeopt, "verbose") == 0)
268 verbose += 1;
269 }
270 else if (strcmp (argv[i], "--mod-location") == 0)
271 {
272 printf ("%s\n", ELLCC_MODDIR);
273 return 0;
274 }
275 else if (strcmp (argv[i], "--mod-site-location") == 0)
276 {
277 printf ("%s\n", ELLCC_SITEMODS);
278 return 0;
279 }
280 else if (strcmp (argv[i], "--mod-archdir") == 0)
281 {
282 printf ("%s\n", ELLCC_ARCHDIR);
283 return 0;
284 }
285 else if (strcmp (argv[i], "--mod-config") == 0)
286 {
287 printf ("%s\n", ELLCC_CONFIG);
288 return 0;
289 }
290 else if (strncmp (argv[i], "--mod-name=", 10) == 0)
291 mod_name = argv[i] + 11;
292 else if (strncmp (argv[i], "--mod-title=", 11) == 0)
293 mod_title = argv[i] + 12;
294 else if (strncmp (argv[i], "--mod-version=", 13) == 0)
295 mod_version = argv[i] + 14;
296 else if (strncmp (argv[i], "--mod-output=", 12) == 0)
297 mod_output = argv[i] + 13;
298 else
299 {
300 exec_args[exec_argc] = i;
301 exec_argc++;
302 }
303 }
304
305 if (ellcc_mode == ELLCC_LINK_MODE && mod_output == (char *)0)
306 fatal ("must specify --mod-output when linking", (char *)0);
307 if (ellcc_mode == ELLCC_INIT_MODE && mod_output == (char *)0)
308 fatal ("must specify --mod-output when creating init file", (char *)0);
309 if (ellcc_mode == ELLCC_INIT_MODE && mod_name == (char *)0)
310 fatal ("must specify --mod-name when creating init file", (char *)0);
311
312 /*
313 * We now have the list of arguments to pass to the compiler or
314 * linker (or to process for doc files). We can do the real work
315 * now.
316 */
317 if (verbose)
318 printf ("ellcc driver version %s for EMODULES version %s (%ld)\n",
319 ELLCC_EMACS_VER, EMODULES_VERSION, EMODULES_REVISION);
320 #ifdef DEBUG
321 if (verbose >= 2)
322 {
323 printf (" mode = %d (%s)\n", ellcc_mode,
324 ellcc_mode == ELLCC_COMPILE_MODE ? "compile" :
325 ellcc_mode == ELLCC_LINK_MODE ? "link" : "init");
326 printf (" module_name = \"%s\"\n", SSTR(mod_name));
327 printf (" module_title = \"%s\"\n", SSTR(mod_title));
328 printf (" module_version = \"%s\"\n", SSTR(mod_version));
329
330 printf (" CC = %s\n", ELLCC_CC);
331 printf (" CFLAGS = %s\n", ELLCC_CFLAGS);
332 printf (" CC PIC flags = %s\n", ELLCC_DLL_CFLAGS);
333 printf (" LD = %s\n", ELLCC_DLL_LD);
334 printf (" LDFLAGS = %s\n", ELLCC_DLL_LDFLAGS);
335 printf (" architecture = %s\n", ELLCC_CONFIG);
336 printf (" Include directory = %s/include\n", ELLCC_ARCHDIR);
337 printf ("\n");
338 }
339 #endif
340
341 if (exec_argc < 2)
342 fatal ("too few arguments");
343
344 /*
345 * Get the over-rides from the environment
346 */
347 OVERENV(ellcc, "ELLCC", ELLCC_CC);
348 OVERENV(ellld, "ELLLD", ELLCC_DLL_LD);
349 OVERENV(ellcflags, "ELLCFLAGS", ELLCC_CFLAGS);
350 OVERENV(ellldflags, "ELLLDFLAGS", ELLCC_LDFLAGS);
351 OVERENV(elldllflags, "ELLDLLFLAGS", ELLCC_DLL_LDFLAGS);
352 OVERENV(ellpicflags, "ELLPICFLAGS", ELLCC_DLL_CFLAGS);
353
354 if (ellcc_mode == ELLCC_COMPILE_MODE)
355 do_compile_mode();
356 else if (ellcc_mode == ELLCC_LINK_MODE)
357 do_link_mode();
358 else
359 do_init_mode();
360
361 /*
362 * The arguments to pass on to the desired program have now been set
363 * up and we can run the program.
364 */
365 if (verbose)
366 {
367 for (i = 0; i < real_argc; i++)
368 printf ("%s ", exec_argv[i]);
369 printf ("\n");
370 fflush (stdout);
371 }
372 exec_argv[real_argc] = (char *)0; /* Terminate argument list */
373
374 i = execvp (exec_argv[0], exec_argv);
375 if (verbose)
376 printf ("%s exited with status %d\n", exec_argv[0], i);
377 return i;
378 }
379
380 /* Like malloc but get fatal error if memory is exhausted. */
381 long *
382 xmalloc (size)
383 unsigned int size;
384 {
385 long *result = (long *) malloc (size);
386 if (result == NULL)
387 fatal ("virtual memory exhausted", (char *)NULL);
388 return result;
389 }
390
391 long *
392 xrealloc (ptr, size)
393 char *ptr;
394 unsigned int size;
395 {
396 long *result = (long *) realloc (ptr, size);
397 if (result == NULL)
398 fatal ("virtual memory exhausted", (char *)NULL);
399 return result;
400 }
401
402 /* Print error message and exit. */
403 void
404 fatal (s1, s2)
405 char *s1, *s2;
406 {
407 fprintf (stderr, "%s: ", progname);
408 fprintf (stderr, s1, s2);
409 fprintf (stderr, "\n");
410 exit (BAD);
411 }
412
413 void
414 pfatal (s1)
415 char *s1;
416 {
417 perror (s1);
418 exit (BAD);
419 }
420
421 /*
422 * Return the ptr in sp at which the character c last
423 * appears; NULL if not found
424 *
425 * Identical to System V strrchr, included for portability.
426 */
427 char *
428 ellcc_strrchr (sp, c)
429 register char *sp, c;
430 {
431 register char *r;
432
433 r = NULL;
434 do
435 {
436 if (*sp == c)
437 r = sp;
438 } while (*sp++);
439 return r;
440 }
441
442 /*
443 * Return the ptr in sp at which the character c first
444 * appears; NULL if not found
445 *
446 * Identical to System V strchr, included for portability.
447 */
448 char *
449 ellcc_strchr (sp, c)
450 register char *sp, c;
451 {
452 do
453 {
454 if (*sp == c)
455 return sp;
456 } while (*sp++);
457 return NULL;
458 }
459
460 /*
461 * Add a string to the argument vector list that will be passed on down
462 * to the compiler or linker. We need to split individual words into
463 * arguments, taking quoting into account. This can get ugly.
464 */
465 void
466 add_to_argv (str)
467 CONST char *str;
468 {
469 int sm = 0;
470 CONST char *s = (CONST char *)0;
471
472 if ((str == (CONST char *)0) || (str[0] == '\0'))
473 return;
474
475 while (*str)
476 {
477 switch (sm)
478 {
479 case 0: /* Start of case - string leading whitespace */
480 if (isspace (*str))
481 str++;
482 else
483 {
484 sm = 1; /* Change state to non-whitespace */
485 s = str; /* Mark the start of THIS argument */
486 }
487 break;
488
489 case 1: /* Non-whitespace character. Mark the start */
490 if (isspace (*str))
491 {
492 /* Reached the end of the argument. Add it. */
493 int l = str-s;
494 exec_argv[real_argc] = xnew (l+2, char);
495 strncpy (exec_argv[real_argc], s, l);
496 exec_argv[real_argc][l] = '\0';
497 real_argc++;
498 sm = 0; /* Back to start state */
499 s = (CONST char *)0;
500 break;
501 }
502 else if (*str == '\\')
503 {
504 sm = 2; /* Escaped character */
505 str++;
506 break;
507 }
508 else if (*str == '\'')
509 {
510 /* Start of quoted string (single quotes) */
511 sm = 3;
512 }
513 else if (*str == '"')
514 {
515 /* Start of quoted string (double quotes) */
516 sm = 4;
517 }
518 else
519 {
520 /* This was just a normal character. Advance the pointer. */
521 str++;
522 }
523 break;
524
525 case 2: /* Escaped character */
526 str++; /* Preserve the quoted character */
527 sm = 1; /* Go back to gathering state */
528 break;
529
530 case 3: /* Inside single quoted string */
531 if (*str == '\'')
532 sm = 1;
533 str++;
534 break;
535
536 case 4: /* inside double quoted string */
537 if (*str == '"')
538 sm = 1;
539 str++;
540 break;
541 }
542 }
543
544 if (s != (CONST char *)0)
545 {
546 int l = str-s;
547 exec_argv[real_argc] = xnew (l+2, char);
548 strncpy (exec_argv[real_argc], s, l);
549 exec_argv[real_argc][l] = '\0';
550 real_argc++;
551 s = (CONST char *)0;
552 }
553 }
554
555 /*
556 * For compile mode, things are pretty straight forward. All we need to do
557 * is build up the argument vector and exec() it. We must just make sure
558 * that we get all of the required arguments in place.
559 */
560 void
561 do_compile_mode()
562 {
563 int i;
564 char ts[4096]; /* Plenty big enough */
565
566 add_to_argv (ellcc);
567 add_to_argv (ellcflags);
568 add_to_argv (ellpicflags);
569 add_to_argv ("-DPIC");
570 add_to_argv ("-DEMACS_MODULE");
571 #ifdef XEMACS
572 add_to_argv ("-DXEMACS_MODULE"); /* Cover both cases */
573 add_to_argv ("-Dxemacs");
574 #endif
575 add_to_argv ("-Demacs");
576 sprintf (ts, "-I%s/include", ELLCC_ARCHDIR);
577 add_to_argv (ts);
578 add_to_argv (ELLCC_CF_ALL);
579 for (i = 1; i < exec_argc; i++)
580 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]);
581 }
582
583 /*
584 * For link mode, things are a little bit more complicated. We need to
585 * insert the linker commands first, replace any occurrence of ELLSONAME
586 * with the desired output file name, insert the output arguments, then
587 * all of the provided arguments, then the final post arguments. Once
588 * all of this has been done, the argument vector is ready to run.
589 */
590 void
591 do_link_mode()
592 {
593 int i,x;
594 char *t, ts[4096]; /* Plenty big enough */
595
596 add_to_argv (ellld);
597 add_to_argv (ellldflags);
598 add_to_argv (elldllflags);
599 add_to_argv (ELLCC_DLL_LDO);
600 add_to_argv (mod_output);
601 for (i = 1; i < exec_argc; i++)
602 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]);
603 add_to_argv (ELLCC_DLL_POST);
604
605 /*
606 * Now go through each argument and replace ELLSONAME with mod_output.
607 */
608 for (i = 0; i < real_argc; i++)
609 {
610 x = 0;
611 ts[0] = '\0';
612
613 t = exec_argv[i];
614 while (*t)
615 {
616 if (*t == 'E')
617 {
618 if (strncmp (t, "ELLSONAME", 9) == 0)
619 {
620 strcat (ts, mod_output);
621 t += 8;
622 x += strlen (mod_output);
623 }
624 else
625 {
626 ts[x] = *t;
627 x++;
628 ts[x] = '\0';
629 }
630 }
631 else
632 {
633 ts[x] = *t;
634 x++;
635 ts[x] = '\0';
636 }
637 t++;
638 }
639 free (exec_argv[i]);
640 exec_argv[i] = strdup (ts);
641 }
642 }
643
644 /*
645 * In init mode, things are a bit easier. We assume that the only things
646 * passed on the command line are the names of source files which the
647 * make-doc program will be processing. We prepare the output file with
648 * the header information first, as make-doc will append to the file by
649 * special dispensation.
650 */
651 void
652 do_init_mode()
653 {
654 int i;
655 char ts[4096]; /* Plenty big enough */
656 char *mdocprog;
657 FILE *mout = fopen (mod_output, "w");
658
659 if (mout == (FILE *)0)
660 fatal ("failed to open output file", mod_output);
661 fprintf (mout, "/* DO NOT EDIT - AUTOMATICALLY GENERATED */\n\n");
662 fprintf (mout, "#include <emodules.h>\n\n");
663 fprintf (mout, "const long emodule_compiler = %ld;\n", EMODULES_REVISION);
664 fprintf (mout, "const char *emodule_name = \"%s\";\n", SSTR(mod_name));
665 fprintf (mout, "const char *emodule_version = \"%s\";\n", SSTR(mod_version));
666 fprintf (mout, "const char *emodule_title = \"%s\";\n", SSTR(mod_title));
667 fprintf (mout, "\n\n");
668 fprintf (mout, "void docs_of_%s()\n", SSTR(mod_name));
669 fclose (mout);
670
671 sprintf (ts, "%s/make-docfile", ELLCC_ARCHDIR);
672 OVERENV(mdocprog, "ELLMAKEDOC", ts);
673 add_to_argv (mdocprog);
674 sprintf (ts, "-E %s", mod_output);
675 add_to_argv (ts);
676 for (i = 1; i < exec_argc; i++)
677 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]);
678 }
679
680 #endif /* HAVE_SHLIB */
681