Revision 65d5762485dfdc3d57f8463ba1852d6526019c70 authored by Jameson Nash on 20 April 2017, 18:42:56 UTC, committed by Jameson Nash on 22 April 2017, 18:58:09 UTC
previously we couldn't reliably tell the difference between a failure to context switch
and an explicitly scheduled error

in the former case, we often need to undo some prior action
by moving the code for the later into Julia,
we can reliably run the necessary undo action when required

fix #21442
1 parent 45092ff
Raw File
jloptions.c
// This file is a part of Julia. License is MIT: http://julialang.org/license

#include <limits.h>

#include "julia.h"

#ifndef _MSC_VER
#include <unistd.h>
#include <getopt.h>
#else
#include "getopt.h"
#endif

#ifdef _OS_WINDOWS_
char *shlib_ext = ".dll";
#elif defined(_OS_DARWIN_)
char *shlib_ext = ".dylib";
#else
char *shlib_ext = ".so";
#endif

static char system_image_path[256] = "\0" JL_SYSTEM_IMAGE_PATH;
JL_DLLEXPORT const char *jl_get_default_sysimg_path(void)
{
#ifdef CPUID_SPECIFIC_BINARIES
    char *path = &system_image_path[1];
    size_t existing_length = strlen(path) - strlen(shlib_ext);
    path += existing_length;
    snprintf(path, sizeof(system_image_path) - existing_length,
        "_%" PRIx64 "%s", jl_cpuid_tag(), shlib_ext);
#endif
    return &system_image_path[1];
}


jl_options_t jl_options = { 0,    // quiet
                            NULL, // julia_home
                            NULL, // julia_bin
                            NULL, // eval
                            NULL, // print
                            NULL, // load
                            NULL, // image_file (will be filled in below)
                            NULL, // cpu_target ("native", "core2", etc...)
                            0,    // nprocs
                            NULL, // machinefile
                            0,    // isinteractive
                            0,    // color
                            JL_OPTIONS_HISTORYFILE_ON, // history file
                            0,    // startup file
                            JL_OPTIONS_COMPILE_DEFAULT, // compile_enabled
                            0,    // code_coverage
                            0,    // malloc_log
                            2,    // opt_level
#ifdef JL_DEBUG_BUILD
                            2,    // debug_level [debug build]
#else
                            1,    // debug_level [release build]
#endif
                            JL_OPTIONS_CHECK_BOUNDS_DEFAULT, // check_bounds
                            1,    // deprecation warning
                            1,    // can_inline
                            JL_OPTIONS_POLLY_ON, // polly
                            JL_OPTIONS_FAST_MATH_DEFAULT,
                            0,    // worker
                            JL_OPTIONS_HANDLE_SIGNALS_ON,
                            JL_OPTIONS_USE_PRECOMPILED_YES,
                            JL_OPTIONS_USE_COMPILECACHE_YES,
                            NULL, // bind-to
                            NULL, // output-bc
                            NULL, // output-o
                            NULL, // output-ji
                            0, // incremental
                            0 // image_file_specified
};

static const char usage[] = "julia [switches] -- [programfile] [args...]\n";
static const char opts[]  =
    " -v, --version             Display version information\n"
    " -h, --help                Print this message\n\n"

    // startup options
    " -J, --sysimage <file>     Start up with the given system image file\n"
    " --precompiled={yes|no}    Use precompiled code from system image if available\n"
    " --compilecache={yes|no}   Enable/disable incremental precompilation of modules\n"
    " -H, --home <dir>          Set location of `julia` executable\n"
    " --startup-file={yes|no}   Load ~/.juliarc.jl\n"
    " --handle-signals={yes|no} Enable or disable Julia's default signal handlers\n\n"

    // actions
    " -e, --eval <expr>         Evaluate <expr>\n"
    " -E, --print <expr>        Evaluate and show <expr>\n"
    " -L, --load <file>         Load <file> immediately on all processors\n\n"

    // parallel options
    " -p, --procs {N|auto}      Integer value N launches N additional local worker processes\n"
    "                           \"auto\" launches as many workers as the number of local cores\n"
    " --machinefile <file>      Run processes on hosts listed in <file>\n\n"

    // interactive options
    " -i                        Interactive mode; REPL runs and isinteractive() is true\n"
    " -q, --quiet               Quiet startup (no banner)\n"
    " --color={yes|no}          Enable or disable color text\n"
    " --history-file={yes|no}   Load or save history\n\n"

    // code generation options
    " --compile={yes|no|all|min}Enable or disable JIT compiler, or request exhaustive compilation\n"
    " -C, --cpu-target <target> Limit usage of cpu features up to <target>; set to \"help\" to see the available options\n"
    " -O, --optimize={0,1,2,3}  Set the optimization level (default level is 2 if unspecified or 3 if used without a level)\n"
    " -g, -g <level>            Enable / Set the level of debug info generation"
#ifdef JL_DEBUG_BUILD
        " (default level for julia-debug is 2 if unspecified or if used without a level)\n"
#else
        " (default level is 1 if unspecified or 2 if used without a level)\n"
#endif
    " --inline={yes|no}         Control whether inlining is permitted (overrides functions declared as @inline)\n"
    " --check-bounds={yes|no}   Emit bounds checks always or never (ignoring declarations)\n"
#ifdef USE_POLLY
    " --polly={yes|no}          Enable or disable the polyhedral optimizer Polly (overrides @polly declaration)\n"
#endif
    " --math-mode={ieee,fast}   Disallow or enable unsafe floating point optimizations (overrides @fastmath declaration)\n\n"

    // error and warning options
    " --depwarn={yes|no|error}  Enable or disable syntax and method deprecation warnings (\"error\" turns warnings into errors)\n\n"

    // compiler output options
    " --output-o name           Generate an object file (including system image data)\n"
    " --output-ji name          Generate a system image data file (.ji)\n"
    " --output-bc name          Generate LLVM bitcode (.bc)\n"
    " --output-incremental=no   Generate an incremental output file (rather than complete)\n\n"

    // instrumentation options
    " --code-coverage={none|user|all}, --code-coverage\n"
    "                           Count executions of source lines (omitting setting is equivalent to \"user\")\n"
    " --track-allocation={none|user|all}, --track-allocation\n"
    "                           Count bytes allocated by each source line\n\n"
;

JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
{
    enum { opt_machinefile = 300,
           opt_color,
           opt_history_file,
           opt_startup_file,
           opt_compile,
           opt_code_coverage,
           opt_track_allocation,
           opt_check_bounds,
           opt_output_bc,
           opt_depwarn,
           opt_inline,
           opt_polly,
           opt_math_mode,
           opt_worker,
           opt_bind_to,
           opt_handle_signals,
           opt_output_o,
           opt_output_ji,
           opt_use_precompiled,
           opt_use_compilecache,
           opt_incremental
    };
    static const char* const shortopts = "+vhqH:e:E:L:J:C:ip:O:g:";
    static const struct option longopts[] = {
        // exposed command line options
        // NOTE: This set of required arguments need to be kept in sync
        // with the required arguments defined in base/client.jl `process_options()`
        { "version",         no_argument,       0, 'v' },
        { "help",            no_argument,       0, 'h' },
        { "quiet",           no_argument,       0, 'q' },
        { "home",            required_argument, 0, 'H' },
        { "eval",            required_argument, 0, 'e' },
        { "print",           required_argument, 0, 'E' },
        { "load",            required_argument, 0, 'L' },
        { "sysimage",        required_argument, 0, 'J' },
        { "precompiled",     required_argument, 0, opt_use_precompiled },
        { "compilecache",    required_argument, 0, opt_use_compilecache },
        { "cpu-target",      required_argument, 0, 'C' },
        { "procs",           required_argument, 0, 'p' },
        { "machinefile",     required_argument, 0, opt_machinefile },
        { "color",           required_argument, 0, opt_color },
        { "history-file",    required_argument, 0, opt_history_file },
        { "startup-file",    required_argument, 0, opt_startup_file },
        { "compile",         required_argument, 0, opt_compile },
        { "code-coverage",   optional_argument, 0, opt_code_coverage },
        { "track-allocation",optional_argument, 0, opt_track_allocation },
        { "optimize",        optional_argument, 0, 'O' },
        { "check-bounds",    required_argument, 0, opt_check_bounds },
        { "output-bc",       required_argument, 0, opt_output_bc },
        { "output-o",        required_argument, 0, opt_output_o },
        { "output-ji",       required_argument, 0, opt_output_ji },
        { "output-incremental",required_argument, 0, opt_incremental },
        { "depwarn",         required_argument, 0, opt_depwarn },
        { "inline",          required_argument, 0, opt_inline },
        { "polly",           required_argument, 0, opt_polly },
        { "math-mode",       required_argument, 0, opt_math_mode },
        { "handle-signals",  required_argument, 0, opt_handle_signals },
        // hidden command line options
        { "worker",          required_argument, 0, opt_worker },
        { "bind-to",         required_argument, 0, opt_bind_to },
        { "lisp",            no_argument,       0, 1 },
        { 0, 0, 0, 0 }
    };

    // If CPUID specific binaries are enabled, this varies between runs, so initialize
    // it here, rather than as part of the static initialization above.
    jl_options.image_file = jl_get_default_sysimg_path();

    int codecov  = JL_LOG_NONE;
    int malloclog= JL_LOG_NONE;
    // getopt handles argument parsing up to -- delineator
    int argc = *argcp;
    char **argv = *argvp;
    if (argc > 0) {
        for (int i=0; i < argc; i++) {
            if (!strcmp(argv[i], "--")) {
                argc = i;
                break;
            }
        }
    }
    char *endptr;
    opterr = 0; // suppress getopt warning messages
    while (1) {
        int lastind = optind;
        int c = getopt_long(argc, argv, shortopts, longopts, 0);
        if (c == -1) break;
restart_switch:
        switch (c) {
        case 0:
            break;
        case 1:
            jl_errorf("--lisp must be specified as the first argument");
            break;
        case '?':
        case ':':
            if (optopt) {
                if (optopt == 'g') {
                    c = 'g';
                    goto restart_switch;
                }
                for (const struct option *o = longopts; o->val; o++) {
                    if (optopt == o->val) {
                        if (o->has_arg == optional_argument) {
                            c = o->val;
                            goto restart_switch;
                        }
                        else if (strchr(shortopts, o->val)) {
                            jl_errorf("option `-%c/--%s` is missing an argument", o->val, o->name);
                        }
                        else {
                            jl_errorf("option `--%s` is missing an argument", o->name);
                        }
                    }
                }
                jl_errorf("unknown option `-%c`", optopt);
            }
            else {
                jl_errorf("unknown option `%s`", argv[lastind]);
            }
            break;
        case 'v': // version
            jl_printf(JL_STDOUT, "julia version %s\n", JULIA_VERSION_STRING);
            jl_exit(0);
        case 'h': // help
            jl_printf(JL_STDOUT, "%s%s", usage, opts);
            jl_exit(0);
        case 'q': // quiet
            jl_options.quiet = 1;
            break;
        case 'g': // debug info
            if (optarg != NULL) {
                if (!strcmp(optarg,"0"))
                    jl_options.debug_level = 0;
                else if (!strcmp(optarg,"1"))
                    jl_options.debug_level = 1;
                else if (!strcmp(optarg,"2"))
                    jl_options.debug_level = 2;
                else
                    jl_errorf("julia: invalid argument to -g (%s)", optarg);
                break;
            }
            else {
                jl_options.debug_level = 2;
            }
            break;
        case 'H': // home
            jl_options.julia_home = strdup(optarg);
            break;
        case 'e': // eval
            jl_options.eval = strdup(optarg);
            break;
        case 'E': // print
            jl_options.print = strdup(optarg);
            break;
        case 'L': // load
            jl_options.load = strdup(optarg);
            break;
        case 'J': // sysimage
            jl_options.image_file = strdup(optarg);
            jl_options.image_file_specified = 1;
            break;
        case opt_use_precompiled:
            if (!strcmp(optarg,"yes"))
                jl_options.use_precompiled = JL_OPTIONS_USE_PRECOMPILED_YES;
            else if (!strcmp(optarg,"no"))
                jl_options.use_precompiled = JL_OPTIONS_USE_PRECOMPILED_NO;
            else
                jl_errorf("julia: invalid argument to --precompiled={yes|no} (%s)", optarg);
            break;
        case opt_use_compilecache:
            if (!strcmp(optarg,"yes"))
                jl_options.use_compilecache = JL_OPTIONS_USE_COMPILECACHE_YES;
            else if (!strcmp(optarg,"no"))
                jl_options.use_compilecache = JL_OPTIONS_USE_COMPILECACHE_NO;
            else
                jl_errorf("julia: invalid argument to --compilecache={yes|no} (%s)", optarg);
            break;
        case 'C': // cpu-target
            jl_options.cpu_target = strdup(optarg);
            break;
        case 'p': // procs
            errno = 0;
            if (!strcmp(optarg,"auto")) {
                jl_options.nprocs = jl_cpu_cores();
            }
            else {
                long nprocs = strtol(optarg, &endptr, 10);
                if (errno != 0 || optarg == endptr || *endptr != 0 || nprocs < 1 || nprocs >= INT_MAX)
                    jl_errorf("julia: -p,--procs=<n> must be an integer >= 1");
                jl_options.nprocs = (int)nprocs;
            }
            break;
        case opt_machinefile:
            jl_options.machinefile = strdup(optarg);
            break;
        case opt_color:
            if (!strcmp(optarg,"yes"))
                jl_options.color = JL_OPTIONS_COLOR_ON;
            else if (!strcmp(optarg,"no"))
                jl_options.color = JL_OPTIONS_COLOR_OFF;
            else
                jl_errorf("julia: invalid argument to --color={yes|no} (%s)", optarg);
            break;
        case opt_history_file:
            if (!strcmp(optarg,"yes"))
                jl_options.historyfile = JL_OPTIONS_HISTORYFILE_ON;
            else if (!strcmp(optarg,"no"))
                jl_options.historyfile = JL_OPTIONS_HISTORYFILE_OFF;
            else
                jl_errorf("julia: invalid argument to --history-file={yes|no} (%s)", optarg);
            break;
        case opt_startup_file:
            if (!strcmp(optarg,"yes"))
                jl_options.startupfile = JL_OPTIONS_STARTUPFILE_ON;
            else if (!strcmp(optarg,"no"))
                jl_options.startupfile = JL_OPTIONS_STARTUPFILE_OFF;
            else
                jl_errorf("julia: invalid argument to --startup-file={yes|no} (%s)", optarg);
            break;
        case opt_compile:
            if (!strcmp(optarg,"yes"))
                jl_options.compile_enabled = JL_OPTIONS_COMPILE_ON;
            else if (!strcmp(optarg,"no"))
                jl_options.compile_enabled = JL_OPTIONS_COMPILE_OFF;
            else if (!strcmp(optarg,"all"))
                jl_options.compile_enabled = JL_OPTIONS_COMPILE_ALL;
            else if (!strcmp(optarg,"min"))
                jl_options.compile_enabled = JL_OPTIONS_COMPILE_MIN;
            else
                jl_errorf("julia: invalid argument to --compile (%s)", optarg);
            break;
        case opt_code_coverage:
            if (optarg != NULL) {
                if (!strcmp(optarg,"user"))
                    codecov = JL_LOG_USER;
                else if (!strcmp(optarg,"all"))
                    codecov = JL_LOG_ALL;
                else if (!strcmp(optarg,"none"))
                    codecov = JL_LOG_NONE;
                else
                    jl_errorf("julia: invalid argument to --code-coverage (%s)", optarg);
                break;
            }
            else {
                codecov = JL_LOG_USER;
            }
            break;
        case opt_track_allocation:
            if (optarg != NULL) {
                if (!strcmp(optarg,"user"))
                    malloclog = JL_LOG_USER;
                else if (!strcmp(optarg,"all"))
                    malloclog = JL_LOG_ALL;
                else if (!strcmp(optarg,"none"))
                    malloclog = JL_LOG_NONE;
                else
                    jl_errorf("julia: invalid argument to --track-allocation (%s)", optarg);
                break;
            }
            else {
                malloclog = JL_LOG_USER;
            }
            break;
        case 'O': // optimize
            if (optarg != NULL) {
                if (!strcmp(optarg,"0"))
                    jl_options.opt_level = 0;
                else if (!strcmp(optarg,"1"))
                    jl_options.opt_level = 1;
                else if (!strcmp(optarg,"2"))
                    jl_options.opt_level = 2;
                else if (!strcmp(optarg,"3"))
                    jl_options.opt_level = 3;
                else
                    jl_errorf("julia: invalid argument to -O (%s)", optarg);
                break;
            }
            else {
                jl_options.opt_level = 3;
            }
            break;
        case 'i': // isinteractive
            jl_options.isinteractive = 1;
            break;
        case opt_check_bounds:
            if (!strcmp(optarg,"yes"))
                jl_options.check_bounds = JL_OPTIONS_CHECK_BOUNDS_ON;
            else if (!strcmp(optarg,"no"))
                jl_options.check_bounds = JL_OPTIONS_CHECK_BOUNDS_OFF;
            else
                jl_errorf("julia: invalid argument to --check-bounds={yes|no} (%s)", optarg);
            break;
        case opt_output_bc:
            jl_options.outputbc = optarg;
            if (!jl_options.image_file_specified) jl_options.image_file = NULL;
            break;
        case opt_output_o:
            jl_options.outputo = optarg;
            if (!jl_options.image_file_specified) jl_options.image_file = NULL;
            break;
        case opt_output_ji:
            jl_options.outputji = optarg;
            if (!jl_options.image_file_specified) jl_options.image_file = NULL;
            break;
        case opt_incremental:
            if (!strcmp(optarg,"yes"))
                jl_options.incremental = 1;
            else if (!strcmp(optarg,"no"))
                jl_options.incremental = 0;
            else
                jl_errorf("julia: invalid argument to --output-incremental={yes|no} (%s)", optarg);
            break;
        case opt_depwarn:
            if (!strcmp(optarg,"yes"))
                jl_options.depwarn = JL_OPTIONS_DEPWARN_ON;
            else if (!strcmp(optarg,"no"))
                jl_options.depwarn = JL_OPTIONS_DEPWARN_OFF;
            else if (!strcmp(optarg,"error"))
                jl_options.depwarn = JL_OPTIONS_DEPWARN_ERROR;
            else
                jl_errorf("julia: invalid argument to --depwarn={yes|no|error} (%s)", optarg);
            break;
        case opt_inline:
            if (!strcmp(optarg,"yes"))
                jl_options.can_inline = 1;
            else if (!strcmp(optarg,"no"))
                jl_options.can_inline = 0;
            else {
                jl_errorf("julia: invalid argument to --inline (%s)", optarg);
            }
            break;
       case opt_polly:
            if (!strcmp(optarg,"yes"))
                jl_options.polly = JL_OPTIONS_POLLY_ON;
            else if (!strcmp(optarg,"no"))
                jl_options.polly = JL_OPTIONS_POLLY_OFF;
            else {
                jl_errorf("julia: invalid argument to --polly (%s)", optarg);
            }
            break;
        case opt_math_mode:
            if (!strcmp(optarg,"ieee"))
                jl_options.fast_math = JL_OPTIONS_FAST_MATH_OFF;
            else if (!strcmp(optarg,"fast"))
                jl_options.fast_math = JL_OPTIONS_FAST_MATH_ON;
            else if (!strcmp(optarg,"user"))
                jl_options.fast_math = JL_OPTIONS_FAST_MATH_DEFAULT;
            else
                jl_errorf("julia: invalid argument to --math-mode (%s)", optarg);
            break;
        case opt_worker:
            jl_options.worker = strdup(optarg);
            break;
        case opt_bind_to:
            jl_options.bindto = strdup(optarg);
            break;
        case opt_handle_signals:
            if (!strcmp(optarg,"yes"))
                jl_options.handle_signals = JL_OPTIONS_HANDLE_SIGNALS_ON;
            else if (!strcmp(optarg,"no"))
                jl_options.handle_signals = JL_OPTIONS_HANDLE_SIGNALS_OFF;
            else
                jl_errorf("julia: invalid argument to --handle-signals (%s)", optarg);
            break;
        default:
            jl_errorf("julia: unhandled option -- %c\n"
                      "This is a bug, please report it.", c);
        }
    }
    jl_options.code_coverage = codecov;
    jl_options.malloc_log = malloclog;
    *argvp += optind;
    *argcp -= optind;
}

JL_DLLEXPORT void jl_set_ARGS(int argc, char **argv)
{
    if (jl_core_module != NULL) {
        jl_array_t *args = (jl_array_t*)jl_get_global(jl_core_module, jl_symbol("ARGS"));
        if (args == NULL) {
            args = jl_alloc_vec_any(0);
            JL_GC_PUSH1(&args);
            jl_set_const(jl_core_module, jl_symbol("ARGS"), (jl_value_t*)args);
            JL_GC_POP();
        }
        assert(jl_array_len(args) == 0);
        jl_array_grow_end(args, argc);
        int i;
        for (i=0; i < argc; i++) {
            jl_value_t *s = (jl_value_t*)jl_cstr_to_string(argv[i]);
            jl_arrayset(args, s, i);
        }
    }
}
back to top