1/*
2 * QuickJS command line compiler
3 *
4 * Copyright (c) 2018-2021 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
39typedef struct {
40 char *name;
41 char *short_name;
42 int flags;
43} namelist_entry_t;
44
45typedef struct namelist_t {
46 namelist_entry_t *array;
47 int count;
48 int size;
49} namelist_t;
50
51typedef struct {
52 const char *option_name;
53 const char *init_name;
54} FeatureEntry;
55
56static namelist_t cname_list;
57static namelist_t cmodule_list;
58static namelist_t init_module_list;
59static uint64_t feature_bitmap;
60static FILE *outfile;
61static BOOL byte_swap;
62static BOOL dynamic_export;
63static const char *c_ident_prefix = "qjsc_";
64
65#define FE_ALL (-1)
66
67static 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 { "weakref", "WeakRef" },
80};
81
82void namelist_add(namelist_t *lp, const char *name, const char *short_name,
83 int flags)
84{
85 namelist_entry_t *e;
86 if (lp->count == lp->size) {
87 size_t newsize = lp->size + (lp->size >> 1) + 4;
88 namelist_entry_t *a =
89 realloc(lp->array, sizeof(lp->array[0]) * newsize);
90 /* XXX: check for realloc failure */
91 lp->array = a;
92 lp->size = newsize;
93 }
94 e = &lp->array[lp->count++];
95 e->name = strdup(name);
96 if (short_name)
97 e->short_name = strdup(short_name);
98 else
99 e->short_name = NULL;
100 e->flags = flags;
101}
102
103void namelist_free(namelist_t *lp)
104{
105 while (lp->count > 0) {
106 namelist_entry_t *e = &lp->array[--lp->count];
107 free(e->name);
108 free(e->short_name);
109 }
110 free(lp->array);
111 lp->array = NULL;
112 lp->size = 0;
113}
114
115namelist_entry_t *namelist_find(namelist_t *lp, const char *name)
116{
117 int i;
118 for(i = 0; i < lp->count; i++) {
119 namelist_entry_t *e = &lp->array[i];
120 if (!strcmp(e->name, name))
121 return e;
122 }
123 return NULL;
124}
125
126static void get_c_name(char *buf, size_t buf_size, const char *file)
127{
128 const char *p, *r;
129 size_t len, i;
130 int c;
131 char *q;
132
133 p = strrchr(file, '/');
134 if (!p)
135 p = file;
136 else
137 p++;
138 r = strrchr(p, '.');
139 if (!r)
140 len = strlen(p);
141 else
142 len = r - p;
143 pstrcpy(buf, buf_size, c_ident_prefix);
144 q = buf + strlen(buf);
145 for(i = 0; i < len; i++) {
146 c = p[i];
147 if (!((c >= '0' && c <= '9') ||
148 (c >= 'A' && c <= 'Z') ||
149 (c >= 'a' && c <= 'z'))) {
150 c = '_';
151 }
152 if ((q - buf) < buf_size - 1)
153 *q++ = c;
154 }
155 *q = '\0';
156}
157
158static void dump_hex(FILE *f, const uint8_t *buf, size_t len)
159{
160 size_t i, col;
161 col = 0;
162 for(i = 0; i < len; i++) {
163 fprintf(f, " 0x%02x,", buf[i]);
164 if (++col == 8) {
165 fprintf(f, "\n");
166 col = 0;
167 }
168 }
169 if (col != 0)
170 fprintf(f, "\n");
171}
172
173static void output_object_code(JSContext *ctx,
174 FILE *fo, JSValueConst obj, const char *c_name,
175 BOOL load_only)
176{
177 uint8_t *out_buf;
178 size_t out_buf_len;
179 int flags;
180 flags = JS_WRITE_OBJ_BYTECODE;
181 if (byte_swap)
182 flags |= JS_WRITE_OBJ_BSWAP;
183 out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags);
184 if (!out_buf) {
185 js_std_dump_error(ctx);
186 exit(1);
187 }
188
189 namelist_add(&cname_list, c_name, NULL, load_only);
190
191 fprintf(fo, "const uint32_t %s_size = %u;\n\n",
192 c_name, (unsigned int)out_buf_len);
193 fprintf(fo, "const uint8_t %s[%u] = {\n",
194 c_name, (unsigned int)out_buf_len);
195 dump_hex(fo, out_buf, out_buf_len);
196 fprintf(fo, "};\n\n");
197
198 js_free(ctx, out_buf);
199}
200
201static int js_module_dummy_init(JSContext *ctx, JSModuleDef *m)
202{
203 /* should never be called when compiling JS code */
204 abort();
205}
206
207static void find_unique_cname(char *cname, size_t cname_size)
208{
209 char cname1[1024];
210 int suffix_num;
211 size_t len, max_len;
212 assert(cname_size >= 32);
213 /* find a C name not matching an existing module C name by
214 adding a numeric suffix */
215 len = strlen(cname);
216 max_len = cname_size - 16;
217 if (len > max_len)
218 cname[max_len] = '\0';
219 suffix_num = 1;
220 for(;;) {
221 snprintf(cname1, sizeof(cname1), "%s_%d", cname, suffix_num);
222 if (!namelist_find(&cname_list, cname1))
223 break;
224 suffix_num++;
225 }
226 pstrcpy(cname, cname_size, cname1);
227}
228
229JSModuleDef *jsc_module_loader(JSContext *ctx,
230 const char *module_name, void *opaque)
231{
232 JSModuleDef *m;
233 namelist_entry_t *e;
234
235 /* check if it is a declared C or system module */
236 e = namelist_find(&cmodule_list, module_name);
237 if (e) {
238 /* add in the static init module list */
239 namelist_add(&init_module_list, e->name, e->short_name, 0);
240 /* create a dummy module */
241 m = JS_NewCModule(ctx, module_name, js_module_dummy_init);
242 } else if (has_suffix(module_name, ".so")) {
243 fprintf(stderr, "Warning: binary module '%s' will be dynamically loaded\n", module_name);
244 /* create a dummy module */
245 m = JS_NewCModule(ctx, module_name, js_module_dummy_init);
246 /* the resulting executable will export its symbols for the
247 dynamic library */
248 dynamic_export = TRUE;
249 } else {
250 size_t buf_len;
251 uint8_t *buf;
252 JSValue func_val;
253 char cname[1024];
254
255 buf = js_load_file(ctx, &buf_len, module_name);
256 if (!buf) {
257 JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
258 module_name);
259 return NULL;
260 }
261
262 /* compile the module */
263 func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
264 JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
265 js_free(ctx, buf);
266 if (JS_IsException(func_val))
267 return NULL;
268 get_c_name(cname, sizeof(cname), module_name);
269 if (namelist_find(&cname_list, cname)) {
270 find_unique_cname(cname, sizeof(cname));
271 }
272 output_object_code(ctx, outfile, func_val, cname, TRUE);
273
274 /* the module is already referenced, so we must free it */
275 m = JS_VALUE_GET_PTR(func_val);
276 JS_FreeValue(ctx, func_val);
277 }
278 return m;
279}
280
281static void compile_file(JSContext *ctx, FILE *fo,
282 const char *filename,
283 const char *c_name1,
284 int module)
285{
286 uint8_t *buf;
287 char c_name[1024];
288 int eval_flags;
289 JSValue obj;
290 size_t buf_len;
291
292 buf = js_load_file(ctx, &buf_len, filename);
293 if (!buf) {
294 fprintf(stderr, "Could not load '%s'\n", filename);
295 exit(1);
296 }
297 eval_flags = JS_EVAL_FLAG_COMPILE_ONLY;
298 if (module < 0) {
299 module = (has_suffix(filename, ".mjs") ||
300 JS_DetectModule((const char *)buf, buf_len));
301 }
302 if (module)
303 eval_flags |= JS_EVAL_TYPE_MODULE;
304 else
305 eval_flags |= JS_EVAL_TYPE_GLOBAL;
306 obj = JS_Eval(ctx, (const char *)buf, buf_len, filename, eval_flags);
307 if (JS_IsException(obj)) {
308 js_std_dump_error(ctx);
309 exit(1);
310 }
311 js_free(ctx, buf);
312 if (c_name1) {
313 pstrcpy(c_name, sizeof(c_name), c_name1);
314 } else {
315 get_c_name(c_name, sizeof(c_name), filename);
316 }
317 output_object_code(ctx, fo, obj, c_name, FALSE);
318 JS_FreeValue(ctx, obj);
319}
320
321static const char main_c_template1[] =
322 "int main(int argc, char **argv)\n"
323 "{\n"
324 " JSRuntime *rt;\n"
325 " JSContext *ctx;\n"
326 " rt = JS_NewRuntime();\n"
327 " js_std_set_worker_new_context_func(JS_NewCustomContext);\n"
328 " js_std_init_handlers(rt);\n"
329 ;
330
331static const char main_c_template2[] =
332 " js_std_loop(ctx);\n"
333 " js_std_free_handlers(rt);\n"
334 " JS_FreeContext(ctx);\n"
335 " JS_FreeRuntime(rt);\n"
336 " return 0;\n"
337 "}\n";
338
339#define PROG_NAME "qjsc"
340
341void 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 to a C file\n"
348 "-e output main() and bytecode to 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 "-D module_name compile a dynamically loaded module or worker\n"
353 "-M module_name[,cname] add initialization code for an external C module\n"
354 "-x byte swapped output\n"
355 "-p prefix set the prefix of the generated C names\n"
356 "-S n set the maximum stack size to 'n' bytes (default=%d)\n"
357 "-s strip all the debug info\n"
358 "--keep-source keep the source code\n",
359 JS_DEFAULT_STACK_SIZE);
360#ifdef CONFIG_LTO
361 {
362 int i;
363 printf("-flto use link time optimization\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
379int 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
397static 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
468static 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
477static size_t get_suffixed_size(const char *str)
478{
479 char *p;
480 size_t v;
481 v = (size_t)strtod(str, &p);
482 switch(*p) {
483 case 'G':
484 v <<= 30;
485 break;
486 case 'M':
487 v <<= 20;
488 break;
489 case 'k':
490 case 'K':
491 v <<= 10;
492 break;
493 default:
494 if (*p != '\0') {
495 fprintf(stderr, "qjs: invalid suffix: %s\n", p);
496 exit(1);
497 }
498 break;
499 }
500 return v;
501}
502
503typedef enum {
504 OUTPUT_C,
505 OUTPUT_C_MAIN,
506 OUTPUT_EXECUTABLE,
507} OutputTypeEnum;
508
509static const char *get_short_optarg(int *poptind, int opt,
510 const char *arg, int argc, char **argv)
511{
512 const char *optarg;
513 if (*arg) {
514 optarg = arg;
515 } else if (*poptind < argc) {
516 optarg = argv[(*poptind)++];
517 } else {
518 fprintf(stderr, "qjsc: expecting parameter for -%c\n", opt);
519 exit(1);
520 }
521 return optarg;
522}
523
524int main(int argc, char **argv)
525{
526 int i, verbose, strip_flags;
527 const char *out_filename, *cname;
528 char cfilename[1024];
529 FILE *fo;
530 JSRuntime *rt;
531 JSContext *ctx;
532 BOOL use_lto;
533 int module;
534 OutputTypeEnum output_type;
535 size_t stack_size;
536 namelist_t dynamic_module_list;
537
538 out_filename = NULL;
539 output_type = OUTPUT_EXECUTABLE;
540 cname = NULL;
541 feature_bitmap = FE_ALL;
542 module = -1;
543 byte_swap = FALSE;
544 verbose = 0;
545 strip_flags = JS_STRIP_SOURCE;
546 use_lto = FALSE;
547 stack_size = 0;
548 memset(&dynamic_module_list, 0, sizeof(dynamic_module_list));
549
550 /* add system modules */
551 namelist_add(&cmodule_list, "std", "std", 0);
552 namelist_add(&cmodule_list, "os", "os", 0);
553
554 optind = 1;
555 while (optind < argc && *argv[optind] == '-') {
556 char *arg = argv[optind] + 1;
557 const char *longopt = "";
558 const char *optarg;
559 /* a single - is not an option, it also stops argument scanning */
560 if (!*arg)
561 break;
562 optind++;
563 if (*arg == '-') {
564 longopt = arg + 1;
565 arg += strlen(arg);
566 /* -- stops argument scanning */
567 if (!*longopt)
568 break;
569 }
570 for (; *arg || *longopt; longopt = "") {
571 char opt = *arg;
572 if (opt)
573 arg++;
574 if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) {
575 help();
576 continue;
577 }
578 if (opt == 'o') {
579 out_filename = get_short_optarg(&optind, opt, arg, argc, argv);
580 break;
581 }
582 if (opt == 'c') {
583 output_type = OUTPUT_C;
584 continue;
585 }
586 if (opt == 'e') {
587 output_type = OUTPUT_C_MAIN;
588 continue;
589 }
590 if (opt == 'N') {
591 cname = get_short_optarg(&optind, opt, arg, argc, argv);
592 break;
593 }
594 if (opt == 'f') {
595 const char *p;
596 optarg = get_short_optarg(&optind, opt, arg, argc, argv);
597 p = optarg;
598 if (!strcmp(p, "lto")) {
599 use_lto = TRUE;
600 } else if (strstart(p, "no-", &p)) {
601 use_lto = TRUE;
602 for(i = 0; i < countof(feature_list); i++) {
603 if (!strcmp(p, feature_list[i].option_name)) {
604 feature_bitmap &= ~((uint64_t)1 << i);
605 break;
606 }
607 }
608 if (i == countof(feature_list))
609 goto bad_feature;
610 } else {
611 bad_feature:
612 fprintf(stderr, "unsupported feature: %s\n", optarg);
613 exit(1);
614 }
615 break;
616 }
617 if (opt == 'm') {
618 module = 1;
619 continue;
620 }
621 if (opt == 'M') {
622 char *p;
623 char path[1024];
624 char cname[1024];
625
626 optarg = get_short_optarg(&optind, opt, arg, argc, argv);
627 pstrcpy(path, sizeof(path), optarg);
628 p = strchr(path, ',');
629 if (p) {
630 *p = '\0';
631 pstrcpy(cname, sizeof(cname), p + 1);
632 } else {
633 get_c_name(cname, sizeof(cname), path);
634 }
635 namelist_add(&cmodule_list, path, cname, 0);
636 break;
637 }
638 if (opt == 'D') {
639 optarg = get_short_optarg(&optind, opt, arg, argc, argv);
640 namelist_add(&dynamic_module_list, optarg, NULL, 0);
641 break;
642 }
643 if (opt == 'x') {
644 byte_swap = 1;
645 continue;
646 }
647 if (opt == 'v') {
648 verbose++;
649 continue;
650 }
651 if (opt == 'p') {
652 c_ident_prefix = get_short_optarg(&optind, opt, arg, argc, argv);
653 break;
654 }
655 if (opt == 'S') {
656 optarg = get_short_optarg(&optind, opt, arg, argc, argv);
657 stack_size = get_suffixed_size(optarg);
658 break;
659 }
660 if (opt == 's') {
661 strip_flags = JS_STRIP_DEBUG;
662 continue;
663 }
664 if (!strcmp(longopt, "keep-source")) {
665 strip_flags = 0;
666 continue;
667 }
668 if (opt) {
669 fprintf(stderr, "qjsc: unknown option '-%c'\n", opt);
670 } else {
671 fprintf(stderr, "qjsc: unknown option '--%s'\n", longopt);
672 }
673 help();
674 }
675 }
676
677 if (optind >= argc)
678 help();
679
680 if (!out_filename) {
681 if (output_type == OUTPUT_EXECUTABLE) {
682 out_filename = "a.out";
683 } else {
684 out_filename = "out.c";
685 }
686 }
687
688 if (output_type == OUTPUT_EXECUTABLE) {
689#if defined(_WIN32) || defined(__ANDROID__)
690 /* XXX: find a /tmp directory ? */
691 snprintf(cfilename, sizeof(cfilename), "out%d.c", getpid());
692#else
693 snprintf(cfilename, sizeof(cfilename), "/tmp/out%d.c", getpid());
694#endif
695 } else {
696 pstrcpy(cfilename, sizeof(cfilename), out_filename);
697 }
698
699 fo = fopen(cfilename, "w");
700 if (!fo) {
701 perror(cfilename);
702 exit(1);
703 }
704 outfile = fo;
705
706 rt = JS_NewRuntime();
707 ctx = JS_NewContext(rt);
708
709 JS_SetStripInfo(rt, strip_flags);
710
711 /* loader for ES6 modules */
712 JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL);
713
714 fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n"
715 "\n"
716 );
717
718 if (output_type != OUTPUT_C) {
719 fprintf(fo, "#include \"quickjs-libc.h\"\n"
720 "\n"
721 );
722 } else {
723 fprintf(fo, "#include <inttypes.h>\n"
724 "\n"
725 );
726 }
727
728 for(i = optind; i < argc; i++) {
729 const char *filename = argv[i];
730 compile_file(ctx, fo, filename, cname, module);
731 cname = NULL;
732 }
733
734 for(i = 0; i < dynamic_module_list.count; i++) {
735 if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) {
736 fprintf(stderr, "Could not load dynamic module '%s'\n",
737 dynamic_module_list.array[i].name);
738 exit(1);
739 }
740 }
741
742 if (output_type != OUTPUT_C) {
743 fprintf(fo,
744 "static JSContext *JS_NewCustomContext(JSRuntime *rt)\n"
745 "{\n"
746 " JSContext *ctx = JS_NewContextRaw(rt);\n"
747 " if (!ctx)\n"
748 " return NULL;\n");
749 /* add the basic objects */
750 fprintf(fo, " JS_AddIntrinsicBaseObjects(ctx);\n");
751 for(i = 0; i < countof(feature_list); i++) {
752 if ((feature_bitmap & ((uint64_t)1 << i)) &&
753 feature_list[i].init_name) {
754 fprintf(fo, " JS_AddIntrinsic%s(ctx);\n",
755 feature_list[i].init_name);
756 }
757 }
758 /* add the precompiled modules (XXX: could modify the module
759 loader instead) */
760 for(i = 0; i < init_module_list.count; i++) {
761 namelist_entry_t *e = &init_module_list.array[i];
762 /* initialize the static C modules */
763
764 fprintf(fo,
765 " {\n"
766 " extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n"
767 " js_init_module_%s(ctx, \"%s\");\n"
768 " }\n",
769 e->short_name, e->short_name, e->name);
770 }
771 for(i = 0; i < cname_list.count; i++) {
772 namelist_entry_t *e = &cname_list.array[i];
773 if (e->flags) {
774 fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n",
775 e->name, e->name);
776 }
777 }
778 fprintf(fo,
779 " return ctx;\n"
780 "}\n\n");
781
782 fputs(main_c_template1, fo);
783
784 if (stack_size != 0) {
785 fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n",
786 (unsigned int)stack_size);
787 }
788
789 /* add the module loader if necessary */
790 if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
791 fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
792 }
793
794 fprintf(fo,
795 " ctx = JS_NewCustomContext(rt);\n"
796 " js_std_add_helpers(ctx, argc, argv);\n");
797
798 for(i = 0; i < cname_list.count; i++) {
799 namelist_entry_t *e = &cname_list.array[i];
800 if (!e->flags) {
801 fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n",
802 e->name, e->name);
803 }
804 }
805 fputs(main_c_template2, fo);
806 }
807
808 JS_FreeContext(ctx);
809 JS_FreeRuntime(rt);
810
811 fclose(fo);
812
813 if (output_type == OUTPUT_EXECUTABLE) {
814 return output_executable(out_filename, cfilename, use_lto, verbose,
815 argv[0]);
816 }
817 namelist_free(&cname_list);
818 namelist_free(&cmodule_list);
819 namelist_free(&init_module_list);
820 return 0;
821}
822