commands.nim 46 KB

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