mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-01 13:09:14 +00:00
## Summary Adds `--genBif:on|off`, allowing regular compiler builds to generate per-module semantic BIF artifacts in `nimcache`. This reuses the semantic artifact format produced by incremental compilation without enabling IC or changing the normal code-generation and linking pipeline. In comparison to `nim check --compress ...` this new flag `nim c --genBif:on --compileOnly yourlib.nim` is considerably more useful for tooling. That produced full semantic proc declarations, Nim visibility, signatures, overload disambiguators, and pragmas. For a proc that was actually code-generated, it also recorded the exact backend name, for example. ## Motivation External tools such as language servers, debuggers, and binding generators can benefit from resolved symbol and type information produced during an ordinary build. Previously, these semantic BIF artifacts were tied to the incremental compiler workflow. ## Details With the option enabled: ```sh nim c --genBif:on project.nim ``` the compiler writes semantic `.s.bif` files and their supporting sidecars for each semantically checked module while continuing with the requested backend normally. The option: - Works with non-IC builds. - Does not enable incremental compilation. - Does not change generated program behavior. - Does not enable or introduce native ABI exports. - Does not generate `.abi.nif` manifests. - Is ignored for NimScript compilation. The `genBif` name follows existing artifact-generation options such as `genScript`, `genMapping`, and `genCDeps`. ## Testing Added a focused C backend test that runs a regular build with `--genBif:on` and verifies that semantic `.s.bif` artifacts are generated. A release-mode temporary compiler build and the focused Testament test both pass.
1343 lines
56 KiB
Nim
1343 lines
56 KiB
Nim
#
|
|
#
|
|
# The Nim Compiler
|
|
# (c) Copyright 2015 Andreas Rumpf
|
|
#
|
|
# See the file "copying.txt", included in this
|
|
# distribution, for details about the copyright.
|
|
#
|
|
|
|
# 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.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(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(usedGoGC, defined(gogc), "--gc:go")
|
|
bootSwitch(usedNoGC, defined(nogc), "--gc:none")
|
|
|
|
import std/[setutils, sets, os, strutils, parseutils, parseopt, sequtils, strtabs, enumutils]
|
|
import
|
|
msgs, options, nversion, condsyms, extccomp, platform,
|
|
wordrecg, nimblecmd, lineinfos, pathutils
|
|
|
|
import std/pathnorm
|
|
|
|
from ast import setUseIc, eqTypeFlags, tfGcSafe, tfNoSideEffect
|
|
|
|
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
|
|
passCmd1, # first pass over the command line
|
|
passCmd2, # second pass over the command line
|
|
passPP # preprocessor called processCommand()
|
|
|
|
const
|
|
HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" &
|
|
"Compiled at $4\n" &
|
|
"Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"
|
|
|
|
proc genFeatureDesc[T: enum](t: typedesc[T]): string {.compileTime.} =
|
|
result = ""
|
|
for f in T:
|
|
if result.len > 0: result.add "|"
|
|
result.add $f
|
|
|
|
const
|
|
Usage = slurp"../doc/basicopt.txt".replace(" //", " ")
|
|
AdvancedUsage = slurp"../doc/advopt.txt".replace(" //", " ") % [genFeatureDesc(Feature), genFeatureDesc(LegacyFeature)]
|
|
|
|
proc getCommandLineDesc(conf: ConfigRef): string =
|
|
result = (HelpMessage % [VersionAsString, platform.OS[conf.target.hostOS].name,
|
|
CPU[conf.target.hostCPU].name, CompileDate]) &
|
|
Usage
|
|
|
|
proc helpOnError(conf: ConfigRef; pass: TCmdLinePass) =
|
|
if pass == passCmd1:
|
|
msgWriteln(conf, getCommandLineDesc(conf), {msgStdout})
|
|
msgQuit(0)
|
|
|
|
proc writeAdvancedUsage(conf: ConfigRef; pass: TCmdLinePass) =
|
|
if pass == passCmd1:
|
|
msgWriteln(conf, (HelpMessage % [VersionAsString,
|
|
platform.OS[conf.target.hostOS].name,
|
|
CPU[conf.target.hostCPU].name, CompileDate]) &
|
|
AdvancedUsage,
|
|
{msgStdout})
|
|
msgQuit(0)
|
|
|
|
proc writeFullhelp(conf: ConfigRef; pass: TCmdLinePass) =
|
|
if pass == passCmd1:
|
|
msgWriteln(conf, `%`(HelpMessage, [VersionAsString,
|
|
platform.OS[conf.target.hostOS].name,
|
|
CPU[conf.target.hostCPU].name, CompileDate]) &
|
|
Usage & AdvancedUsage,
|
|
{msgStdout})
|
|
msgQuit(0)
|
|
|
|
proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) =
|
|
if pass == passCmd1:
|
|
msgWriteln(conf, `%`(HelpMessage, [VersionAsString,
|
|
platform.OS[conf.target.hostOS].name,
|
|
CPU[conf.target.hostCPU].name, CompileDate]),
|
|
{msgStdout})
|
|
|
|
const gitHash {.strdefine.} = gorge("git log -n 1 --format=%H").strip
|
|
# xxx move this logic to std/private/gitutils
|
|
when gitHash.len == 40:
|
|
msgWriteln(conf, "git hash: " & gitHash, {msgStdout})
|
|
|
|
msgWriteln(conf, "active boot switches:" & usedRelease & usedDanger &
|
|
usedTinyC & useLinenoise &
|
|
usedFFI & usedBoehm & usedMarkAndSweep & usedGoGC & usedNoGC,
|
|
{msgStdout})
|
|
msgQuit(0)
|
|
|
|
proc writeCommandLineUsage*(conf: ConfigRef) =
|
|
msgWriteln(conf, getCommandLineDesc(conf), {msgStdout})
|
|
|
|
proc addPrefix(switch: string): string =
|
|
if switch.len <= 1: result = "-" & switch
|
|
else: result = "--" & 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', 'warning', 'error' or 'usages' expected, but '$1' found"
|
|
|
|
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 < 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', '_', '.': cmd.add(switch[i])
|
|
else: break
|
|
inc(i)
|
|
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(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
|
|
info: TLineInfo) =
|
|
case arg.normalize
|
|
of "", "on": conf.options.incl op
|
|
of "off": conf.options.excl op
|
|
else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
|
|
|
|
proc processOnOffSwitchOrList(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
|
|
info: TLineInfo): bool =
|
|
result = false
|
|
case arg.normalize
|
|
of "on": conf.options.incl op
|
|
of "off": conf.options.excl op
|
|
of "list": result = true
|
|
else: localError(conf, info, errOnOffOrListExpectedButXFound % arg)
|
|
|
|
proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass,
|
|
info: TLineInfo) =
|
|
case arg.normalize
|
|
of "", "on": conf.globalOptions.incl op
|
|
of "off": conf.globalOptions.excl op
|
|
else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
|
|
|
|
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(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; conf: ConfigRef) =
|
|
var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off
|
|
var i = 0
|
|
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 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}
|
|
let isSomeWarning = state in {wWarning, wWarningAsError}
|
|
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 or isSomeWarning:
|
|
message(conf, info, warnUnknownNotes, "unknown $#: $#" % [name, 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:
|
|
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', 'yrc', '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"
|
|
errDefaultOrSsoExpectedButXFound = "'default' or 'sso' 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", "mm":
|
|
case arg.normalize
|
|
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 "yrc": result = conf.selectedGC == gcYrc
|
|
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(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(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(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 "strings":
|
|
case arg.normalize
|
|
of "default": result = conf.selectedStrings == stringDefault
|
|
of "sso": result = conf.selectedStrings == stringSso
|
|
else:
|
|
result = false
|
|
localError(conf, info, errDefaultOrSsoExpectedButXFound % 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*(conf: ConfigRef; switch: string, info: TLineInfo): bool =
|
|
case switch.normalize
|
|
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 = 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)
|
|
of "mangle": result = contains(conf.globalOptions, optItaniumMangle)
|
|
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:
|
|
conf.projectPath.string / path
|
|
try:
|
|
result = AbsoluteDir pathSubs(conf, p, toFullPath(conf, info).splitFile().dir)
|
|
except ValueError:
|
|
localError(conf, info, "invalid path: " & p)
|
|
result = AbsoluteDir p
|
|
|
|
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 = AbsoluteDir pathSubs(conf, p, basedir)
|
|
except ValueError:
|
|
localError(conf, info, "invalid path: " & p)
|
|
result = AbsoluteDir p
|
|
|
|
const
|
|
errInvalidNumber = "$1 is not a valid number"
|
|
|
|
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)
|
|
|
|
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 trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) =
|
|
var a = arg.split(',')
|
|
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(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 = conf.stdinFile.string
|
|
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 "nif": cmdCompileToNif
|
|
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 "secret": cmdInteractive
|
|
of "nop", "help": cmdNop
|
|
of "jsonscript": cmdJsonscript
|
|
of "nifc": cmdNifC # generate C from NIF files
|
|
of "ic": cmdIc # generate .build.nif for nifmake
|
|
of "icconfig": cmdIcConfig # produce the precompiled config artifact
|
|
of "track": cmdTrack # IDE goto-def / find-usages over `nim ic`'s NIF output
|
|
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
|
|
of cmdCompileToNif: conf.backend = backendNif
|
|
of cmdNifC:
|
|
conf.backend = backendC # NIF to C compilation
|
|
of cmdM:
|
|
# cmdM requires optCompress for proper IC handling (include files, etc.)
|
|
conf.globalOptions.incl optCompress
|
|
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, "gcyrc")
|
|
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 "yrc":
|
|
conf.selectedGC = gcYrc
|
|
defineSymbol(conf.symbols, "gcyrc")
|
|
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 = ""
|
|
# Record config-file switches so the `nim ic` driver can serialise them into a
|
|
# precompiled-config artifact and have its per-module child processes replay
|
|
# them instead of re-parsing the `nim.cfg` chain (and re-running `config.nims`
|
|
# in the VM) on every invocation. Only `passPP` (config-file) switches are
|
|
# captured; command-line switches are forwarded by the build graph as usual.
|
|
# Path-search switches are skipped: their net effect already lives in the
|
|
# resolved `searchPaths` the driver forwards as `--path`, and replaying their
|
|
# raw (often relative-to-config-dir) arguments here would misresolve.
|
|
if pass == passPP and switch.normalize notin
|
|
["path", "p", "nimblepath", "lazypath", "excludepath",
|
|
"nonimblepath", "clearnimblepath", "nimcache"]:
|
|
conf.icConfigSwitches.add (switch, arg)
|
|
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(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(conf, switch, arg, pass, info)
|
|
let path = processPath(conf, arg, info)
|
|
conf.searchPaths.keepItIf(it != path)
|
|
conf.lazyPaths.keepItIf(it != path)
|
|
of "nimcache":
|
|
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(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 "ideimports":
|
|
# nimsuggest: where the import closure comes from. IC is opt-in.
|
|
# nif|on load unchanged imports from precompiled NIF (cmdM)
|
|
# source|off (default) recompile the whole closure from source (cmdCheck)
|
|
case arg.normalize
|
|
of "nif", "on", "": conf.ideImportsFromNif = true
|
|
of "source", "off": conf.ideImportsFromNif = false
|
|
else: localError(conf, info, "'--ideImports' expects 'nif' or 'source', got: '$1'" % arg)
|
|
of "docseesrcurl":
|
|
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(conf, switch, arg, pass, info)
|
|
if {':', '='} in arg:
|
|
splitSwitch(conf, arg, key, val, pass, info)
|
|
specialDefine(conf, key, pass)
|
|
defineSymbol(conf.symbols, key, val)
|
|
else:
|
|
specialDefine(conf, arg, pass)
|
|
defineSymbol(conf.symbols, arg)
|
|
of "undef", "u":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
undefSymbol(conf.symbols, arg)
|
|
of "compile":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}: processCompile(conf, arg)
|
|
of "link":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}:
|
|
addExternalFileToLink(conf, AbsoluteFile arg)
|
|
of "debuginfo":
|
|
processOnOffSwitchG(conf, {optCDebug}, arg, pass, info)
|
|
of "embedsrc":
|
|
processOnOffSwitchG(conf, {optEmbedOrigSrc}, arg, pass, info)
|
|
of "compileonly", "c":
|
|
processOnOffSwitchG(conf, {optCompileOnly}, arg, pass, info)
|
|
of "nolinking":
|
|
processOnOffSwitchG(conf, {optNoLinking}, arg, pass, info)
|
|
of "nomain":
|
|
processOnOffSwitchG(conf, {optNoMain}, arg, pass, info)
|
|
of "forcebuild", "f":
|
|
processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info)
|
|
of "project":
|
|
processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info)
|
|
of "gc":
|
|
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 "strings":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}:
|
|
case arg.normalize
|
|
of "default":
|
|
conf.selectedStrings = stringDefault
|
|
of "sso":
|
|
conf.selectedStrings = stringSso
|
|
defineSymbol(conf.symbols, "nimsso")
|
|
else:
|
|
localError(conf, info, errDefaultOrSsoExpectedButXFound % arg)
|
|
of "warnings", "w":
|
|
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(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", "native", "gdb":
|
|
conf.globalOptions.incl optCDebug
|
|
conf.options.incl optLineDir
|
|
#defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
|
|
of "off":
|
|
conf.globalOptions.excl optCDebug
|
|
else:
|
|
localError(conf, info, "expected native|gdb|on|off but found " & arg)
|
|
of "mangle":
|
|
case arg.normalize
|
|
of "nim":
|
|
conf.globalOptions.excl optItaniumMangle
|
|
of "cpp":
|
|
conf.globalOptions.incl optItaniumMangle
|
|
else:
|
|
localError(conf, info, "expected nim|cpp but found " & arg)
|
|
of "compress":
|
|
conf.globalOptions.incl optCompress
|
|
of "genbif":
|
|
processOnOffSwitchG(conf, {optGenBif}, arg, pass, info)
|
|
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(conf, {optProfiler}, arg, pass, info)
|
|
if optProfiler in conf.options: defineSymbol(conf.symbols, "profiler")
|
|
else: undefSymbol(conf.symbols, "profiler")
|
|
of "memtracker":
|
|
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(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":
|
|
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(conf, {optImplicitStatic}, arg, pass, info)
|
|
of "patterns", "trmacros":
|
|
if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros")
|
|
processOnOffSwitch(conf, {optTrMacros}, arg, pass, info)
|
|
of "opt":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
case arg.normalize
|
|
of "speed":
|
|
incl(conf.options, optOptimizeSpeed)
|
|
excl(conf.options, optOptimizeSize)
|
|
of "size":
|
|
excl(conf.options, optOptimizeSpeed)
|
|
incl(conf.options, optOptimizeSize)
|
|
of "none":
|
|
excl(conf.options, optOptimizeSpeed)
|
|
excl(conf.options, optOptimizeSize)
|
|
else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
|
|
of "app":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
case arg.normalize
|
|
of "gui":
|
|
incl(conf.globalOptions, optGenGuiApp)
|
|
defineSymbol(conf.symbols, "executable")
|
|
defineSymbol(conf.symbols, "guiapp")
|
|
of "console":
|
|
excl(conf.globalOptions, optGenGuiApp)
|
|
defineSymbol(conf.symbols, "executable")
|
|
defineSymbol(conf.symbols, "consoleapp")
|
|
of "lib":
|
|
incl(conf.globalOptions, optGenDynLib)
|
|
excl(conf.globalOptions, optGenGuiApp)
|
|
defineSymbol(conf.symbols, "library")
|
|
defineSymbol(conf.symbols, "dll")
|
|
of "staticlib":
|
|
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(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(conf, arg)
|
|
of "passl", "l":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(conf, arg)
|
|
of "cincludes":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}: conf.cIncludes.add processPath(conf, arg, info)
|
|
of "clibdir":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}: conf.cLibs.add processPath(conf, arg, info)
|
|
of "clib":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}:
|
|
conf.cLinkedLibs.add arg
|
|
of "header":
|
|
if conf != nil: conf.headerFile = arg
|
|
incl(conf.globalOptions, optGenIndex)
|
|
of "nimbasepattern":
|
|
if conf != nil: conf.nimbasePattern = arg
|
|
of "index":
|
|
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 "ismainmodule":
|
|
# `nim m` (IC) only: marks the single module being checked as the program's
|
|
# real entry point so that `isMainModule` and `when isMainModule:` resolve
|
|
# correctly even though every module is compiled with `sfMainModule` set.
|
|
conf.isMainModule = switchOn(arg)
|
|
of "icgroup":
|
|
# `nim m` only: register a module that belongs to the current strongly-
|
|
# connected import group, so it is compiled from source (not loaded from a
|
|
# precompiled NIF) and gets its own NIF written. `deps.nim` emits one
|
|
# `--icGroup:<path>` per member of a dependency cycle. The argument is an
|
|
# absolute .nim path produced by the dependency scanner.
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}:
|
|
conf.icGroup.incl(canonicalizePath(conf, AbsoluteFile arg).string)
|
|
of "icproject":
|
|
# `nim m`/`nim nifc` only: the ORIGINAL project file (see options.icProject)
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}:
|
|
conf.icProject = canonicalizePath(conf, AbsoluteFile arg).string
|
|
of "icpreparsedconfig":
|
|
# `nim m`/`nim nifc` only: path of the precompiled-config artifact (see
|
|
# options.icPreparsedConfig). Read in `passCmd1`, before `loadConfigs`, so
|
|
# config loading can replay it instead of re-parsing the `nim.cfg` chain.
|
|
expectArg(conf, switch, arg, pass, info)
|
|
conf.icPreparsedConfig = arg
|
|
of "icconfigout":
|
|
# `nim icconfig` only: where to write the precompiled config artifact (see
|
|
# options.icConfigOut). The `nim ic` driver spawns the producer with this.
|
|
expectArg(conf, switch, arg, pass, info)
|
|
conf.icConfigOut = arg
|
|
of "icbackendstage":
|
|
# `nim nifc` only: per-module backend stage, one of cg|merge|emit (see
|
|
# options.icBackendStage). Empty (switch unused) keeps the whole-program
|
|
# backend. Emitted by `deps.nim`'s backend build file.
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}:
|
|
conf.icBackendStage = arg
|
|
of "icbackendmodule":
|
|
# `nim nifc` only: the NIF module suffix the cg/emit stage operates on (see
|
|
# options.icBackendModule).
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}:
|
|
conf.icBackendModule = arg
|
|
of "import":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}:
|
|
let m = findModule(conf, arg, toFullPath(conf, info)).string
|
|
if m.len == 0:
|
|
localError(conf, info, "Cannot resolve filename: " & arg)
|
|
else:
|
|
conf.implicitImports.add(if arg.startsWith(stdPrefix): arg else: m)
|
|
of "include":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
if pass in {passCmd2, passPP}:
|
|
let m = findModule(conf, arg, toFullPath(conf, info)).string
|
|
if m.len == 0:
|
|
localError(conf, info, "Cannot resolve filename: " & arg)
|
|
else:
|
|
conf.implicitIncludes.add m
|
|
of "listcmd":
|
|
processOnOffSwitchG(conf, {optListCmd}, arg, pass, info)
|
|
of "asm":
|
|
processOnOffSwitchG(conf, {optProduceAsm}, arg, pass, info)
|
|
of "genmapping":
|
|
processOnOffSwitchG(conf, {optGenMapping}, arg, pass, info)
|
|
of "os":
|
|
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(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":
|
|
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 value <= 0: localError(conf, info, "maxLoopIterationsVM must be a positive integer greater than zero")
|
|
conf.maxLoopIterationsVM = value
|
|
of "maxcalldepthvm":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
var value: int = 2_000
|
|
discard parseSaturatedNatural(arg, value)
|
|
if value <= 0: localError(conf, info, "maxCallDepthVM must be a positive integer greater than zero")
|
|
conf.maxCallDepthVM = 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 "stdinfile":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
conf.stdinFile = if os.isAbsolute(arg): AbsoluteFile(arg)
|
|
else: AbsoluteFile(getCurrentDir() / arg)
|
|
of "verbosity":
|
|
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(conf, switch, arg, pass, info)
|
|
var value: int = 0
|
|
discard parseSaturatedNatural(arg, value)
|
|
conf.numberOfProcessors = value
|
|
of "version", "v":
|
|
expectNoArg(conf, switch, arg, pass, info)
|
|
writeVersionInfo(conf, pass)
|
|
of "advanced":
|
|
expectNoArg(conf, switch, arg, pass, info)
|
|
writeAdvancedUsage(conf, pass)
|
|
of "fullhelp":
|
|
expectNoArg(conf, switch, arg, pass, info)
|
|
writeFullhelp(conf, pass)
|
|
of "help", "h":
|
|
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.ic = true
|
|
of "legacy": 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":
|
|
processOnOffSwitchG(conf, {optSkipSystemConfigFile}, arg, pass, info)
|
|
of "skipprojcfg":
|
|
processOnOffSwitchG(conf, {optSkipProjConfigFile}, arg, pass, info)
|
|
of "skipusercfg":
|
|
processOnOffSwitchG(conf, {optSkipUserConfigFile}, arg, pass, info)
|
|
of "skipparentcfg":
|
|
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(conf, switch, arg, pass, info)
|
|
conf.libpath = processPath(conf, arg, info, notRelativeToProj=true)
|
|
of "putenv":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
splitSwitch(conf, arg, key, val, pass, info)
|
|
os.putEnv(key, val)
|
|
of "cc":
|
|
if conf.backend != backendJs: # bug #19330
|
|
expectArg(conf, switch, arg, pass, info)
|
|
setCC(conf, arg, info)
|
|
of "track":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
track(conf, arg, info)
|
|
of "trackdirty":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
trackDirty(conf, arg, info)
|
|
of "suggest":
|
|
expectNoArg(conf, switch, arg, pass, info)
|
|
conf.ideCmd = ideSug
|
|
of "def":
|
|
expectArg(conf, switch, arg, pass, info)
|
|
trackIde(conf, ideDef, arg, info)
|
|
of "context":
|
|
expectNoArg(conf, switch, arg, pass, info)
|
|
conf.ideCmd = ideCon
|
|
of "usages":
|
|
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":
|
|
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":
|
|
# 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(conf, switch, arg, pass, info)
|
|
of "dynliboverrideall":
|
|
processOnOffSwitchG(conf, {optDynlibOverrideAll}, arg, pass, info)
|
|
of "experimental":
|
|
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(conf, switch, arg, pass, info)
|
|
conf.exc = low(ExceptionSystem)
|
|
defineSymbol(conf.symbols, "noCppExceptions")
|
|
of "shownonexports":
|
|
expectNoArg(conf, switch, arg, pass, info)
|
|
showNonExportedFields(conf)
|
|
of "raw":
|
|
expectNoArg(conf, switch, arg, pass, info)
|
|
docRawOutput(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(conf, switch, arg, pass, info)
|
|
if conf != nil:
|
|
conf.cppDefine(arg)
|
|
of "newruntime":
|
|
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, optStyleWarning}
|
|
of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint} - {optStyleError, optStyleWarning}
|
|
of "warning": conf.globalOptions = conf.globalOptions + {optStyleWarning} - {optStyleHint, optStyleError}
|
|
of "error": conf.globalOptions = conf.globalOptions + {optStyleError} - {optStyleHint, optStyleWarning}
|
|
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(conf, switch, arg)
|
|
else: invalidCmdLineOption(conf, pass, switch, info)
|
|
|
|
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)
|
|
|
|
proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) =
|
|
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
|
|
# 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) & ':' & p.val
|
|
processSwitch(key, val, pass, gCmdLineInfo, config)
|
|
else:
|
|
processSwitch(p.key, p.val, pass, gCmdLineInfo, config)
|
|
|
|
proc processArgument*(pass: TCmdLinePass; p: OptParser;
|
|
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"):
|
|
config.setCmd cmdNimscript
|
|
incl(config.globalOptions, optWasNimscript)
|
|
config.projectName = unixToNativePath(p.key)
|
|
config.arguments = cmdLineRest(p)
|
|
result = true
|
|
elif pass != passCmd2:
|
|
setCommandEarly(config, p.key)
|
|
result = false
|
|
else: result = false
|
|
else:
|
|
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:
|
|
if config.projectName.len == 0:
|
|
config.projectName = unixToNativePath(p.key)
|
|
if config.cmd == cmdTrack:
|
|
# `nim track PROJ --def:...`: unlike a normal command (where everything
|
|
# after the project file is passed to the compiled program), `track`
|
|
# accepts its IDE-query switches AFTER the project — the natural,
|
|
# nimsuggest-like invocation form. So don't swallow the rest of the line
|
|
# into `arguments`; keep parsing the remaining tokens as switches.
|
|
result = false
|
|
else:
|
|
config.arguments = cmdLineRest(p)
|
|
result = true
|
|
else:
|
|
result = false
|
|
inc argsCount
|