• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_set_worker_new_context_func(JS_NewCustomContext);\n"
330     "  js_std_init_handlers(rt);\n"
331     ;
332 
333 static const char main_c_template2[] =
334     "  js_std_loop(ctx);\n"
335     "  JS_FreeContext(ctx);\n"
336     "  JS_FreeRuntime(rt);\n"
337     "  return 0;\n"
338     "}\n";
339 
340 #define PROG_NAME "qjsc"
341 
help(void)342 void help(void)
343 {
344     printf("QuickJS Compiler version " CONFIG_VERSION "\n"
345            "usage: " PROG_NAME " [options] [files]\n"
346            "\n"
347            "options are:\n"
348            "-c          only output bytecode in a C file\n"
349            "-e          output main() and bytecode in a C file (default = executable output)\n"
350            "-o output   set the output filename\n"
351            "-N cname    set the C name of the generated data\n"
352            "-m          compile as Javascript module (default=autodetect)\n"
353            "-D module_name         compile a dynamically loaded module or worker\n"
354            "-M module_name[,cname] add initialization code for an external C module\n"
355            "-x          byte swapped output\n"
356            "-p prefix   set the prefix of the generated C names\n"
357            "-S n        set the maximum stack size to 'n' bytes (default=%d)\n",
358            JS_DEFAULT_STACK_SIZE);
359 #ifdef CONFIG_LTO
360     {
361         int i;
362         printf("-flto       use link time optimization\n");
363         printf("-fbignum    enable bignum extensions\n");
364         printf("-fno-[");
365         for(i = 0; i < countof(feature_list); i++) {
366             if (i != 0)
367                 printf("|");
368             printf("%s", feature_list[i].option_name);
369         }
370         printf("]\n"
371                "            disable selected language features (smaller code size)\n");
372     }
373 #endif
374     exit(1);
375 }
376 
377 #if defined(CONFIG_CC) && !defined(_WIN32)
378 
exec_cmd(char ** argv)379 int exec_cmd(char **argv)
380 {
381     int pid, status, ret;
382 
383     pid = fork();
384     if (pid == 0) {
385         execvp(argv[0], argv);
386         exit(1);
387     }
388 
389     for(;;) {
390         ret = waitpid(pid, &status, 0);
391         if (ret == pid && WIFEXITED(status))
392             break;
393     }
394     return WEXITSTATUS(status);
395 }
396 
output_executable(const char * out_filename,const char * cfilename,BOOL use_lto,BOOL verbose,const char * exename)397 static int output_executable(const char *out_filename, const char *cfilename,
398                              BOOL use_lto, BOOL verbose, const char *exename)
399 {
400     const char *argv[64];
401     const char **arg, *bn_suffix, *lto_suffix;
402     char libjsname[1024];
403     char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p;
404     int ret;
405 
406     /* get the directory of the executable */
407     pstrcpy(exe_dir, sizeof(exe_dir), exename);
408     p = strrchr(exe_dir, '/');
409     if (p) {
410         *p = '\0';
411     } else {
412         pstrcpy(exe_dir, sizeof(exe_dir), ".");
413     }
414 
415     /* if 'quickjs.h' is present at the same path as the executable, we
416        use it as include and lib directory */
417     snprintf(buf, sizeof(buf), "%s/quickjs.h", exe_dir);
418     if (access(buf, R_OK) == 0) {
419         pstrcpy(inc_dir, sizeof(inc_dir), exe_dir);
420         pstrcpy(lib_dir, sizeof(lib_dir), exe_dir);
421     } else {
422         snprintf(inc_dir, sizeof(inc_dir), "%s/include/quickjs", CONFIG_PREFIX);
423         snprintf(lib_dir, sizeof(lib_dir), "%s/lib/quickjs", CONFIG_PREFIX);
424     }
425 
426     lto_suffix = "";
427     bn_suffix = "";
428 
429     arg = argv;
430     *arg++ = CONFIG_CC;
431     *arg++ = "-O2";
432 #ifdef CONFIG_LTO
433     if (use_lto) {
434         *arg++ = "-flto";
435         lto_suffix = ".lto";
436     }
437 #endif
438     /* XXX: use the executable path to find the includes files and
439        libraries */
440     *arg++ = "-D";
441     *arg++ = "_GNU_SOURCE";
442     *arg++ = "-I";
443     *arg++ = inc_dir;
444     *arg++ = "-o";
445     *arg++ = out_filename;
446     if (dynamic_export)
447         *arg++ = "-rdynamic";
448     *arg++ = cfilename;
449     snprintf(libjsname, sizeof(libjsname), "%s/libquickjs%s%s.a",
450              lib_dir, bn_suffix, lto_suffix);
451     *arg++ = libjsname;
452     *arg++ = "-lm";
453     *arg++ = "-ldl";
454     *arg++ = "-lpthread";
455     *arg = NULL;
456 
457     if (verbose) {
458         for(arg = argv; *arg != NULL; arg++)
459             printf("%s ", *arg);
460         printf("\n");
461     }
462 
463     ret = exec_cmd((char **)argv);
464     unlink(cfilename);
465     return ret;
466 }
467 #else
output_executable(const char * out_filename,const char * cfilename,BOOL use_lto,BOOL verbose,const char * exename)468 static int output_executable(const char *out_filename, const char *cfilename,
469                              BOOL use_lto, BOOL verbose, const char *exename)
470 {
471     fprintf(stderr, "Executable output is not supported for this target\n");
472     exit(1);
473     return 0;
474 }
475 #endif
476 
477 
478 typedef enum {
479     OUTPUT_C,
480     OUTPUT_C_MAIN,
481     OUTPUT_EXECUTABLE,
482 } OutputTypeEnum;
483 
main(int argc,char ** argv)484 int main(int argc, char **argv)
485 {
486     int c, i, verbose;
487     const char *out_filename, *cname;
488     char cfilename[1024];
489     FILE *fo;
490     JSRuntime *rt;
491     JSContext *ctx;
492     BOOL use_lto;
493     int module;
494     OutputTypeEnum output_type;
495     size_t stack_size;
496 #ifdef CONFIG_BIGNUM
497     BOOL bignum_ext = FALSE;
498 #endif
499     namelist_t dynamic_module_list;
500 
501     out_filename = NULL;
502     output_type = OUTPUT_EXECUTABLE;
503     cname = NULL;
504     feature_bitmap = FE_ALL;
505     module = -1;
506     byte_swap = FALSE;
507     verbose = 0;
508     use_lto = FALSE;
509     stack_size = 0;
510     memset(&dynamic_module_list, 0, sizeof(dynamic_module_list));
511 
512     /* add system modules */
513     namelist_add(&cmodule_list, "std", "std", 0);
514     namelist_add(&cmodule_list, "os", "os", 0);
515 
516     for(;;) {
517         c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:");
518         if (c == -1)
519             break;
520         switch(c) {
521         case 'h':
522             help();
523         case 'o':
524             out_filename = optarg;
525             break;
526         case 'c':
527             output_type = OUTPUT_C;
528             break;
529         case 'e':
530             output_type = OUTPUT_C_MAIN;
531             break;
532         case 'N':
533             cname = optarg;
534             break;
535         case 'f':
536             {
537                 const char *p;
538                 p = optarg;
539                 if (!strcmp(optarg, "lto")) {
540                     use_lto = TRUE;
541                 } else if (strstart(p, "no-", &p)) {
542                     use_lto = TRUE;
543                     for(i = 0; i < countof(feature_list); i++) {
544                         if (!strcmp(p, feature_list[i].option_name)) {
545                             feature_bitmap &= ~((uint64_t)1 << i);
546                             break;
547                         }
548                     }
549                     if (i == countof(feature_list))
550                         goto bad_feature;
551                 } else
552 #ifdef CONFIG_BIGNUM
553                 if (!strcmp(optarg, "bignum")) {
554                     bignum_ext = TRUE;
555                 } else
556 #endif
557                 {
558                 bad_feature:
559                     fprintf(stderr, "unsupported feature: %s\n", optarg);
560                     exit(1);
561                 }
562             }
563             break;
564         case 'm':
565             module = 1;
566             break;
567         case 'M':
568             {
569                 char *p;
570                 char path[1024];
571                 char cname[1024];
572                 pstrcpy(path, sizeof(path), optarg);
573                 p = strchr(path, ',');
574                 if (p) {
575                     *p = '\0';
576                     pstrcpy(cname, sizeof(cname), p + 1);
577                 } else {
578                     get_c_name(cname, sizeof(cname), path);
579                 }
580                 namelist_add(&cmodule_list, path, cname, 0);
581             }
582             break;
583         case 'D':
584             namelist_add(&dynamic_module_list, optarg, NULL, 0);
585             break;
586         case 'x':
587             byte_swap = TRUE;
588             break;
589         case 'v':
590             verbose++;
591             break;
592         case 'p':
593             c_ident_prefix = optarg;
594             break;
595         case 'S':
596             stack_size = (size_t)strtod(optarg, NULL);
597             break;
598         default:
599             break;
600         }
601     }
602 
603     if (optind >= argc)
604         help();
605 
606     if (!out_filename) {
607         if (output_type == OUTPUT_EXECUTABLE) {
608             out_filename = "a.out";
609         } else {
610             out_filename = "out.c";
611         }
612     }
613 
614     if (output_type == OUTPUT_EXECUTABLE) {
615 #if defined(_WIN32) || defined(__ANDROID__)
616         /* XXX: find a /tmp directory ? */
617         snprintf(cfilename, sizeof(cfilename), "out%d.c", getpid());
618 #else
619         snprintf(cfilename, sizeof(cfilename), "/tmp/out%d.c", getpid());
620 #endif
621     } else {
622         pstrcpy(cfilename, sizeof(cfilename), out_filename);
623     }
624 
625     fo = fopen(cfilename, "w");
626     if (!fo) {
627         perror(cfilename);
628         exit(1);
629     }
630     outfile = fo;
631 
632     rt = JS_NewRuntime();
633     ctx = JS_NewContext(rt);
634 #ifdef CONFIG_BIGNUM
635     if (bignum_ext) {
636         JS_AddIntrinsicBigFloat(ctx);
637         JS_AddIntrinsicBigDecimal(ctx);
638         JS_AddIntrinsicOperators(ctx);
639         JS_EnableBignumExt(ctx, TRUE);
640     }
641 #endif
642 
643     /* loader for ES6 modules */
644     JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL);
645 
646     fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n"
647             "\n"
648             );
649 
650     if (output_type != OUTPUT_C) {
651         fprintf(fo, "#include \"quickjs-libc.h\"\n"
652                 "\n"
653                 );
654     } else {
655         fprintf(fo, "#include <inttypes.h>\n"
656                 "\n"
657                 );
658     }
659 
660     for(i = optind; i < argc; i++) {
661         const char *filename = argv[i];
662         compile_file(ctx, fo, filename, cname, module);
663         cname = NULL;
664     }
665 
666     for(i = 0; i < dynamic_module_list.count; i++) {
667         if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) {
668             fprintf(stderr, "Could not load dynamic module '%s'\n",
669                     dynamic_module_list.array[i].name);
670             exit(1);
671         }
672     }
673 
674     if (output_type != OUTPUT_C) {
675         fprintf(fo,
676                 "static JSContext *JS_NewCustomContext(JSRuntime *rt)\n"
677                 "{\n"
678                 "  JSContext *ctx = JS_NewContextRaw(rt);\n"
679                 "  if (!ctx)\n"
680                 "    return NULL;\n");
681         /* add the basic objects */
682         fprintf(fo, "  JS_AddIntrinsicBaseObjects(ctx);\n");
683         for(i = 0; i < countof(feature_list); i++) {
684             if ((feature_bitmap & ((uint64_t)1 << i)) &&
685                 feature_list[i].init_name) {
686                 fprintf(fo, "  JS_AddIntrinsic%s(ctx);\n",
687                         feature_list[i].init_name);
688             }
689         }
690 #ifdef CONFIG_BIGNUM
691         if (bignum_ext) {
692             fprintf(fo,
693                     "  JS_AddIntrinsicBigFloat(ctx);\n"
694                     "  JS_AddIntrinsicBigDecimal(ctx);\n"
695                     "  JS_AddIntrinsicOperators(ctx);\n"
696                     "  JS_EnableBignumExt(ctx, 1);\n");
697         }
698 #endif
699         /* add the precompiled modules (XXX: could modify the module
700            loader instead) */
701         for(i = 0; i < init_module_list.count; i++) {
702             namelist_entry_t *e = &init_module_list.array[i];
703             /* initialize the static C modules */
704 
705             fprintf(fo,
706                     "  {\n"
707                     "    extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n"
708                     "    js_init_module_%s(ctx, \"%s\");\n"
709                     "  }\n",
710                     e->short_name, e->short_name, e->name);
711         }
712         for(i = 0; i < cname_list.count; i++) {
713             namelist_entry_t *e = &cname_list.array[i];
714             if (e->flags) {
715                 fprintf(fo, "  js_std_eval_binary(ctx, %s, %s_size, 1);\n",
716                         e->name, e->name);
717             }
718         }
719         fprintf(fo,
720                 "  return ctx;\n"
721                 "}\n\n");
722 
723         fputs(main_c_template1, fo);
724 
725         if (stack_size != 0) {
726             fprintf(fo, "  JS_SetMaxStackSize(rt, %u);\n",
727                     (unsigned int)stack_size);
728         }
729 
730         /* add the module loader if necessary */
731         if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
732             fprintf(fo, "  JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
733         }
734 
735         fprintf(fo,
736                 "  ctx = JS_NewCustomContext(rt);\n"
737                 "  js_std_add_helpers(ctx, argc, argv);\n");
738 
739         for(i = 0; i < cname_list.count; i++) {
740             namelist_entry_t *e = &cname_list.array[i];
741             if (!e->flags) {
742                 fprintf(fo, "  js_std_eval_binary(ctx, %s, %s_size, 0);\n",
743                         e->name, e->name);
744             }
745         }
746         fputs(main_c_template2, fo);
747     }
748 
749     JS_FreeContext(ctx);
750     JS_FreeRuntime(rt);
751 
752     fclose(fo);
753 
754     if (output_type == OUTPUT_EXECUTABLE) {
755         return output_executable(out_filename, cfilename, use_lto, verbose,
756                                  argv[0]);
757     }
758     namelist_free(&cname_list);
759     namelist_free(&cmodule_list);
760     namelist_free(&init_module_list);
761     return 0;
762 }
763