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.
68 #include <sys/types.h>
72 #endif /* HAVE_UNISTD_H */
74 #define EMODULES_GATHER_VERSION
77 #include <ellcc.h> /* Generated files must be included using <...> */
83 main (int argc, char *argv[])
85 fprintf (stderr, "Dynamic modules not supported on this platform\n");
91 * Try to figure out the commands we need to use to create shared objects,
92 * and how to compile for PIC mode.
96 * xnew, xrnew -- allocate, reallocate storage
98 * SYNOPSIS: Type *xnew (int n, Type);
99 * Type *xrnew (OldPointer, int n, Type);
102 # include "chkmalloc.h"
103 # define xnew(n,Type) ((Type *) trace_malloc (__FILE__, __LINE__, \
104 (n) * sizeof (Type)))
105 # define xrnew(op,n,Type) ((Type *) trace_realloc (__FILE__, __LINE__, \
106 (op), (n) * sizeof (Type)))
108 # define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
109 # define xrnew(op,n,Type) ((Type *) xrealloc ((op), (n) * sizeof (Type)))
111 static void *xmalloc (size_t);
112 static void fatal (char *, char *);
113 static void add_to_argv (const char *);
114 static void do_compile_mode (void);
115 static void do_link_mode (void);
116 static void do_init_mode (void);
118 #define SSTR(S) ((S)?(S):"")
120 #define ELLCC_COMPILE_MODE 0
121 #define ELLCC_LINK_MODE 1
122 #define ELLCC_INIT_MODE 2
124 static int ellcc_mode = ELLCC_COMPILE_MODE;
125 static char *progname;
126 static char *mod_name = NULL;
127 static char *mod_version = NULL;
128 static char *mod_title = NULL;
129 static char *mod_output = NULL;
130 static int verbose = 0;
131 static char **exec_argv;
132 static int exec_argc = 1;
133 static int *exec_args;
134 static int real_argc = 0;
135 static int prog_argc;
136 static char **prog_argv;
139 * We allow the user to over-ride things in the environment
141 char *ellcc, *ellld, *ellcflags, *ellldflags, *ellpicflags, *elldllflags;
142 #define OVERENV(STR,EVAR,DFLT) \
143 STR = getenv(EVAR); \
144 if ((STR) == (char *)0) \
148 main (int argc, char *argv[])
151 int i, done_mode = 0;
156 #if defined(WIN32_NATIVE)
157 tmp = strrchr (argv[0], '\\');
158 if (tmp != (char *)0)
161 tmp = strrchr (argv[0], '/');
162 if (tmp != (char *)0)
168 if (tmp != (char *)0)
173 tmp = &progname[strlen(progname)-2];
174 if (strcmp (tmp, "cc") == 0)
175 ellcc_mode = ELLCC_COMPILE_MODE;
176 else if (strcmp (tmp, "ld") == 0)
177 ellcc_mode = ELLCC_LINK_MODE;
178 else if (strcmp (tmp, "it") == 0)
179 ellcc_mode = ELLCC_INIT_MODE;
181 exec_argv = xnew(argc + 20, char *);
182 exec_args = xnew(argc, int);
183 for (i = 0; i < argc; i++)
187 fatal ("too few arguments", (char *)0);
191 for (i = 1; i < argc; i++)
193 if (strncmp (argv[i], "--mode=", 7) == 0)
195 char *modeopt = argv[i] + 7;
197 if (done_mode && strcmp (modeopt, "verbose"))
198 fatal ("more than one mode specified", (char *) 0);
199 if (strcmp (modeopt, "link") == 0)
202 ellcc_mode = ELLCC_LINK_MODE;
204 else if (strcmp (modeopt, "compile") == 0)
207 ellcc_mode = ELLCC_COMPILE_MODE;
209 else if (strcmp (modeopt, "init") == 0)
212 ellcc_mode = ELLCC_INIT_MODE;
214 else if (strcmp (modeopt, "verbose") == 0)
217 else if (strcmp (argv[i], "--mod-location") == 0)
219 printf ("%s\n", ELLCC_MODDIR);
222 else if (strcmp (argv[i], "--mod-site-location") == 0)
224 printf ("%s\n", ELLCC_SITEMODS);
227 else if (strcmp (argv[i], "--mod-archdir") == 0)
229 printf ("%s\n", ELLCC_ARCHDIR);
232 else if (strcmp (argv[i], "--mod-config") == 0)
234 printf ("%s\n", ELLCC_CONFIG);
237 else if (strncmp (argv[i], "--mod-name=", 11) == 0)
238 mod_name = argv[i] + 11;
239 else if (strncmp (argv[i], "--mod-title=", 12) == 0)
240 mod_title = argv[i] + 12;
241 else if (strncmp (argv[i], "--mod-version=", 14) == 0)
242 mod_version = argv[i] + 14;
243 else if (strncmp (argv[i], "--mod-output=", 13) == 0)
244 mod_output = argv[i] + 13;
247 exec_args[exec_argc] = i;
252 if (ellcc_mode == ELLCC_LINK_MODE && mod_output == (char *)0)
253 fatal ("must specify --mod-output when linking", (char *)0);
254 if (ellcc_mode == ELLCC_INIT_MODE && mod_output == (char *)0)
255 fatal ("must specify --mod-output when creating init file", (char *)0);
256 if (ellcc_mode == ELLCC_INIT_MODE && mod_name == (char *)0)
257 fatal ("must specify --mod-name when creating init file", (char *)0);
260 * We now have the list of arguments to pass to the compiler or
261 * linker (or to process for doc files). We can do the real work
265 printf ("ellcc driver version %s for EMODULES version %s (%ld)\n",
266 ELLCC_EMACS_VER, EMODULES_VERSION, EMODULES_REVISION);
270 printf (" mode = %d (%s)\n", ellcc_mode,
271 ellcc_mode == ELLCC_COMPILE_MODE ? "compile" :
272 ellcc_mode == ELLCC_LINK_MODE ? "link" : "init");
273 printf (" module_name = \"%s\"\n", SSTR(mod_name));
274 printf (" module_title = \"%s\"\n", SSTR(mod_title));
275 printf (" module_version = \"%s\"\n", SSTR(mod_version));
277 printf (" CC = %s\n", ELLCC_CC);
278 printf (" CFLAGS = %s\n", ELLCC_CFLAGS);
279 printf (" CC PIC flags = %s\n", ELLCC_DLL_CFLAGS);
280 printf (" LD = %s\n", ELLCC_DLL_LD);
281 printf (" LDFLAGS = %s\n", ELLCC_DLL_LDFLAGS);
282 printf (" architecture = %s\n", ELLCC_CONFIG);
283 printf (" Include directory = %s/include\n", ELLCC_ARCHDIR);
289 fatal ("too few arguments", (char *) 0);
292 * Get the over-rides from the environment
294 OVERENV(ellcc, "ELLCC", ELLCC_CC);
295 OVERENV(ellld, "ELLLD", ELLCC_DLL_LD);
296 OVERENV(ellcflags, "ELLCFLAGS", ELLCC_CFLAGS);
297 OVERENV(ellldflags, "ELLLDFLAGS", ELLCC_LDFLAGS);
298 OVERENV(elldllflags, "ELLDLLFLAGS", ELLCC_DLL_LDFLAGS);
299 OVERENV(ellpicflags, "ELLPICFLAGS", ELLCC_DLL_CFLAGS);
301 if (ellcc_mode == ELLCC_COMPILE_MODE)
303 else if (ellcc_mode == ELLCC_LINK_MODE)
309 * The arguments to pass on to the desired program have now been set
310 * up and we can run the program.
314 for (i = 0; i < real_argc; i++)
315 printf ("%s ", exec_argv[i]);
319 exec_argv[real_argc] = (char *)0; /* Terminate argument list */
321 i = execvp (exec_argv[0], exec_argv);
323 printf ("%s exited with status %d\n", exec_argv[0], i);
327 /* Like malloc but get fatal error if memory is exhausted. */
329 xmalloc (size_t size)
331 void *result = malloc (size);
333 fatal ("virtual memory exhausted", (char *)0);
337 /* Print error message and exit. */
339 fatal (char *s1, char *s2)
341 fprintf (stderr, "%s: ", progname);
342 fprintf (stderr, s1, s2);
343 fprintf (stderr, "\n");
348 * Add a string to the argument vector list that will be passed on down
349 * to the compiler or linker. We need to split individual words into
350 * arguments, taking quoting into account. This can get ugly.
353 add_to_argv (const char *str)
356 const char *s = (const char *)0;
358 if ((str == (const char *)0) || (str[0] == '\0'))
365 case 0: /* Start of case - string leading whitespace */
366 if (isspace ((unsigned char) *str))
370 sm = 1; /* Change state to non-whitespace */
371 s = str; /* Mark the start of THIS argument */
375 case 1: /* Non-whitespace character. Mark the start */
376 if (isspace ((unsigned char) *str))
378 /* Reached the end of the argument. Add it. */
380 exec_argv[real_argc] = xnew (l+2, char);
381 strncpy (exec_argv[real_argc], s, l);
382 exec_argv[real_argc][l] = '\0';
384 sm = 0; /* Back to start state */
388 else if (*str == '\\')
390 sm = 2; /* Escaped character */
394 else if (*str == '\'')
396 /* Start of quoted string (single quotes) */
399 else if (*str == '"')
401 /* Start of quoted string (double quotes) */
406 /* This was just a normal character. Advance the pointer. */
411 case 2: /* Escaped character */
412 str++; /* Preserve the quoted character */
413 sm = 1; /* Go back to gathering state */
416 case 3: /* Inside single quoted string */
422 case 4: /* inside double quoted string */
430 if (s != (const char *)0)
433 exec_argv[real_argc] = xnew (l+2, char);
434 strncpy (exec_argv[real_argc], s, l);
435 exec_argv[real_argc][l] = '\0';
442 * For compile mode, things are pretty straight forward. All we need to do
443 * is build up the argument vector and exec() it. We must just make sure
444 * that we get all of the required arguments in place.
447 do_compile_mode (void)
450 char ts[4096]; /* Plenty big enough */
453 add_to_argv (ellcflags);
454 add_to_argv (ellpicflags);
455 add_to_argv ("-DPIC");
456 add_to_argv ("-DEMACS_MODULE");
458 add_to_argv ("-DXEMACS_MODULE"); /* Cover both cases */
459 add_to_argv ("-Dxemacs");
461 add_to_argv ("-Demacs");
462 sprintf (ts, "-I%s/include", ELLCC_ARCHDIR);
464 add_to_argv (ELLCC_CF_ALL);
465 for (i = 1; i < exec_argc; i++)
466 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]);
470 * For link mode, things are a little bit more complicated. We need to
471 * insert the linker commands first, replace any occurrence of ELLSONAME
472 * with the desired output file name, insert the output arguments, then
473 * all of the provided arguments, then the final post arguments. Once
474 * all of this has been done, the argument vector is ready to run.
480 char *t, ts[4096]; /* Plenty big enough */
483 add_to_argv (ellldflags);
484 add_to_argv (elldllflags);
485 add_to_argv (ELLCC_DLL_LDO);
486 add_to_argv (mod_output);
487 for (i = 1; i < exec_argc; i++)
488 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]);
489 add_to_argv (ELLCC_DLL_POST);
492 * Now go through each argument and replace ELLSONAME with mod_output.
494 for (i = 0; i < real_argc; i++)
504 if (strncmp (t, "ELLSONAME", 9) == 0)
506 strcat (ts, mod_output);
508 x += strlen (mod_output);
526 exec_argv[i] = strdup (ts);
531 * In init mode, things are a bit easier. We assume that the only things
532 * passed on the command line are the names of source files which the
533 * make-doc program will be processing. We prepare the output file with
534 * the header information first, as make-doc will append to the file by
535 * special dispensation.
541 char ts[4096]; /* Plenty big enough */
543 FILE *mout = fopen (mod_output, "w");
545 if (mout == (FILE *)0)
546 fatal ("failed to open output file", mod_output);
547 fprintf (mout, "/* DO NOT EDIT - AUTOMATICALLY GENERATED */\n\n");
548 fprintf (mout, "#include <emodules.h>\n\n");
549 fprintf (mout, "const long emodule_compiler = %ld;\n", EMODULES_REVISION);
550 fprintf (mout, "const char *emodule_name = \"%s\";\n", SSTR(mod_name));
551 fprintf (mout, "const char *emodule_version = \"%s\";\n", SSTR(mod_version));
552 fprintf (mout, "const char *emodule_title = \"%s\";\n", SSTR(mod_title));
553 fprintf (mout, "\n\n");
554 fprintf (mout, "void docs_of_%s()\n", SSTR(mod_name));
557 sprintf (ts, "%s/make-docfile", ELLCC_ARCHDIR);
558 OVERENV(mdocprog, "ELLMAKEDOC", ts);
559 add_to_argv (mdocprog);
560 sprintf (ts, "-E %s", mod_output);
562 for (i = 1; i < exec_argc; i++)
563 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]);
566 #endif /* HAVE_SHLIB */