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.
67 #include <sys/types.h>
71 #endif /* HAVE_UNISTD_H */
73 #define EMODULES_GATHER_VERSION
76 #include <ellcc.h> /* Generated files must be included using <...> */
82 main (int argc, char *argv[])
84 fprintf (stderr, "Dynamic modules not supported on this platform\n");
90 * Try to figure out the commands we need to use to create shared objects,
91 * and how to compile for PIC mode.
95 * xnew, xrnew -- allocate, reallocate storage
97 * SYNOPSIS: Type *xnew (int n, Type);
98 * Type *xrnew (OldPointer, int n, Type);
101 # include "chkmalloc.h"
102 # define xnew(n,Type) ((Type *) trace_malloc (__FILE__, __LINE__, \
103 (n) * sizeof (Type)))
104 # define xrnew(op,n,Type) ((Type *) trace_realloc (__FILE__, __LINE__, \
105 (op), (n) * sizeof (Type)))
107 # define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
108 # define xrnew(op,n,Type) ((Type *) xrealloc ((op), (n) * sizeof (Type)))
110 static void *xmalloc (size_t);
111 static void fatal (char *, char *);
112 static void add_to_argv (const char *);
113 static void do_compile_mode (void);
114 static void do_link_mode (void);
115 static void do_init_mode (void);
117 #define SSTR(S) ((S)?(S):"")
119 #define ELLCC_COMPILE_MODE 0
120 #define ELLCC_LINK_MODE 1
121 #define ELLCC_INIT_MODE 2
123 int ellcc_mode = ELLCC_COMPILE_MODE;
125 char *mod_name = (char *)0, *mod_version = (char *)0, *mod_title = (char *)0;
126 char *mod_output = (char *)0;
129 int exec_argc = 1, *exec_args;
135 * We allow the user to over-ride things in the environment
137 char *ellcc, *ellld, *ellcflags, *ellldflags, *ellpicflags, *elldllflags;
138 #define OVERENV(STR,EVAR,DFLT) \
139 STR = getenv(EVAR); \
140 if ((STR) == (char *)0) \
144 main (int argc, char *argv[])
147 int i, done_mode = 0;
152 #if defined(MSDOS) || defined(WINDOWSNT)
153 tmp = strrchr (argv[0], '\\');
154 if (tmp != (char *)0)
157 tmp = strrchr (argv[0], '/');
158 if (tmp != (char *)0)
164 if (tmp != (char *)0)
169 tmp = &progname[strlen(progname)-2];
170 if (strcmp (tmp, "cc") == 0)
171 ellcc_mode = ELLCC_COMPILE_MODE;
172 else if (strcmp (tmp, "ld") == 0)
173 ellcc_mode = ELLCC_LINK_MODE;
174 else if (strcmp (tmp, "it") == 0)
175 ellcc_mode = ELLCC_INIT_MODE;
177 exec_argv = xnew(argc + 20, char *);
178 exec_args = xnew(argc, int);
179 for (i = 0; i < argc; i++)
183 fatal ("too few arguments", (char *)0);
187 for (i = 1; i < argc; i++)
189 if (strncmp (argv[i], "--mode=", 7) == 0)
191 char *modeopt = argv[i] + 7;
193 if (done_mode && strcmp (modeopt, "verbose"))
194 fatal ("more than one mode specified", (char *) 0);
195 if (strcmp (modeopt, "link") == 0)
198 ellcc_mode = ELLCC_LINK_MODE;
200 else if (strcmp (modeopt, "compile") == 0)
203 ellcc_mode = ELLCC_COMPILE_MODE;
205 else if (strcmp (modeopt, "init") == 0)
208 ellcc_mode = ELLCC_INIT_MODE;
210 else if (strcmp (modeopt, "verbose") == 0)
213 else if (strcmp (argv[i], "--mod-location") == 0)
215 printf ("%s\n", ELLCC_MODDIR);
218 else if (strcmp (argv[i], "--mod-site-location") == 0)
220 printf ("%s\n", ELLCC_SITEMODS);
223 else if (strcmp (argv[i], "--mod-archdir") == 0)
225 printf ("%s\n", ELLCC_ARCHDIR);
228 else if (strcmp (argv[i], "--mod-config") == 0)
230 printf ("%s\n", ELLCC_CONFIG);
233 else if (strncmp (argv[i], "--mod-name=", 11) == 0)
234 mod_name = argv[i] + 11;
235 else if (strncmp (argv[i], "--mod-title=", 12) == 0)
236 mod_title = argv[i] + 12;
237 else if (strncmp (argv[i], "--mod-version=", 14) == 0)
238 mod_version = argv[i] + 14;
239 else if (strncmp (argv[i], "--mod-output=", 13) == 0)
240 mod_output = argv[i] + 13;
243 exec_args[exec_argc] = i;
248 if (ellcc_mode == ELLCC_LINK_MODE && mod_output == (char *)0)
249 fatal ("must specify --mod-output when linking", (char *)0);
250 if (ellcc_mode == ELLCC_INIT_MODE && mod_output == (char *)0)
251 fatal ("must specify --mod-output when creating init file", (char *)0);
252 if (ellcc_mode == ELLCC_INIT_MODE && mod_name == (char *)0)
253 fatal ("must specify --mod-name when creating init file", (char *)0);
256 * We now have the list of arguments to pass to the compiler or
257 * linker (or to process for doc files). We can do the real work
261 printf ("ellcc driver version %s for EMODULES version %s (%ld)\n",
262 ELLCC_EMACS_VER, EMODULES_VERSION, EMODULES_REVISION);
266 printf (" mode = %d (%s)\n", ellcc_mode,
267 ellcc_mode == ELLCC_COMPILE_MODE ? "compile" :
268 ellcc_mode == ELLCC_LINK_MODE ? "link" : "init");
269 printf (" module_name = \"%s\"\n", SSTR(mod_name));
270 printf (" module_title = \"%s\"\n", SSTR(mod_title));
271 printf (" module_version = \"%s\"\n", SSTR(mod_version));
273 printf (" CC = %s\n", ELLCC_CC);
274 printf (" CFLAGS = %s\n", ELLCC_CFLAGS);
275 printf (" CC PIC flags = %s\n", ELLCC_DLL_CFLAGS);
276 printf (" LD = %s\n", ELLCC_DLL_LD);
277 printf (" LDFLAGS = %s\n", ELLCC_DLL_LDFLAGS);
278 printf (" architecture = %s\n", ELLCC_CONFIG);
279 printf (" Include directory = %s/include\n", ELLCC_ARCHDIR);
285 fatal ("too few arguments", (char *) 0);
288 * Get the over-rides from the environment
290 OVERENV(ellcc, "ELLCC", ELLCC_CC);
291 OVERENV(ellld, "ELLLD", ELLCC_DLL_LD);
292 OVERENV(ellcflags, "ELLCFLAGS", ELLCC_CFLAGS);
293 OVERENV(ellldflags, "ELLLDFLAGS", ELLCC_LDFLAGS);
294 OVERENV(elldllflags, "ELLDLLFLAGS", ELLCC_DLL_LDFLAGS);
295 OVERENV(ellpicflags, "ELLPICFLAGS", ELLCC_DLL_CFLAGS);
297 if (ellcc_mode == ELLCC_COMPILE_MODE)
299 else if (ellcc_mode == ELLCC_LINK_MODE)
305 * The arguments to pass on to the desired program have now been set
306 * up and we can run the program.
310 for (i = 0; i < real_argc; i++)
311 printf ("%s ", exec_argv[i]);
315 exec_argv[real_argc] = (char *)0; /* Terminate argument list */
317 i = execvp (exec_argv[0], exec_argv);
319 printf ("%s exited with status %d\n", exec_argv[0], i);
323 /* Like malloc but get fatal error if memory is exhausted. */
325 xmalloc (size_t size)
327 void *result = malloc (size);
329 fatal ("virtual memory exhausted", (char *)0);
333 /* Print error message and exit. */
335 fatal (char *s1, char *s2)
337 fprintf (stderr, "%s: ", progname);
338 fprintf (stderr, s1, s2);
339 fprintf (stderr, "\n");
344 * Add a string to the argument vector list that will be passed on down
345 * to the compiler or linker. We need to split individual words into
346 * arguments, taking quoting into account. This can get ugly.
349 add_to_argv (const char *str)
352 const char *s = (const char *)0;
354 if ((str == (const char *)0) || (str[0] == '\0'))
361 case 0: /* Start of case - string leading whitespace */
362 if (isspace ((unsigned char) *str))
366 sm = 1; /* Change state to non-whitespace */
367 s = str; /* Mark the start of THIS argument */
371 case 1: /* Non-whitespace character. Mark the start */
372 if (isspace ((unsigned char) *str))
374 /* Reached the end of the argument. Add it. */
376 exec_argv[real_argc] = xnew (l+2, char);
377 strncpy (exec_argv[real_argc], s, l);
378 exec_argv[real_argc][l] = '\0';
380 sm = 0; /* Back to start state */
384 else if (*str == '\\')
386 sm = 2; /* Escaped character */
390 else if (*str == '\'')
392 /* Start of quoted string (single quotes) */
395 else if (*str == '"')
397 /* Start of quoted string (double quotes) */
402 /* This was just a normal character. Advance the pointer. */
407 case 2: /* Escaped character */
408 str++; /* Preserve the quoted character */
409 sm = 1; /* Go back to gathering state */
412 case 3: /* Inside single quoted string */
418 case 4: /* inside double quoted string */
426 if (s != (const char *)0)
429 exec_argv[real_argc] = xnew (l+2, char);
430 strncpy (exec_argv[real_argc], s, l);
431 exec_argv[real_argc][l] = '\0';
438 * For compile mode, things are pretty straight forward. All we need to do
439 * is build up the argument vector and exec() it. We must just make sure
440 * that we get all of the required arguments in place.
443 do_compile_mode (void)
446 char ts[4096]; /* Plenty big enough */
449 add_to_argv (ellcflags);
450 add_to_argv (ellpicflags);
451 add_to_argv ("-DPIC");
452 add_to_argv ("-DEMACS_MODULE");
454 add_to_argv ("-DXEMACS_MODULE"); /* Cover both cases */
455 add_to_argv ("-Dxemacs");
457 add_to_argv ("-Demacs");
458 sprintf (ts, "-I%s/include", ELLCC_ARCHDIR);
460 add_to_argv (ELLCC_CF_ALL);
461 for (i = 1; i < exec_argc; i++)
462 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]);
466 * For link mode, things are a little bit more complicated. We need to
467 * insert the linker commands first, replace any occurrence of ELLSONAME
468 * with the desired output file name, insert the output arguments, then
469 * all of the provided arguments, then the final post arguments. Once
470 * all of this has been done, the argument vector is ready to run.
476 char *t, ts[4096]; /* Plenty big enough */
479 add_to_argv (ellldflags);
480 add_to_argv (elldllflags);
481 add_to_argv (ELLCC_DLL_LDO);
482 add_to_argv (mod_output);
483 for (i = 1; i < exec_argc; i++)
484 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]);
485 add_to_argv (ELLCC_DLL_POST);
488 * Now go through each argument and replace ELLSONAME with mod_output.
490 for (i = 0; i < real_argc; i++)
500 if (strncmp (t, "ELLSONAME", 9) == 0)
502 strcat (ts, mod_output);
504 x += strlen (mod_output);
522 exec_argv[i] = strdup (ts);
527 * In init mode, things are a bit easier. We assume that the only things
528 * passed on the command line are the names of source files which the
529 * make-doc program will be processing. We prepare the output file with
530 * the header information first, as make-doc will append to the file by
531 * special dispensation.
537 char ts[4096]; /* Plenty big enough */
539 FILE *mout = fopen (mod_output, "w");
541 if (mout == (FILE *)0)
542 fatal ("failed to open output file", mod_output);
543 fprintf (mout, "/* DO NOT EDIT - AUTOMATICALLY GENERATED */\n\n");
544 fprintf (mout, "#include <emodules.h>\n\n");
545 fprintf (mout, "const long emodule_compiler = %ld;\n", EMODULES_REVISION);
546 fprintf (mout, "const char *emodule_name = \"%s\";\n", SSTR(mod_name));
547 fprintf (mout, "const char *emodule_version = \"%s\";\n", SSTR(mod_version));
548 fprintf (mout, "const char *emodule_title = \"%s\";\n", SSTR(mod_title));
549 fprintf (mout, "\n\n");
550 fprintf (mout, "void docs_of_%s()\n", SSTR(mod_name));
553 sprintf (ts, "%s/make-docfile", ELLCC_ARCHDIR);
554 OVERENV(mdocprog, "ELLMAKEDOC", ts);
555 add_to_argv (mdocprog);
556 sprintf (ts, "-E %s", mod_output);
558 for (i = 1; i < exec_argc; i++)
559 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]);
562 #endif /* HAVE_SHLIB */