1 /* ellcc.c - front-end for compiling Emacs modules
2 Copyright (C) 1998, 1999 J. Kean Johnston.
4 This file is part of XEmacs.
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
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
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.
21 Author: J. Kean Johnston (jkj@sco.com).
22 Please mail bugs and suggestions to the XEmacs maintainer.
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
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:
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.
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:
47 make CC=ellcc LD='ellcc --mode=link'
49 The only additional requirement is an entry in the Makefile to produce
50 the module initialization file, which will usually be something along
54 ellcc --mode=init --mod-name=\"$(MODNAME)\" \
55 --mod-title=\"$(MODTITLE)\" --mod-version=\"$(MODVERSION)\" \
58 See the samples for more details.
61 #include <../src/config.h>
67 #include <sys/types.h>
71 #endif /* HAVE_UNISTD_H */
73 #define EMODULES_GATHER_VERSION
81 main (int argc, char *argv[])
83 fprintf (stderr, "Dynamic modules not supported on this platform\n");
89 * Try to figure out the commands we need to use to create shared objects,
90 * and how to compile for PIC mode.
94 * xnew, xrnew -- allocate, reallocate storage
96 * SYNOPSIS: Type *xnew (int n, Type);
97 * Type *xrnew (OldPointer, int n, Type);
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)))
106 # define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
107 # define xrnew(op,n,Type) ((Type *) xrealloc ((op), (n) * sizeof (Type)))
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);
116 #define SSTR(S) ((S)?(S):"")
118 #define ELLCC_COMPILE_MODE 0
119 #define ELLCC_LINK_MODE 1
120 #define ELLCC_INIT_MODE 2
122 int ellcc_mode = ELLCC_COMPILE_MODE;
124 char *mod_name = (char *)0, *mod_version = (char *)0, *mod_title = (char *)0;
125 char *mod_output = (char *)0;
128 int exec_argc = 1, *exec_args;
134 * We allow the user to over-ride things in the environment
136 char *ellcc, *ellld, *ellcflags, *ellldflags, *ellpicflags, *elldllflags;
137 #define OVERENV(STR,EVAR,DFLT) \
138 STR = getenv(EVAR); \
139 if ((STR) == (char *)0) \
143 main (int argc, char *argv[])
146 int i, done_mode = 0;
151 #if defined(MSDOS) || defined(WINDOWSNT)
152 tmp = strrchr (argv[0], '\\');
153 if (tmp != (char *)0)
156 tmp = strrchr (argv[0], '/');
157 if (tmp != (char *)0)
163 if (tmp != (char *)0)
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;
176 exec_argv = xnew(argc + 20, char *);
177 exec_args = xnew(argc, int);
178 for (i = 0; i < argc; i++)
182 fatal ("too few arguments", (char *)0);
186 for (i = 1; i < argc; i++)
188 if (strncmp (argv[i], "--mode=", 7) == 0)
190 char *modeopt = argv[i] + 7;
192 if (done_mode && strcmp (modeopt, "verbose"))
193 fatal ("more than one mode specified", (char *) 0);
194 if (strcmp (modeopt, "link") == 0)
197 ellcc_mode = ELLCC_LINK_MODE;
199 else if (strcmp (modeopt, "compile") == 0)
202 ellcc_mode = ELLCC_COMPILE_MODE;
204 else if (strcmp (modeopt, "init") == 0)
207 ellcc_mode = ELLCC_INIT_MODE;
209 else if (strcmp (modeopt, "verbose") == 0)
212 else if (strcmp (argv[i], "--mod-location") == 0)
214 printf ("%s\n", ELLCC_MODDIR);
217 else if (strcmp (argv[i], "--mod-site-location") == 0)
219 printf ("%s\n", ELLCC_SITEMODS);
222 else if (strcmp (argv[i], "--mod-archdir") == 0)
224 printf ("%s\n", ELLCC_ARCHDIR);
227 else if (strcmp (argv[i], "--mod-config") == 0)
229 printf ("%s\n", ELLCC_CONFIG);
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;
242 exec_args[exec_argc] = i;
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);
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
260 printf ("ellcc driver version %s for EMODULES version %s (%ld)\n",
261 ELLCC_EMACS_VER, EMODULES_VERSION, EMODULES_REVISION);
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));
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);
284 fatal ("too few arguments", (char *) 0);
287 * Get the over-rides from the environment
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);
296 if (ellcc_mode == ELLCC_COMPILE_MODE)
298 else if (ellcc_mode == ELLCC_LINK_MODE)
304 * The arguments to pass on to the desired program have now been set
305 * up and we can run the program.
309 for (i = 0; i < real_argc; i++)
310 printf ("%s ", exec_argv[i]);
314 exec_argv[real_argc] = (char *)0; /* Terminate argument list */
316 i = execvp (exec_argv[0], exec_argv);
318 printf ("%s exited with status %d\n", exec_argv[0], i);
322 /* Like malloc but get fatal error if memory is exhausted. */
324 xmalloc (size_t size)
326 void *result = malloc (size);
328 fatal ("virtual memory exhausted", (char *)0);
332 /* Print error message and exit. */
334 fatal (char *s1, char *s2)
336 fprintf (stderr, "%s: ", progname);
337 fprintf (stderr, s1, s2);
338 fprintf (stderr, "\n");
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.
348 add_to_argv (CONST char *str)
351 CONST char *s = (CONST char *)0;
353 if ((str == (CONST char *)0) || (str[0] == '\0'))
360 case 0: /* Start of case - string leading whitespace */
365 sm = 1; /* Change state to non-whitespace */
366 s = str; /* Mark the start of THIS argument */
370 case 1: /* Non-whitespace character. Mark the start */
373 /* Reached the end of the argument. Add it. */
375 exec_argv[real_argc] = xnew (l+2, char);
376 strncpy (exec_argv[real_argc], s, l);
377 exec_argv[real_argc][l] = '\0';
379 sm = 0; /* Back to start state */
383 else if (*str == '\\')
385 sm = 2; /* Escaped character */
389 else if (*str == '\'')
391 /* Start of quoted string (single quotes) */
394 else if (*str == '"')
396 /* Start of quoted string (double quotes) */
401 /* This was just a normal character. Advance the pointer. */
406 case 2: /* Escaped character */
407 str++; /* Preserve the quoted character */
408 sm = 1; /* Go back to gathering state */
411 case 3: /* Inside single quoted string */
417 case 4: /* inside double quoted string */
425 if (s != (CONST char *)0)
428 exec_argv[real_argc] = xnew (l+2, char);
429 strncpy (exec_argv[real_argc], s, l);
430 exec_argv[real_argc][l] = '\0';
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.
442 do_compile_mode (void)
445 char ts[4096]; /* Plenty big enough */
448 add_to_argv (ellcflags);
449 add_to_argv (ellpicflags);
450 add_to_argv ("-DPIC");
451 add_to_argv ("-DEMACS_MODULE");
453 add_to_argv ("-DXEMACS_MODULE"); /* Cover both cases */
454 add_to_argv ("-Dxemacs");
456 add_to_argv ("-Demacs");
457 sprintf (ts, "-I%s/include", ELLCC_ARCHDIR);
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]]);
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.
475 char *t, ts[4096]; /* Plenty big enough */
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);
487 * Now go through each argument and replace ELLSONAME with mod_output.
489 for (i = 0; i < real_argc; i++)
499 if (strncmp (t, "ELLSONAME", 9) == 0)
501 strcat (ts, mod_output);
503 x += strlen (mod_output);
521 exec_argv[i] = strdup (ts);
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.
536 char ts[4096]; /* Plenty big enough */
538 FILE *mout = fopen (mod_output, "w");
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));
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);
557 for (i = 1; i < exec_argc; i++)
558 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]);
561 #endif /* HAVE_SHLIB */