in rts/RtsFlags.c [764:1602]
static void procRtsOpts (int rts_argc0,
RtsOptsEnabledEnum rtsOptsEnabled)
{
bool error = false;
int arg;
int unchecked_arg_start;
if (!(rts_argc0 < rts_argc)) return;
if (rtsOptsEnabled == RtsOptsNone) {
errorRtsOptsDisabled("RTS options are disabled. %s");
stg_exit(EXIT_FAILURE);
}
checkSuid(rtsOptsEnabled);
// Process RTS (rts_argv) part: mainly to determine statsfile
for (arg = rts_argc0; arg < rts_argc; arg++) {
/* We handle RtsOptsSafeOnly mode by declaring each option as
either OPTION_SAFE or OPTION_UNSAFE. To make sure we cover
every branch we use an option_checked flag which is reset
at the start each iteration and checked at the end. */
bool option_checked = false;
// See Note [OPTION_SAFE vs OPTION_UNSAFE].
#define OPTION_SAFE option_checked = true;
#define OPTION_UNSAFE checkUnsafe(rtsOptsEnabled); option_checked = true;
if (rts_argv[arg][0] != '-') {
fflush(stdout);
errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
error = true;
} else {
/* 0 is dash, 1 is first letter */
/* see Trac #9839 */
unchecked_arg_start = 1;
switch(rts_argv[arg][1]) {
/* process: general args, then PROFILING-only ones, then
CONCURRENT-only, TICKY-only (same order as defined in
RtsFlags.lh); within those groups, mostly in
case-insensitive alphabetical order. Final group is
x*, which allows for more options.
*/
#if defined(TICKY_TICKY)
# define TICKY_BUILD_ONLY(x) x
#else
# define TICKY_BUILD_ONLY(x) \
errorBelch("the flag %s requires the program to be built with -ticky", \
rts_argv[arg]); \
error = true;
#endif
#if defined(PROFILING)
# define PROFILING_BUILD_ONLY(x) x
#else
# define PROFILING_BUILD_ONLY(x) \
errorBelch("the flag %s requires the program to be built with -prof", \
rts_argv[arg]); \
error = true;
#endif
#if defined(TRACING)
# define TRACING_BUILD_ONLY(x) x
#else
# define TRACING_BUILD_ONLY(x) \
errorBelch("the flag %s requires the program to be built with -eventlog or -debug", \
rts_argv[arg]); \
error = true;
#endif
#if defined(THREADED_RTS)
# define THREADED_BUILD_ONLY(x) x
#else
# define THREADED_BUILD_ONLY(x) \
errorBelch("the flag %s requires the program to be built with -threaded", \
rts_argv[arg]); \
error = true;
#endif
#if defined(DEBUG)
# define DEBUG_BUILD_ONLY(x) x
#else
# define DEBUG_BUILD_ONLY(x) \
errorBelch("the flag %s requires the program to be built with -debug", \
rts_argv[arg]); \
error = true;
#endif
/* =========== GENERAL ========================== */
case '?':
OPTION_SAFE;
error = true;
break;
/* This isn't going to allow us to keep related options
together as we add more --* flags. We really need a
proper options parser. */
case '-':
if (strequal("install-signal-handlers=yes",
&rts_argv[arg][2])) {
OPTION_UNSAFE;
RtsFlags.MiscFlags.install_signal_handlers = true;
}
else if (strequal("install-signal-handlers=no",
&rts_argv[arg][2])) {
OPTION_UNSAFE;
RtsFlags.MiscFlags.install_signal_handlers = false;
}
else if (strequal("install-seh-handlers=yes",
&rts_argv[arg][2])) {
OPTION_UNSAFE;
RtsFlags.MiscFlags.install_seh_handlers = true;
}
else if (strequal("install-seh-handlers=no",
&rts_argv[arg][2])) {
OPTION_UNSAFE;
RtsFlags.MiscFlags.install_seh_handlers = false;
}
else if (strequal("generate-stack-traces=yes",
&rts_argv[arg][2])) {
OPTION_UNSAFE;
RtsFlags.MiscFlags.generate_stack_trace = true;
}
else if (strequal("generate-stack-traces=no",
&rts_argv[arg][2])) {
OPTION_UNSAFE;
RtsFlags.MiscFlags.generate_stack_trace = false;
}
else if (strequal("generate-crash-dumps",
&rts_argv[arg][2])) {
OPTION_UNSAFE;
RtsFlags.MiscFlags.generate_dump_file = true;
}
else if (strequal("machine-readable",
&rts_argv[arg][2])) {
OPTION_UNSAFE;
RtsFlags.MiscFlags.machineReadable = true;
}
else if (strequal("internal-counters",
&rts_argv[arg][2])) {
OPTION_SAFE;
RtsFlags.MiscFlags.internalCounters = true;
}
else if (strequal("info",
&rts_argv[arg][2])) {
OPTION_SAFE;
printRtsInfo(rtsConfig);
stg_exit(0);
}
#if defined(THREADED_RTS)
else if (!strncmp("numa", &rts_argv[arg][2], 4)) {
if (!osBuiltWithNumaSupport()) {
errorBelch("%s: This GHC build was compiled without NUMA support.",
rts_argv[arg]);
error = true;
break;
}
OPTION_SAFE;
StgWord mask;
if (rts_argv[arg][6] == '=') {
mask = (StgWord)strtol(rts_argv[arg]+7,
(char **) NULL, 10);
} else {
mask = (StgWord)~0;
}
if (!osNumaAvailable()) {
errorBelch("%s: OS reports NUMA is not available",
rts_argv[arg]);
error = true;
break;
}
RtsFlags.GcFlags.numa = true;
RtsFlags.GcFlags.numaMask = mask;
}
#endif
#if defined(DEBUG) && defined(THREADED_RTS)
else if (!strncmp("debug-numa", &rts_argv[arg][2], 10)) {
OPTION_SAFE;
size_t nNodes;
if (rts_argv[arg][12] == '=' &&
isdigit(rts_argv[arg][13])) {
nNodes = (StgWord)strtol(rts_argv[arg]+13,
(char **) NULL, 10);
} else {
errorBelch("%s: missing number of nodes",
rts_argv[arg]);
error = true;
break;
}
if (nNodes > MAX_NUMA_NODES) {
errorBelch("%s: Too many NUMA nodes (max %d)",
rts_argv[arg], MAX_NUMA_NODES);
error = true;
} else {
RtsFlags.GcFlags.numa = true;
RtsFlags.DebugFlags.numa = true;
RtsFlags.GcFlags.numaMask = (1<<nNodes) - 1;
}
}
#endif
else if (!strncmp("long-gc-sync=", &rts_argv[arg][2], 13)) {
OPTION_SAFE;
if (rts_argv[arg][2] == '\0') {
/* use default */
} else {
RtsFlags.GcFlags.longGCSync =
fsecondsToTime(atof(rts_argv[arg]+16));
}
break;
}
else {
OPTION_SAFE;
errorBelch("unknown RTS option: %s",rts_argv[arg]);
error = true;
}
break;
case 'A':
OPTION_UNSAFE;
if (rts_argv[arg][2] == 'L') {
RtsFlags.GcFlags.largeAllocLim
= decodeSize(rts_argv[arg], 3, 2*BLOCK_SIZE,
HS_INT_MAX) / BLOCK_SIZE;
} else {
// minimum two blocks in the nursery, so that we have one
// to grab for allocate().
RtsFlags.GcFlags.minAllocAreaSize
= decodeSize(rts_argv[arg], 2, 2*BLOCK_SIZE,
HS_INT_MAX) / BLOCK_SIZE;
}
break;
case 'n':
OPTION_UNSAFE;
RtsFlags.GcFlags.nurseryChunkSize
= decodeSize(rts_argv[arg], 2, 2*BLOCK_SIZE, HS_INT_MAX)
/ BLOCK_SIZE;
break;
case 'B':
OPTION_UNSAFE;
RtsFlags.GcFlags.ringBell = true;
unchecked_arg_start++;
goto check_rest;
case 'c':
OPTION_UNSAFE;
if (rts_argv[arg][2] != '\0') {
RtsFlags.GcFlags.compactThreshold =
atof(rts_argv[arg]+2);
} else {
RtsFlags.GcFlags.compact = true;
}
break;
case 'w':
OPTION_UNSAFE;
RtsFlags.GcFlags.sweep = true;
unchecked_arg_start++;
goto check_rest;
case 'F':
OPTION_UNSAFE;
RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);
if (RtsFlags.GcFlags.oldGenFactor < 0)
bad_option( rts_argv[arg] );
break;
case 'D':
OPTION_SAFE;
DEBUG_BUILD_ONLY(read_debug_flags(rts_argv[arg]);)
break;
case 'K':
OPTION_UNSAFE;
RtsFlags.GcFlags.maxStkSize =
decodeSize(rts_argv[arg], 2, 0, HS_WORD_MAX)
/ sizeof(W_);
break;
case 'k':
OPTION_UNSAFE;
switch(rts_argv[arg][2]) {
case 'c':
RtsFlags.GcFlags.stkChunkSize =
decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
/ sizeof(W_);
break;
case 'b':
RtsFlags.GcFlags.stkChunkBufferSize =
decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
/ sizeof(W_);
break;
case 'i':
RtsFlags.GcFlags.initialStkSize =
decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
/ sizeof(W_);
break;
default:
RtsFlags.GcFlags.initialStkSize =
decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX)
/ sizeof(W_);
break;
}
break;
case 'M':
OPTION_UNSAFE;
if (0 == strncmp("grace=", rts_argv[arg] + 2, 6)) {
RtsFlags.GcFlags.heapLimitGrace =
decodeSize(rts_argv[arg], 8, BLOCK_SIZE, HS_WORD_MAX);
} else {
RtsFlags.GcFlags.maxHeapSize =
decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX)
/ BLOCK_SIZE;
// user give size in *bytes* but "maxHeapSize" is in
// *blocks*
}
break;
case 'm':
/* Case for maxN feature request ticket #10728, it's a little
odd being so far from the N case. */
#if !defined(NOSMP)
if (strncmp("maxN", &rts_argv[arg][1], 4) == 0) {
OPTION_SAFE;
THREADED_BUILD_ONLY(
int nCapabilities;
int proc = (int)getNumberOfProcessors();
nCapabilities = strtol(rts_argv[arg]+5, (char **) NULL, 10);
if (nCapabilities > proc) { nCapabilities = proc; }
if (nCapabilities <= 0) {
errorBelch("bad value for -maxN");
error = true;
}
#if defined(PROFILING)
RtsFlags.ParFlags.nCapabilities = 1;
#else
RtsFlags.ParFlags.nCapabilities = (uint32_t)nCapabilities;
#endif
) break;
} else {
#endif
OPTION_UNSAFE;
RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
/* -m was allowing bad flags to go unreported */
if (RtsFlags.GcFlags.pcFreeHeap == 0.0 &&
rts_argv[arg][2] != '0')
bad_option( rts_argv[arg] );
if (RtsFlags.GcFlags.pcFreeHeap < 0 ||
RtsFlags.GcFlags.pcFreeHeap > 100)
bad_option( rts_argv[arg] );
break;
#if !defined(NOSMP)
}
#endif
case 'G':
OPTION_UNSAFE;
RtsFlags.GcFlags.generations =
decodeSize(rts_argv[arg], 2, 1, HS_INT_MAX);
break;
case 'H':
OPTION_UNSAFE;
if (rts_argv[arg][2] == '\0') {
RtsFlags.GcFlags.heapSizeSuggestionAuto = true;
} else {
RtsFlags.GcFlags.heapSizeSuggestion = (uint32_t)
(decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX)
/ BLOCK_SIZE);
}
break;
case 'O':
OPTION_UNSAFE;
RtsFlags.GcFlags.minOldGenSize =
(uint32_t)(decodeSize(rts_argv[arg], 2, BLOCK_SIZE,
HS_WORD_MAX)
/ BLOCK_SIZE);
break;
case 'I': /* idle GC delay */
OPTION_UNSAFE;
if (rts_argv[arg][2] == '\0') {
/* use default */
} else {
Time t = fsecondsToTime(atof(rts_argv[arg]+2));
if (t == 0) {
RtsFlags.GcFlags.doIdleGC = false;
} else {
RtsFlags.GcFlags.doIdleGC = true;
RtsFlags.GcFlags.idleGCDelayTime = t;
}
}
break;
case 'T':
OPTION_SAFE;
RtsFlags.GcFlags.giveStats = COLLECT_GC_STATS;
unchecked_arg_start++;
goto check_rest; /* Don't initialize statistics file. */
case 'S':
OPTION_SAFE; /* but see below */
RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS;
goto stats;
case 's':
OPTION_SAFE; /* but see below */
RtsFlags.GcFlags.giveStats = SUMMARY_GC_STATS;
goto stats;
case 't':
OPTION_SAFE; /* but see below */
RtsFlags.GcFlags.giveStats = ONELINE_GC_STATS;
goto stats;
stats:
{
int r;
if (rts_argv[arg][2] != '\0') {
OPTION_UNSAFE;
}
r = openStatsFile(rts_argv[arg]+2, NULL,
&RtsFlags.GcFlags.statsFile);
if (r == -1) { error = true; }
}
break;
case 'Z':
OPTION_UNSAFE;
RtsFlags.GcFlags.squeezeUpdFrames = false;
unchecked_arg_start++;
goto check_rest;
/* =========== PROFILING ========================== */
case 'P': /* detailed cost centre profiling (time/alloc) */
case 'p': /* cost centre profiling (time/alloc) */
OPTION_SAFE;
PROFILING_BUILD_ONLY(
switch (rts_argv[arg][2]) {
case 'a':
RtsFlags.CcFlags.doCostCentres = COST_CENTRES_ALL;
if (rts_argv[arg][3] != '\0') {
errorBelch("flag -Pa given an argument"
" when none was expected: %s"
,rts_argv[arg]);
error = true;
}
break;
case 'j':
RtsFlags.CcFlags.doCostCentres = COST_CENTRES_JSON;
break;
case 'o':
if (rts_argv[arg][3] == '\0') {
errorBelch("flag -po expects an argument");
error = true;
break;
}
RtsFlags.CcFlags.outputFileNameStem = rts_argv[arg]+3;
break;
case '\0':
if (rts_argv[arg][1] == 'P') {
RtsFlags.CcFlags.doCostCentres = COST_CENTRES_VERBOSE;
} else {
RtsFlags.CcFlags.doCostCentres = COST_CENTRES_SUMMARY;
}
break;
default:
unchecked_arg_start++;
goto check_rest;
}
) break;
case 'R':
OPTION_SAFE;
PROFILING_BUILD_ONLY(
RtsFlags.ProfFlags.maxRetainerSetSize =
atof(rts_argv[arg]+2);
) break;
case 'L':
OPTION_SAFE;
PROFILING_BUILD_ONLY(
RtsFlags.ProfFlags.ccsLength = atof(rts_argv[arg]+2);
if(RtsFlags.ProfFlags.ccsLength <= 0) {
bad_option(rts_argv[arg]);
}
) break;
case 'h': /* serial heap profile */
#if !defined(PROFILING)
switch (rts_argv[arg][2]) {
case '\0':
case 'T':
OPTION_UNSAFE;
RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE;
break;
default:
OPTION_SAFE;
PROFILING_BUILD_ONLY();
}
#else
OPTION_SAFE;
PROFILING_BUILD_ONLY(
error = read_heap_profiling_flag(rts_argv[arg]);
);
#endif /* PROFILING */
break;
case 'i': /* heap sample interval */
OPTION_UNSAFE;
if (rts_argv[arg][2] == '\0') {
/* use default */
} else {
RtsFlags.ProfFlags.heapProfileInterval =
fsecondsToTime(atof(rts_argv[arg]+2));
}
break;
/* =========== CONCURRENT ========================= */
case 'C': /* context switch interval */
OPTION_UNSAFE;
if (rts_argv[arg][2] == '\0')
RtsFlags.ConcFlags.ctxtSwitchTime = 0;
else {
RtsFlags.ConcFlags.ctxtSwitchTime =
fsecondsToTime(atof(rts_argv[arg]+2));
}
break;
case 'V': /* master tick interval */
OPTION_UNSAFE;
if (rts_argv[arg][2] == '\0') {
// turns off ticks completely
RtsFlags.MiscFlags.tickInterval = 0;
} else {
RtsFlags.MiscFlags.tickInterval =
fsecondsToTime(atof(rts_argv[arg]+2));
}
break;
#if !defined(NOSMP)
case 'N':
OPTION_SAFE;
THREADED_BUILD_ONLY(
if (rts_argv[arg][2] == '\0') {
RtsFlags.ParFlags.nCapabilities = getNumberOfProcessors();
} else {
int nCapabilities;
OPTION_SAFE; /* but see extra checks below... */
nCapabilities = strtol(rts_argv[arg]+2, (char **) NULL, 10);
if (nCapabilities <= 0) {
errorBelch("bad value for -N");
error = true;
}
if (rtsOptsEnabled == RtsOptsSafeOnly &&
nCapabilities > (int)getNumberOfProcessors()) {
errorRtsOptsDisabled("Using large values for -N is not allowed by default. %s");
stg_exit(EXIT_FAILURE);
}
RtsFlags.ParFlags.nCapabilities = (uint32_t)nCapabilities;
}
) break;
case 'g':
OPTION_UNSAFE;
THREADED_BUILD_ONLY(
switch (rts_argv[arg][2]) {
case '1':
// backwards compat only
RtsFlags.ParFlags.parGcEnabled = false;
break;
default:
errorBelch("unknown RTS option: %s",rts_argv[arg]);
error = true;
break;
}
) break;
case 'q':
OPTION_UNSAFE;
THREADED_BUILD_ONLY(
switch (rts_argv[arg][2]) {
case '\0':
errorBelch("incomplete RTS option: %s",rts_argv[arg]);
error = true;
break;
case 'g':
if (rts_argv[arg][3] == '\0') {
RtsFlags.ParFlags.parGcEnabled = false;
} else {
RtsFlags.ParFlags.parGcEnabled = true;
RtsFlags.ParFlags.parGcGen
= strtol(rts_argv[arg]+3, (char **) NULL, 10);
}
break;
case 'b':
if (rts_argv[arg][3] == '\0') {
RtsFlags.ParFlags.parGcLoadBalancingEnabled =
false;
}
else {
RtsFlags.ParFlags.parGcLoadBalancingEnabled =
true;
RtsFlags.ParFlags.parGcLoadBalancingGen
= strtol(rts_argv[arg]+3, (char **) NULL, 10);
}
break;
case 'i':
RtsFlags.ParFlags.parGcNoSyncWithIdle
= strtol(rts_argv[arg]+3, (char **) NULL, 10);
break;
case 'n': {
int threads;
threads = strtol(rts_argv[arg]+3, (char **) NULL, 10);
if (threads <= 0) {
errorBelch("-qn must be 1 or greater");
error = true;
} else {
RtsFlags.ParFlags.parGcThreads = threads;
}
break;
}
case 'a':
RtsFlags.ParFlags.setAffinity = true;
break;
case 'm':
RtsFlags.ParFlags.migrate = false;
break;
case 'w':
// -qw was removed; accepted for backwards compat
break;
default:
errorBelch("unknown RTS option: %s",rts_argv[arg]);
error = true;
break;
}
) break;
#endif
/* =========== PARALLEL =========================== */
case 'e':
OPTION_UNSAFE;
THREADED_BUILD_ONLY(
if (rts_argv[arg][2] != '\0') {
RtsFlags.ParFlags.maxLocalSparks
= strtol(rts_argv[arg]+2, (char **) NULL, 10);
if (RtsFlags.ParFlags.maxLocalSparks <= 0) {
errorBelch("bad value for -e");
error = true;
}
}
) break;
/* =========== TICKY ============================== */
case 'r': /* Basic profiling stats */
OPTION_SAFE;
TICKY_BUILD_ONLY(
RtsFlags.TickyFlags.showTickyStats = true;
{
int r;
if (rts_argv[arg][2] != '\0') {
OPTION_UNSAFE;
}
r = openStatsFile(rts_argv[arg]+2,
TICKY_FILENAME_FMT,
&RtsFlags.TickyFlags.tickyFile);
if (r == -1) { error = true; }
}
) break;
/* =========== OUTPUT ============================ */
case 'o':
switch(rts_argv[arg][2]) {
case 'l':
OPTION_SAFE;
TRACING_BUILD_ONLY(
if (strlen(&rts_argv[arg][3]) == 0) {
errorBelch("-ol expects filename");
error = true;
} else {
RtsFlags.TraceFlags.trace_output =
strdup(&rts_argv[arg][3]);
}
);
break;
default:
errorBelch("Unknown output flag -o%c", rts_argv[arg][2]);
error = true;
}
break;
/* =========== TRACING ============================ */
case 'l':
OPTION_SAFE;
TRACING_BUILD_ONLY(
RtsFlags.TraceFlags.tracing = TRACE_EVENTLOG;
read_trace_flags(&rts_argv[arg][2]);
);
break;
case 'v':
OPTION_SAFE;
DEBUG_BUILD_ONLY(
RtsFlags.TraceFlags.tracing = TRACE_STDERR;
read_trace_flags(&rts_argv[arg][2]);
);
break;
/* =========== EXTENDED OPTIONS =================== */
case 'x': /* Extend the argument space */
unchecked_arg_start++;
switch(rts_argv[arg][2]) {
case '\0':
OPTION_SAFE;
errorBelch("incomplete RTS option: %s",rts_argv[arg]);
error = true;
break;
case 'b': /* heapBase in hex; undocumented */
OPTION_UNSAFE;
if (rts_argv[arg][3] != '\0') {
RtsFlags.GcFlags.heapBase
= strToStgWord(rts_argv[arg]+3, (char **) NULL, 0);
} else {
errorBelch("-xb: requires argument");
error = true;
}
break;
#if defined(x86_64_HOST_ARCH)
case 'p': /* linkerAlwaysPic */
OPTION_UNSAFE;
RtsFlags.MiscFlags.linkerAlwaysPic = true;
break;
case 'm': /* linkerMemBase */
OPTION_UNSAFE;
if (rts_argv[arg][3] != '\0') {
RtsFlags.MiscFlags.linkerMemBase
= strtol(rts_argv[arg]+3, (char **) NULL, 16);
if (RtsFlags.MiscFlags.linkerMemBase > 0x80000000) {
errorBelch("-xm: value must be <80000000");
error = true;
}
} else {
RtsFlags.MiscFlags.linkerMemBase = 0;
}
break;
#endif
case 'c': /* Debugging tool: show current cost centre on
an exception */
OPTION_SAFE;
PROFILING_BUILD_ONLY(
RtsFlags.ProfFlags.showCCSOnException = true;
);
unchecked_arg_start++;
goto check_rest;
case 't': /* Include memory used by TSOs in a heap profile */
OPTION_SAFE;
PROFILING_BUILD_ONLY(
RtsFlags.ProfFlags.includeTSOs = true;
);
unchecked_arg_start++;
goto check_rest;
/*
* The option prefix '-xx' is reserved for future
* extension. KSW 1999-11.
*/
case 'q':
OPTION_UNSAFE;
RtsFlags.GcFlags.allocLimitGrace
= decodeSize(rts_argv[arg], 3, BLOCK_SIZE, HS_INT_MAX)
/ BLOCK_SIZE;
break;
default:
OPTION_SAFE;
errorBelch("unknown RTS option: %s",rts_argv[arg]);
error = true;
break;
}
break; /* defensive programming */
/* check the rest to be sure there is nothing afterwards.*/
/* see Trac #9839 */
check_rest:
{
/* start checking from the first unchecked position,
* not from index 2*/
/* see Trac #9839 */
if (rts_argv[arg][unchecked_arg_start] != '\0') {
errorBelch("flag -%c given an argument"
" when none was expected: %s",
rts_argv[arg][1],rts_argv[arg]);
error = true;
}
break;
}
/* =========== OH DEAR ============================ */
default:
OPTION_SAFE;
errorBelch("unknown RTS option: %s",rts_argv[arg]);
error = true;
break;
}
if (!option_checked) {
/* Naughty! Someone didn't use OPTION_UNSAFE / OPTION_SAFE for
an option above */
errorBelch("Internal error in the RTS options parser");
stg_exit(EXIT_FAILURE);
}
}
}
if (error) errorUsage();
}