commands.nim 48 KB

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