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 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
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.
66 # include <sys/param.h>
68 # ifndef HAVE_CONFIG_H
70 # include <sys/config.h>
79 # define MAXPATHLEN _MAX_PATH
85 # endif /* not HAVE_CONFIG_H */
86 #endif /* WINDOWSNT */
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. */
93 #endif /* HAVE_CONFIG_H */
95 #if !defined (WINDOWSNT) && defined (STDC_HEADERS)
104 extern char *getcwd ();
106 #endif /* HAVE_UNISTD_H */
114 #include <sys/types.h>
115 #include <sys/stat.h>
117 #define EMODULES_GATHER_VERSION
118 #include "emodules.h"
121 #if !defined (S_ISREG) && defined (S_IFREG)
122 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
125 /* Exit codes for success and failure. */
140 fprintf (stderr, "Dynamic modules not supported on this platform\n");
146 * Try to figure out the commands we need to use to create shared objects,
147 * and how to compile for PIC mode.
151 * xnew, xrnew -- allocate, reallocate storage
153 * SYNOPSIS: Type *xnew (int n, Type);
154 * Type *xrnew (OldPointer, int n, Type);
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)))
163 # define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
164 # define xrnew(op,n,Type) ((Type *) xrealloc ((op), (n) * sizeof (Type)))
166 long *xmalloc (), *xrealloc ();
167 void fatal (), pfatal ();
168 char *ellcc_strchr (), *ellcc_strrchr ();
170 void do_compile_mode(), do_link_mode(), do_init_mode();
172 #define SSTR(S) ((S)?(S):"")
174 #define ELLCC_COMPILE_MODE 0
175 #define ELLCC_LINK_MODE 1
176 #define ELLCC_INIT_MODE 2
178 int ellcc_mode = ELLCC_COMPILE_MODE;
180 char *mod_name = (char *)0, *mod_version = (char *)0, *mod_title = (char *)0;
181 char *mod_output = (char *)0;
184 int exec_argc = 1, *exec_args;
190 * We allow the user to over-ride things in the environment
192 char *ellcc, *ellld, *ellcflags, *ellldflags, *ellpicflags, *elldllflags;
193 #define OVERENV(STR,EVAR,DFLT) \
194 STR = getenv(EVAR); \
195 if ((STR) == (char *)0) \
204 int i, done_mode = 0;
209 #if defined(MSDOS) || defined(WINDOWSNT)
210 tmp = ellcc_strrchr (argv[0], '\\');
211 if (tmp != (char *)0)
214 tmp = ellcc_strrchr (argv[0], '/');
215 if (tmp != (char *)0)
221 if (tmp != (char *)0)
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;
234 exec_argv = xnew(argc + 20, char *);
235 exec_args = xnew(argc, int);
236 for (i = 0; i < argc; i++)
240 fatal ("too few arguments", (char *)0);
244 for (i = 1; i < argc; i++)
246 if (strncmp (argv[i], "--mode=", 7) == 0)
248 char *modeopt = argv[i] + 7;
250 if (done_mode && strcmp (modeopt, "verbose"))
251 fatal ("more than one mode specified");
252 if (strcmp (modeopt, "link") == 0)
255 ellcc_mode = ELLCC_LINK_MODE;
257 else if (strcmp (modeopt, "compile") == 0)
260 ellcc_mode = ELLCC_COMPILE_MODE;
262 else if (strcmp (modeopt, "init") == 0)
265 ellcc_mode = ELLCC_INIT_MODE;
267 else if (strcmp (modeopt, "verbose") == 0)
270 else if (strcmp (argv[i], "--mod-location") == 0)
272 printf ("%s\n", ELLCC_MODDIR);
275 else if (strcmp (argv[i], "--mod-site-location") == 0)
277 printf ("%s\n", ELLCC_SITEMODS);
280 else if (strcmp (argv[i], "--mod-archdir") == 0)
282 printf ("%s\n", ELLCC_ARCHDIR);
285 else if (strcmp (argv[i], "--mod-config") == 0)
287 printf ("%s\n", ELLCC_CONFIG);
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;
300 exec_args[exec_argc] = i;
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);
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
318 printf ("ellcc driver version %s for EMODULES version %s (%ld)\n",
319 ELLCC_EMACS_VER, EMODULES_VERSION, EMODULES_REVISION);
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));
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);
342 fatal ("too few arguments");
345 * Get the over-rides from the environment
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);
354 if (ellcc_mode == ELLCC_COMPILE_MODE)
356 else if (ellcc_mode == ELLCC_LINK_MODE)
362 * The arguments to pass on to the desired program have now been set
363 * up and we can run the program.
367 for (i = 0; i < real_argc; i++)
368 printf ("%s ", exec_argv[i]);
372 exec_argv[real_argc] = (char *)0; /* Terminate argument list */
374 i = execvp (exec_argv[0], exec_argv);
376 printf ("%s exited with status %d\n", exec_argv[0], i);
380 /* Like malloc but get fatal error if memory is exhausted. */
385 long *result = (long *) malloc (size);
387 fatal ("virtual memory exhausted", (char *)NULL);
396 long *result = (long *) realloc (ptr, size);
398 fatal ("virtual memory exhausted", (char *)NULL);
402 /* Print error message and exit. */
407 fprintf (stderr, "%s: ", progname);
408 fprintf (stderr, s1, s2);
409 fprintf (stderr, "\n");
422 * Return the ptr in sp at which the character c last
423 * appears; NULL if not found
425 * Identical to System V strrchr, included for portability.
428 ellcc_strrchr (sp, c)
429 register char *sp, c;
443 * Return the ptr in sp at which the character c first
444 * appears; NULL if not found
446 * Identical to System V strchr, included for portability.
450 register char *sp, c;
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.
470 CONST char *s = (CONST char *)0;
472 if ((str == (CONST char *)0) || (str[0] == '\0'))
479 case 0: /* Start of case - string leading whitespace */
484 sm = 1; /* Change state to non-whitespace */
485 s = str; /* Mark the start of THIS argument */
489 case 1: /* Non-whitespace character. Mark the start */
492 /* Reached the end of the argument. Add it. */
494 exec_argv[real_argc] = xnew (l+2, char);
495 strncpy (exec_argv[real_argc], s, l);
496 exec_argv[real_argc][l] = '\0';
498 sm = 0; /* Back to start state */
502 else if (*str == '\\')
504 sm = 2; /* Escaped character */
508 else if (*str == '\'')
510 /* Start of quoted string (single quotes) */
513 else if (*str == '"')
515 /* Start of quoted string (double quotes) */
520 /* This was just a normal character. Advance the pointer. */
525 case 2: /* Escaped character */
526 str++; /* Preserve the quoted character */
527 sm = 1; /* Go back to gathering state */
530 case 3: /* Inside single quoted string */
536 case 4: /* inside double quoted string */
544 if (s != (CONST char *)0)
547 exec_argv[real_argc] = xnew (l+2, char);
548 strncpy (exec_argv[real_argc], s, l);
549 exec_argv[real_argc][l] = '\0';
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.
564 char ts[4096]; /* Plenty big enough */
567 add_to_argv (ellcflags);
568 add_to_argv (ellpicflags);
569 add_to_argv ("-DPIC");
570 add_to_argv ("-DEMACS_MODULE");
572 add_to_argv ("-DXEMACS_MODULE"); /* Cover both cases */
573 add_to_argv ("-Dxemacs");
575 add_to_argv ("-Demacs");
576 sprintf (ts, "-I%s/include", ELLCC_ARCHDIR);
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]]);
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.
594 char *t, ts[4096]; /* Plenty big enough */
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);
606 * Now go through each argument and replace ELLSONAME with mod_output.
608 for (i = 0; i < real_argc; i++)
618 if (strncmp (t, "ELLSONAME", 9) == 0)
620 strcat (ts, mod_output);
622 x += strlen (mod_output);
640 exec_argv[i] = strdup (ts);
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.
655 char ts[4096]; /* Plenty big enough */
657 FILE *mout = fopen (mod_output, "w");
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));
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);
676 for (i = 1; i < exec_argc; i++)
677 exec_argv[real_argc++] = strdup (prog_argv[exec_args[i]]);
680 #endif /* HAVE_SHLIB */