qjsc.c (26436B)
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 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 { "weakref", "WeakRef" }, 80 }; 81 82 void 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 103 void 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 115 namelist_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 126 static 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 158 static 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 173 typedef enum { 174 CNAME_TYPE_SCRIPT, 175 CNAME_TYPE_MODULE, 176 CNAME_TYPE_JSON_MODULE, 177 } CNameTypeEnum; 178 179 static void output_object_code(JSContext *ctx, 180 FILE *fo, JSValueConst obj, const char *c_name, 181 CNameTypeEnum c_name_type) 182 { 183 uint8_t *out_buf; 184 size_t out_buf_len; 185 int flags; 186 187 if (c_name_type == CNAME_TYPE_JSON_MODULE) 188 flags = 0; 189 else 190 flags = JS_WRITE_OBJ_BYTECODE; 191 if (byte_swap) 192 flags |= JS_WRITE_OBJ_BSWAP; 193 out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags); 194 if (!out_buf) { 195 js_std_dump_error(ctx); 196 exit(1); 197 } 198 199 namelist_add(&cname_list, c_name, NULL, c_name_type); 200 201 fprintf(fo, "const uint32_t %s_size = %u;\n\n", 202 c_name, (unsigned int)out_buf_len); 203 fprintf(fo, "const uint8_t %s[%u] = {\n", 204 c_name, (unsigned int)out_buf_len); 205 dump_hex(fo, out_buf, out_buf_len); 206 fprintf(fo, "};\n\n"); 207 208 js_free(ctx, out_buf); 209 } 210 211 static int js_module_dummy_init(JSContext *ctx, JSModuleDef *m) 212 { 213 /* should never be called when compiling JS code */ 214 abort(); 215 } 216 217 static void find_unique_cname(char *cname, size_t cname_size) 218 { 219 char cname1[1024]; 220 int suffix_num; 221 size_t len, max_len; 222 assert(cname_size >= 32); 223 /* find a C name not matching an existing module C name by 224 adding a numeric suffix */ 225 len = strlen(cname); 226 max_len = cname_size - 16; 227 if (len > max_len) 228 cname[max_len] = '\0'; 229 suffix_num = 1; 230 for(;;) { 231 snprintf(cname1, sizeof(cname1), "%s_%d", cname, suffix_num); 232 if (!namelist_find(&cname_list, cname1)) 233 break; 234 suffix_num++; 235 } 236 pstrcpy(cname, cname_size, cname1); 237 } 238 239 JSModuleDef *jsc_module_loader(JSContext *ctx, 240 const char *module_name, void *opaque, 241 JSValueConst attributes) 242 { 243 JSModuleDef *m; 244 namelist_entry_t *e; 245 246 /* check if it is a declared C or system module */ 247 e = namelist_find(&cmodule_list, module_name); 248 if (e) { 249 /* add in the static init module list */ 250 namelist_add(&init_module_list, e->name, e->short_name, 0); 251 /* create a dummy module */ 252 m = JS_NewCModule(ctx, module_name, js_module_dummy_init); 253 } else if (has_suffix(module_name, ".so")) { 254 fprintf(stderr, "Warning: binary module '%s' will be dynamically loaded\n", module_name); 255 /* create a dummy module */ 256 m = JS_NewCModule(ctx, module_name, js_module_dummy_init); 257 /* the resulting executable will export its symbols for the 258 dynamic library */ 259 dynamic_export = TRUE; 260 } else { 261 size_t buf_len; 262 uint8_t *buf; 263 char cname[1024]; 264 int res; 265 266 buf = js_load_file(ctx, &buf_len, module_name); 267 if (!buf) { 268 JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 269 module_name); 270 return NULL; 271 } 272 273 res = js_module_test_json(ctx, attributes); 274 if (has_suffix(module_name, ".json") || res > 0) { 275 /* compile as JSON or JSON5 depending on "type" */ 276 JSValue val; 277 int flags; 278 279 if (res == 2) 280 flags = JS_PARSE_JSON_EXT; 281 else 282 flags = 0; 283 val = JS_ParseJSON2(ctx, (char *)buf, buf_len, module_name, flags); 284 js_free(ctx, buf); 285 if (JS_IsException(val)) 286 return NULL; 287 /* create a dummy module */ 288 m = JS_NewCModule(ctx, module_name, js_module_dummy_init); 289 if (!m) { 290 JS_FreeValue(ctx, val); 291 return NULL; 292 } 293 294 get_c_name(cname, sizeof(cname), module_name); 295 if (namelist_find(&cname_list, cname)) { 296 find_unique_cname(cname, sizeof(cname)); 297 } 298 299 /* output the module name */ 300 fprintf(outfile, "static const uint8_t %s_module_name[] = {\n", 301 cname); 302 dump_hex(outfile, (const uint8_t *)module_name, strlen(module_name) + 1); 303 fprintf(outfile, "};\n\n"); 304 305 output_object_code(ctx, outfile, val, cname, CNAME_TYPE_JSON_MODULE); 306 JS_FreeValue(ctx, val); 307 } else { 308 JSValue func_val; 309 310 /* compile the module */ 311 func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, 312 JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); 313 js_free(ctx, buf); 314 if (JS_IsException(func_val)) 315 return NULL; 316 get_c_name(cname, sizeof(cname), module_name); 317 if (namelist_find(&cname_list, cname)) { 318 find_unique_cname(cname, sizeof(cname)); 319 } 320 output_object_code(ctx, outfile, func_val, cname, CNAME_TYPE_MODULE); 321 322 /* the module is already referenced, so we must free it */ 323 m = JS_VALUE_GET_PTR(func_val); 324 JS_FreeValue(ctx, func_val); 325 } 326 } 327 return m; 328 } 329 330 static void compile_file(JSContext *ctx, FILE *fo, 331 const char *filename, 332 const char *c_name1, 333 int module) 334 { 335 uint8_t *buf; 336 char c_name[1024]; 337 int eval_flags; 338 JSValue obj; 339 size_t buf_len; 340 341 buf = js_load_file(ctx, &buf_len, filename); 342 if (!buf) { 343 fprintf(stderr, "Could not load '%s'\n", filename); 344 exit(1); 345 } 346 eval_flags = JS_EVAL_FLAG_COMPILE_ONLY; 347 if (module < 0) { 348 module = (has_suffix(filename, ".mjs") || 349 JS_DetectModule((const char *)buf, buf_len)); 350 } 351 if (module) 352 eval_flags |= JS_EVAL_TYPE_MODULE; 353 else 354 eval_flags |= JS_EVAL_TYPE_GLOBAL; 355 // obj = JS_Eval(ctx, (const char *)buf, buf_len, filename, eval_flags); // filename contains full path 356 obj = JS_Eval(ctx, (const char *)buf, buf_len, "<compiled_js>", eval_flags); // which we don't want to expose 357 // TODO: In the future we should to make this behavior configurable with a flag to qjsc 358 if (JS_IsException(obj)) { 359 js_std_dump_error(ctx); 360 exit(1); 361 } 362 js_free(ctx, buf); 363 if (c_name1) { 364 pstrcpy(c_name, sizeof(c_name), c_name1); 365 } else { 366 get_c_name(c_name, sizeof(c_name), filename); 367 if (namelist_find(&cname_list, c_name)) { 368 find_unique_cname(c_name, sizeof(c_name)); 369 } 370 } 371 output_object_code(ctx, fo, obj, c_name, CNAME_TYPE_SCRIPT); 372 JS_FreeValue(ctx, obj); 373 } 374 375 static const char main_c_template1[] = 376 "int main(int argc, char **argv)\n" 377 "{\n" 378 " JSRuntime *rt;\n" 379 " JSContext *ctx;\n" 380 " rt = JS_NewRuntime();\n" 381 " js_std_set_worker_new_context_func(JS_NewCustomContext);\n" 382 " js_std_init_handlers(rt);\n" 383 ; 384 385 static const char main_c_template2[] = 386 " js_std_loop(ctx);\n" 387 " js_std_free_handlers(rt);\n" 388 " JS_FreeContext(ctx);\n" 389 " JS_FreeRuntime(rt);\n" 390 " return 0;\n" 391 "}\n"; 392 393 #define PROG_NAME "qjsc" 394 395 void help(void) 396 { 397 printf("QuickJS Compiler version " CONFIG_VERSION "\n" 398 "usage: " PROG_NAME " [options] [files]\n" 399 "\n" 400 "options are:\n" 401 "-c only output bytecode to a C file\n" 402 "-e output main() and bytecode to a C file (default = executable output)\n" 403 "-o output set the output filename\n" 404 "-N cname set the C name of the generated data\n" 405 "-m compile as Javascript module (default=autodetect)\n" 406 "-D module_name compile a dynamically loaded module or worker\n" 407 "-M module_name[,cname] add initialization code for an external C module\n" 408 "-x byte swapped output\n" 409 "-p prefix set the prefix of the generated C names\n" 410 "-S n set the maximum stack size to 'n' bytes (default=%d)\n" 411 "-s strip all the debug info\n" 412 "--keep-source keep the source code\n", 413 JS_DEFAULT_STACK_SIZE); 414 #ifdef CONFIG_LTO 415 { 416 int i; 417 printf("-flto use link time optimization\n"); 418 printf("-fno-["); 419 for(i = 0; i < countof(feature_list); i++) { 420 if (i != 0) 421 printf("|"); 422 printf("%s", feature_list[i].option_name); 423 } 424 printf("]\n" 425 " disable selected language features (smaller code size)\n"); 426 } 427 #endif 428 exit(1); 429 } 430 431 #if defined(CONFIG_CC) && !defined(_WIN32) 432 433 int exec_cmd(char **argv) 434 { 435 int pid, status, ret; 436 437 pid = fork(); 438 if (pid == 0) { 439 execvp(argv[0], argv); 440 exit(1); 441 } 442 443 for(;;) { 444 ret = waitpid(pid, &status, 0); 445 if (ret == pid && WIFEXITED(status)) 446 break; 447 } 448 return WEXITSTATUS(status); 449 } 450 451 static int output_executable(const char *out_filename, const char *cfilename, 452 BOOL use_lto, BOOL verbose, const char *exename) 453 { 454 const char *argv[64]; 455 const char **arg, *bn_suffix, *lto_suffix; 456 char libjsname[1024]; 457 char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p; 458 int ret; 459 460 /* get the directory of the executable */ 461 pstrcpy(exe_dir, sizeof(exe_dir), exename); 462 p = strrchr(exe_dir, '/'); 463 if (p) { 464 *p = '\0'; 465 } else { 466 pstrcpy(exe_dir, sizeof(exe_dir), "."); 467 } 468 469 /* if 'quickjs.h' is present at the same path as the executable, we 470 use it as include and lib directory */ 471 snprintf(buf, sizeof(buf), "%s/quickjs.h", exe_dir); 472 if (access(buf, R_OK) == 0) { 473 pstrcpy(inc_dir, sizeof(inc_dir), exe_dir); 474 pstrcpy(lib_dir, sizeof(lib_dir), exe_dir); 475 } else { 476 snprintf(inc_dir, sizeof(inc_dir), "%s/include/quickjs", CONFIG_PREFIX); 477 snprintf(lib_dir, sizeof(lib_dir), "%s/lib/quickjs", CONFIG_PREFIX); 478 } 479 480 lto_suffix = ""; 481 bn_suffix = ""; 482 483 arg = argv; 484 *arg++ = CONFIG_CC; 485 *arg++ = "-O2"; 486 #ifdef CONFIG_LTO 487 if (use_lto) { 488 *arg++ = "-flto"; 489 lto_suffix = ".lto"; 490 } 491 #endif 492 /* XXX: use the executable path to find the includes files and 493 libraries */ 494 *arg++ = "-D"; 495 *arg++ = "_GNU_SOURCE"; 496 *arg++ = "-I"; 497 *arg++ = inc_dir; 498 *arg++ = "-o"; 499 *arg++ = out_filename; 500 if (dynamic_export) 501 *arg++ = "-rdynamic"; 502 *arg++ = cfilename; 503 snprintf(libjsname, sizeof(libjsname), "%s/libquickjs%s%s.a", 504 lib_dir, bn_suffix, lto_suffix); 505 *arg++ = libjsname; 506 *arg++ = "-lm"; 507 *arg++ = "-ldl"; 508 *arg++ = "-lpthread"; 509 // FIXME: Make conditional 510 *arg++ = "-lcurl"; 511 *arg++ = "-lsodium"; 512 *arg++ = "-lmbedcrypto"; 513 *arg = NULL; 514 515 if (verbose) { 516 for(arg = argv; *arg != NULL; arg++) 517 printf("%s ", *arg); 518 printf("\n"); 519 } 520 521 ret = exec_cmd((char **)argv); 522 unlink(cfilename); 523 return ret; 524 } 525 #else 526 static int output_executable(const char *out_filename, const char *cfilename, 527 BOOL use_lto, BOOL verbose, const char *exename) 528 { 529 fprintf(stderr, "Executable output is not supported for this target\n"); 530 exit(1); 531 return 0; 532 } 533 #endif 534 535 static size_t get_suffixed_size(const char *str) 536 { 537 char *p; 538 size_t v; 539 v = (size_t)strtod(str, &p); 540 switch(*p) { 541 case 'G': 542 v <<= 30; 543 break; 544 case 'M': 545 v <<= 20; 546 break; 547 case 'k': 548 case 'K': 549 v <<= 10; 550 break; 551 default: 552 if (*p != '\0') { 553 fprintf(stderr, "qjs: invalid suffix: %s\n", p); 554 exit(1); 555 } 556 break; 557 } 558 return v; 559 } 560 561 typedef enum { 562 OUTPUT_C, 563 OUTPUT_C_MAIN, 564 OUTPUT_EXECUTABLE, 565 } OutputTypeEnum; 566 567 static const char *get_short_optarg(int *poptind, int opt, 568 const char *arg, int argc, char **argv) 569 { 570 const char *optarg; 571 if (*arg) { 572 optarg = arg; 573 } else if (*poptind < argc) { 574 optarg = argv[(*poptind)++]; 575 } else { 576 fprintf(stderr, "qjsc: expecting parameter for -%c\n", opt); 577 exit(1); 578 } 579 return optarg; 580 } 581 582 int main(int argc, char **argv) 583 { 584 int i, verbose, strip_flags; 585 const char *out_filename, *cname; 586 char cfilename[1024]; 587 FILE *fo; 588 JSRuntime *rt; 589 JSContext *ctx; 590 BOOL use_lto; 591 int module; 592 OutputTypeEnum output_type; 593 size_t stack_size; 594 namelist_t dynamic_module_list; 595 596 out_filename = NULL; 597 output_type = OUTPUT_EXECUTABLE; 598 cname = NULL; 599 feature_bitmap = FE_ALL; 600 module = -1; 601 byte_swap = FALSE; 602 verbose = 0; 603 strip_flags = JS_STRIP_SOURCE; 604 use_lto = FALSE; 605 stack_size = 0; 606 memset(&dynamic_module_list, 0, sizeof(dynamic_module_list)); 607 608 /* add system modules */ 609 namelist_add(&cmodule_list, "std", "std", 0); 610 namelist_add(&cmodule_list, "os", "os", 0); 611 612 optind = 1; 613 while (optind < argc && *argv[optind] == '-') { 614 char *arg = argv[optind] + 1; 615 const char *longopt = ""; 616 const char *optarg; 617 /* a single - is not an option, it also stops argument scanning */ 618 if (!*arg) 619 break; 620 optind++; 621 if (*arg == '-') { 622 longopt = arg + 1; 623 arg += strlen(arg); 624 /* -- stops argument scanning */ 625 if (!*longopt) 626 break; 627 } 628 for (; *arg || *longopt; longopt = "") { 629 char opt = *arg; 630 if (opt) 631 arg++; 632 if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) { 633 help(); 634 continue; 635 } 636 if (opt == 'o') { 637 out_filename = get_short_optarg(&optind, opt, arg, argc, argv); 638 break; 639 } 640 if (opt == 'c') { 641 output_type = OUTPUT_C; 642 continue; 643 } 644 if (opt == 'e') { 645 output_type = OUTPUT_C_MAIN; 646 continue; 647 } 648 if (opt == 'N') { 649 cname = get_short_optarg(&optind, opt, arg, argc, argv); 650 break; 651 } 652 if (opt == 'f') { 653 const char *p; 654 optarg = get_short_optarg(&optind, opt, arg, argc, argv); 655 p = optarg; 656 if (!strcmp(p, "lto")) { 657 use_lto = TRUE; 658 } else if (strstart(p, "no-", &p)) { 659 use_lto = TRUE; 660 for(i = 0; i < countof(feature_list); i++) { 661 if (!strcmp(p, feature_list[i].option_name)) { 662 feature_bitmap &= ~((uint64_t)1 << i); 663 break; 664 } 665 } 666 if (i == countof(feature_list)) 667 goto bad_feature; 668 } else { 669 bad_feature: 670 fprintf(stderr, "unsupported feature: %s\n", optarg); 671 exit(1); 672 } 673 break; 674 } 675 if (opt == 'm') { 676 module = 1; 677 continue; 678 } 679 if (opt == 'M') { 680 char *p; 681 char path[1024]; 682 char cname[1024]; 683 684 optarg = get_short_optarg(&optind, opt, arg, argc, argv); 685 pstrcpy(path, sizeof(path), optarg); 686 p = strchr(path, ','); 687 if (p) { 688 *p = '\0'; 689 pstrcpy(cname, sizeof(cname), p + 1); 690 } else { 691 get_c_name(cname, sizeof(cname), path); 692 } 693 namelist_add(&cmodule_list, path, cname, 0); 694 break; 695 } 696 if (opt == 'D') { 697 optarg = get_short_optarg(&optind, opt, arg, argc, argv); 698 namelist_add(&dynamic_module_list, optarg, NULL, 0); 699 break; 700 } 701 if (opt == 'x') { 702 byte_swap = 1; 703 continue; 704 } 705 if (opt == 'v') { 706 verbose++; 707 continue; 708 } 709 if (opt == 'p') { 710 c_ident_prefix = get_short_optarg(&optind, opt, arg, argc, argv); 711 break; 712 } 713 if (opt == 'S') { 714 optarg = get_short_optarg(&optind, opt, arg, argc, argv); 715 stack_size = get_suffixed_size(optarg); 716 break; 717 } 718 if (opt == 's') { 719 strip_flags = JS_STRIP_DEBUG; 720 continue; 721 } 722 if (!strcmp(longopt, "keep-source")) { 723 strip_flags = 0; 724 continue; 725 } 726 if (opt) { 727 fprintf(stderr, "qjsc: unknown option '-%c'\n", opt); 728 } else { 729 fprintf(stderr, "qjsc: unknown option '--%s'\n", longopt); 730 } 731 help(); 732 } 733 } 734 735 if (optind >= argc) 736 help(); 737 738 if (!out_filename) { 739 if (output_type == OUTPUT_EXECUTABLE) { 740 out_filename = "a.out"; 741 } else { 742 out_filename = "out.c"; 743 } 744 } 745 746 if (output_type == OUTPUT_EXECUTABLE) { 747 #if defined(_WIN32) || defined(__ANDROID__) 748 /* XXX: find a /tmp directory ? */ 749 snprintf(cfilename, sizeof(cfilename), "out%d.c", getpid()); 750 #else 751 snprintf(cfilename, sizeof(cfilename), "/tmp/out%d.c", getpid()); 752 #endif 753 } else { 754 pstrcpy(cfilename, sizeof(cfilename), out_filename); 755 } 756 757 fo = fopen(cfilename, "w"); 758 if (!fo) { 759 perror(cfilename); 760 exit(1); 761 } 762 outfile = fo; 763 764 rt = JS_NewRuntime(); 765 ctx = JS_NewContext(rt); 766 767 JS_SetStripInfo(rt, strip_flags); 768 769 /* loader for ES6 modules */ 770 JS_SetModuleLoaderFunc2(rt, NULL, jsc_module_loader, NULL, NULL); 771 772 fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n" 773 "\n" 774 ); 775 776 if (output_type != OUTPUT_C) { 777 fprintf(fo, "#include \"quickjs-libc.h\"\n" 778 "\n" 779 ); 780 } else { 781 fprintf(fo, "#include <inttypes.h>\n" 782 "\n" 783 ); 784 } 785 786 for(i = optind; i < argc; i++) { 787 const char *filename = argv[i]; 788 compile_file(ctx, fo, filename, cname, module); 789 cname = NULL; 790 } 791 792 for(i = 0; i < dynamic_module_list.count; i++) { 793 if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL, JS_UNDEFINED)) { 794 fprintf(stderr, "Could not load dynamic module '%s'\n", 795 dynamic_module_list.array[i].name); 796 exit(1); 797 } 798 } 799 800 if (output_type != OUTPUT_C) { 801 fprintf(fo, 802 "static JSContext *JS_NewCustomContext(JSRuntime *rt)\n" 803 "{\n" 804 " JSContext *ctx = JS_NewContextRaw(rt);\n" 805 " if (!ctx)\n" 806 " return NULL;\n"); 807 /* add the basic objects */ 808 fprintf(fo, " JS_AddIntrinsicBaseObjects(ctx);\n"); 809 for(i = 0; i < countof(feature_list); i++) { 810 if ((feature_bitmap & ((uint64_t)1 << i)) && 811 feature_list[i].init_name) { 812 fprintf(fo, " JS_AddIntrinsic%s(ctx);\n", 813 feature_list[i].init_name); 814 } 815 } 816 /* add the precompiled modules (XXX: could modify the module 817 loader instead) */ 818 for(i = 0; i < init_module_list.count; i++) { 819 namelist_entry_t *e = &init_module_list.array[i]; 820 /* initialize the static C modules */ 821 822 fprintf(fo, 823 " {\n" 824 " extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n" 825 " js_init_module_%s(ctx, \"%s\");\n" 826 " }\n", 827 e->short_name, e->short_name, e->name); 828 } 829 for(i = 0; i < cname_list.count; i++) { 830 namelist_entry_t *e = &cname_list.array[i]; 831 if (e->flags == CNAME_TYPE_MODULE) { 832 fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n", 833 e->name, e->name); 834 } else if (e->flags == CNAME_TYPE_JSON_MODULE) { 835 fprintf(fo, " js_std_eval_binary_json_module(ctx, %s, %s_size, (const char *)%s_module_name);\n", 836 e->name, e->name, e->name); 837 } 838 } 839 fprintf(fo, 840 " return ctx;\n" 841 "}\n\n"); 842 843 fputs(main_c_template1, fo); 844 845 if (stack_size != 0) { 846 fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n", 847 (unsigned int)stack_size); 848 } 849 850 /* add the module loader if necessary */ 851 if (feature_bitmap & (1 << FE_MODULE_LOADER)) { 852 fprintf(fo, " JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);\n"); 853 } 854 855 fprintf(fo, 856 " ctx = JS_NewCustomContext(rt);\n" 857 " js_std_add_helpers(ctx, argc, argv);\n"); 858 859 for(i = 0; i < cname_list.count; i++) { 860 namelist_entry_t *e = &cname_list.array[i]; 861 if (e->flags == CNAME_TYPE_SCRIPT) { 862 fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n", 863 e->name, e->name); 864 } 865 } 866 fputs(main_c_template2, fo); 867 } 868 869 JS_FreeContext(ctx); 870 JS_FreeRuntime(rt); 871 872 fclose(fo); 873 874 if (output_type == OUTPUT_EXECUTABLE) { 875 return output_executable(out_filename, cfilename, use_lto, verbose, 876 argv[0]); 877 } 878 namelist_free(&cname_list); 879 namelist_free(&cmodule_list); 880 namelist_free(&init_module_list); 881 return 0; 882 }