1 /*
2  * QuickJS command line compiler
3  *
4  * Copyright (c) 2018-2020 Fabrice Bellard
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <inttypes.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #if !defined(_WIN32)
33 #include <sys/wait.h>
34 #endif
35 
36 #include "cutils.h"
37 #include "quickjs-libc.h"
38 
39 typedef struct {
40     char *name;
41     char *short_name;
42     int flags;
43 } namelist_entry_t;
44 
45 typedef struct namelist_t {
46     namelist_entry_t *array;
47     int count;
48     int size;
49 } namelist_t;
50 
51 typedef struct {
52     const char *option_name;
53     const char *init_name;
54 } FeatureEntry;
55 
56 static namelist_t cname_list;
57 static namelist_t cmodule_list;
58 static namelist_t init_module_list;
59 static uint64_t feature_bitmap;
60 static FILE *outfile;
61 static BOOL byte_swap;
62 static BOOL dynamic_export;
63 static const char *c_ident_prefix = "qjsc_";
64 
65 #define FE_ALL (-1)
66 
67 static const FeatureEntry feature_list[] = {
68     { "date", "Date" },
69     { "eval", "Eval" },
70     { "string-normalize", "StringNormalize" },
71     { "regexp", "RegExp" },
72     { "json", "JSON" },
73     { "proxy", "Proxy" },
74     { "map", "MapSet" },
75     { "typedarray", "TypedArrays" },
76     { "promise", "Promise" },
77 #define FE_MODULE_LOADER 9
78     { "module-loader", NULL },
79 #ifdef CONFIG_BIGNUM
80     { "bigint", "BigInt" },
81 #endif
82 };
83 
namelist_add(namelist_t * lp,const char * name,const char * short_name,int flags)84 void namelist_add(namelist_t *lp, const char *name, const char *short_name,
85                   int flags)
86 {
87     namelist_entry_t *e;
88     if (lp->count == lp->size) {
89         size_t newsize = lp->size + (lp->size >> 1) + 4;
90         namelist_entry_t *a =
91             realloc(lp->array, sizeof(lp->array[0]) * newsize);
92         /* XXX: check for realloc failure */
93         lp->array = a;
94         lp->size = newsize;
95     }
96     e =  &lp->array[lp->count++];
97     e->name = strdup(name);
98     if (short_name)
99         e->short_name = strdup(short_name);
100     else
101         e->short_name = NULL;
102     e->flags = flags;
103 }
104 
namelist_free(namelist_t * lp)105 void namelist_free(namelist_t *lp)
106 {
107     while (lp->count > 0) {
108         namelist_entry_t *e = &lp->array[--lp->count];
109         free(e->name);
110         free(e->short_name);
111     }
112     free(lp->array);
113     lp->array = NULL;
114     lp->size = 0;
115 }
116 
namelist_find(namelist_t * lp,const char * name)117 namelist_entry_t *namelist_find(namelist_t *lp, const char *name)
118 {
119     int i;
120     for(i = 0; i < lp->count; i++) {
121         namelist_entry_t *e = &lp->array[i];
122         if (!strcmp(e->name, name))
123             return e;
124     }
125     return NULL;
126 }
127 
get_c_name(char * buf,size_t buf_size,const char * file)128 static void get_c_name(char *buf, size_t buf_size, const char *file)
129 {
130     const char *p, *r;
131     size_t len, i;
132     int c;
133     char *q;
134 
135     p = strrchr(file, '/');
136     if (!p)
137         p = file;
138     else
139         p++;
140     r = strrchr(p, '.');
141     if (!r)
142         len = strlen(p);
143     else
144         len = r - p;
145     pstrcpy(buf, buf_size, c_ident_prefix);
146     q = buf + strlen(buf);
147     for(i = 0; i < len; i++) {
148         c = p[i];
149         if (!((c >= '0' && c <= '9') ||
150               (c >= 'A' && c <= 'Z') ||
151               (c >= 'a' && c <= 'z'))) {
152             c = '_';
153         }
154         if ((q - buf) < buf_size - 1)
155             *q++ = c;
156     }
157     *q = '\0';
158 }
159 
dump_hex(FILE * f,const uint8_t * buf,size_t len)160 static void dump_hex(FILE *f, const uint8_t *buf, size_t len)
161 {
162     size_t i, col;
163     col = 0;
164     for(i = 0; i < len; i++) {
165         fprintf(f, " 0x%02x,", buf[i]);
166         if (++col == 8) {
167             fprintf(f, "\n");
168             col = 0;
169         }
170     }
171     if (col != 0)
172         fprintf(f, "\n");
173 }
174 
output_object_code(JSContext * ctx,FILE * fo,JSValueConst obj,const char * c_name,BOOL load_only)175 static void output_object_code(JSContext *ctx,
176                                FILE *fo, JSValueConst obj, const char *c_name,
177                                BOOL load_only)
178 {
179     uint8_t *out_buf;
180     size_t out_buf_len;
181     int flags;
182     flags = JS_WRITE_OBJ_BYTECODE;
183     if (byte_swap)
184         flags |= JS_WRITE_OBJ_BSWAP;
185     out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags);
186     if (!out_buf) {
187         js_std_dump_error(ctx);
188         exit(1);
189     }
190 
191     namelist_add(&cname_list, c_name, NULL, load_only);
192 
193     fprintf(fo, "const uint32_t %s_size = %u;\n\n",
194             c_name, (unsigned int)out_buf_len);
195     fprintf(fo, "const uint8_t %s[%u] = {\n",
196             c_name, (unsigned int)out_buf_len);
197     dump_hex(fo, out_buf, out_buf_len);
198     fprintf(fo, "};\n\n");
199 
200     js_free(ctx, out_buf);
201 }
202 
js_module_dummy_init(JSContext * ctx,JSModuleDef * m)203 static int js_module_dummy_init(JSContext *ctx, JSModuleDef *m)
204 {
205     /* should never be called when compiling JS code */
206     abort();
207 }
208 
find_unique_cname(char * cname,size_t cname_size)209 static void find_unique_cname(char *cname, size_t cname_size)
210 {
211     char cname1[1024];
212     int suffix_num;
213     size_t len, max_len;
214     assert(cname_size >= 32);
215     /* find a C name not matching an existing module C name by
216        adding a numeric suffix */
217     len = strlen(cname);
218     max_len = cname_size - 16;
219     if (len > max_len)
220         cname[max_len] = '\0';
221     suffix_num = 1;
222     for(;;) {
223         snprintf(cname1, sizeof(cname1), "%s_%d", cname, suffix_num);
224         if (!namelist_find(&cname_list, cname1))
225             break;
226         suffix_num++;
227     }
228     pstrcpy(cname, cname_size, cname1);
229 }
230 
jsc_module_loader(JSContext * ctx,const char * module_name,void * opaque)231 JSModuleDef *jsc_module_loader(JSContext *ctx,
232                               const char *module_name, void *opaque)
233 {
234     JSModuleDef *m;
235     namelist_entry_t *e;
236 
237     /* check if it is a declared C or system module */
238     e = namelist_find(&cmodule_list, module_name);
239     if (e) {
240         /* add in the static init module list */
241         namelist_add(&init_module_list, e->name, e->short_name, 0);
242         /* create a dummy module */
243         m = JS_NewCModule(ctx, module_name, js_module_dummy_init);
244     } else if (has_suffix(module_name, ".so")) {
245         fprintf(stderr, "Warning: binary module '%s' will be dynamically loaded\n", module_name);
246         /* create a dummy module */
247         m = JS_NewCModule(ctx, module_name, js_module_dummy_init);
248         /* the resulting executable will export its symbols for the
249            dynamic library */
250         dynamic_export = TRUE;
251     } else {
252         size_t buf_len;
253         uint8_t *buf;
254         JSValue func_val;
255         char cname[1024];
256 
257         buf = js_load_file(ctx, &buf_len, module_name);
258         if (!buf) {
259             JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
260                                    module_name);
261             return NULL;
262         }
263 
264         /* compile the module */
265         func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
266                            JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
267         js_free(ctx, buf);
268         if (JS_IsException(func_val))
269             return NULL;
270         get_c_name(cname, sizeof(cname), module_name);
271         if (namelist_find(&cname_list, cname)) {
272             find_unique_cname(cname, sizeof(cname));
273         }
274         output_object_code(ctx, outfile, func_val, cname, TRUE);
275 
276         /* the module is already referenced, so we must free it */
277         m = JS_VALUE_GET_PTR(func_val);
278         JS_FreeValue(ctx, func_val);
279     }
280     return m;
281 }
282 
compile_file(JSContext * ctx,FILE * fo,const char * filename,const char * c_name1,int module)283 static void compile_file(JSContext *ctx, FILE *fo,
284                          const char *filename,
285                          const char *c_name1,
286                          int module)
287 {
288     uint8_t *buf;
289     char c_name[1024];
290     int eval_flags;
291     JSValue obj;
292     size_t buf_len;
293 
294     buf = js_load_file(ctx, &buf_len, filename);
295     if (!buf) {
296         fprintf(stderr, "Could not load '%s'\n", filename);
297         exit(1);
298     }
299     eval_flags = JS_EVAL_FLAG_COMPILE_ONLY;
300     if (module < 0) {
301         module = (has_suffix(filename, ".mjs") ||
302                   JS_DetectModule((const char *)buf, buf_len));
303     }
304     if (module)
305         eval_flags |= JS_EVAL_TYPE_MODULE;
306     else
307         eval_flags |= JS_EVAL_TYPE_GLOBAL;
308     obj = JS_Eval(ctx, (const char *)buf, buf_len, filename, eval_flags);
309     if (JS_IsException(obj)) {
310         js_std_dump_error(ctx);
311         exit(1);
312     }
313     js_free(ctx, buf);
314     if (c_name1) {
315         pstrcpy(c_name, sizeof(c_name), c_name1);
316     } else {
317         get_c_name(c_name, sizeof(c_name), filename);
318     }
319     output_object_code(ctx, fo, obj, c_name, FALSE);
320     JS_FreeValue(ctx, obj);
321 }
322 
323 static const char main_c_template1[] =
324     "int main(int argc, char **argv)\n"
325     "{\n"
326     "  JSRuntime *rt;\n"
327     "  JSContext *ctx;\n"
328     "  rt = JS_NewRuntime();\n"
329     "  js_std_init_handlers(rt);\n"
330     ;
331 
332 static const char main_c_template2[] =
333     "  js_std_loop(ctx);\n"
334     "  JS_FreeContext(ctx);\n"
335     "  JS_FreeRuntime(rt);\n"
336     "  return 0;\n"
337     "}\n";
338 
339 #define PROG_NAME "qjsc"
340 
help(void)341 void help(void)
342 {
343     printf("QuickJS Compiler version " CONFIG_VERSION "\n"
344            "usage: " PROG_NAME " [options] [files]\n"
345            "\n"
346            "options are:\n"
347            "-c          only output bytecode in a C file\n"
348            "-e          output main() and bytecode in a C file (default = executable output)\n"
349            "-o output   set the output filename\n"
350            "-N cname    set the C name of the generated data\n"
351            "-m          compile as Javascript module (default=autodetect)\n"
352            "-M module_name[,cname] add initialization code for an external C module\n"
353            "-x          byte swapped output\n"
354            "-p prefix   set the prefix of the generated C names\n"
355            "-S n        set the maximum stack size to 'n' bytes (default=%d)\n",
356            JS_DEFAULT_STACK_SIZE);
357 #ifdef CONFIG_LTO
358     {
359         int i;
360         printf("-flto       use link time optimization\n");
361         printf("-fbignum    enable bignum extensions\n");
362         printf("-fno-[");
363         for(i = 0; i < countof(feature_list); i++) {
364             if (i != 0)
365                 printf("|");
366             printf("%s", feature_list[i].option_name);
367         }
368         printf("]\n"
369                "            disable selected language features (smaller code size)\n");
370     }
371 #endif
372     exit(1);
373 }
374 
375 #if defined(CONFIG_CC) && !defined(_WIN32)
376 
exec_cmd(char ** argv)377 int exec_cmd(char **argv)
378 {
379     int pid, status, ret;
380 
381     pid = fork();
382     if (pid == 0) {
383         execvp(argv[0], argv);
384         exit(1);
385     }
386 
387     for(;;) {
388         ret = waitpid(pid, &status, 0);
389         if (ret == pid && WIFEXITED(status))
390             break;
391     }
392     return WEXITSTATUS(status);
393 }
394 
output_executable(const char * out_filename,const char * cfilename,BOOL use_lto,BOOL verbose,const char * exename)395 static int output_executable(const char *out_filename, const char *cfilename,
396                              BOOL use_lto, BOOL verbose, const char *exename)
397 {
398     const char *argv[64];
399     const char **arg, *bn_suffix, *lto_suffix;
400     char libjsname[1024];
401     char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p;
402     int ret;
403 
404     /* get the directory of the executable */
405     pstrcpy(exe_dir, sizeof(exe_dir), exename);
406     p = strrchr(exe_dir, '/');
407     if (p) {
408         *p = '\0';
409     } else {
410         pstrcpy(exe_dir, sizeof(exe_dir), ".");
411     }
412 
413     /* if 'quickjs.h' is present at the same path as the executable, we
414        use it as include and lib directory */
415     snprintf(buf, sizeof(buf), "%s/quickjs.h", exe_dir);
416     if (access(buf, R_OK) == 0) {
417         pstrcpy(inc_dir, sizeof(inc_dir), exe_dir);
418         pstrcpy(lib_dir, sizeof(lib_dir), exe_dir);
419     } else {
420         snprintf(inc_dir, sizeof(inc_dir), "%s/include/quickjs", CONFIG_PREFIX);
421         snprintf(lib_dir, sizeof(lib_dir), "%s/lib/quickjs", CONFIG_PREFIX);
422     }
423 
424     lto_suffix = "";
425     bn_suffix = "";
426 
427     arg = argv;
428     *arg++ = CONFIG_CC;
429     *arg++ = "-O2";
430 #ifdef CONFIG_LTO
431     if (use_lto) {
432         *arg++ = "-flto";
433         lto_suffix = ".lto";
434     }
435 #endif
436     /* XXX: use the executable path to find the includes files and
437        libraries */
438     *arg++ = "-D";
439     *arg++ = "_GNU_SOURCE";
440     *arg++ = "-I";
441     *arg++ = inc_dir;
442     *arg++ = "-o";
443     *arg++ = out_filename;
444     if (dynamic_export)
445         *arg++ = "-rdynamic";
446     *arg++ = cfilename;
447     snprintf(libjsname, sizeof(libjsname), "%s/libquickjs%s%s.a",
448              lib_dir, bn_suffix, lto_suffix);
449     *arg++ = libjsname;
450     *arg++ = "-lm";
451     *arg++ = "-ldl";
452     *arg++ = "-lpthread";
453     *arg = NULL;
454 
455     if (verbose) {
456         for(arg = argv; *arg != NULL; arg++)
457             printf("%s ", *arg);
458         printf("\n");
459     }
460 
461     ret = exec_cmd((char **)argv);
462     unlink(cfilename);
463     return ret;
464 }
465 #else
output_executable(const char * out_filename,const char * cfilename,BOOL use_lto,BOOL verbose,const char * exename)466 static int output_executable(const char *out_filename, const char *cfilename,
467                              BOOL use_lto, BOOL verbose, const char *exename)
468 {
469     fprintf(stderr, "Executable output is not supported for this target\n");
470     exit(1);
471     return 0;
472 }
473 #endif
474 
475 
476 typedef enum {
477     OUTPUT_C,
478     OUTPUT_C_MAIN,
479     OUTPUT_EXECUTABLE,
480 } OutputTypeEnum;
481 
main(int argc,char ** argv)482 int main(int argc, char **argv)
483 {
484     int c, i, verbose;
485     const char *out_filename, *cname;
486     char cfilename[1024];
487     FILE *fo;
488     JSRuntime *rt;
489     JSContext *ctx;
490     BOOL use_lto;
491     int module;
492     OutputTypeEnum output_type;
493     size_t stack_size;
494 #ifdef CONFIG_BIGNUM
495     BOOL bignum_ext = FALSE;
496 #endif
497 
498     out_filename = NULL;
499     output_type = OUTPUT_EXECUTABLE;
500     cname = NULL;
501     feature_bitmap = FE_ALL;
502     module = -1;
503     byte_swap = FALSE;
504     verbose = 0;
505     use_lto = FALSE;
506     stack_size = 0;
507 
508     /* add system modules */
509     namelist_add(&cmodule_list, "std", "std", 0);
510     namelist_add(&cmodule_list, "os", "os", 0);
511 
512     for(;;) {
513         c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:");
514         if (c == -1)
515             break;
516         switch(c) {
517         case 'h':
518             help();
519         case 'o':
520             out_filename = optarg;
521             break;
522         case 'c':
523             output_type = OUTPUT_C;
524             break;
525         case 'e':
526             output_type = OUTPUT_C_MAIN;
527             break;
528         case 'N':
529             cname = optarg;
530             break;
531         case 'f':
532             {
533                 const char *p;
534                 p = optarg;
535                 if (!strcmp(optarg, "lto")) {
536                     use_lto = TRUE;
537                 } else if (strstart(p, "no-", &p)) {
538                     use_lto = TRUE;
539                     for(i = 0; i < countof(feature_list); i++) {
540                         if (!strcmp(p, feature_list[i].option_name)) {
541                             feature_bitmap &= ~((uint64_t)1 << i);
542                             break;
543                         }
544                     }
545                     if (i == countof(feature_list))
546                         goto bad_feature;
547                 } else
548 #ifdef CONFIG_BIGNUM
549                 if (!strcmp(optarg, "bignum")) {
550                     bignum_ext = TRUE;
551                 } else
552 #endif
553                 {
554                 bad_feature:
555                     fprintf(stderr, "unsupported feature: %s\n", optarg);
556                     exit(1);
557                 }
558             }
559             break;
560         case 'm':
561             module = 1;
562             break;
563         case 'M':
564             {
565                 char *p;
566                 char path[1024];
567                 char cname[1024];
568                 pstrcpy(path, sizeof(path), optarg);
569                 p = strchr(path, ',');
570                 if (p) {
571                     *p = '\0';
572                     pstrcpy(cname, sizeof(cname), p + 1);
573                 } else {
574                     get_c_name(cname, sizeof(cname), path);
575                 }
576                 namelist_add(&cmodule_list, path, cname, 0);
577             }
578             break;
579         case 'x':
580             byte_swap = TRUE;
581             break;
582         case 'v':
583             verbose++;
584             break;
585         case 'p':
586             c_ident_prefix = optarg;
587             break;
588         case 'S':
589             stack_size = (size_t)strtod(optarg, NULL);
590             break;
591         default:
592             break;
593         }
594     }
595 
596     if (optind >= argc)
597         help();
598 
599     if (!out_filename) {
600         if (output_type == OUTPUT_EXECUTABLE) {
601             out_filename = "a.out";
602         } else {
603             out_filename = "out.c";
604         }
605     }
606 
607     if (output_type == OUTPUT_EXECUTABLE) {
608 #if defined(_WIN32) || defined(__ANDROID__)
609         /* XXX: find a /tmp directory ? */
610         snprintf(cfilename, sizeof(cfilename), "out%d.c", getpid());
611 #else
612         snprintf(cfilename, sizeof(cfilename), "/tmp/out%d.c", getpid());
613 #endif
614     } else {
615         pstrcpy(cfilename, sizeof(cfilename), out_filename);
616     }
617 
618     fo = fopen(cfilename, "w");
619     if (!fo) {
620         perror(cfilename);
621         exit(1);
622     }
623     outfile = fo;
624 
625     rt = JS_NewRuntime();
626     ctx = JS_NewContext(rt);
627 #ifdef CONFIG_BIGNUM
628     if (bignum_ext) {
629         JS_AddIntrinsicBigFloat(ctx);
630         JS_AddIntrinsicBigDecimal(ctx);
631         JS_AddIntrinsicOperators(ctx);
632         JS_EnableBignumExt(ctx, TRUE);
633     }
634 #endif
635 
636     /* loader for ES6 modules */
637     JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL);
638 
639     fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n"
640             "\n"
641             );
642 
643     if (output_type != OUTPUT_C) {
644         fprintf(fo, "#include \"quickjs-libc.h\"\n"
645                 "\n"
646                 );
647     } else {
648         fprintf(fo, "#include <inttypes.h>\n"
649                 "\n"
650                 );
651     }
652 
653     for(i = optind; i < argc; i++) {
654         const char *filename = argv[i];
655         compile_file(ctx, fo, filename, cname, module);
656         cname = NULL;
657     }
658 
659     if (output_type != OUTPUT_C) {
660         fputs(main_c_template1, fo);
661         fprintf(fo, "  ctx = JS_NewContextRaw(rt);\n");
662 
663         if (stack_size != 0) {
664             fprintf(fo, "  JS_SetMaxStackSize(rt, %u);\n",
665                     (unsigned int)stack_size);
666         }
667 
668         /* add the module loader if necessary */
669         if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
670             fprintf(fo, "  JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
671         }
672 
673         /* add the basic objects */
674 
675         fprintf(fo, "  JS_AddIntrinsicBaseObjects(ctx);\n");
676         for(i = 0; i < countof(feature_list); i++) {
677             if ((feature_bitmap & ((uint64_t)1 << i)) &&
678                 feature_list[i].init_name) {
679                 fprintf(fo, "  JS_AddIntrinsic%s(ctx);\n",
680                         feature_list[i].init_name);
681             }
682         }
683 #ifdef CONFIG_BIGNUM
684         if (bignum_ext) {
685             fprintf(fo,
686                     "  JS_AddIntrinsicBigFloat(ctx);\n"
687                     "  JS_AddIntrinsicBigDecimal(ctx);\n"
688                     "  JS_AddIntrinsicOperators(ctx);\n"
689                     "  JS_EnableBignumExt(ctx, 1);\n");
690         }
691 #endif
692         fprintf(fo, "  js_std_add_helpers(ctx, argc, argv);\n");
693 
694         for(i = 0; i < init_module_list.count; i++) {
695             namelist_entry_t *e = &init_module_list.array[i];
696             /* initialize the static C modules */
697 
698             fprintf(fo,
699                     "  {\n"
700                     "    extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n"
701                     "    js_init_module_%s(ctx, \"%s\");\n"
702                     "  }\n",
703                     e->short_name, e->short_name, e->name);
704         }
705 
706         for(i = 0; i < cname_list.count; i++) {
707             namelist_entry_t *e = &cname_list.array[i];
708             fprintf(fo, "  js_std_eval_binary(ctx, %s, %s_size, %s);\n",
709                     e->name, e->name,
710                     e->flags ? "1" : "0");
711         }
712         fputs(main_c_template2, fo);
713     }
714 
715     JS_FreeContext(ctx);
716     JS_FreeRuntime(rt);
717 
718     fclose(fo);
719 
720     if (output_type == OUTPUT_EXECUTABLE) {
721         return output_executable(out_filename, cfilename, use_lto, verbose,
722                                  argv[0]);
723     }
724     namelist_free(&cname_list);
725     namelist_free(&cmodule_list);
726     namelist_free(&init_module_list);
727     return 0;
728 }
729