Mercurial > hg > xemacs-beta
comparison lib-src/ellcc.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | 84b14dcb0985 |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
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 don't have reliable scripting that suits | |
28 our needs. We don't want to rely 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 <../src/config.h> | |
62 #include <stdio.h> | |
63 #include <stdlib.h> | |
64 #include <string.h> | |
65 #include <ctype.h> | |
66 #include <errno.h> | |
67 #include <sys/types.h> | |
68 | |
69 #ifdef HAVE_UNISTD_H | |
70 # include <unistd.h> | |
71 #endif /* HAVE_UNISTD_H */ | |
72 | |
73 #define EMODULES_GATHER_VERSION | |
74 #include "emodules.h" | |
75 #include "ellcc.h" | |
76 | |
77 #define DEBUG | |
78 | |
79 #ifndef HAVE_SHLIB | |
80 int | |
81 main (int argc, char *argv[]) | |
82 { | |
83 fprintf (stderr, "Dynamic modules not supported on this platform\n"); | |
84 return EXIT_FAILURE; | |
85 } | |
86 #else | |
87 | |
88 /* | |
89 * Try to figure out the commands we need to use to create shared objects, | |
90 * and how to compile for PIC mode. | |
91 */ | |
92 | |
93 /* | |
94 * xnew, xrnew -- allocate, reallocate storage | |
95 * | |
96 * SYNOPSIS: Type *xnew (int n, Type); | |
97 * Type *xrnew (OldPointer, int n, Type); | |
98 */ | |
99 #ifdef chkmalloc | |
100 # include "chkmalloc.h" | |
101 # define xnew(n,Type) ((Type *) trace_malloc (__FILE__, __LINE__, \ | |
102 (n) * sizeof (Type))) | |
103 # define xrnew(op,n,Type) ((Type *) trace_realloc (__FILE__, __LINE__, \ | |
104 (op), (n) * sizeof (Type))) | |
105 #else | |
106 # define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type))) | |
107 # define xrnew(op,n,Type) ((Type *) xrealloc ((op), (n) * sizeof (Type))) | |
108 #endif | |
109 static void *xmalloc (size_t); | |
110 static void fatal (char *, char *); | |
111 static void add_to_argv (CONST char *); | |
112 static void do_compile_mode (void); | |
113 static void do_link_mode (void); | |
114 static void do_init_mode (void); | |
115 | |
116 #define SSTR(S) ((S)?(S):"") | |
117 | |
118 #define ELLCC_COMPILE_MODE 0 | |
119 #define ELLCC_LINK_MODE 1 | |
120 #define ELLCC_INIT_MODE 2 | |
121 | |
122 int ellcc_mode = ELLCC_COMPILE_MODE; | |
123 char *progname; | |
124 char *mod_name = (char *)0, *mod_version = (char *)0, *mod_title = (char *)0; | |
125 char *mod_output = (char *)0; | |
126 int verbose = 0; | |
127 char **exec_argv; | |
128 int exec_argc = 1, *exec_args; | |
129 int real_argc = 0; | |
130 int prog_argc; | |
131 char **prog_argv; | |
132 | |
133 /* | |
134 * We allow the user to over-ride things in the environment | |
135 */ | |
136 char *ellcc, *ellld, *ellcflags, *ellldflags, *ellpicflags, *elldllflags; | |
137 #define OVERENV(STR,EVAR,DFLT) \ | |
138 STR = getenv(EVAR); \ | |
139 if ((STR) == (char *)0) \ | |
140 STR = DFLT | |
141 | |
142 int | |
143 main (int argc, char *argv[]) | |
144 { | |
145 char *tmp; | |
146 int i, done_mode = 0; | |
147 | |
148 prog_argc = argc; | |
149 prog_argv = argv; | |
150 | |
151 #if defined(MSDOS) || defined(WINDOWSNT) | |
152 tmp = strrchr (argv[0], '\\'); | |
153 if (tmp != (char *)0) | |
154 tmp++; | |
155 #elif !defined (VMS) | |
156 tmp = strrchr (argv[0], '/'); | |
157 if (tmp != (char *)0) | |
158 tmp++; | |
159 #else | |
160 tmp = argv[0]; | |
161 #endif | |
162 | |
163 if (tmp != (char *)0) | |
164 progname = tmp; | |
165 else | |
166 progname = argv[0]; | |
167 | |
168 tmp = &progname[strlen(progname)-2]; | |
169 if (strcmp (tmp, "cc") == 0) | |
170 ellcc_mode = ELLCC_COMPILE_MODE; | |
171 else if (strcmp (tmp, "ld") == 0) | |
172 ellcc_mode = ELLCC_LINK_MODE; | |
173 else if (strcmp (tmp, "it") == 0) | |
174 ellcc_mode = ELLCC_INIT_MODE; | |
175 | |
176 exec_argv = xnew(argc + 20, char *); | |
177 exec_args = xnew(argc, int); | |
178 for (i = 0; i < argc; i++) | |
179 exec_args[i] = -1; | |
180 | |
181 if (argc < 2) | |
182 fatal ("too few arguments", (char *)0); | |
183 | |
184 exec_args[0] = 0; | |
185 | |
186 for (i = 1; i < argc; i++) | |
187 { | |
188 if (strncmp (argv[i], "--mode=", 7) == 0) | |
189 { | |
190 char *modeopt = argv[i] + 7; | |
191 | |
192 if (done_mode && strcmp (modeopt, "verbose")) | |
193 fatal ("more than one mode specified", (char *) 0); | |
194 if (strcmp (modeopt, "link") == 0) | |
195 { | |
196 done_mode++; | |
197 ellcc_mode = ELLCC_LINK_MODE; | |
198 } | |
199 else if (strcmp (modeopt, "compile") == 0) | |
200 { | |
201 done_mode++; | |
202 ellcc_mode = ELLCC_COMPILE_MODE; | |
203 } | |
204 else if (strcmp (modeopt, "init") == 0) | |
205 { | |
206 done_mode++; | |
207 ellcc_mode = ELLCC_INIT_MODE; | |
208 } | |
209 else if (strcmp (modeopt, "verbose") == 0) | |
210 verbose += 1; | |
211 } | |
212 else if (strcmp (argv[i], "--mod-location") == 0) | |
213 { | |
214 printf ("%s\n", ELLCC_MODDIR); | |
215 return 0; | |
216 } | |
217 else if (strcmp (argv[i], "--mod-site-location") == 0) | |
218 { | |
219 printf ("%s\n", ELLCC_SITEMODS); | |
220 return 0; | |
221 } | |
222 else if (strcmp (argv[i], "--mod-archdir") == 0) | |
223 { | |
224 printf ("%s\n", ELLCC_ARCHDIR); | |
225 return 0; | |
226 } | |
227 else if (strcmp (argv[i], "--mod-config") == 0) | |
228 { | |
229 printf ("%s\n", ELLCC_CONFIG); | |
230 return 0; | |
231 } | |
232 else if (strncmp (argv[i], "--mod-name=", 11) == 0) | |
233 mod_name = argv[i] + 11; | |
234 else if (strncmp (argv[i], "--mod-title=", 12) == 0) | |
235 mod_title = argv[i] + 12; | |
236 else if (strncmp (argv[i], "--mod-version=", 14) == 0) | |
237 mod_version = argv[i] + 14; | |
238 else if (strncmp (argv[i], "--mod-output=", 13) == 0) | |
239 mod_output = argv[i] + 13; | |
240 else | |
241 { | |
242 exec_args[exec_argc] = i; | |
243 exec_argc++; | |
244 } | |
245 } | |
246 | |
247 if (ellcc_mode == ELLCC_LINK_MODE && mod_output == (char *)0) | |
248 fatal ("must specify --mod-output when linking", (char *)0); | |
249 if (ellcc_mode == ELLCC_INIT_MODE && mod_output == (char *)0) | |
250 fatal ("must specify --mod-output when creating init file", (char *)0); | |
251 if (ellcc_mode == ELLCC_INIT_MODE && mod_name == (char *)0) | |
252 fatal ("must specify --mod-name when creating init file", (char *)0); | |
253 | |
254 /* | |
255 * We now have the list of arguments to pass to the compiler or | |
256 * linker (or to process for doc files). We can do the real work | |
257 * now. | |
258 */ | |
259 if (verbose) | |
260 printf ("ellcc driver version %s for EMODULES version %s (%ld)\n", | |
261 ELLCC_EMACS_VER, EMODULES_VERSION, EMODULES_REVISION); | |
262 #ifdef DEBUG | |
263 if (verbose >= 2) | |
264 { | |
265 printf (" mode = %d (%s)\n", ellcc_mode, | |
266 ellcc_mode == ELLCC_COMPILE_MODE ? "compile" : | |
267 ellcc_mode == ELLCC_LINK_MODE ? "link" : "init"); | |
268 printf (" module_name = \"%s\"\n", SSTR(mod_name)); | |
269 printf (" module_title = \"%s\"\n", SSTR(mod_title)); | |
270 printf (" module_version = \"%s\"\n", SSTR(mod_version)); | |
271 | |
272 printf (" CC = %s\n", ELLCC_CC); | |
273 printf (" CFLAGS = %s\n", ELLCC_CFLAGS); | |
274 printf (" CC PIC flags = %s\n", ELLCC_DLL_CFLAGS); | |
275 printf (" LD = %s\n", ELLCC_DLL_LD); | |
276 printf (" LDFLAGS = %s\n", ELLCC_DLL_LDFLAGS); | |
277 printf (" architecture = %s\n", ELLCC_CONFIG); | |
278 printf (" Include directory = %s/include\n", ELLCC_ARCHDIR); | |
279 printf ("\n"); | |
280 } | |
281 #endif | |
282 | |
283 if (exec_argc < 2) | |
284 fatal ("too few arguments", (char *) 0); | |
285 | |
286 /* | |
287 * Get the over-rides from the environment | |
288 */ | |
289 OVERENV(ellcc, "ELLCC", ELLCC_CC); | |
290 OVERENV(ellld, "ELLLD", ELLCC_DLL_LD); | |
291 OVERENV(ellcflags, "ELLCFLAGS", ELLCC_CFLAGS); | |
292 OVERENV(ellldflags, "ELLLDFLAGS", ELLCC_LDFLAGS); | |
293 OVERENV(elldllflags, "ELLDLLFLAGS", ELLCC_DLL_LDFLAGS); | |
294 OVERENV(ellpicflags, "ELLPICFLAGS", ELLCC_DLL_CFLAGS); | |
295 | |
296 if (ellcc_mode == ELLCC_COMPILE_MODE) | |
297 do_compile_mode(); | |
298 else if (ellcc_mode == ELLCC_LINK_MODE) | |
299 do_link_mode(); | |
300 else | |
301 do_init_mode(); | |
302 | |
303 /* | |
304 * The arguments to pass on to the desired program have now been set | |
305 * up and we can run the program. | |
306 */ | |
307 if (verbose) | |
308 { | |
309 for (i = 0; i < real_argc; i++) | |
310 printf ("%s ", exec_argv[i]); | |
311 printf ("\n"); | |
312 fflush (stdout); | |
313 } | |
314 exec_argv[real_argc] = (char *)0; /* Terminate argument list */ | |
315 | |
316 i = execvp (exec_argv[0], exec_argv); | |
317 if (verbose) | |
318 printf ("%s exited with status %d\n", exec_argv[0], i); | |
319 return i; | |
320 } | |
321 | |
322 /* Like malloc but get fatal error if memory is exhausted. */ | |
323 static void * | |
324 xmalloc (size_t size) | |
325 { | |
326 void *result = malloc (size); | |
327 if (result == NULL) | |
328 fatal ("virtual memory exhausted", (char *)0); | |
329 return result; | |
330 } | |
331 | |
332 /* Print error message and exit. */ | |
333 static void | |
334 fatal (char *s1, char *s2) | |
335 { | |
336 fprintf (stderr, "%s: ", progname); | |
337 fprintf (stderr, s1, s2); | |
338 fprintf (stderr, "\n"); | |
339 exit (EXIT_FAILURE); | |
340 } | |
341 | |
342 /* | |
343 * Add a string to the argument vector list that will be passed on down | |
344 * to the compiler or linker. We need to split individual words into | |
345 * arguments, taking quoting into account. This can get ugly. | |
346 */ | |
347 static void | |
348 add_to_argv (CONST char *str) | |
349 { | |
350 int sm = 0; | |
351 CONST char *s = (CONST char *)0; | |
352 | |
353 if ((str == (CONST char *)0) || (str[0] == '\0')) | |
354 return; | |
355 | |
356 while (*str) | |
357 { | |
358 switch (sm) | |
359 { | |
360 case 0: /* Start of case - string leading whitespace */ | |
361 if (isspace (*str)) | |
362 str++; | |
363 else | |
364 { | |
365 sm = 1; /* Change state to non-whitespace */ | |
366 s = str; /* Mark the start of THIS argument */ | |
367 } | |
368 break; | |
369 | |
370 case 1: /* Non-whitespace character. Mark the start */ | |
371 if (isspace (*str)) | |
372 { | |
373 /* Reached the end of the argument. Add it. */ | |
374 int l = str-s; | |
375 exec_argv[real_argc] = xnew (l+2, char); | |
376 strncpy (exec_argv[real_argc], s, l); | |
377 exec_argv[real_argc][l] = '\0'; | |
378 real_argc++; | |
379 sm = 0; /* Back to start state */ | |
380 s = (CONST char *)0; | |
381 break; | |
382 } | |
383 else if (*str == '\\') | |
384 { | |
385 sm = 2; /* Escaped character */ | |
386 str++; | |
387 break; | |
388 } | |
389 else if (*str == '\'') | |
390 { | |
391 /* Start of quoted string (single quotes) */ | |
392 sm = 3; | |
393 } | |
394 else if (*str == '"') | |
395 { | |
396 /* Start of quoted string (double quotes) */ | |
397 sm = 4; | |
398 } | |
399 else | |
400 { | |
401 /* This was just a normal character. Advance the pointer. */ | |
402 str++; | |
403 } | |
404 break; | |
405 | |
406 case 2: /* Escaped character */ | |
407 str++; /* Preserve the quoted character */ | |
408 sm = 1; /* Go back to gathering state */ | |
409 break; | |
410 | |
411 case 3: /* Inside single quoted string */ | |
412 if (*str == '\'') | |
413 sm = 1; | |
414 str++; | |
415 break; | |
416 | |
417 case 4: /* inside double quoted string */ | |
418 if (*str == '"') | |
419 sm = 1; | |
420 str++; | |
421 break; | |
422 } | |
423 } | |
424 | |
425 if (s != (CONST char *)0) | |
426 { | |
427 int l = str-s; | |
428 exec_argv[real_argc] = xnew (l+2, char); | |
429 strncpy (exec_argv[real_argc], s, l); | |
430 exec_argv[real_argc][l] = '\0'; | |
431 real_argc++; | |
432 s = (CONST char *)0; | |
433 } | |
434 } | |
435 | |
436 /* | |
437 * For compile mode, things are pretty straight forward. All we need to do | |
438 * is build up the argument vector and exec() it. We must just make sure | |
439 * that we get all of the required arguments in place. | |
440 */ | |
441 static void | |
442 do_compile_mode (void) | |
443 { | |
444 int i; | |
445 char ts[4096]; /* Plenty big enough */ | |
446 | |
447 add_to_argv (ellcc); | |
448 add_to_argv (ellcflags); | |
449 add_to_argv (ellpicflags); | |
450 add_to_argv ("-DPIC"); | |
451 add_to_argv ("-DEMACS_MODULE"); | |
452 #ifdef XEMACS | |
453 add_to_argv ("-DXEMACS_MODULE"); /* Cover both cases */ | |
454 add_to_argv ("-Dxemacs"); | |
455 #endif | |
456 add_to_argv ("-Demacs"); | |
457 sprintf (ts, "-I%s/include", ELLCC_ARCHDIR); | |
458 add_to_argv (ts); | |
459 add_to_argv (ELLCC_CF_ALL); | |
460 for (i = 1; i < exec_argc; i++) | |
461 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]); | |
462 } | |
463 | |
464 /* | |
465 * For link mode, things are a little bit more complicated. We need to | |
466 * insert the linker commands first, replace any occurrence of ELLSONAME | |
467 * with the desired output file name, insert the output arguments, then | |
468 * all of the provided arguments, then the final post arguments. Once | |
469 * all of this has been done, the argument vector is ready to run. | |
470 */ | |
471 static void | |
472 do_link_mode (void) | |
473 { | |
474 int i,x; | |
475 char *t, ts[4096]; /* Plenty big enough */ | |
476 | |
477 add_to_argv (ellld); | |
478 add_to_argv (ellldflags); | |
479 add_to_argv (elldllflags); | |
480 add_to_argv (ELLCC_DLL_LDO); | |
481 add_to_argv (mod_output); | |
482 for (i = 1; i < exec_argc; i++) | |
483 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]); | |
484 add_to_argv (ELLCC_DLL_POST); | |
485 | |
486 /* | |
487 * Now go through each argument and replace ELLSONAME with mod_output. | |
488 */ | |
489 for (i = 0; i < real_argc; i++) | |
490 { | |
491 x = 0; | |
492 ts[0] = '\0'; | |
493 | |
494 t = exec_argv[i]; | |
495 while (*t) | |
496 { | |
497 if (*t == 'E') | |
498 { | |
499 if (strncmp (t, "ELLSONAME", 9) == 0) | |
500 { | |
501 strcat (ts, mod_output); | |
502 t += 8; | |
503 x += strlen (mod_output); | |
504 } | |
505 else | |
506 { | |
507 ts[x] = *t; | |
508 x++; | |
509 ts[x] = '\0'; | |
510 } | |
511 } | |
512 else | |
513 { | |
514 ts[x] = *t; | |
515 x++; | |
516 ts[x] = '\0'; | |
517 } | |
518 t++; | |
519 } | |
520 free (exec_argv[i]); | |
521 exec_argv[i] = strdup (ts); | |
522 } | |
523 } | |
524 | |
525 /* | |
526 * In init mode, things are a bit easier. We assume that the only things | |
527 * passed on the command line are the names of source files which the | |
528 * make-doc program will be processing. We prepare the output file with | |
529 * the header information first, as make-doc will append to the file by | |
530 * special dispensation. | |
531 */ | |
532 static void | |
533 do_init_mode (void) | |
534 { | |
535 int i; | |
536 char ts[4096]; /* Plenty big enough */ | |
537 char *mdocprog; | |
538 FILE *mout = fopen (mod_output, "w"); | |
539 | |
540 if (mout == (FILE *)0) | |
541 fatal ("failed to open output file", mod_output); | |
542 fprintf (mout, "/* DO NOT EDIT - AUTOMATICALLY GENERATED */\n\n"); | |
543 fprintf (mout, "#include <emodules.h>\n\n"); | |
544 fprintf (mout, "const long emodule_compiler = %ld;\n", EMODULES_REVISION); | |
545 fprintf (mout, "const char *emodule_name = \"%s\";\n", SSTR(mod_name)); | |
546 fprintf (mout, "const char *emodule_version = \"%s\";\n", SSTR(mod_version)); | |
547 fprintf (mout, "const char *emodule_title = \"%s\";\n", SSTR(mod_title)); | |
548 fprintf (mout, "\n\n"); | |
549 fprintf (mout, "void docs_of_%s()\n", SSTR(mod_name)); | |
550 fclose (mout); | |
551 | |
552 sprintf (ts, "%s/make-docfile", ELLCC_ARCHDIR); | |
553 OVERENV(mdocprog, "ELLMAKEDOC", ts); | |
554 add_to_argv (mdocprog); | |
555 sprintf (ts, "-E %s", mod_output); | |
556 add_to_argv (ts); | |
557 for (i = 1; i < exec_argc; i++) | |
558 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]); | |
559 } | |
560 | |
561 #endif /* HAVE_SHLIB */ | |
562 |