quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

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 }