commands.nim 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # This module handles the parsing of command line arguments.
  10. # We do this here before the 'import' statement so 'defined' does not get
  11. # confused with 'TGCMode.gcMarkAndSweep' etc.
  12. template bootSwitch(name, expr, userString) =
  13. # Helper to build boot constants, for debugging you can 'echo' the else part.
  14. const name = if expr: " " & userString else: ""
  15. bootSwitch(usedRelease, defined(release), "-d:release")
  16. bootSwitch(usedDanger, defined(danger), "-d:danger")
  17. # `useLinenoise` deprecated in favor of `nimUseLinenoise`, kept for backward compatibility
  18. bootSwitch(useLinenoise, defined(nimUseLinenoise) or defined(useLinenoise), "-d:nimUseLinenoise")
  19. bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm")
  20. bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
  21. bootSwitch(usedGoGC, defined(gogc), "--gc:go")
  22. bootSwitch(usedNoGC, defined(nogc), "--gc:none")
  23. import std/[setutils, os, strutils, parseutils, parseopt, sequtils, strtabs, enumutils]
  24. import
  25. msgs, options, nversion, condsyms, extccomp, platform,
  26. wordrecg, nimblecmd, lineinfos, pathutils
  27. import std/pathnorm
  28. from ast import setUseIc, eqTypeFlags, tfGcSafe, tfNoSideEffect
  29. when defined(nimPreviewSlimSystem):
  30. import std/assertions
  31. # but some have deps to imported modules. Yay.
  32. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
  33. bootSwitch(usedFFI, hasFFI, "-d:nimHasLibFFI")
  34. type
  35. TCmdLinePass* = enum
  36. passCmd1, # first pass over the command line
  37. passCmd2, # second pass over the command line
  38. passPP # preprocessor called processCommand()
  39. const
  40. HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" &
  41. "Compiled at $4\n" &
  42. "Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"
  43. proc genFeatureDesc[T: enum](t: typedesc[T]): string {.compileTime.} =
  44. result = ""
  45. for f in T:
  46. if result.len > 0: result.add "|"
  47. result.add $f
  48. const
  49. Usage = slurp"../doc/basicopt.txt".replace(" //", " ")
  50. AdvancedUsage = slurp"../doc/advopt.txt".replace(" //", " ") % [genFeatureDesc(Feature), genFeatureDesc(LegacyFeature)]
  51. proc getCommandLineDesc(conf: ConfigRef): string =
  52. result = (HelpMessage % [VersionAsString, platform.OS[conf.target.hostOS].name,
  53. CPU[conf.target.hostCPU].name, CompileDate]) &
  54. Usage
  55. proc helpOnError(conf: ConfigRef; pass: TCmdLinePass) =
  56. if pass == passCmd1:
  57. msgWriteln(conf, getCommandLineDesc(conf), {msgStdout})
  58. msgQuit(0)
  59. proc writeAdvancedUsage(conf: ConfigRef; pass: TCmdLinePass) =
  60. if pass == passCmd1:
  61. msgWriteln(conf, (HelpMessage % [VersionAsString,
  62. platform.OS[conf.target.hostOS].name,
  63. CPU[conf.target.hostCPU].name, CompileDate]) &
  64. AdvancedUsage,
  65. {msgStdout})
  66. msgQuit(0)
  67. proc writeFullhelp(conf: ConfigRef; pass: TCmdLinePass) =
  68. if pass == passCmd1:
  69. msgWriteln(conf, `%`(HelpMessage, [VersionAsString,
  70. platform.OS[conf.target.hostOS].name,
  71. CPU[conf.target.hostCPU].name, CompileDate]) &
  72. Usage & AdvancedUsage,
  73. {msgStdout})
  74. msgQuit(0)
  75. proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) =
  76. if pass == passCmd1:
  77. msgWriteln(conf, `%`(HelpMessage, [VersionAsString,
  78. platform.OS[conf.target.hostOS].name,
  79. CPU[conf.target.hostCPU].name, CompileDate]),
  80. {msgStdout})
  81. const gitHash {.strdefine.} = gorge("git log -n 1 --format=%H").strip
  82. # xxx move this logic to std/private/gitutils
  83. when gitHash.len == 40:
  84. msgWriteln(conf, "git hash: " & gitHash, {msgStdout})
  85. msgWriteln(conf, "active boot switches:" & usedRelease & usedDanger &
  86. usedTinyC & useLinenoise &
  87. usedFFI & usedBoehm & usedMarkAndSweep & usedGoGC & usedNoGC,
  88. {msgStdout})
  89. msgQuit(0)
  90. proc writeCommandLineUsage*(conf: ConfigRef) =
  91. msgWriteln(conf, getCommandLineDesc(conf), {msgStdout})
  92. proc addPrefix(switch: string): string =
  93. if switch.len <= 1: result = "-" & switch
  94. else: result = "--" & switch
  95. const
  96. errInvalidCmdLineOption = "invalid command line option: '$1'"
  97. errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found"
  98. errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found"
  99. errOffHintsError = "'off', 'hint', 'error' or 'usages' expected, but '$1' found"
  100. proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) =
  101. if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-")
  102. else: localError(conf, info, errInvalidCmdLineOption % addPrefix(switch))
  103. proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TCmdLinePass,
  104. info: TLineInfo) =
  105. cmd = ""
  106. var i = 0
  107. if i < switch.len and switch[i] == '-': inc(i)
  108. if i < switch.len and switch[i] == '-': inc(i)
  109. while i < switch.len:
  110. case switch[i]
  111. of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': cmd.add(switch[i])
  112. else: break
  113. inc(i)
  114. if i >= switch.len: arg = ""
  115. # cmd:arg => (cmd,arg)
  116. elif switch[i] in {':', '='}: arg = substr(switch, i + 1)
  117. # cmd[sub]:rest => (cmd,[sub]:rest)
  118. elif switch[i] == '[': arg = substr(switch, i)
  119. else: invalidCmdLineOption(conf, pass, switch, info)
  120. template switchOn(arg: string): bool =
  121. # xxx use `switchOn` wherever appropriate
  122. case arg.normalize
  123. of "", "on": true
  124. of "off": false
  125. else:
  126. localError(conf, info, errOnOrOffExpectedButXFound % arg)
  127. false
  128. proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
  129. info: TLineInfo) =
  130. case arg.normalize
  131. of "", "on": conf.options.incl op
  132. of "off": conf.options.excl op
  133. else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
  134. proc processOnOffSwitchOrList(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
  135. info: TLineInfo): bool =
  136. result = false
  137. case arg.normalize
  138. of "on": conf.options.incl op
  139. of "off": conf.options.excl op
  140. of "list": result = true
  141. else: localError(conf, info, errOnOffOrListExpectedButXFound % arg)
  142. proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass,
  143. info: TLineInfo) =
  144. case arg.normalize
  145. of "", "on": conf.globalOptions.incl op
  146. of "off": conf.globalOptions.excl op
  147. else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
  148. proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
  149. if arg == "":
  150. localError(conf, info, "argument for command line option expected: '$1'" % addPrefix(switch))
  151. proc expectNoArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
  152. if arg != "":
  153. localError(conf, info, "invalid argument for command line option: '$1'" % addPrefix(switch))
  154. proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
  155. info: TLineInfo; orig: string; conf: ConfigRef) =
  156. var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off
  157. var i = 0
  158. var notes: set[TMsgKind] = {}
  159. var isBracket = false
  160. if i < arg.len and arg[i] == '[':
  161. isBracket = true
  162. inc(i)
  163. while i < arg.len and (arg[i] notin {':', '=', ']'}):
  164. id.add(arg[i])
  165. inc(i)
  166. if isBracket:
  167. if i < arg.len and arg[i] == ']': inc(i)
  168. else: invalidCmdLineOption(conf, pass, orig, info)
  169. if i == arg.len: discard
  170. elif i < arg.len and (arg[i] in {':', '='}): inc(i)
  171. else: invalidCmdLineOption(conf, pass, orig, info)
  172. let isSomeHint = state in {wHint, wHintAsError}
  173. let isSomeWarning = state in {wWarning, wWarningAsError}
  174. template findNote(noteMin, noteMax, name) =
  175. # unfortunately, hintUser and warningUser clash, otherwise implementation would simplify a bit
  176. let x = findStr(noteMin, noteMax, id, errUnknown)
  177. if x != errUnknown: notes = {TNoteKind(x)}
  178. else:
  179. if isSomeHint or isSomeWarning:
  180. message(conf, info, warnUnknownNotes, "unknown $#: $#" % [name, id])
  181. else:
  182. localError(conf, info, "unknown $#: $#" % [name, id])
  183. case id.normalize
  184. of "all": # other note groups would be easy to support via additional cases
  185. notes = if isSomeHint: {hintMin..hintMax} else: {warnMin..warnMax}
  186. elif isSomeHint: findNote(hintMin, hintMax, "hint")
  187. else: findNote(warnMin, warnMax, "warning")
  188. var val = substr(arg, i).normalize
  189. if val == "": val = "on"
  190. if val notin ["on", "off"]:
  191. # xxx in future work we should also allow users to have control over `foreignPackageNotes`
  192. # so that they can enable `hints|warnings|warningAsErrors` for all the code they depend on.
  193. localError(conf, info, errOnOrOffExpectedButXFound % arg)
  194. else:
  195. let isOn = val == "on"
  196. if isOn and id.normalize == "all":
  197. localError(conf, info, "only 'all:off' is supported")
  198. for n in notes:
  199. if n notin conf.cmdlineNotes or pass == passCmd1:
  200. if pass == passCmd1: incl(conf.cmdlineNotes, n)
  201. incl(conf.modifiedyNotes, n)
  202. if state in {wWarningAsError, wHintAsError}:
  203. conf.warningAsErrors[n] = isOn # xxx rename warningAsErrors to noteAsErrors
  204. else:
  205. conf.notes[n] = isOn
  206. conf.mainPackageNotes[n] = isOn
  207. if not isOn: excl(conf.foreignPackageNotes, n)
  208. proc processCompile(conf: ConfigRef; filename: string) =
  209. var found = findFile(conf, filename)
  210. if found.isEmpty: found = AbsoluteFile filename
  211. extccomp.addExternalFileToCompile(conf, found)
  212. const
  213. errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'atomicArc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
  214. errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
  215. errGuiConsoleOrLibExpectedButXFound = "'gui', 'console', 'lib' or 'staticlib' expected, but '$1' found"
  216. errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found"
  217. errInvalidFeatureButXFound = Feature.toSeq.map(proc(val:Feature): string = "'$1'" % $val).join(", ") & " expected, but '$1' found"
  218. template warningOptionNoop(switch: string) =
  219. warningDeprecated(conf, info, "'$#' is deprecated, now a noop" % switch)
  220. template deprecatedAlias(oldName, newName: string) =
  221. warningDeprecated(conf, info, "'$#' is a deprecated alias for '$#'" % [oldName, newName])
  222. proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool =
  223. case switch.normalize
  224. of "gc", "mm":
  225. case arg.normalize
  226. of "boehm": result = conf.selectedGC == gcBoehm
  227. of "refc": result = conf.selectedGC == gcRefc
  228. of "markandsweep": result = conf.selectedGC == gcMarkAndSweep
  229. of "destructors", "arc": result = conf.selectedGC == gcArc
  230. of "orc": result = conf.selectedGC == gcOrc
  231. of "hooks": result = conf.selectedGC == gcHooks
  232. of "go": result = conf.selectedGC == gcGo
  233. of "none": result = conf.selectedGC == gcNone
  234. of "stack", "regions": result = conf.selectedGC == gcRegions
  235. of "atomicarc": result = conf.selectedGC == gcAtomicArc
  236. else:
  237. result = false
  238. localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
  239. of "opt":
  240. case arg.normalize
  241. of "speed": result = contains(conf.options, optOptimizeSpeed)
  242. of "size": result = contains(conf.options, optOptimizeSize)
  243. of "none": result = conf.options * {optOptimizeSpeed, optOptimizeSize} == {}
  244. else:
  245. result = false
  246. localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
  247. of "verbosity": result = $conf.verbosity == arg
  248. of "app":
  249. case arg.normalize
  250. of "gui": result = contains(conf.globalOptions, optGenGuiApp)
  251. of "console": result = not contains(conf.globalOptions, optGenGuiApp)
  252. of "lib": result = contains(conf.globalOptions, optGenDynLib) and
  253. not contains(conf.globalOptions, optGenGuiApp)
  254. of "staticlib": result = contains(conf.globalOptions, optGenStaticLib) and
  255. not contains(conf.globalOptions, optGenGuiApp)
  256. else:
  257. result = false
  258. localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
  259. of "dynliboverride":
  260. result = isDynlibOverride(conf, arg)
  261. of "exceptions":
  262. case arg.normalize
  263. of "cpp": result = conf.exc == excCpp
  264. of "setjmp": result = conf.exc == excSetjmp
  265. of "quirky": result = conf.exc == excQuirky
  266. of "goto": result = conf.exc == excGoto
  267. else:
  268. result = false
  269. localError(conf, info, errInvalidExceptionSystem % arg)
  270. of "experimental":
  271. try:
  272. result = conf.features.contains parseEnum[Feature](arg)
  273. except ValueError:
  274. result = false
  275. localError(conf, info, errInvalidFeatureButXFound % arg)
  276. else:
  277. result = false
  278. invalidCmdLineOption(conf, passCmd1, switch, info)
  279. proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool =
  280. case switch.normalize
  281. of "debuginfo": result = contains(conf.globalOptions, optCDebug)
  282. of "compileonly", "c": result = contains(conf.globalOptions, optCompileOnly)
  283. of "nolinking": result = contains(conf.globalOptions, optNoLinking)
  284. of "nomain": result = contains(conf.globalOptions, optNoMain)
  285. of "forcebuild", "f": result = contains(conf.globalOptions, optForceFullMake)
  286. of "warnings", "w": result = contains(conf.options, optWarns)
  287. of "hints": result = contains(conf.options, optHints)
  288. of "threadanalysis": result = contains(conf.globalOptions, optThreadAnalysis)
  289. of "stacktrace": result = contains(conf.options, optStackTrace)
  290. of "stacktracemsgs": result = contains(conf.options, optStackTraceMsgs)
  291. of "linetrace": result = contains(conf.options, optLineTrace)
  292. of "debugger": result = contains(conf.globalOptions, optCDebug)
  293. of "profiler": result = contains(conf.options, optProfiler)
  294. of "memtracker": result = contains(conf.options, optMemTracker)
  295. of "checks", "x": result = conf.options * ChecksOptions == ChecksOptions
  296. of "floatchecks":
  297. result = conf.options * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck}
  298. of "infchecks": result = contains(conf.options, optInfCheck)
  299. of "nanchecks": result = contains(conf.options, optNaNCheck)
  300. of "objchecks": result = contains(conf.options, optObjCheck)
  301. of "fieldchecks": result = contains(conf.options, optFieldCheck)
  302. of "rangechecks": result = contains(conf.options, optRangeCheck)
  303. of "boundchecks": result = contains(conf.options, optBoundsCheck)
  304. of "refchecks":
  305. warningDeprecated(conf, info, "refchecks is deprecated!")
  306. result = contains(conf.options, optRefCheck)
  307. of "overflowchecks": result = contains(conf.options, optOverflowCheck)
  308. of "staticboundchecks": result = contains(conf.options, optStaticBoundsCheck)
  309. of "stylechecks": result = contains(conf.options, optStyleCheck)
  310. of "linedir": result = contains(conf.options, optLineDir)
  311. of "assertions", "a": result = contains(conf.options, optAssert)
  312. of "run", "r": result = contains(conf.globalOptions, optRun)
  313. of "symbolfiles": result = conf.symbolFiles != disabledSf
  314. of "genscript": result = contains(conf.globalOptions, optGenScript)
  315. of "gencdeps": result = contains(conf.globalOptions, optGenCDeps)
  316. of "threads": result = contains(conf.globalOptions, optThreads)
  317. of "tlsemulation": result = contains(conf.globalOptions, optTlsEmulation)
  318. of "implicitstatic": result = contains(conf.options, optImplicitStatic)
  319. of "patterns", "trmacros":
  320. if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros")
  321. result = contains(conf.options, optTrMacros)
  322. of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
  323. of "nilseqs", "nilchecks", "taintmode":
  324. warningOptionNoop(switch)
  325. result = false
  326. of "panics": result = contains(conf.globalOptions, optPanics)
  327. of "jsbigint64": result = contains(conf.globalOptions, optJsBigInt64)
  328. else:
  329. result = false
  330. invalidCmdLineOption(conf, passCmd1, switch, info)
  331. proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
  332. notRelativeToProj = false): AbsoluteDir =
  333. let p = if os.isAbsolute(path) or '$' in path:
  334. path
  335. elif notRelativeToProj:
  336. getCurrentDir() / path
  337. else:
  338. conf.projectPath.string / path
  339. try:
  340. result = AbsoluteDir pathSubs(conf, p, toFullPath(conf, info).splitFile().dir)
  341. except ValueError:
  342. localError(conf, info, "invalid path: " & p)
  343. result = AbsoluteDir p
  344. proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): AbsoluteDir =
  345. let path = if path.len > 0 and path[0] == '"': strutils.unescape(path)
  346. else: path
  347. let basedir = toFullPath(conf, info).splitFile().dir
  348. let p = if os.isAbsolute(path) or '$' in path:
  349. path
  350. else:
  351. basedir / path
  352. try:
  353. result = AbsoluteDir pathSubs(conf, p, basedir)
  354. except ValueError:
  355. localError(conf, info, "invalid path: " & p)
  356. result = AbsoluteDir p
  357. const
  358. errInvalidNumber = "$1 is not a valid number"
  359. proc makeAbsolute(s: string): AbsoluteFile =
  360. if isAbsolute(s):
  361. AbsoluteFile pathnorm.normalizePath(s)
  362. else:
  363. AbsoluteFile pathnorm.normalizePath(os.getCurrentDir() / s)
  364. proc setTrackingInfo(conf: ConfigRef; dirty, file, line, column: string,
  365. info: TLineInfo) =
  366. ## set tracking info, common code for track, trackDirty, & ideTrack
  367. var ln: int = 0
  368. var col: int = 0
  369. if parseUtils.parseInt(line, ln) <= 0:
  370. localError(conf, info, errInvalidNumber % line)
  371. if parseUtils.parseInt(column, col) <= 0:
  372. localError(conf, info, errInvalidNumber % column)
  373. let a = makeAbsolute(file)
  374. if dirty == "":
  375. conf.m.trackPos = newLineInfo(conf, a, ln, col)
  376. else:
  377. let dirtyOriginalIdx = fileInfoIdx(conf, a)
  378. if dirtyOriginalIdx.int32 >= 0:
  379. msgs.setDirtyFile(conf, dirtyOriginalIdx, makeAbsolute(dirty))
  380. conf.m.trackPos = newLineInfo(dirtyOriginalIdx, ln, col)
  381. proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) =
  382. var a = arg.split(',')
  383. if a.len != 4: localError(conf, info,
  384. "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN expected")
  385. setTrackingInfo(conf, a[0], a[1], a[2], a[3], info)
  386. proc track(conf: ConfigRef; arg: string, info: TLineInfo) =
  387. var a = arg.split(',')
  388. if a.len != 3: localError(conf, info, "FILE,LINE,COLUMN expected")
  389. setTrackingInfo(conf, "", a[0], a[1], a[2], info)
  390. proc trackIde(conf: ConfigRef; cmd: IdeCmd, arg: string, info: TLineInfo) =
  391. ## set the tracking info related to an ide cmd, supports optional dirty file
  392. var a = arg.split(',')
  393. case a.len
  394. of 4:
  395. setTrackingInfo(conf, a[0], a[1], a[2], a[3], info)
  396. of 3:
  397. setTrackingInfo(conf, "", a[0], a[1], a[2], info)
  398. else:
  399. localError(conf, info, "[DIRTY_BUFFER,]ORIGINAL_FILE,LINE,COLUMN expected")
  400. conf.ideCmd = cmd
  401. proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
  402. if pass in {passCmd2, passPP}:
  403. expectArg(conf, switch, arg, pass, info)
  404. options.inclDynlibOverride(conf, arg)
  405. template handleStdinOrCmdInput =
  406. conf.projectFull = conf.projectName.AbsoluteFile
  407. conf.projectPath = AbsoluteDir getCurrentDir()
  408. if conf.outDir.isEmpty:
  409. conf.outDir = getNimcacheDir(conf)
  410. proc handleStdinInput*(conf: ConfigRef) =
  411. conf.projectName = conf.stdinFile.string
  412. conf.projectIsStdin = true
  413. handleStdinOrCmdInput()
  414. proc handleCmdInput*(conf: ConfigRef) =
  415. conf.projectName = "cmdfile"
  416. handleStdinOrCmdInput()
  417. proc parseCommand*(command: string): Command =
  418. case command.normalize
  419. of "c", "cc", "compile", "compiletoc": cmdCompileToC
  420. of "cpp", "compiletocpp": cmdCompileToCpp
  421. of "objc", "compiletooc": cmdCompileToOC
  422. of "js", "compiletojs": cmdCompileToJS
  423. of "nif": cmdCompileToNif
  424. of "r": cmdCrun
  425. of "m": cmdM
  426. of "run": cmdTcc
  427. of "check": cmdCheck
  428. of "e": cmdNimscript
  429. of "doc0": cmdDoc0
  430. of "doc2", "doc": cmdDoc
  431. of "doc2tex": cmdDoc2tex
  432. of "rst2html": cmdRst2html
  433. of "md2tex": cmdMd2tex
  434. of "md2html": cmdMd2html
  435. of "rst2tex": cmdRst2tex
  436. of "jsondoc0": cmdJsondoc0
  437. of "jsondoc2", "jsondoc": cmdJsondoc
  438. of "ctags": cmdCtags
  439. of "buildindex": cmdBuildindex
  440. of "gendepend": cmdGendepend
  441. of "dump": cmdDump
  442. of "parse": cmdParse
  443. of "rod": cmdRod
  444. of "secret": cmdInteractive
  445. of "nop", "help": cmdNop
  446. of "jsonscript": cmdJsonscript
  447. else: cmdUnknown
  448. proc setCmd*(conf: ConfigRef, cmd: Command) =
  449. ## sets cmd, backend so subsequent flags can query it (e.g. so --gc:arc can be ignored for backendJs)
  450. # Note that `--backend` can override the backend, so the logic here must remain reversible.
  451. conf.cmd = cmd
  452. case cmd
  453. of cmdCompileToC, cmdCrun, cmdTcc: conf.backend = backendC
  454. of cmdCompileToCpp: conf.backend = backendCpp
  455. of cmdCompileToOC: conf.backend = backendObjc
  456. of cmdCompileToJS: conf.backend = backendJs
  457. of cmdCompileToNif: conf.backend = backendNif
  458. else: discard
  459. proc setCommandEarly*(conf: ConfigRef, command: string) =
  460. conf.command = command
  461. setCmd(conf, command.parseCommand)
  462. # command early customizations
  463. # must be handled here to honor subsequent `--hint:x:on|off`
  464. case conf.cmd
  465. of cmdRst2html, cmdRst2tex, cmdMd2html, cmdMd2tex:
  466. # xxx see whether to add others: cmdGendepend, etc.
  467. conf.foreignPackageNotes = {hintSuccessX}
  468. else:
  469. conf.foreignPackageNotes = foreignPackageNotesDefault
  470. proc specialDefine(conf: ConfigRef, key: string; pass: TCmdLinePass) =
  471. # Keep this syncronized with the default config/nim.cfg!
  472. if cmpIgnoreStyle(key, "nimQuirky") == 0:
  473. conf.exc = excQuirky
  474. elif cmpIgnoreStyle(key, "release") == 0 or cmpIgnoreStyle(key, "danger") == 0:
  475. if pass in {passCmd1, passPP}:
  476. conf.options.excl {optStackTrace, optLineTrace, optLineDir, optOptimizeSize}
  477. conf.globalOptions.excl {optExcessiveStackTrace, optCDebug}
  478. conf.options.incl optOptimizeSpeed
  479. if cmpIgnoreStyle(key, "danger") == 0 or cmpIgnoreStyle(key, "quick") == 0:
  480. if pass in {passCmd1, passPP}:
  481. conf.options.excl {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
  482. optOverflowCheck, optAssert, optStackTrace, optLineTrace, optLineDir}
  483. conf.globalOptions.excl {optCDebug}
  484. proc initOrcDefines*(conf: ConfigRef) =
  485. conf.selectedGC = gcOrc
  486. defineSymbol(conf.symbols, "gcorc")
  487. defineSymbol(conf.symbols, "gcdestructors")
  488. incl conf.globalOptions, optSeqDestructors
  489. incl conf.globalOptions, optTinyRtti
  490. defineSymbol(conf.symbols, "nimSeqsV2")
  491. defineSymbol(conf.symbols, "nimV2")
  492. if conf.exc == excNone and conf.backend != backendCpp:
  493. conf.exc = excGoto
  494. proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef) =
  495. defineSymbol(conf.symbols, "gcdestructors")
  496. incl conf.globalOptions, optSeqDestructors
  497. incl conf.globalOptions, optTinyRtti
  498. if pass in {passCmd2, passPP}:
  499. defineSymbol(conf.symbols, "nimSeqsV2")
  500. defineSymbol(conf.symbols, "nimV2")
  501. if conf.exc == excNone and conf.backend != backendCpp:
  502. conf.exc = excGoto
  503. proc unregisterArcOrc*(conf: ConfigRef) =
  504. undefSymbol(conf.symbols, "gcdestructors")
  505. undefSymbol(conf.symbols, "gcarc")
  506. undefSymbol(conf.symbols, "gcorc")
  507. undefSymbol(conf.symbols, "gcatomicarc")
  508. undefSymbol(conf.symbols, "nimSeqsV2")
  509. undefSymbol(conf.symbols, "nimV2")
  510. excl conf.globalOptions, optSeqDestructors
  511. excl conf.globalOptions, optTinyRtti
  512. proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
  513. info: TLineInfo; conf: ConfigRef) =
  514. if conf.backend == backendJs: return # for: bug #16033
  515. expectArg(conf, switch, arg, pass, info)
  516. if pass in {passCmd2, passPP}:
  517. case arg.normalize
  518. of "boehm":
  519. unregisterArcOrc(conf)
  520. conf.selectedGC = gcBoehm
  521. defineSymbol(conf.symbols, "boehmgc")
  522. incl conf.globalOptions, optTlsEmulation # Boehm GC doesn't scan the real TLS
  523. of "refc":
  524. unregisterArcOrc(conf)
  525. defineSymbol(conf.symbols, "gcrefc")
  526. conf.selectedGC = gcRefc
  527. of "markandsweep":
  528. unregisterArcOrc(conf)
  529. conf.selectedGC = gcMarkAndSweep
  530. defineSymbol(conf.symbols, "gcmarkandsweep")
  531. of "destructors", "arc":
  532. conf.selectedGC = gcArc
  533. defineSymbol(conf.symbols, "gcarc")
  534. registerArcOrc(pass, conf)
  535. of "orc":
  536. conf.selectedGC = gcOrc
  537. defineSymbol(conf.symbols, "gcorc")
  538. registerArcOrc(pass, conf)
  539. of "atomicarc":
  540. conf.selectedGC = gcAtomicArc
  541. defineSymbol(conf.symbols, "gcatomicarc")
  542. registerArcOrc(pass, conf)
  543. of "hooks":
  544. conf.selectedGC = gcHooks
  545. defineSymbol(conf.symbols, "gchooks")
  546. incl conf.globalOptions, optSeqDestructors
  547. processOnOffSwitchG(conf, {optSeqDestructors}, arg, pass, info)
  548. if pass in {passCmd2, passPP}:
  549. defineSymbol(conf.symbols, "nimSeqsV2")
  550. of "go":
  551. unregisterArcOrc(conf)
  552. conf.selectedGC = gcGo
  553. defineSymbol(conf.symbols, "gogc")
  554. of "none":
  555. unregisterArcOrc(conf)
  556. conf.selectedGC = gcNone
  557. defineSymbol(conf.symbols, "nogc")
  558. of "stack", "regions":
  559. unregisterArcOrc(conf)
  560. conf.selectedGC = gcRegions
  561. defineSymbol(conf.symbols, "gcregions")
  562. else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
  563. proc pathRelativeToConfig(arg: string, pass: TCmdLinePass, conf: ConfigRef): string =
  564. if pass == passPP and not isAbsolute(arg):
  565. assert isAbsolute(conf.currentConfigDir), "something is wrong with currentConfigDir"
  566. result = conf.currentConfigDir / arg
  567. else:
  568. result = arg
  569. proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
  570. conf: ConfigRef) =
  571. var key = ""
  572. var val = ""
  573. case switch.normalize
  574. of "eval":
  575. expectArg(conf, switch, arg, pass, info)
  576. conf.projectIsCmd = true
  577. conf.cmdInput = arg # can be empty (a nim file with empty content is valid too)
  578. if conf.cmd == cmdNone:
  579. conf.command = "e"
  580. conf.setCmd cmdNimscript # better than `cmdCrun` as a default
  581. conf.implicitCmd = true
  582. of "path", "p":
  583. expectArg(conf, switch, arg, pass, info)
  584. for path in nimbleSubs(conf, arg):
  585. addPath(conf, if pass == passPP: processCfgPath(conf, path, info)
  586. else: processPath(conf, path, info), info)
  587. of "nimblepath":
  588. if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions:
  589. expectArg(conf, switch, arg, pass, info)
  590. var path = processPath(conf, arg, info, notRelativeToProj=true)
  591. let nimbleDir = AbsoluteDir getEnv("NIMBLE_DIR")
  592. if not nimbleDir.isEmpty and pass == passPP:
  593. path = nimbleDir / RelativeDir"pkgs2"
  594. nimblePath(conf, path, info)
  595. path = nimbleDir / RelativeDir"pkgs"
  596. nimblePath(conf, path, info)
  597. of "nonimblepath":
  598. expectNoArg(conf, switch, arg, pass, info)
  599. disableNimblePath(conf)
  600. of "clearnimblepath":
  601. expectNoArg(conf, switch, arg, pass, info)
  602. clearNimblePath(conf)
  603. of "excludepath":
  604. expectArg(conf, switch, arg, pass, info)
  605. let path = processPath(conf, arg, info)
  606. conf.searchPaths.keepItIf(it != path)
  607. conf.lazyPaths.keepItIf(it != path)
  608. of "nimcache":
  609. expectArg(conf, switch, arg, pass, info)
  610. var arg = arg
  611. # refs bug #18674, otherwise `--os:windows` messes up with `--nimcache` set
  612. # in config nims files, e.g. via: `import os; switch("nimcache", "/tmp/somedir")`
  613. if conf.target.targetOS == osWindows and DirSep == '/': arg = arg.replace('\\', '/')
  614. conf.nimcacheDir = processPath(conf, pathRelativeToConfig(arg, pass, conf), info, notRelativeToProj=true)
  615. of "out", "o":
  616. expectArg(conf, switch, arg, pass, info)
  617. let f = splitFile(processPath(conf, arg, info, notRelativeToProj=true).string)
  618. conf.outFile = RelativeFile f.name & f.ext
  619. conf.outDir = toAbsoluteDir f.dir
  620. of "outdir":
  621. expectArg(conf, switch, arg, pass, info)
  622. conf.outDir = processPath(conf, arg, info, notRelativeToProj=true)
  623. of "usenimcache":
  624. processOnOffSwitchG(conf, {optUseNimcache}, arg, pass, info)
  625. of "docseesrcurl":
  626. expectArg(conf, switch, arg, pass, info)
  627. conf.docSeeSrcUrl = arg
  628. of "docroot":
  629. conf.docRoot = if arg.len == 0: docRootDefault else: arg
  630. of "backend", "b":
  631. let backend = parseEnum(arg.normalize, TBackend.default)
  632. if backend == TBackend.default: localError(conf, info, "invalid backend: '$1'" % arg)
  633. if backend == backendJs: # bug #21209
  634. conf.globalOptions.excl {optThreadAnalysis, optThreads}
  635. if optRun in conf.globalOptions:
  636. # for now, -r uses nodejs, so define nodejs
  637. defineSymbol(conf.symbols, "nodejs")
  638. conf.backend = backend
  639. of "doccmd": conf.docCmd = arg
  640. of "define", "d":
  641. expectArg(conf, switch, arg, pass, info)
  642. if {':', '='} in arg:
  643. splitSwitch(conf, arg, key, val, pass, info)
  644. specialDefine(conf, key, pass)
  645. defineSymbol(conf.symbols, key, val)
  646. else:
  647. specialDefine(conf, arg, pass)
  648. defineSymbol(conf.symbols, arg)
  649. of "undef", "u":
  650. expectArg(conf, switch, arg, pass, info)
  651. undefSymbol(conf.symbols, arg)
  652. of "compile":
  653. expectArg(conf, switch, arg, pass, info)
  654. if pass in {passCmd2, passPP}: processCompile(conf, arg)
  655. of "link":
  656. expectArg(conf, switch, arg, pass, info)
  657. if pass in {passCmd2, passPP}:
  658. addExternalFileToLink(conf, AbsoluteFile arg)
  659. of "debuginfo":
  660. processOnOffSwitchG(conf, {optCDebug}, arg, pass, info)
  661. of "embedsrc":
  662. processOnOffSwitchG(conf, {optEmbedOrigSrc}, arg, pass, info)
  663. of "compileonly", "c":
  664. processOnOffSwitchG(conf, {optCompileOnly}, arg, pass, info)
  665. of "nolinking":
  666. processOnOffSwitchG(conf, {optNoLinking}, arg, pass, info)
  667. of "nomain":
  668. processOnOffSwitchG(conf, {optNoMain}, arg, pass, info)
  669. of "forcebuild", "f":
  670. processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info)
  671. of "project":
  672. processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info)
  673. of "gc":
  674. warningDeprecated(conf, info, "`gc:option` is deprecated; use `mm:option` instead")
  675. processMemoryManagementOption(switch, arg, pass, info, conf)
  676. of "mm":
  677. processMemoryManagementOption(switch, arg, pass, info, conf)
  678. of "warnings", "w":
  679. if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf)
  680. of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf)
  681. of "hint": processSpecificNote(arg, wHint, pass, info, switch, conf)
  682. of "warningaserror": processSpecificNote(arg, wWarningAsError, pass, info, switch, conf)
  683. of "hintaserror": processSpecificNote(arg, wHintAsError, pass, info, switch, conf)
  684. of "hints":
  685. if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf)
  686. of "threadanalysis":
  687. if conf.backend == backendJs: discard
  688. else: processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info)
  689. of "stacktrace": processOnOffSwitch(conf, {optStackTrace}, arg, pass, info)
  690. of "stacktracemsgs": processOnOffSwitch(conf, {optStackTraceMsgs}, arg, pass, info)
  691. of "excessivestacktrace": processOnOffSwitchG(conf, {optExcessiveStackTrace}, arg, pass, info)
  692. of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info)
  693. of "debugger":
  694. case arg.normalize
  695. of "on", "native", "gdb":
  696. conf.globalOptions.incl optCDebug
  697. conf.options.incl optLineDir
  698. #defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
  699. of "off":
  700. conf.globalOptions.excl optCDebug
  701. else:
  702. localError(conf, info, "expected native|gdb|on|off but found " & arg)
  703. of "g": # alias for --debugger:native
  704. conf.globalOptions.incl optCDebug
  705. conf.options.incl optLineDir
  706. #defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
  707. of "profiler":
  708. processOnOffSwitch(conf, {optProfiler}, arg, pass, info)
  709. if optProfiler in conf.options: defineSymbol(conf.symbols, "profiler")
  710. else: undefSymbol(conf.symbols, "profiler")
  711. of "memtracker":
  712. processOnOffSwitch(conf, {optMemTracker}, arg, pass, info)
  713. if optMemTracker in conf.options: defineSymbol(conf.symbols, "memtracker")
  714. else: undefSymbol(conf.symbols, "memtracker")
  715. of "hotcodereloading":
  716. processOnOffSwitchG(conf, {optHotCodeReloading}, arg, pass, info)
  717. if conf.hcrOn:
  718. defineSymbol(conf.symbols, "hotcodereloading")
  719. defineSymbol(conf.symbols, "useNimRtl")
  720. # hardcoded linking with dynamic runtime for MSVC for smaller binaries
  721. # should do the same for all compilers (wherever applicable)
  722. if isVSCompatible(conf):
  723. extccomp.addCompileOptionCmd(conf, "/MD")
  724. else:
  725. undefSymbol(conf.symbols, "hotcodereloading")
  726. undefSymbol(conf.symbols, "useNimRtl")
  727. of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info)
  728. of "floatchecks":
  729. processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info)
  730. of "infchecks": processOnOffSwitch(conf, {optInfCheck}, arg, pass, info)
  731. of "nanchecks": processOnOffSwitch(conf, {optNaNCheck}, arg, pass, info)
  732. of "objchecks": processOnOffSwitch(conf, {optObjCheck}, arg, pass, info)
  733. of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info)
  734. of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info)
  735. of "boundchecks": processOnOffSwitch(conf, {optBoundsCheck}, arg, pass, info)
  736. of "refchecks":
  737. warningDeprecated(conf, info, "refchecks is deprecated!")
  738. processOnOffSwitch(conf, {optRefCheck}, arg, pass, info)
  739. of "overflowchecks": processOnOffSwitch(conf, {optOverflowCheck}, arg, pass, info)
  740. of "staticboundchecks": processOnOffSwitch(conf, {optStaticBoundsCheck}, arg, pass, info)
  741. of "stylechecks": processOnOffSwitch(conf, {optStyleCheck}, arg, pass, info)
  742. of "linedir": processOnOffSwitch(conf, {optLineDir}, arg, pass, info)
  743. of "assertions", "a": processOnOffSwitch(conf, {optAssert}, arg, pass, info)
  744. of "threads":
  745. if conf.backend == backendJs or conf.cmd == cmdNimscript: discard
  746. else: processOnOffSwitchG(conf, {optThreads}, arg, pass, info)
  747. #if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe)
  748. of "tlsemulation":
  749. processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
  750. if optTlsEmulation in conf.globalOptions:
  751. conf.legacyFeatures.incl emitGenerics
  752. of "implicitstatic":
  753. processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info)
  754. of "patterns", "trmacros":
  755. if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros")
  756. processOnOffSwitch(conf, {optTrMacros}, arg, pass, info)
  757. of "opt":
  758. expectArg(conf, switch, arg, pass, info)
  759. case arg.normalize
  760. of "speed":
  761. incl(conf.options, optOptimizeSpeed)
  762. excl(conf.options, optOptimizeSize)
  763. of "size":
  764. excl(conf.options, optOptimizeSpeed)
  765. incl(conf.options, optOptimizeSize)
  766. of "none":
  767. excl(conf.options, optOptimizeSpeed)
  768. excl(conf.options, optOptimizeSize)
  769. else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
  770. of "app":
  771. expectArg(conf, switch, arg, pass, info)
  772. case arg.normalize
  773. of "gui":
  774. incl(conf.globalOptions, optGenGuiApp)
  775. defineSymbol(conf.symbols, "executable")
  776. defineSymbol(conf.symbols, "guiapp")
  777. of "console":
  778. excl(conf.globalOptions, optGenGuiApp)
  779. defineSymbol(conf.symbols, "executable")
  780. defineSymbol(conf.symbols, "consoleapp")
  781. of "lib":
  782. incl(conf.globalOptions, optGenDynLib)
  783. excl(conf.globalOptions, optGenGuiApp)
  784. defineSymbol(conf.symbols, "library")
  785. defineSymbol(conf.symbols, "dll")
  786. of "staticlib":
  787. incl(conf.globalOptions, optGenStaticLib)
  788. incl(conf.globalOptions, optNoMain)
  789. excl(conf.globalOptions, optGenGuiApp)
  790. defineSymbol(conf.symbols, "library")
  791. defineSymbol(conf.symbols, "staticlib")
  792. else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
  793. of "passc", "t":
  794. expectArg(conf, switch, arg, pass, info)
  795. if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(conf, arg)
  796. of "passl", "l":
  797. expectArg(conf, switch, arg, pass, info)
  798. if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(conf, arg)
  799. of "cincludes":
  800. expectArg(conf, switch, arg, pass, info)
  801. if pass in {passCmd2, passPP}: conf.cIncludes.add processPath(conf, arg, info)
  802. of "clibdir":
  803. expectArg(conf, switch, arg, pass, info)
  804. if pass in {passCmd2, passPP}: conf.cLibs.add processPath(conf, arg, info)
  805. of "clib":
  806. expectArg(conf, switch, arg, pass, info)
  807. if pass in {passCmd2, passPP}:
  808. conf.cLinkedLibs.add arg
  809. of "header":
  810. if conf != nil: conf.headerFile = arg
  811. incl(conf.globalOptions, optGenIndex)
  812. of "nimbasepattern":
  813. if conf != nil: conf.nimbasePattern = arg
  814. of "index":
  815. case arg.normalize
  816. of "", "on": conf.globalOptions.incl {optGenIndex}
  817. of "only": conf.globalOptions.incl {optGenIndexOnly, optGenIndex}
  818. of "off": conf.globalOptions.excl {optGenIndex, optGenIndexOnly}
  819. else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
  820. of "noimportdoc":
  821. processOnOffSwitchG(conf, {optNoImportdoc}, arg, pass, info)
  822. of "import":
  823. expectArg(conf, switch, arg, pass, info)
  824. if pass in {passCmd2, passPP}:
  825. conf.implicitImports.add findModule(conf, arg, toFullPath(conf, info)).string
  826. of "include":
  827. expectArg(conf, switch, arg, pass, info)
  828. if pass in {passCmd2, passPP}:
  829. conf.implicitIncludes.add findModule(conf, arg, toFullPath(conf, info)).string
  830. of "listcmd":
  831. processOnOffSwitchG(conf, {optListCmd}, arg, pass, info)
  832. of "asm":
  833. processOnOffSwitchG(conf, {optProduceAsm}, arg, pass, info)
  834. of "genmapping":
  835. processOnOffSwitchG(conf, {optGenMapping}, arg, pass, info)
  836. of "os":
  837. expectArg(conf, switch, arg, pass, info)
  838. let theOS = platform.nameToOS(arg)
  839. if theOS == osNone:
  840. let osList = platform.listOSnames().join(", ")
  841. localError(conf, info, "unknown OS: '$1'. Available options are: $2" % [arg, $osList])
  842. else:
  843. setTarget(conf.target, theOS, conf.target.targetCPU)
  844. of "cpu":
  845. expectArg(conf, switch, arg, pass, info)
  846. let cpu = platform.nameToCPU(arg)
  847. if cpu == cpuNone:
  848. let cpuList = platform.listCPUnames().join(", ")
  849. localError(conf, info, "unknown CPU: '$1'. Available options are: $2" % [ arg, cpuList])
  850. else:
  851. setTarget(conf.target, conf.target.targetOS, cpu)
  852. of "run", "r":
  853. processOnOffSwitchG(conf, {optRun}, arg, pass, info)
  854. if conf.backend == backendJs:
  855. # for now, -r uses nodejs, so define nodejs
  856. defineSymbol(conf.symbols, "nodejs")
  857. of "maxloopiterationsvm":
  858. expectArg(conf, switch, arg, pass, info)
  859. var value: int = 10_000_000
  860. discard parseSaturatedNatural(arg, value)
  861. if not value > 0: localError(conf, info, "maxLoopIterationsVM must be a positive integer greater than zero")
  862. conf.maxLoopIterationsVM = value
  863. of "maxcalldepthvm":
  864. expectArg(conf, switch, arg, pass, info)
  865. var value: int = 2_000
  866. discard parseSaturatedNatural(arg, value)
  867. if value <= 0: localError(conf, info, "maxCallDepthVM must be a positive integer greater than zero")
  868. conf.maxCallDepthVM = value
  869. of "errormax":
  870. expectArg(conf, switch, arg, pass, info)
  871. # Note: `nim check` (etc) can overwrite this.
  872. # `0` is meaningless, give it a useful meaning as in clang's -ferror-limit
  873. # If user doesn't set this flag and the code doesn't either, it'd
  874. # have the same effect as errorMax = 1
  875. var value: int = 0
  876. discard parseSaturatedNatural(arg, value)
  877. conf.errorMax = if value == 0: high(int) else: value
  878. of "stdinfile":
  879. expectArg(conf, switch, arg, pass, info)
  880. conf.stdinFile = if os.isAbsolute(arg): AbsoluteFile(arg)
  881. else: AbsoluteFile(getCurrentDir() / arg)
  882. of "verbosity":
  883. expectArg(conf, switch, arg, pass, info)
  884. let verbosity = parseInt(arg)
  885. if verbosity notin 0..3:
  886. localError(conf, info, "invalid verbosity level: '$1'" % arg)
  887. conf.verbosity = verbosity
  888. var verb = NotesVerbosity[conf.verbosity]
  889. ## We override the default `verb` by explicitly modified (set/unset) notes.
  890. conf.notes = (conf.modifiedyNotes * conf.notes + verb) -
  891. (conf.modifiedyNotes * verb - conf.notes)
  892. conf.mainPackageNotes = conf.notes
  893. of "parallelbuild":
  894. expectArg(conf, switch, arg, pass, info)
  895. var value: int = 0
  896. discard parseSaturatedNatural(arg, value)
  897. conf.numberOfProcessors = value
  898. of "version", "v":
  899. expectNoArg(conf, switch, arg, pass, info)
  900. writeVersionInfo(conf, pass)
  901. of "advanced":
  902. expectNoArg(conf, switch, arg, pass, info)
  903. writeAdvancedUsage(conf, pass)
  904. of "fullhelp":
  905. expectNoArg(conf, switch, arg, pass, info)
  906. writeFullhelp(conf, pass)
  907. of "help", "h":
  908. expectNoArg(conf, switch, arg, pass, info)
  909. helpOnError(conf, pass)
  910. of "symbolfiles", "incremental", "ic":
  911. if switch.normalize == "symbolfiles": deprecatedAlias(switch, "incremental")
  912. # xxx maybe also ic, since not in help?
  913. if pass in {passCmd2, passPP}:
  914. case arg.normalize
  915. of "on": conf.symbolFiles = v2Sf
  916. of "off": conf.symbolFiles = disabledSf
  917. of "writeonly": conf.symbolFiles = writeOnlySf
  918. of "readonly": conf.symbolFiles = readOnlySf
  919. of "v2": conf.symbolFiles = v2Sf
  920. of "stress": conf.symbolFiles = stressTest
  921. else: localError(conf, info, "invalid option for --incremental: " & arg)
  922. setUseIc(conf.symbolFiles != disabledSf)
  923. of "skipcfg":
  924. processOnOffSwitchG(conf, {optSkipSystemConfigFile}, arg, pass, info)
  925. of "skipprojcfg":
  926. processOnOffSwitchG(conf, {optSkipProjConfigFile}, arg, pass, info)
  927. of "skipusercfg":
  928. processOnOffSwitchG(conf, {optSkipUserConfigFile}, arg, pass, info)
  929. of "skipparentcfg":
  930. processOnOffSwitchG(conf, {optSkipParentConfigFiles}, arg, pass, info)
  931. of "genscript", "gendeps":
  932. if switch.normalize == "gendeps": deprecatedAlias(switch, "genscript")
  933. processOnOffSwitchG(conf, {optGenScript}, arg, pass, info)
  934. processOnOffSwitchG(conf, {optCompileOnly}, arg, pass, info)
  935. of "gencdeps":
  936. processOnOffSwitchG(conf, {optGenCDeps}, arg, pass, info)
  937. of "colors": processOnOffSwitchG(conf, {optUseColors}, arg, pass, info)
  938. of "lib":
  939. expectArg(conf, switch, arg, pass, info)
  940. conf.libpath = processPath(conf, arg, info, notRelativeToProj=true)
  941. of "putenv":
  942. expectArg(conf, switch, arg, pass, info)
  943. splitSwitch(conf, arg, key, val, pass, info)
  944. os.putEnv(key, val)
  945. of "cc":
  946. if conf.backend != backendJs: # bug #19330
  947. expectArg(conf, switch, arg, pass, info)
  948. setCC(conf, arg, info)
  949. of "track":
  950. expectArg(conf, switch, arg, pass, info)
  951. track(conf, arg, info)
  952. of "trackdirty":
  953. expectArg(conf, switch, arg, pass, info)
  954. trackDirty(conf, arg, info)
  955. of "suggest":
  956. expectNoArg(conf, switch, arg, pass, info)
  957. conf.ideCmd = ideSug
  958. of "def":
  959. expectArg(conf, switch, arg, pass, info)
  960. trackIde(conf, ideDef, arg, info)
  961. of "context":
  962. expectNoArg(conf, switch, arg, pass, info)
  963. conf.ideCmd = ideCon
  964. of "usages":
  965. expectArg(conf, switch, arg, pass, info)
  966. trackIde(conf, ideUse, arg, info)
  967. of "defusages":
  968. expectArg(conf, switch, arg, pass, info)
  969. trackIde(conf, ideDus, arg, info)
  970. of "stdout":
  971. processOnOffSwitchG(conf, {optStdout}, arg, pass, info)
  972. of "filenames":
  973. case arg.normalize
  974. of "abs": conf.filenameOption = foAbs
  975. of "canonical": conf.filenameOption = foCanonical
  976. of "legacyrelproj": conf.filenameOption = foLegacyRelProj
  977. else: localError(conf, info, "expected: abs|canonical|legacyRelProj, got: $1" % arg)
  978. of "processing":
  979. incl(conf.notes, hintProcessing)
  980. incl(conf.mainPackageNotes, hintProcessing)
  981. case arg.normalize
  982. of "dots": conf.hintProcessingDots = true
  983. of "filenames": conf.hintProcessingDots = false
  984. of "off":
  985. excl(conf.notes, hintProcessing)
  986. excl(conf.mainPackageNotes, hintProcessing)
  987. else: localError(conf, info, "expected: dots|filenames|off, got: $1" % arg)
  988. of "unitsep":
  989. conf.unitSep = if switchOn(arg): "\31" else: ""
  990. of "listfullpaths":
  991. # xxx in future work, use `warningDeprecated`
  992. conf.filenameOption = if switchOn(arg): foAbs else: foCanonical
  993. of "spellsuggest":
  994. if arg.len == 0: conf.spellSuggestMax = spellSuggestSecretSauce
  995. elif arg == "auto": conf.spellSuggestMax = spellSuggestSecretSauce
  996. else: conf.spellSuggestMax = parseInt(arg)
  997. of "declaredlocs":
  998. processOnOffSwitchG(conf, {optDeclaredLocs}, arg, pass, info)
  999. of "dynliboverride":
  1000. dynlibOverride(conf, switch, arg, pass, info)
  1001. of "dynliboverrideall":
  1002. processOnOffSwitchG(conf, {optDynlibOverrideAll}, arg, pass, info)
  1003. of "experimental":
  1004. if arg.len == 0:
  1005. conf.features.incl oldExperimentalFeatures
  1006. else:
  1007. try:
  1008. conf.features.incl parseEnum[Feature](arg)
  1009. except ValueError:
  1010. localError(conf, info, "unknown experimental feature")
  1011. of "legacy":
  1012. try:
  1013. conf.legacyFeatures.incl parseEnum[LegacyFeature](arg)
  1014. except ValueError:
  1015. localError(conf, info, "unknown obsolete feature")
  1016. of "nocppexceptions":
  1017. expectNoArg(conf, switch, arg, pass, info)
  1018. conf.exc = low(ExceptionSystem)
  1019. defineSymbol(conf.symbols, "noCppExceptions")
  1020. of "shownonexports":
  1021. expectNoArg(conf, switch, arg, pass, info)
  1022. showNonExportedFields(conf)
  1023. of "exceptions":
  1024. case arg.normalize
  1025. of "cpp": conf.exc = excCpp
  1026. of "setjmp": conf.exc = excSetjmp
  1027. of "quirky": conf.exc = excQuirky
  1028. of "goto": conf.exc = excGoto
  1029. else: localError(conf, info, errInvalidExceptionSystem % arg)
  1030. of "cppdefine":
  1031. expectArg(conf, switch, arg, pass, info)
  1032. if conf != nil:
  1033. conf.cppDefine(arg)
  1034. of "newruntime":
  1035. warningDeprecated(conf, info, "newruntime is deprecated, use arc/orc instead!")
  1036. expectNoArg(conf, switch, arg, pass, info)
  1037. if pass in {passCmd2, passPP}:
  1038. doAssert(conf != nil)
  1039. incl(conf.features, destructor)
  1040. incl(conf.globalOptions, optTinyRtti)
  1041. incl(conf.globalOptions, optOwnedRefs)
  1042. incl(conf.globalOptions, optSeqDestructors)
  1043. defineSymbol(conf.symbols, "nimV2")
  1044. conf.selectedGC = gcHooks
  1045. defineSymbol(conf.symbols, "gchooks")
  1046. defineSymbol(conf.symbols, "nimSeqsV2")
  1047. defineSymbol(conf.symbols, "nimOwnedEnabled")
  1048. of "seqsv2":
  1049. processOnOffSwitchG(conf, {optSeqDestructors}, arg, pass, info)
  1050. if pass in {passCmd2, passPP}:
  1051. defineSymbol(conf.symbols, "nimSeqsV2")
  1052. of "stylecheck":
  1053. case arg.normalize
  1054. of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError}
  1055. of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint} - {optStyleError}
  1056. of "error": conf.globalOptions = conf.globalOptions + {optStyleError}
  1057. of "usages": conf.globalOptions.incl optStyleUsages
  1058. else: localError(conf, info, errOffHintsError % arg)
  1059. of "showallmismatches":
  1060. processOnOffSwitchG(conf, {optShowAllMismatches}, arg, pass, info)
  1061. of "cppcompiletonamespace":
  1062. if arg.len > 0:
  1063. conf.cppCustomNamespace = arg
  1064. else:
  1065. conf.cppCustomNamespace = "Nim"
  1066. defineSymbol(conf.symbols, "cppCompileToNamespace", conf.cppCustomNamespace)
  1067. of "docinternal":
  1068. processOnOffSwitchG(conf, {optDocInternal}, arg, pass, info)
  1069. of "multimethods":
  1070. processOnOffSwitchG(conf, {optMultiMethods}, arg, pass, info)
  1071. of "expandmacro":
  1072. expectArg(conf, switch, arg, pass, info)
  1073. conf.macrosToExpand[arg] = "T"
  1074. of "expandarc":
  1075. expectArg(conf, switch, arg, pass, info)
  1076. conf.arcToExpand[arg] = "T"
  1077. of "benchmarkvm":
  1078. processOnOffSwitchG(conf, {optBenchmarkVM}, arg, pass, info)
  1079. of "profilevm":
  1080. processOnOffSwitchG(conf, {optProfileVM}, arg, pass, info)
  1081. of "sinkinference":
  1082. processOnOffSwitch(conf, {optSinkInference}, arg, pass, info)
  1083. of "cursorinference":
  1084. # undocumented, for debugging purposes only:
  1085. processOnOffSwitch(conf, {optCursorInference}, arg, pass, info)
  1086. of "panics":
  1087. processOnOffSwitchG(conf, {optPanics}, arg, pass, info)
  1088. if optPanics in conf.globalOptions:
  1089. defineSymbol(conf.symbols, "nimPanics")
  1090. of "jsbigint64":
  1091. processOnOffSwitchG(conf, {optJsBigInt64}, arg, pass, info)
  1092. of "sourcemap": # xxx document in --fullhelp
  1093. conf.globalOptions.incl optSourcemap
  1094. conf.options.incl optLineDir
  1095. of "deepcopy":
  1096. processOnOffSwitchG(conf, {optEnableDeepCopy}, arg, pass, info)
  1097. of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -)
  1098. handleStdinInput(conf)
  1099. of "nilseqs", "nilchecks", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch)
  1100. of "nimmainprefix": conf.nimMainPrefix = arg
  1101. else:
  1102. if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
  1103. else: invalidCmdLineOption(conf, pass, switch, info)
  1104. proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
  1105. var cmd = ""
  1106. var arg = ""
  1107. splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)
  1108. processSwitch(cmd, arg, pass, gCmdLineInfo, config)
  1109. proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) =
  1110. # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
  1111. # we transform it to (key = hint, val = [X]:off)
  1112. var bracketLe = strutils.find(p.key, '[')
  1113. if bracketLe >= 0:
  1114. var key = substr(p.key, 0, bracketLe - 1)
  1115. var val = substr(p.key, bracketLe) & ':' & p.val
  1116. processSwitch(key, val, pass, gCmdLineInfo, config)
  1117. else:
  1118. processSwitch(p.key, p.val, pass, gCmdLineInfo, config)
  1119. proc processArgument*(pass: TCmdLinePass; p: OptParser;
  1120. argsCount: var int; config: ConfigRef): bool =
  1121. if argsCount == 0 and config.implicitCmd:
  1122. argsCount.inc
  1123. if argsCount == 0:
  1124. # nim filename.nims is the same as "nim e filename.nims":
  1125. if p.key.endsWith(".nims"):
  1126. config.setCmd cmdNimscript
  1127. incl(config.globalOptions, optWasNimscript)
  1128. config.projectName = unixToNativePath(p.key)
  1129. config.arguments = cmdLineRest(p)
  1130. result = true
  1131. elif pass != passCmd2:
  1132. setCommandEarly(config, p.key)
  1133. result = false
  1134. else: result = false
  1135. else:
  1136. if pass == passCmd1: config.commandArgs.add p.key
  1137. if argsCount == 1:
  1138. if p.key.endsWith(".nims"):
  1139. incl(config.globalOptions, optWasNimscript)
  1140. # support UNIX style filenames everywhere for portable build scripts:
  1141. if config.projectName.len == 0:
  1142. config.projectName = unixToNativePath(p.key)
  1143. config.arguments = cmdLineRest(p)
  1144. result = true
  1145. else:
  1146. result = false
  1147. inc argsCount