diff options
Diffstat (limited to 'compiler/commands.nim')
-rw-r--r-- | compiler/commands.nim | 1498 |
1 files changed, 989 insertions, 509 deletions
diff --git a/compiler/commands.nim b/compiler/commands.nim index 71de28e09..cbf915ca6 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -9,36 +9,36 @@ # This module handles the parsing of command line arguments. - # We do this here before the 'import' statement so 'defined' does not get -# confused with 'TGCMode.gcGenerational' etc. +# confused with 'TGCMode.gcMarkAndSweep' etc. template bootSwitch(name, expr, userString) = # Helper to build boot constants, for debugging you can 'echo' the else part. const name = if expr: " " & userString else: "" bootSwitch(usedRelease, defined(release), "-d:release") -bootSwitch(usedGnuReadline, defined(useLinenoise), "-d:useLinenoise") -bootSwitch(usedNoCaas, defined(noCaas), "-d:noCaas") +bootSwitch(usedDanger, defined(danger), "-d:danger") +# `useLinenoise` deprecated in favor of `nimUseLinenoise`, kept for backward compatibility +bootSwitch(useLinenoise, defined(nimUseLinenoise) or defined(useLinenoise), "-d:nimUseLinenoise") bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm") bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep") -bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational") bootSwitch(usedGoGC, defined(gogc), "--gc:go") bootSwitch(usedNoGC, defined(nogc), "--gc:none") +import std/[setutils, os, strutils, parseutils, parseopt, sequtils, strtabs, enumutils] import - os, msgs, options, nversion, condsyms, strutils, extccomp, platform, - wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils + msgs, options, nversion, condsyms, extccomp, platform, + wordrecg, nimblecmd, lineinfos, pathutils -# but some have deps to imported modules. Yay. -bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") -bootSwitch(usedAvoidTimeMachine, noTimeMachine, "-d:avoidTimeMachine") -bootSwitch(usedNativeStacktrace, - defined(nativeStackTrace) and nativeStackTraceSupported, - "-d:nativeStackTrace") -bootSwitch(usedFFI, hasFFI, "-d:useFFI") +import std/pathnorm +from ast import setUseIc, eqTypeFlags, tfGcSafe, tfNoSideEffect -proc writeCommandLineUsage*() +when defined(nimPreviewSlimSystem): + import std/assertions + +# but some have deps to imported modules. Yay. +bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") +bootSwitch(usedFFI, hasFFI, "-d:nimHasLibFFI") type TCmdLinePass* = enum @@ -46,674 +46,1154 @@ type passCmd2, # second pass over the command line passPP # preprocessor called processCommand() -proc processCommand*(switch: string, pass: TCmdLinePass) -proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; - config: ConfigRef = nil) +const + HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" & + "Compiled at $4\n" & + "Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n" -# implementation +proc genFeatureDesc[T: enum](t: typedesc[T]): string {.compileTime.} = + result = "" + for f in T: + if result.len > 0: result.add "|" + result.add $f const - HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" & - "Copyright (c) 2006-" & CompileDate.substr(0, 3) & " by Andreas Rumpf\n" + Usage = slurp"../doc/basicopt.txt".replace(" //", " ") + AdvancedUsage = slurp"../doc/advopt.txt".replace(" //", " ") % [genFeatureDesc(Feature), genFeatureDesc(LegacyFeature)] -const - Usage = slurp"../doc/basicopt.txt".replace("//", "") - AdvancedUsage = slurp"../doc/advopt.txt".replace("//", "") +proc getCommandLineDesc(conf: ConfigRef): string = + result = (HelpMessage % [VersionAsString, platform.OS[conf.target.hostOS].name, + CPU[conf.target.hostCPU].name, CompileDate]) & + Usage -proc getCommandLineDesc(): string = - result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name]) & Usage +proc helpOnError(conf: ConfigRef; pass: TCmdLinePass) = + if pass == passCmd1: + msgWriteln(conf, getCommandLineDesc(conf), {msgStdout}) + msgQuit(0) -proc helpOnError(pass: TCmdLinePass) = +proc writeAdvancedUsage(conf: ConfigRef; pass: TCmdLinePass) = if pass == passCmd1: - msgWriteln(getCommandLineDesc(), {msgStdout}) + msgWriteln(conf, (HelpMessage % [VersionAsString, + platform.OS[conf.target.hostOS].name, + CPU[conf.target.hostCPU].name, CompileDate]) & + AdvancedUsage, + {msgStdout}) msgQuit(0) -proc writeAdvancedUsage(pass: TCmdLinePass) = +proc writeFullhelp(conf: ConfigRef; pass: TCmdLinePass) = if pass == passCmd1: - msgWriteln(`%`(HelpMessage, [VersionAsString, - platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name]) & AdvancedUsage, + msgWriteln(conf, `%`(HelpMessage, [VersionAsString, + platform.OS[conf.target.hostOS].name, + CPU[conf.target.hostCPU].name, CompileDate]) & + Usage & AdvancedUsage, {msgStdout}) msgQuit(0) -proc writeVersionInfo(pass: TCmdLinePass) = +proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) = if pass == passCmd1: - msgWriteln(`%`(HelpMessage, [VersionAsString, - platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name]), + msgWriteln(conf, `%`(HelpMessage, [VersionAsString, + platform.OS[conf.target.hostOS].name, + CPU[conf.target.hostCPU].name, CompileDate]), {msgStdout}) - const gitHash = gorge("git log -n 1 --format=%H").strip + const gitHash {.strdefine.} = gorge("git log -n 1 --format=%H").strip + # xxx move this logic to std/private/gitutils when gitHash.len == 40: - msgWriteln("git hash: " & gitHash, {msgStdout}) + msgWriteln(conf, "git hash: " & gitHash, {msgStdout}) - msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine & - usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas & - usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC, + msgWriteln(conf, "active boot switches:" & usedRelease & usedDanger & + usedTinyC & useLinenoise & + usedFFI & usedBoehm & usedMarkAndSweep & usedGoGC & usedNoGC, {msgStdout}) msgQuit(0) -var - helpWritten: bool - -proc writeCommandLineUsage() = - if not helpWritten: - msgWriteln(getCommandLineDesc(), {msgStdout}) - helpWritten = true +proc writeCommandLineUsage*(conf: ConfigRef) = + msgWriteln(conf, getCommandLineDesc(conf), {msgStdout}) proc addPrefix(switch: string): string = - if len(switch) == 1: result = "-" & switch + if switch.len <= 1: result = "-" & switch else: result = "--" & switch -proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) = - if switch == " ": localError(info, errInvalidCmdLineOption, "-") - else: localError(info, errInvalidCmdLineOption, addPrefix(switch)) +const + errInvalidCmdLineOption = "invalid command line option: '$1'" + errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found" + errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found" + errOffHintsError = "'off', 'hint', 'error' or 'usages' expected, but '$1' found" -proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, +proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) = + if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-") + else: localError(conf, info, errInvalidCmdLineOption % addPrefix(switch)) + +proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TCmdLinePass, info: TLineInfo) = cmd = "" var i = 0 - if i < len(switch) and switch[i] == '-': inc(i) - if i < len(switch) and switch[i] == '-': inc(i) - while i < len(switch): + if i < switch.len and switch[i] == '-': inc(i) + if i < switch.len and switch[i] == '-': inc(i) + while i < switch.len: case switch[i] - of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i]) + of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': cmd.add(switch[i]) else: break inc(i) - if i >= len(switch): arg = "" - elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1) - else: invalidCmdLineOption(pass, switch, info) + if i >= switch.len: arg = "" + # cmd:arg => (cmd,arg) + elif switch[i] in {':', '='}: arg = substr(switch, i + 1) + # cmd[sub]:rest => (cmd,[sub]:rest) + elif switch[i] == '[': arg = substr(switch, i) + else: invalidCmdLineOption(conf, pass, switch, info) + +template switchOn(arg: string): bool = + # xxx use `switchOn` wherever appropriate + case arg.normalize + of "", "on": true + of "off": false + else: + localError(conf, info, errOnOrOffExpectedButXFound % arg) + false -proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass, +proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize - of "on": gOptions = gOptions + op - of "off": gOptions = gOptions - op - else: localError(info, errOnOrOffExpectedButXFound, arg) + of "", "on": conf.options.incl op + of "off": conf.options.excl op + else: localError(conf, info, errOnOrOffExpectedButXFound % arg) -proc processOnOffSwitchOrList(op: TOptions, arg: string, pass: TCmdLinePass, +proc processOnOffSwitchOrList(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo): bool = result = false case arg.normalize - of "on": gOptions = gOptions + op - of "off": gOptions = gOptions - op - else: - if arg == "list": - result = true - else: - localError(info, errOnOffOrListExpectedButXFound, arg) + of "on": conf.options.incl op + of "off": conf.options.excl op + of "list": result = true + else: localError(conf, info, errOnOffOrListExpectedButXFound % arg) -proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass, +proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize - of "on": gGlobalOptions = gGlobalOptions + op - of "off": gGlobalOptions = gGlobalOptions - op - else: localError(info, errOnOrOffExpectedButXFound, arg) + of "", "on": conf.globalOptions.incl op + of "off": conf.globalOptions.excl op + else: localError(conf, info, errOnOrOffExpectedButXFound % arg) -proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = - if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch)) +proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = + if arg == "": + localError(conf, info, "argument for command line option expected: '$1'" % addPrefix(switch)) -proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = - if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch)) - -var - enableNotes: TNoteKinds - disableNotes: TNoteKinds +proc expectNoArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = + if arg != "": + localError(conf, info, "invalid argument for command line option: '$1'" % addPrefix(switch)) proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, - info: TLineInfo; orig: string) = - var id = "" # arg = "X]:on|off" + info: TLineInfo; orig: string; conf: ConfigRef) = + var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off var i = 0 - var n = hintMin - while i < len(arg) and (arg[i] != ']'): - add(id, arg[i]) + var notes: set[TMsgKind] = {} + var isBracket = false + if i < arg.len and arg[i] == '[': + isBracket = true + inc(i) + while i < arg.len and (arg[i] notin {':', '=', ']'}): + id.add(arg[i]) inc(i) - if i < len(arg) and (arg[i] == ']'): inc(i) - else: invalidCmdLineOption(pass, orig, info) - if i < len(arg) and (arg[i] in {':', '='}): inc(i) - else: invalidCmdLineOption(pass, orig, info) - if state == wHint: - var x = findStr(msgs.HintsToStr, id) - if x >= 0: n = TNoteKind(x + ord(hintMin)) - else: localError(info, "unknown hint: " & id) + if isBracket: + if i < arg.len and arg[i] == ']': inc(i) + else: invalidCmdLineOption(conf, pass, orig, info) + + if i == arg.len: discard + elif i < arg.len and (arg[i] in {':', '='}): inc(i) + else: invalidCmdLineOption(conf, pass, orig, info) + + let isSomeHint = state in {wHint, wHintAsError} + template findNote(noteMin, noteMax, name) = + # unfortunately, hintUser and warningUser clash, otherwise implementation would simplify a bit + let x = findStr(noteMin, noteMax, id, errUnknown) + if x != errUnknown: notes = {TNoteKind(x)} + else: + if isSomeHint: + message(conf, info, hintUnknownHint, id) + else: + localError(conf, info, "unknown $#: $#" % [name, id]) + case id.normalize + of "all": # other note groups would be easy to support via additional cases + notes = if isSomeHint: {hintMin..hintMax} else: {warnMin..warnMax} + elif isSomeHint: findNote(hintMin, hintMax, "hint") + else: findNote(warnMin, warnMax, "warning") + var val = substr(arg, i).normalize + if val == "": val = "on" + if val notin ["on", "off"]: + # xxx in future work we should also allow users to have control over `foreignPackageNotes` + # so that they can enable `hints|warnings|warningAsErrors` for all the code they depend on. + localError(conf, info, errOnOrOffExpectedButXFound % arg) else: - var x = findStr(msgs.WarningsToStr, id) - if x >= 0: n = TNoteKind(x + ord(warnMin)) - else: localError(info, "unknown warning: " & id) - case substr(arg, i).normalize - of "on": - incl(gNotes, n) - incl(gMainPackageNotes, n) - incl(enableNotes, n) - of "off": - excl(gNotes, n) - excl(gMainPackageNotes, n) - incl(disableNotes, n) - excl(ForeignPackageNotes, n) - else: localError(info, errOnOrOffExpectedButXFound, arg) - -proc processCompile(filename: string) = - var found = findFile(filename) - if found == "": found = filename - extccomp.addExternalFileToCompile(found) - -proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool = + let isOn = val == "on" + if isOn and id.normalize == "all": + localError(conf, info, "only 'all:off' is supported") + for n in notes: + if n notin conf.cmdlineNotes or pass == passCmd1: + if pass == passCmd1: incl(conf.cmdlineNotes, n) + incl(conf.modifiedyNotes, n) + if state in {wWarningAsError, wHintAsError}: + conf.warningAsErrors[n] = isOn # xxx rename warningAsErrors to noteAsErrors + else: + conf.notes[n] = isOn + conf.mainPackageNotes[n] = isOn + if not isOn: excl(conf.foreignPackageNotes, n) + +proc processCompile(conf: ConfigRef; filename: string) = + var found = findFile(conf, filename) + if found.isEmpty: found = AbsoluteFile filename + extccomp.addExternalFileToCompile(conf, found) + +const + errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'atomicArc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found" + errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found" + errGuiConsoleOrLibExpectedButXFound = "'gui', 'console', 'lib' or 'staticlib' expected, but '$1' found" + errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found" + errInvalidFeatureButXFound = Feature.toSeq.map(proc(val:Feature): string = "'$1'" % $val).join(", ") & " expected, but '$1' found" + +template warningOptionNoop(switch: string) = + warningDeprecated(conf, info, "'$#' is deprecated, now a noop" % switch) + +template deprecatedAlias(oldName, newName: string) = + warningDeprecated(conf, info, "'$#' is a deprecated alias for '$#'" % [oldName, newName]) + +proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool = case switch.normalize - of "gc": + of "gc", "mm": case arg.normalize - of "boehm": result = gSelectedGC == gcBoehm - of "refc": result = gSelectedGC == gcRefc - of "v2": result = gSelectedGC == gcV2 - of "markandsweep": result = gSelectedGC == gcMarkAndSweep - of "generational": result = gSelectedGC == gcGenerational - of "go": result = gSelectedGC == gcGo - of "none": result = gSelectedGC == gcNone - of "stack", "regions": result = gSelectedGC == gcRegions - else: localError(info, errNoneBoehmRefcExpectedButXFound, arg) + of "boehm": result = conf.selectedGC == gcBoehm + of "refc": result = conf.selectedGC == gcRefc + of "markandsweep": result = conf.selectedGC == gcMarkAndSweep + of "destructors", "arc": result = conf.selectedGC == gcArc + of "orc": result = conf.selectedGC == gcOrc + of "hooks": result = conf.selectedGC == gcHooks + of "go": result = conf.selectedGC == gcGo + of "none": result = conf.selectedGC == gcNone + of "stack", "regions": result = conf.selectedGC == gcRegions + of "atomicarc": result = conf.selectedGC == gcAtomicArc + else: + result = false + localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) of "opt": case arg.normalize - of "speed": result = contains(gOptions, optOptimizeSpeed) - of "size": result = contains(gOptions, optOptimizeSize) - of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {} - else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg) - of "verbosity": result = $gVerbosity == arg + of "speed": result = contains(conf.options, optOptimizeSpeed) + of "size": result = contains(conf.options, optOptimizeSize) + of "none": result = conf.options * {optOptimizeSpeed, optOptimizeSize} == {} + else: + result = false + localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg) + of "verbosity": result = $conf.verbosity == arg of "app": case arg.normalize - of "gui": result = contains(gGlobalOptions, optGenGuiApp) - of "console": result = not contains(gGlobalOptions, optGenGuiApp) - of "lib": result = contains(gGlobalOptions, optGenDynLib) and - not contains(gGlobalOptions, optGenGuiApp) - of "staticlib": result = contains(gGlobalOptions, optGenStaticLib) and - not contains(gGlobalOptions, optGenGuiApp) - else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg) + of "gui": result = contains(conf.globalOptions, optGenGuiApp) + of "console": result = not contains(conf.globalOptions, optGenGuiApp) + of "lib": result = contains(conf.globalOptions, optGenDynLib) and + not contains(conf.globalOptions, optGenGuiApp) + of "staticlib": result = contains(conf.globalOptions, optGenStaticLib) and + not contains(conf.globalOptions, optGenGuiApp) + else: + result = false + localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg) of "dynliboverride": - result = isDynlibOverride(arg) - else: invalidCmdLineOption(passCmd1, switch, info) + result = isDynlibOverride(conf, arg) + of "exceptions": + case arg.normalize + of "cpp": result = conf.exc == excCpp + of "setjmp": result = conf.exc == excSetjmp + of "quirky": result = conf.exc == excQuirky + of "goto": result = conf.exc == excGoto + else: + result = false + localError(conf, info, errInvalidExceptionSystem % arg) + of "experimental": + try: + result = conf.features.contains parseEnum[Feature](arg) + except ValueError: + result = false + localError(conf, info, errInvalidFeatureButXFound % arg) + else: + result = false + invalidCmdLineOption(conf, passCmd1, switch, info) -proc testCompileOption*(switch: string, info: TLineInfo): bool = +proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool = case switch.normalize - of "debuginfo": result = contains(gGlobalOptions, optCDebug) - of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly) - of "nolinking": result = contains(gGlobalOptions, optNoLinking) - of "nomain": result = contains(gGlobalOptions, optNoMain) - of "forcebuild", "f": result = contains(gGlobalOptions, optForceFullMake) - of "warnings", "w": result = contains(gOptions, optWarns) - of "hints": result = contains(gOptions, optHints) - of "threadanalysis": result = contains(gGlobalOptions, optThreadAnalysis) - of "stacktrace": result = contains(gOptions, optStackTrace) - of "linetrace": result = contains(gOptions, optLineTrace) - of "debugger": result = contains(gOptions, optEndb) - of "profiler": result = contains(gOptions, optProfiler) - of "memtracker": result = contains(gOptions, optMemTracker) - of "checks", "x": result = gOptions * ChecksOptions == ChecksOptions + of "debuginfo": result = contains(conf.globalOptions, optCDebug) + of "compileonly", "c": result = contains(conf.globalOptions, optCompileOnly) + of "nolinking": result = contains(conf.globalOptions, optNoLinking) + of "nomain": result = contains(conf.globalOptions, optNoMain) + of "forcebuild", "f": result = contains(conf.globalOptions, optForceFullMake) + of "warnings", "w": result = contains(conf.options, optWarns) + of "hints": result = contains(conf.options, optHints) + of "threadanalysis": result = contains(conf.globalOptions, optThreadAnalysis) + of "stacktrace": result = contains(conf.options, optStackTrace) + of "stacktracemsgs": result = contains(conf.options, optStackTraceMsgs) + of "linetrace": result = contains(conf.options, optLineTrace) + of "debugger": result = contains(conf.globalOptions, optCDebug) + of "profiler": result = contains(conf.options, optProfiler) + of "memtracker": result = contains(conf.options, optMemTracker) + of "checks", "x": result = conf.options * ChecksOptions == ChecksOptions of "floatchecks": - result = gOptions * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck} - of "infchecks": result = contains(gOptions, optInfCheck) - of "nanchecks": result = contains(gOptions, optNaNCheck) - of "nilchecks": result = contains(gOptions, optNilCheck) - of "objchecks": result = contains(gOptions, optObjCheck) - of "fieldchecks": result = contains(gOptions, optFieldCheck) - of "rangechecks": result = contains(gOptions, optRangeCheck) - of "boundchecks": result = contains(gOptions, optBoundsCheck) - of "overflowchecks": result = contains(gOptions, optOverflowCheck) - of "linedir": result = contains(gOptions, optLineDir) - of "assertions", "a": result = contains(gOptions, optAssert) - of "deadcodeelim": result = contains(gGlobalOptions, optDeadCodeElim) - of "run", "r": result = contains(gGlobalOptions, optRun) - of "symbolfiles": result = contains(gGlobalOptions, optSymbolFiles) - of "genscript": result = contains(gGlobalOptions, optGenScript) - of "threads": result = contains(gGlobalOptions, optThreads) - of "taintmode": result = contains(gGlobalOptions, optTaintMode) - of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation) - of "implicitstatic": result = contains(gOptions, optImplicitStatic) - of "patterns": result = contains(gOptions, optPatterns) - of "experimental": result = gExperimentalMode - of "excessivestacktrace": result = contains(gGlobalOptions, optExcessiveStackTrace) - else: invalidCmdLineOption(passCmd1, switch, info) - -proc processPath(path: string, info: TLineInfo, - notRelativeToProj = false): string = - let p = if notRelativeToProj or os.isAbsolute(path) or - '$' in path: + result = conf.options * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck} + of "infchecks": result = contains(conf.options, optInfCheck) + of "nanchecks": result = contains(conf.options, optNaNCheck) + of "objchecks": result = contains(conf.options, optObjCheck) + of "fieldchecks": result = contains(conf.options, optFieldCheck) + of "rangechecks": result = contains(conf.options, optRangeCheck) + of "boundchecks": result = contains(conf.options, optBoundsCheck) + of "refchecks": + warningDeprecated(conf, info, "refchecks is deprecated!") + result = contains(conf.options, optRefCheck) + of "overflowchecks": result = contains(conf.options, optOverflowCheck) + of "staticboundchecks": result = contains(conf.options, optStaticBoundsCheck) + of "stylechecks": result = contains(conf.options, optStyleCheck) + of "linedir": result = contains(conf.options, optLineDir) + of "assertions", "a": result = contains(conf.options, optAssert) + of "run", "r": result = contains(conf.globalOptions, optRun) + of "symbolfiles": result = conf.symbolFiles != disabledSf + of "genscript": result = contains(conf.globalOptions, optGenScript) + of "gencdeps": result = contains(conf.globalOptions, optGenCDeps) + of "threads": result = contains(conf.globalOptions, optThreads) + of "tlsemulation": result = contains(conf.globalOptions, optTlsEmulation) + of "implicitstatic": result = contains(conf.options, optImplicitStatic) + of "patterns", "trmacros": + if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros") + result = contains(conf.options, optTrMacros) + of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace) + of "nilseqs", "nilchecks", "taintmode": + warningOptionNoop(switch) + result = false + of "panics": result = contains(conf.globalOptions, optPanics) + of "jsbigint64": result = contains(conf.globalOptions, optJsBigInt64) + else: + result = false + invalidCmdLineOption(conf, passCmd1, switch, info) + +proc processPath(conf: ConfigRef; path: string, info: TLineInfo, + notRelativeToProj = false): AbsoluteDir = + let p = if os.isAbsolute(path) or '$' in path: path + elif notRelativeToProj: + getCurrentDir() / path else: - options.gProjectPath / path + conf.projectPath.string / path try: - result = pathSubs(p, info.toFullPath().splitFile().dir) + result = AbsoluteDir pathSubs(conf, p, toFullPath(conf, info).splitFile().dir) except ValueError: - localError(info, "invalid path: " & p) - result = p + localError(conf, info, "invalid path: " & p) + result = AbsoluteDir p -proc processCfgPath(path: string, info: TLineInfo): string = - let path = if path[0] == '"': strutils.unescape(path) else: path - let basedir = info.toFullPath().splitFile().dir +proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): AbsoluteDir = + let path = if path.len > 0 and path[0] == '"': strutils.unescape(path) + else: path + let basedir = toFullPath(conf, info).splitFile().dir let p = if os.isAbsolute(path) or '$' in path: path else: basedir / path try: - result = pathSubs(p, basedir) + result = AbsoluteDir pathSubs(conf, p, basedir) except ValueError: - localError(info, "invalid path: " & p) - result = p + localError(conf, info, "invalid path: " & p) + result = AbsoluteDir p -proc trackDirty(arg: string, info: TLineInfo) = - var a = arg.split(',') - if a.len != 4: localError(info, errTokenExpected, - "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN") - var line, column: int - if parseUtils.parseInt(a[2], line) <= 0: - localError(info, errInvalidNumber, a[1]) - if parseUtils.parseInt(a[3], column) <= 0: - localError(info, errInvalidNumber, a[2]) +const + errInvalidNumber = "$1 is not a valid number" - let dirtyOriginalIdx = a[1].fileInfoIdx - if dirtyOriginalIdx >= 0: - msgs.setDirtyFile(dirtyOriginalIdx, a[0]) +proc makeAbsolute(s: string): AbsoluteFile = + if isAbsolute(s): + AbsoluteFile pathnorm.normalizePath(s) + else: + AbsoluteFile pathnorm.normalizePath(os.getCurrentDir() / s) + +proc setTrackingInfo(conf: ConfigRef; dirty, file, line, column: string, + info: TLineInfo) = + ## set tracking info, common code for track, trackDirty, & ideTrack + var ln: int = 0 + var col: int = 0 + if parseUtils.parseInt(line, ln) <= 0: + localError(conf, info, errInvalidNumber % line) + if parseUtils.parseInt(column, col) <= 0: + localError(conf, info, errInvalidNumber % column) - gTrackPos = newLineInfo(dirtyOriginalIdx, line, column) + let a = makeAbsolute(file) + if dirty == "": + conf.m.trackPos = newLineInfo(conf, a, ln, col) + else: + let dirtyOriginalIdx = fileInfoIdx(conf, a) + if dirtyOriginalIdx.int32 >= 0: + msgs.setDirtyFile(conf, dirtyOriginalIdx, makeAbsolute(dirty)) + conf.m.trackPos = newLineInfo(dirtyOriginalIdx, ln, col) -proc track(arg: string, info: TLineInfo) = +proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) = var a = arg.split(',') - if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN") - var line, column: int - if parseUtils.parseInt(a[1], line) <= 0: - localError(info, errInvalidNumber, a[1]) - if parseUtils.parseInt(a[2], column) <= 0: - localError(info, errInvalidNumber, a[2]) - gTrackPos = newLineInfo(a[0], line, column) - -proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = + if a.len != 4: localError(conf, info, + "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN expected") + setTrackingInfo(conf, a[0], a[1], a[2], a[3], info) + +proc track(conf: ConfigRef; arg: string, info: TLineInfo) = + var a = arg.split(',') + if a.len != 3: localError(conf, info, "FILE,LINE,COLUMN expected") + setTrackingInfo(conf, "", a[0], a[1], a[2], info) + +proc trackIde(conf: ConfigRef; cmd: IdeCmd, arg: string, info: TLineInfo) = + ## set the tracking info related to an ide cmd, supports optional dirty file + var a = arg.split(',') + case a.len + of 4: + setTrackingInfo(conf, a[0], a[1], a[2], a[3], info) + of 3: + setTrackingInfo(conf, "", a[0], a[1], a[2], info) + else: + localError(conf, info, "[DIRTY_BUFFER,]ORIGINAL_FILE,LINE,COLUMN expected") + conf.ideCmd = cmd + +proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = if pass in {passCmd2, passPP}: - expectArg(switch, arg, pass, info) - options.inclDynlibOverride(arg) - -proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; - config: ConfigRef = nil) = - var - theOS: TSystemOS - cpu: TSystemCPU - key, val: string + expectArg(conf, switch, arg, pass, info) + options.inclDynlibOverride(conf, arg) + +template handleStdinOrCmdInput = + conf.projectFull = conf.projectName.AbsoluteFile + conf.projectPath = AbsoluteDir getCurrentDir() + if conf.outDir.isEmpty: + conf.outDir = getNimcacheDir(conf) + +proc handleStdinInput*(conf: ConfigRef) = + conf.projectName = "stdinfile" + conf.projectIsStdin = true + handleStdinOrCmdInput() + +proc handleCmdInput*(conf: ConfigRef) = + conf.projectName = "cmdfile" + handleStdinOrCmdInput() + +proc parseCommand*(command: string): Command = + case command.normalize + of "c", "cc", "compile", "compiletoc": cmdCompileToC + of "cpp", "compiletocpp": cmdCompileToCpp + of "objc", "compiletooc": cmdCompileToOC + of "js", "compiletojs": cmdCompileToJS + of "r": cmdCrun + of "m": cmdM + of "run": cmdTcc + of "check": cmdCheck + of "e": cmdNimscript + of "doc0": cmdDoc0 + of "doc2", "doc": cmdDoc + of "doc2tex": cmdDoc2tex + of "rst2html": cmdRst2html + of "md2tex": cmdMd2tex + of "md2html": cmdMd2html + of "rst2tex": cmdRst2tex + of "jsondoc0": cmdJsondoc0 + of "jsondoc2", "jsondoc": cmdJsondoc + of "ctags": cmdCtags + of "buildindex": cmdBuildindex + of "gendepend": cmdGendepend + of "dump": cmdDump + of "parse": cmdParse + of "rod": cmdRod + of "secret": cmdInteractive + of "nop", "help": cmdNop + of "jsonscript": cmdJsonscript + else: cmdUnknown + +proc setCmd*(conf: ConfigRef, cmd: Command) = + ## sets cmd, backend so subsequent flags can query it (e.g. so --gc:arc can be ignored for backendJs) + # Note that `--backend` can override the backend, so the logic here must remain reversible. + conf.cmd = cmd + case cmd + of cmdCompileToC, cmdCrun, cmdTcc: conf.backend = backendC + of cmdCompileToCpp: conf.backend = backendCpp + of cmdCompileToOC: conf.backend = backendObjc + of cmdCompileToJS: conf.backend = backendJs + else: discard + +proc setCommandEarly*(conf: ConfigRef, command: string) = + conf.command = command + setCmd(conf, command.parseCommand) + # command early customizations + # must be handled here to honor subsequent `--hint:x:on|off` + case conf.cmd + of cmdRst2html, cmdRst2tex, cmdMd2html, cmdMd2tex: + # xxx see whether to add others: cmdGendepend, etc. + conf.foreignPackageNotes = {hintSuccessX} + else: + conf.foreignPackageNotes = foreignPackageNotesDefault + +proc specialDefine(conf: ConfigRef, key: string; pass: TCmdLinePass) = + # Keep this syncronized with the default config/nim.cfg! + if cmpIgnoreStyle(key, "nimQuirky") == 0: + conf.exc = excQuirky + elif cmpIgnoreStyle(key, "release") == 0 or cmpIgnoreStyle(key, "danger") == 0: + if pass in {passCmd1, passPP}: + conf.options.excl {optStackTrace, optLineTrace, optLineDir, optOptimizeSize} + conf.globalOptions.excl {optExcessiveStackTrace, optCDebug} + conf.options.incl optOptimizeSpeed + if cmpIgnoreStyle(key, "danger") == 0 or cmpIgnoreStyle(key, "quick") == 0: + if pass in {passCmd1, passPP}: + conf.options.excl {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, + optOverflowCheck, optAssert, optStackTrace, optLineTrace, optLineDir} + conf.globalOptions.excl {optCDebug} + +proc initOrcDefines*(conf: ConfigRef) = + conf.selectedGC = gcOrc + defineSymbol(conf.symbols, "gcorc") + defineSymbol(conf.symbols, "gcdestructors") + incl conf.globalOptions, optSeqDestructors + incl conf.globalOptions, optTinyRtti + defineSymbol(conf.symbols, "nimSeqsV2") + defineSymbol(conf.symbols, "nimV2") + if conf.exc == excNone and conf.backend != backendCpp: + conf.exc = excGoto + +proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef) = + defineSymbol(conf.symbols, "gcdestructors") + incl conf.globalOptions, optSeqDestructors + incl conf.globalOptions, optTinyRtti + if pass in {passCmd2, passPP}: + defineSymbol(conf.symbols, "nimSeqsV2") + defineSymbol(conf.symbols, "nimV2") + if conf.exc == excNone and conf.backend != backendCpp: + conf.exc = excGoto + +proc unregisterArcOrc*(conf: ConfigRef) = + undefSymbol(conf.symbols, "gcdestructors") + undefSymbol(conf.symbols, "gcarc") + undefSymbol(conf.symbols, "gcorc") + undefSymbol(conf.symbols, "gcatomicarc") + undefSymbol(conf.symbols, "nimSeqsV2") + undefSymbol(conf.symbols, "nimV2") + excl conf.globalOptions, optSeqDestructors + excl conf.globalOptions, optTinyRtti + +proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass, + info: TLineInfo; conf: ConfigRef) = + if conf.backend == backendJs: return # for: bug #16033 + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: + case arg.normalize + of "boehm": + unregisterArcOrc(conf) + conf.selectedGC = gcBoehm + defineSymbol(conf.symbols, "boehmgc") + incl conf.globalOptions, optTlsEmulation # Boehm GC doesn't scan the real TLS + of "refc": + unregisterArcOrc(conf) + defineSymbol(conf.symbols, "gcrefc") + conf.selectedGC = gcRefc + of "markandsweep": + unregisterArcOrc(conf) + conf.selectedGC = gcMarkAndSweep + defineSymbol(conf.symbols, "gcmarkandsweep") + of "destructors", "arc": + conf.selectedGC = gcArc + defineSymbol(conf.symbols, "gcarc") + registerArcOrc(pass, conf) + of "orc": + conf.selectedGC = gcOrc + defineSymbol(conf.symbols, "gcorc") + registerArcOrc(pass, conf) + of "atomicarc": + conf.selectedGC = gcAtomicArc + defineSymbol(conf.symbols, "gcatomicarc") + registerArcOrc(pass, conf) + of "hooks": + conf.selectedGC = gcHooks + defineSymbol(conf.symbols, "gchooks") + incl conf.globalOptions, optSeqDestructors + processOnOffSwitchG(conf, {optSeqDestructors}, arg, pass, info) + if pass in {passCmd2, passPP}: + defineSymbol(conf.symbols, "nimSeqsV2") + of "go": + unregisterArcOrc(conf) + conf.selectedGC = gcGo + defineSymbol(conf.symbols, "gogc") + of "none": + unregisterArcOrc(conf) + conf.selectedGC = gcNone + defineSymbol(conf.symbols, "nogc") + of "stack", "regions": + unregisterArcOrc(conf) + conf.selectedGC = gcRegions + defineSymbol(conf.symbols, "gcregions") + else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) + +proc pathRelativeToConfig(arg: string, pass: TCmdLinePass, conf: ConfigRef): string = + if pass == passPP and not isAbsolute(arg): + assert isAbsolute(conf.currentConfigDir), "something is wrong with currentConfigDir" + result = conf.currentConfigDir / arg + else: + result = arg + +proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; + conf: ConfigRef) = + var key = "" + var val = "" case switch.normalize + of "eval": + expectArg(conf, switch, arg, pass, info) + conf.projectIsCmd = true + conf.cmdInput = arg # can be empty (a nim file with empty content is valid too) + if conf.cmd == cmdNone: + conf.command = "e" + conf.setCmd cmdNimscript # better than `cmdCrun` as a default + conf.implicitCmd = true of "path", "p": - expectArg(switch, arg, pass, info) - addPath(if pass == passPP: processCfgPath(arg, info) else: processPath(arg, info), info) - of "nimblepath", "babelpath": - # keep the old name for compat - if pass in {passCmd2, passPP} and not options.gNoNimblePath: - expectArg(switch, arg, pass, info) - var path = processPath(arg, info, notRelativeToProj=true) - let nimbleDir = getEnv("NIMBLE_DIR") - if nimbleDir.len > 0 and pass == passPP: path = nimbleDir / "pkgs" - nimblePath(path, info) - of "nonimblepath", "nobabelpath": - expectNoArg(switch, arg, pass, info) - disableNimblePath() + expectArg(conf, switch, arg, pass, info) + for path in nimbleSubs(conf, arg): + addPath(conf, if pass == passPP: processCfgPath(conf, path, info) + else: processPath(conf, path, info), info) + of "nimblepath": + if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions: + expectArg(conf, switch, arg, pass, info) + var path = processPath(conf, arg, info, notRelativeToProj=true) + let nimbleDir = AbsoluteDir getEnv("NIMBLE_DIR") + if not nimbleDir.isEmpty and pass == passPP: + path = nimbleDir / RelativeDir"pkgs2" + nimblePath(conf, path, info) + path = nimbleDir / RelativeDir"pkgs" + nimblePath(conf, path, info) + of "nonimblepath": + expectNoArg(conf, switch, arg, pass, info) + disableNimblePath(conf) + of "clearnimblepath": + expectNoArg(conf, switch, arg, pass, info) + clearNimblePath(conf) of "excludepath": - expectArg(switch, arg, pass, info) - let path = processPath(arg, info) - - options.searchPaths.keepItIf( cmpPaths(it, path) != 0 ) - options.lazyPaths.keepItIf( cmpPaths(it, path) != 0 ) - - if (len(path) > 0) and (path[len(path) - 1] == DirSep): - let strippedPath = path[0 .. (len(path) - 2)] - options.searchPaths.keepItIf( cmpPaths(it, strippedPath) != 0 ) - options.lazyPaths.keepItIf( cmpPaths(it, strippedPath) != 0 ) + expectArg(conf, switch, arg, pass, info) + let path = processPath(conf, arg, info) + conf.searchPaths.keepItIf(it != path) + conf.lazyPaths.keepItIf(it != path) of "nimcache": - expectArg(switch, arg, pass, info) - options.nimcacheDir = processPath(arg, info, true) + expectArg(conf, switch, arg, pass, info) + var arg = arg + # refs bug #18674, otherwise `--os:windows` messes up with `--nimcache` set + # in config nims files, e.g. via: `import os; switch("nimcache", "/tmp/somedir")` + if conf.target.targetOS == osWindows and DirSep == '/': arg = arg.replace('\\', '/') + conf.nimcacheDir = processPath(conf, pathRelativeToConfig(arg, pass, conf), info, notRelativeToProj=true) of "out", "o": - expectArg(switch, arg, pass, info) - options.outFile = arg + expectArg(conf, switch, arg, pass, info) + let f = splitFile(processPath(conf, arg, info, notRelativeToProj=true).string) + conf.outFile = RelativeFile f.name & f.ext + conf.outDir = toAbsoluteDir f.dir + of "outdir": + expectArg(conf, switch, arg, pass, info) + conf.outDir = processPath(conf, arg, info, notRelativeToProj=true) + of "usenimcache": + processOnOffSwitchG(conf, {optUseNimcache}, arg, pass, info) of "docseesrcurl": - expectArg(switch, arg, pass, info) - options.docSeeSrcUrl = arg - of "mainmodule", "m": - discard "allow for backwards compatibility, but don't do anything" + expectArg(conf, switch, arg, pass, info) + conf.docSeeSrcUrl = arg + of "docroot": + conf.docRoot = if arg.len == 0: docRootDefault else: arg + of "backend", "b": + let backend = parseEnum(arg.normalize, TBackend.default) + if backend == TBackend.default: localError(conf, info, "invalid backend: '$1'" % arg) + if backend == backendJs: # bug #21209 + conf.globalOptions.excl {optThreadAnalysis, optThreads} + if optRun in conf.globalOptions: + # for now, -r uses nodejs, so define nodejs + defineSymbol(conf.symbols, "nodejs") + conf.backend = backend + of "doccmd": conf.docCmd = arg of "define", "d": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) if {':', '='} in arg: - splitSwitch(arg, key, val, pass, info) - defineSymbol(key, val) + splitSwitch(conf, arg, key, val, pass, info) + specialDefine(conf, key, pass) + defineSymbol(conf.symbols, key, val) else: - defineSymbol(arg) + specialDefine(conf, arg, pass) + defineSymbol(conf.symbols, arg) of "undef", "u": - expectArg(switch, arg, pass, info) - undefSymbol(arg) - of "symbol": - expectArg(switch, arg, pass, info) - # deprecated, do nothing + expectArg(conf, switch, arg, pass, info) + undefSymbol(conf.symbols, arg) of "compile": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: processCompile(arg) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: processCompile(conf, arg) of "link": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: addExternalFileToLink(arg) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: + addExternalFileToLink(conf, AbsoluteFile arg) of "debuginfo": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optCDebug) + processOnOffSwitchG(conf, {optCDebug}, arg, pass, info) of "embedsrc": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optEmbedOrigSrc) + processOnOffSwitchG(conf, {optEmbedOrigSrc}, arg, pass, info) of "compileonly", "c": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optCompileOnly) + processOnOffSwitchG(conf, {optCompileOnly}, arg, pass, info) of "nolinking": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optNoLinking) + processOnOffSwitchG(conf, {optNoLinking}, arg, pass, info) of "nomain": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optNoMain) + processOnOffSwitchG(conf, {optNoMain}, arg, pass, info) of "forcebuild", "f": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optForceFullMake) + processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info) of "project": - expectNoArg(switch, arg, pass, info) - gWholeProject = true + processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info) of "gc": - expectArg(switch, arg, pass, info) - case arg.normalize - of "boehm": - gSelectedGC = gcBoehm - defineSymbol("boehmgc") - of "refc": - gSelectedGC = gcRefc - of "v2": - gSelectedGC = gcV2 - of "markandsweep": - gSelectedGC = gcMarkAndSweep - defineSymbol("gcmarkandsweep") - of "generational": - gSelectedGC = gcGenerational - defineSymbol("gcgenerational") - of "go": - gSelectedGC = gcGo - defineSymbol("gogc") - of "none": - gSelectedGC = gcNone - defineSymbol("nogc") - of "stack", "regions": - gSelectedGC= gcRegions - defineSymbol("gcregions") - else: localError(info, errNoneBoehmRefcExpectedButXFound, arg) + warningDeprecated(conf, info, "`gc:option` is deprecated; use `mm:option` instead") + processMemoryManagementOption(switch, arg, pass, info, conf) + of "mm": + processMemoryManagementOption(switch, arg, pass, info, conf) of "warnings", "w": - if processOnOffSwitchOrList({optWarns}, arg, pass, info): listWarnings() - of "warning": processSpecificNote(arg, wWarning, pass, info, switch) - of "hint": processSpecificNote(arg, wHint, pass, info, switch) + if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf) + of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf) + of "hint": processSpecificNote(arg, wHint, pass, info, switch, conf) + of "warningaserror": processSpecificNote(arg, wWarningAsError, pass, info, switch, conf) + of "hintaserror": processSpecificNote(arg, wHintAsError, pass, info, switch, conf) of "hints": - if processOnOffSwitchOrList({optHints}, arg, pass, info): listHints() - of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info) - of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info) - of "excessivestacktrace": processOnOffSwitchG({optExcessiveStackTrace}, arg, pass, info) - of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info) + if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf) + of "threadanalysis": + if conf.backend == backendJs: discard + else: processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info) + of "stacktrace": processOnOffSwitch(conf, {optStackTrace}, arg, pass, info) + of "stacktracemsgs": processOnOffSwitch(conf, {optStackTraceMsgs}, arg, pass, info) + of "excessivestacktrace": processOnOffSwitchG(conf, {optExcessiveStackTrace}, arg, pass, info) + of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info) of "debugger": case arg.normalize - of "on", "endb": - gOptions.incl optEndb - defineSymbol("endb") + of "on", "native", "gdb": + conf.globalOptions.incl optCDebug + conf.options.incl optLineDir + #defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing of "off": - gOptions.excl optEndb - undefSymbol("endb") - of "native", "gdb": - incl(gGlobalOptions, optCDebug) - gOptions = gOptions + {optLineDir} - {optEndb} - defineSymbol("nimTypeNames", nil) # type names are used in gdb pretty printing - undefSymbol("endb") + conf.globalOptions.excl optCDebug else: - localError(info, "expected endb|gdb but found " & arg) + localError(conf, info, "expected native|gdb|on|off but found " & arg) + of "g": # alias for --debugger:native + conf.globalOptions.incl optCDebug + conf.options.incl optLineDir + #defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing of "profiler": - processOnOffSwitch({optProfiler}, arg, pass, info) - if optProfiler in gOptions: defineSymbol("profiler") - else: undefSymbol("profiler") + processOnOffSwitch(conf, {optProfiler}, arg, pass, info) + if optProfiler in conf.options: defineSymbol(conf.symbols, "profiler") + else: undefSymbol(conf.symbols, "profiler") of "memtracker": - processOnOffSwitch({optMemTracker}, arg, pass, info) - if optMemTracker in gOptions: defineSymbol("memtracker") - else: undefSymbol("memtracker") - of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info) + processOnOffSwitch(conf, {optMemTracker}, arg, pass, info) + if optMemTracker in conf.options: defineSymbol(conf.symbols, "memtracker") + else: undefSymbol(conf.symbols, "memtracker") + of "hotcodereloading": + processOnOffSwitchG(conf, {optHotCodeReloading}, arg, pass, info) + if conf.hcrOn: + defineSymbol(conf.symbols, "hotcodereloading") + defineSymbol(conf.symbols, "useNimRtl") + # hardcoded linking with dynamic runtime for MSVC for smaller binaries + # should do the same for all compilers (wherever applicable) + if isVSCompatible(conf): + extccomp.addCompileOptionCmd(conf, "/MD") + else: + undefSymbol(conf.symbols, "hotcodereloading") + undefSymbol(conf.symbols, "useNimRtl") + of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info) of "floatchecks": - processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info) - of "infchecks": processOnOffSwitch({optInfCheck}, arg, pass, info) - of "nanchecks": processOnOffSwitch({optNaNCheck}, arg, pass, info) - of "nilchecks": processOnOffSwitch({optNilCheck}, arg, pass, info) - of "objchecks": processOnOffSwitch({optObjCheck}, arg, pass, info) - of "fieldchecks": processOnOffSwitch({optFieldCheck}, arg, pass, info) - of "rangechecks": processOnOffSwitch({optRangeCheck}, arg, pass, info) - of "boundchecks": processOnOffSwitch({optBoundsCheck}, arg, pass, info) - of "overflowchecks": processOnOffSwitch({optOverflowCheck}, arg, pass, info) - of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info) - of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info) - of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info) + processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info) + of "infchecks": processOnOffSwitch(conf, {optInfCheck}, arg, pass, info) + of "nanchecks": processOnOffSwitch(conf, {optNaNCheck}, arg, pass, info) + of "objchecks": processOnOffSwitch(conf, {optObjCheck}, arg, pass, info) + of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info) + of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info) + of "boundchecks": processOnOffSwitch(conf, {optBoundsCheck}, arg, pass, info) + of "refchecks": + warningDeprecated(conf, info, "refchecks is deprecated!") + processOnOffSwitch(conf, {optRefCheck}, arg, pass, info) + of "overflowchecks": processOnOffSwitch(conf, {optOverflowCheck}, arg, pass, info) + of "staticboundchecks": processOnOffSwitch(conf, {optStaticBoundsCheck}, arg, pass, info) + of "stylechecks": processOnOffSwitch(conf, {optStyleCheck}, arg, pass, info) + of "linedir": processOnOffSwitch(conf, {optLineDir}, arg, pass, info) + of "assertions", "a": processOnOffSwitch(conf, {optAssert}, arg, pass, info) of "threads": - processOnOffSwitchG({optThreads}, arg, pass, info) - #if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe) - of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info) - of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info) + if conf.backend == backendJs or conf.cmd == cmdNimscript: discard + else: processOnOffSwitchG(conf, {optThreads}, arg, pass, info) + #if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe) + of "tlsemulation": + processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info) + if optTlsEmulation in conf.globalOptions: + conf.legacyFeatures.incl emitGenerics of "implicitstatic": - processOnOffSwitch({optImplicitStatic}, arg, pass, info) - of "patterns": - processOnOffSwitch({optPatterns}, arg, pass, info) + processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info) + of "patterns", "trmacros": + if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros") + processOnOffSwitch(conf, {optTrMacros}, arg, pass, info) of "opt": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) case arg.normalize of "speed": - incl(gOptions, optOptimizeSpeed) - excl(gOptions, optOptimizeSize) + incl(conf.options, optOptimizeSpeed) + excl(conf.options, optOptimizeSize) of "size": - excl(gOptions, optOptimizeSpeed) - incl(gOptions, optOptimizeSize) + excl(conf.options, optOptimizeSpeed) + incl(conf.options, optOptimizeSize) of "none": - excl(gOptions, optOptimizeSpeed) - excl(gOptions, optOptimizeSize) - else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg) + excl(conf.options, optOptimizeSpeed) + excl(conf.options, optOptimizeSize) + else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg) of "app": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) case arg.normalize of "gui": - incl(gGlobalOptions, optGenGuiApp) - defineSymbol("executable") - defineSymbol("guiapp") + incl(conf.globalOptions, optGenGuiApp) + defineSymbol(conf.symbols, "executable") + defineSymbol(conf.symbols, "guiapp") of "console": - excl(gGlobalOptions, optGenGuiApp) - defineSymbol("executable") - defineSymbol("consoleapp") + excl(conf.globalOptions, optGenGuiApp) + defineSymbol(conf.symbols, "executable") + defineSymbol(conf.symbols, "consoleapp") of "lib": - incl(gGlobalOptions, optGenDynLib) - excl(gGlobalOptions, optGenGuiApp) - defineSymbol("library") - defineSymbol("dll") + incl(conf.globalOptions, optGenDynLib) + excl(conf.globalOptions, optGenGuiApp) + defineSymbol(conf.symbols, "library") + defineSymbol(conf.symbols, "dll") of "staticlib": - incl(gGlobalOptions, optGenStaticLib) - excl(gGlobalOptions, optGenGuiApp) - defineSymbol("library") - defineSymbol("staticlib") - else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg) + incl(conf.globalOptions, optGenStaticLib) + incl(conf.globalOptions, optNoMain) + excl(conf.globalOptions, optGenGuiApp) + defineSymbol(conf.symbols, "library") + defineSymbol(conf.symbols, "staticlib") + else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg) of "passc", "t": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(arg) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(conf, arg) of "passl", "l": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(arg) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(conf, arg) of "cincludes": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: cIncludes.add arg.processPath(info) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: conf.cIncludes.add processPath(conf, arg, info) of "clibdir": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: cLibs.add arg.processPath(info) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: conf.cLibs.add processPath(conf, arg, info) of "clib": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: + conf.cLinkedLibs.add arg of "header": - if config != nil: config.headerFile = arg - incl(gGlobalOptions, optGenIndex) + if conf != nil: conf.headerFile = arg + incl(conf.globalOptions, optGenIndex) + of "nimbasepattern": + if conf != nil: conf.nimbasePattern = arg of "index": - processOnOffSwitchG({optGenIndex}, arg, pass, info) + case arg.normalize + of "", "on": conf.globalOptions.incl {optGenIndex} + of "only": conf.globalOptions.incl {optGenIndexOnly, optGenIndex} + of "off": conf.globalOptions.excl {optGenIndex, optGenIndexOnly} + else: localError(conf, info, errOnOrOffExpectedButXFound % arg) + of "noimportdoc": + processOnOffSwitchG(conf, {optNoImportdoc}, arg, pass, info) of "import": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: implicitImports.add arg + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: + conf.implicitImports.add findModule(conf, arg, toFullPath(conf, info)).string of "include": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: implicitIncludes.add arg + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: + conf.implicitIncludes.add findModule(conf, arg, toFullPath(conf, info)).string of "listcmd": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optListCmd) + processOnOffSwitchG(conf, {optListCmd}, arg, pass, info) + of "asm": + processOnOffSwitchG(conf, {optProduceAsm}, arg, pass, info) of "genmapping": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optGenMapping) + processOnOffSwitchG(conf, {optGenMapping}, arg, pass, info) of "os": - expectArg(switch, arg, pass, info) - if pass in {passCmd1, passPP}: - theOS = platform.nameToOS(arg) - if theOS == osNone: localError(info, errUnknownOS, arg) - elif theOS != platform.hostOS: - setTarget(theOS, targetCPU) + expectArg(conf, switch, arg, pass, info) + let theOS = platform.nameToOS(arg) + if theOS == osNone: + let osList = platform.listOSnames().join(", ") + localError(conf, info, "unknown OS: '$1'. Available options are: $2" % [arg, $osList]) + else: + setTarget(conf.target, theOS, conf.target.targetCPU) of "cpu": - expectArg(switch, arg, pass, info) - if pass in {passCmd1, passPP}: - cpu = platform.nameToCPU(arg) - if cpu == cpuNone: localError(info, errUnknownCPU, arg) - elif cpu != platform.hostCPU: - setTarget(targetOS, cpu) + expectArg(conf, switch, arg, pass, info) + let cpu = platform.nameToCPU(arg) + if cpu == cpuNone: + let cpuList = platform.listCPUnames().join(", ") + localError(conf, info, "unknown CPU: '$1'. Available options are: $2" % [ arg, cpuList]) + else: + setTarget(conf.target, conf.target.targetOS, cpu) of "run", "r": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optRun) + processOnOffSwitchG(conf, {optRun}, arg, pass, info) + if conf.backend == backendJs: + # for now, -r uses nodejs, so define nodejs + defineSymbol(conf.symbols, "nodejs") + of "maxloopiterationsvm": + expectArg(conf, switch, arg, pass, info) + var value: int = 10_000_000 + discard parseSaturatedNatural(arg, value) + if not value > 0: localError(conf, info, "maxLoopIterationsVM must be a positive integer greater than zero") + conf.maxLoopIterationsVM = value + of "errormax": + expectArg(conf, switch, arg, pass, info) + # Note: `nim check` (etc) can overwrite this. + # `0` is meaningless, give it a useful meaning as in clang's -ferror-limit + # If user doesn't set this flag and the code doesn't either, it'd + # have the same effect as errorMax = 1 + var value: int = 0 + discard parseSaturatedNatural(arg, value) + conf.errorMax = if value == 0: high(int) else: value of "verbosity": - expectArg(switch, arg, pass, info) - gVerbosity = parseInt(arg) - gNotes = NotesVerbosity[gVerbosity] - incl(gNotes, enableNotes) - excl(gNotes, disableNotes) - gMainPackageNotes = gNotes + expectArg(conf, switch, arg, pass, info) + let verbosity = parseInt(arg) + if verbosity notin 0..3: + localError(conf, info, "invalid verbosity level: '$1'" % arg) + conf.verbosity = verbosity + var verb = NotesVerbosity[conf.verbosity] + ## We override the default `verb` by explicitly modified (set/unset) notes. + conf.notes = (conf.modifiedyNotes * conf.notes + verb) - + (conf.modifiedyNotes * verb - conf.notes) + conf.mainPackageNotes = conf.notes of "parallelbuild": - expectArg(switch, arg, pass, info) - gNumberOfProcessors = parseInt(arg) + expectArg(conf, switch, arg, pass, info) + var value: int = 0 + discard parseSaturatedNatural(arg, value) + conf.numberOfProcessors = value of "version", "v": - expectNoArg(switch, arg, pass, info) - writeVersionInfo(pass) + expectNoArg(conf, switch, arg, pass, info) + writeVersionInfo(conf, pass) of "advanced": - expectNoArg(switch, arg, pass, info) - writeAdvancedUsage(pass) + expectNoArg(conf, switch, arg, pass, info) + writeAdvancedUsage(conf, pass) + of "fullhelp": + expectNoArg(conf, switch, arg, pass, info) + writeFullhelp(conf, pass) of "help", "h": - expectNoArg(switch, arg, pass, info) - helpOnError(pass) - of "symbolfiles": - processOnOffSwitchG({optSymbolFiles}, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) + helpOnError(conf, pass) + of "symbolfiles", "incremental", "ic": + if switch.normalize == "symbolfiles": deprecatedAlias(switch, "incremental") + # xxx maybe also ic, since not in help? + if pass in {passCmd2, passPP}: + case arg.normalize + of "on": conf.symbolFiles = v2Sf + of "off": conf.symbolFiles = disabledSf + of "writeonly": conf.symbolFiles = writeOnlySf + of "readonly": conf.symbolFiles = readOnlySf + of "v2": conf.symbolFiles = v2Sf + of "stress": conf.symbolFiles = stressTest + else: localError(conf, info, "invalid option for --incremental: " & arg) + setUseIc(conf.symbolFiles != disabledSf) of "skipcfg": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optSkipConfigFile) + processOnOffSwitchG(conf, {optSkipSystemConfigFile}, arg, pass, info) of "skipprojcfg": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optSkipProjConfigFile) + processOnOffSwitchG(conf, {optSkipProjConfigFile}, arg, pass, info) of "skipusercfg": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optSkipUserConfigFile) + processOnOffSwitchG(conf, {optSkipUserConfigFile}, arg, pass, info) of "skipparentcfg": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optSkipParentConfigFiles) - of "genscript": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optGenScript) - of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info) + processOnOffSwitchG(conf, {optSkipParentConfigFiles}, arg, pass, info) + of "genscript", "gendeps": + if switch.normalize == "gendeps": deprecatedAlias(switch, "genscript") + processOnOffSwitchG(conf, {optGenScript}, arg, pass, info) + processOnOffSwitchG(conf, {optCompileOnly}, arg, pass, info) + of "gencdeps": + processOnOffSwitchG(conf, {optGenCDeps}, arg, pass, info) + of "colors": processOnOffSwitchG(conf, {optUseColors}, arg, pass, info) of "lib": - expectArg(switch, arg, pass, info) - libpath = processPath(arg, info, notRelativeToProj=true) + expectArg(conf, switch, arg, pass, info) + conf.libpath = processPath(conf, arg, info, notRelativeToProj=true) of "putenv": - expectArg(switch, arg, pass, info) - splitSwitch(arg, key, val, pass, info) + expectArg(conf, switch, arg, pass, info) + splitSwitch(conf, arg, key, val, pass, info) os.putEnv(key, val) of "cc": - expectArg(switch, arg, pass, info) - setCC(arg) + if conf.backend != backendJs: # bug #19330 + expectArg(conf, switch, arg, pass, info) + setCC(conf, arg, info) of "track": - expectArg(switch, arg, pass, info) - track(arg, info) + expectArg(conf, switch, arg, pass, info) + track(conf, arg, info) of "trackdirty": - expectArg(switch, arg, pass, info) - trackDirty(arg, info) + expectArg(conf, switch, arg, pass, info) + trackDirty(conf, arg, info) of "suggest": - expectNoArg(switch, arg, pass, info) - gIdeCmd = ideSug + expectNoArg(conf, switch, arg, pass, info) + conf.ideCmd = ideSug of "def": - expectNoArg(switch, arg, pass, info) - gIdeCmd = ideDef - of "eval": - expectArg(switch, arg, pass, info) - gEvalExpr = arg + expectArg(conf, switch, arg, pass, info) + trackIde(conf, ideDef, arg, info) of "context": - expectNoArg(switch, arg, pass, info) - gIdeCmd = ideCon + expectNoArg(conf, switch, arg, pass, info) + conf.ideCmd = ideCon of "usages": - expectNoArg(switch, arg, pass, info) - gIdeCmd = ideUse + expectArg(conf, switch, arg, pass, info) + trackIde(conf, ideUse, arg, info) + of "defusages": + expectArg(conf, switch, arg, pass, info) + trackIde(conf, ideDus, arg, info) of "stdout": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optStdout) + processOnOffSwitchG(conf, {optStdout}, arg, pass, info) + of "filenames": + case arg.normalize + of "abs": conf.filenameOption = foAbs + of "canonical": conf.filenameOption = foCanonical + of "legacyrelproj": conf.filenameOption = foLegacyRelProj + else: localError(conf, info, "expected: abs|canonical|legacyRelProj, got: $1" % arg) + of "processing": + incl(conf.notes, hintProcessing) + incl(conf.mainPackageNotes, hintProcessing) + case arg.normalize + of "dots": conf.hintProcessingDots = true + of "filenames": conf.hintProcessingDots = false + of "off": + excl(conf.notes, hintProcessing) + excl(conf.mainPackageNotes, hintProcessing) + else: localError(conf, info, "expected: dots|filenames|off, got: $1" % arg) + of "unitsep": + conf.unitSep = if switchOn(arg): "\31" else: "" of "listfullpaths": - expectNoArg(switch, arg, pass, info) - gListFullPaths = true + # xxx in future work, use `warningDeprecated` + conf.filenameOption = if switchOn(arg): foAbs else: foCanonical + of "spellsuggest": + if arg.len == 0: conf.spellSuggestMax = spellSuggestSecretSauce + elif arg == "auto": conf.spellSuggestMax = spellSuggestSecretSauce + else: conf.spellSuggestMax = parseInt(arg) + of "declaredlocs": + processOnOffSwitchG(conf, {optDeclaredLocs}, arg, pass, info) of "dynliboverride": - dynlibOverride(switch, arg, pass, info) - of "cs": - # only supported for compatibility. Does nothing. - expectArg(switch, arg, pass, info) + dynlibOverride(conf, switch, arg, pass, info) + of "dynliboverrideall": + processOnOffSwitchG(conf, {optDynlibOverrideAll}, arg, pass, info) of "experimental": - expectNoArg(switch, arg, pass, info) - gExperimentalMode = true + if arg.len == 0: + conf.features.incl oldExperimentalFeatures + else: + try: + conf.features.incl parseEnum[Feature](arg) + except ValueError: + localError(conf, info, "unknown experimental feature") + of "legacy": + try: + conf.legacyFeatures.incl parseEnum[LegacyFeature](arg) + except ValueError: + localError(conf, info, "unknown obsolete feature") of "nocppexceptions": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optNoCppExceptions) - defineSymbol("noCppExceptions") + expectNoArg(conf, switch, arg, pass, info) + conf.exc = low(ExceptionSystem) + defineSymbol(conf.symbols, "noCppExceptions") + of "shownonexports": + expectNoArg(conf, switch, arg, pass, info) + showNonExportedFields(conf) + of "exceptions": + case arg.normalize + of "cpp": conf.exc = excCpp + of "setjmp": conf.exc = excSetjmp + of "quirky": conf.exc = excQuirky + of "goto": conf.exc = excGoto + else: localError(conf, info, errInvalidExceptionSystem % arg) of "cppdefine": - expectArg(switch, arg, pass, info) - if config != nil: - config.cppDefine(arg) + expectArg(conf, switch, arg, pass, info) + if conf != nil: + conf.cppDefine(arg) of "newruntime": - expectNoArg(switch, arg, pass, info) - newDestructors = true - defineSymbol("nimNewRuntime") + warningDeprecated(conf, info, "newruntime is deprecated, use arc/orc instead!") + expectNoArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: + doAssert(conf != nil) + incl(conf.features, destructor) + incl(conf.globalOptions, optTinyRtti) + incl(conf.globalOptions, optOwnedRefs) + incl(conf.globalOptions, optSeqDestructors) + defineSymbol(conf.symbols, "nimV2") + conf.selectedGC = gcHooks + defineSymbol(conf.symbols, "gchooks") + defineSymbol(conf.symbols, "nimSeqsV2") + defineSymbol(conf.symbols, "nimOwnedEnabled") + of "seqsv2": + processOnOffSwitchG(conf, {optSeqDestructors}, arg, pass, info) + if pass in {passCmd2, passPP}: + defineSymbol(conf.symbols, "nimSeqsV2") + of "stylecheck": + case arg.normalize + of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError} + of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint} - {optStyleError} + of "error": conf.globalOptions = conf.globalOptions + {optStyleError} + of "usages": conf.globalOptions.incl optStyleUsages + else: localError(conf, info, errOffHintsError % arg) + of "showallmismatches": + processOnOffSwitchG(conf, {optShowAllMismatches}, arg, pass, info) + of "cppcompiletonamespace": + if arg.len > 0: + conf.cppCustomNamespace = arg + else: + conf.cppCustomNamespace = "Nim" + defineSymbol(conf.symbols, "cppCompileToNamespace", conf.cppCustomNamespace) + of "docinternal": + processOnOffSwitchG(conf, {optDocInternal}, arg, pass, info) + of "multimethods": + processOnOffSwitchG(conf, {optMultiMethods}, arg, pass, info) + of "expandmacro": + expectArg(conf, switch, arg, pass, info) + conf.macrosToExpand[arg] = "T" + of "expandarc": + expectArg(conf, switch, arg, pass, info) + conf.arcToExpand[arg] = "T" + of "benchmarkvm": + processOnOffSwitchG(conf, {optBenchmarkVM}, arg, pass, info) + of "profilevm": + processOnOffSwitchG(conf, {optProfileVM}, arg, pass, info) + of "sinkinference": + processOnOffSwitch(conf, {optSinkInference}, arg, pass, info) + of "cursorinference": + # undocumented, for debugging purposes only: + processOnOffSwitch(conf, {optCursorInference}, arg, pass, info) + of "panics": + processOnOffSwitchG(conf, {optPanics}, arg, pass, info) + if optPanics in conf.globalOptions: + defineSymbol(conf.symbols, "nimPanics") + of "jsbigint64": + processOnOffSwitchG(conf, {optJsBigInt64}, arg, pass, info) + of "sourcemap": # xxx document in --fullhelp + conf.globalOptions.incl optSourcemap + conf.options.incl optLineDir + of "deepcopy": + processOnOffSwitchG(conf, {optEnableDeepCopy}, arg, pass, info) + of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -) + handleStdinInput(conf) + of "nilseqs", "nilchecks", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch) + of "nimmainprefix": conf.nimMainPrefix = arg else: - if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) - else: invalidCmdLineOption(pass, switch, info) + if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg) + else: invalidCmdLineOption(conf, pass, switch, info) -proc processCommand(switch: string, pass: TCmdLinePass) = - var cmd, arg: string - splitSwitch(switch, cmd, arg, pass, gCmdLineInfo) - processSwitch(cmd, arg, pass, gCmdLineInfo) +proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) = + var cmd = "" + var arg = "" + splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo) + processSwitch(cmd, arg, pass, gCmdLineInfo, config) - -var - arguments* = "" - # the arguments to be passed to the program that - # should be run - -proc processSwitch*(pass: TCmdLinePass; p: OptParser) = +proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) = # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") - # we fix this here + # we transform it to (key = hint, val = [X]:off) var bracketLe = strutils.find(p.key, '[') if bracketLe >= 0: var key = substr(p.key, 0, bracketLe - 1) - var val = substr(p.key, bracketLe + 1) & ':' & p.val - processSwitch(key, val, pass, gCmdLineInfo) + var val = substr(p.key, bracketLe) & ':' & p.val + processSwitch(key, val, pass, gCmdLineInfo, config) else: - processSwitch(p.key, p.val, pass, gCmdLineInfo) + processSwitch(p.key, p.val, pass, gCmdLineInfo, config) proc processArgument*(pass: TCmdLinePass; p: OptParser; - argsCount: var int): bool = + argsCount: var int; config: ConfigRef): bool = + if argsCount == 0 and config.implicitCmd: + argsCount.inc if argsCount == 0: # nim filename.nims is the same as "nim e filename.nims": - if p.key.endswith(".nims"): - options.command = "e" - options.gProjectName = unixToNativePath(p.key) - arguments = cmdLineRest(p) + if p.key.endsWith(".nims"): + config.setCmd cmdNimscript + incl(config.globalOptions, optWasNimscript) + config.projectName = unixToNativePath(p.key) + config.arguments = cmdLineRest(p) result = true elif pass != passCmd2: - options.command = p.key + setCommandEarly(config, p.key) + result = false + else: result = false else: - if pass == passCmd1: options.commandArgs.add p.key + if pass == passCmd1: config.commandArgs.add p.key if argsCount == 1: + if p.key.endsWith(".nims"): + incl(config.globalOptions, optWasNimscript) # support UNIX style filenames everywhere for portable build scripts: - options.gProjectName = unixToNativePath(p.key) - arguments = cmdLineRest(p) + if config.projectName.len == 0: + config.projectName = unixToNativePath(p.key) + config.arguments = cmdLineRest(p) result = true + else: + result = false inc argsCount |