commands.nim 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  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.gcGenerational' 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(usedGnuReadline, defined(useLinenoise), "-d:useLinenoise")
  17. bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm")
  18. bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
  19. bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
  20. bootSwitch(usedGoGC, defined(gogc), "--gc:go")
  21. bootSwitch(usedNoGC, defined(nogc), "--gc:none")
  22. import
  23. os, msgs, options, nversion, condsyms, strutils, extccomp, platform,
  24. wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils, lineinfos,
  25. pathutils
  26. # but some have deps to imported modules. Yay.
  27. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
  28. bootSwitch(usedNativeStacktrace,
  29. defined(nativeStackTrace) and nativeStackTraceSupported,
  30. "-d:nativeStackTrace")
  31. bootSwitch(usedFFI, hasFFI, "-d:useFFI")
  32. type
  33. TCmdLinePass* = enum
  34. passCmd1, # first pass over the command line
  35. passCmd2, # second pass over the command line
  36. passPP # preprocessor called processCommand()
  37. const
  38. HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" &
  39. "Compiled at $4\n" &
  40. "Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"
  41. const
  42. Usage = slurp"../doc/basicopt.txt".replace("//", "")
  43. FeatureDesc = block:
  44. var x = ""
  45. for f in low(Feature)..high(Feature):
  46. if x.len > 0: x.add "|"
  47. x.add $f
  48. x
  49. AdvancedUsage = slurp"../doc/advopt.txt".replace("//", "") % FeatureDesc
  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 = gorge("git log -n 1 --format=%H").strip
  81. when gitHash.len == 40:
  82. msgWriteln(conf, "git hash: " & gitHash, {msgStdout})
  83. msgWriteln(conf, "active boot switches:" & usedRelease &
  84. usedTinyC & usedGnuReadline & usedNativeStacktrace &
  85. usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC,
  86. {msgStdout})
  87. msgQuit(0)
  88. proc writeCommandLineUsage*(conf: ConfigRef; helpWritten: var bool) =
  89. if not helpWritten:
  90. msgWriteln(conf, getCommandLineDesc(conf), {msgStdout})
  91. helpWritten = true
  92. proc addPrefix(switch: string): string =
  93. if len(switch) == 1: result = "-" & switch
  94. else: result = "--" & switch
  95. const
  96. errInvalidCmdLineOption = "invalid command line option: '$1'"
  97. errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found"
  98. errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found"
  99. errOffHintsError = "'off', 'hint' or 'error' expected, but '$1' found"
  100. proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) =
  101. if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-")
  102. else: localError(conf, info, errInvalidCmdLineOption % addPrefix(switch))
  103. proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TCmdLinePass,
  104. info: TLineInfo) =
  105. cmd = ""
  106. var i = 0
  107. if i < len(switch) and switch[i] == '-': inc(i)
  108. if i < len(switch) and switch[i] == '-': inc(i)
  109. while i < len(switch):
  110. case switch[i]
  111. of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i])
  112. else: break
  113. inc(i)
  114. if i >= len(switch): arg = ""
  115. # cmd:arg => (cmd,arg)
  116. elif switch[i] in {':', '='}: arg = substr(switch, i + 1)
  117. # cmd[sub]:rest => (cmd,[sub]:rest)
  118. elif switch[i] == '[': arg = substr(switch, i)
  119. else: invalidCmdLineOption(conf, pass, switch, info)
  120. proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
  121. info: TLineInfo) =
  122. case arg.normalize
  123. of "on": conf.options = conf.options + op
  124. of "off": conf.options = conf.options - op
  125. else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
  126. proc processOnOffSwitchOrList(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
  127. info: TLineInfo): bool =
  128. result = false
  129. case arg.normalize
  130. of "on": conf.options = conf.options + op
  131. of "off": conf.options = conf.options - op
  132. of "list": result = true
  133. else: localError(conf, info, errOnOffOrListExpectedButXFound % arg)
  134. proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass,
  135. info: TLineInfo) =
  136. case arg.normalize
  137. of "on": conf.globalOptions = conf.globalOptions + op
  138. of "off": conf.globalOptions = conf.globalOptions - op
  139. else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
  140. proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
  141. if arg == "":
  142. localError(conf, info, "argument for command line option expected: '$1'" % addPrefix(switch))
  143. proc expectNoArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
  144. if arg != "":
  145. localError(conf, info, "invalid argument for command line option: '$1'" % addPrefix(switch))
  146. proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
  147. info: TLineInfo; orig: string; conf: ConfigRef) =
  148. var id = "" # arg = key:val or [key]:val; with val=on|off
  149. var i = 0
  150. var n = hintMin
  151. var isBracket = false
  152. if i < len(arg) and arg[i] == '[':
  153. isBracket = true
  154. inc(i)
  155. while i < len(arg) and (arg[i] notin {':', '=', ']'}):
  156. add(id, arg[i])
  157. inc(i)
  158. if isBracket:
  159. if i < len(arg) and arg[i] == ']': inc(i)
  160. else: invalidCmdLineOption(conf, pass, orig, info)
  161. if i < len(arg) and (arg[i] in {':', '='}): inc(i)
  162. else: invalidCmdLineOption(conf, pass, orig, info)
  163. if state == wHint:
  164. let x = findStr(lineinfos.HintsToStr, id)
  165. if x >= 0: n = TNoteKind(x + ord(hintMin))
  166. else: localError(conf, info, "unknown hint: " & id)
  167. else:
  168. let x = findStr(lineinfos.WarningsToStr, id)
  169. if x >= 0: n = TNoteKind(x + ord(warnMin))
  170. else: localError(conf, info, "unknown warning: " & id)
  171. case substr(arg, i).normalize
  172. of "on":
  173. incl(conf.notes, n)
  174. incl(conf.mainPackageNotes, n)
  175. incl(conf.enableNotes, n)
  176. of "off":
  177. excl(conf.notes, n)
  178. excl(conf.mainPackageNotes, n)
  179. incl(conf.disableNotes, n)
  180. excl(conf.foreignPackageNotes, n)
  181. else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
  182. proc processCompile(conf: ConfigRef; filename: string) =
  183. var found = findFile(conf, filename)
  184. if found.isEmpty: found = AbsoluteFile filename
  185. extccomp.addExternalFileToCompile(conf, found)
  186. const
  187. errNoneBoehmRefcExpectedButXFound = "'none', 'boehm' or 'refc' expected, but '$1' found"
  188. errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
  189. errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found"
  190. proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool =
  191. case switch.normalize
  192. of "gc":
  193. case arg.normalize
  194. of "boehm": result = conf.selectedGC == gcBoehm
  195. of "refc": result = conf.selectedGC == gcRefc
  196. of "v2": result = false
  197. of "markandsweep": result = conf.selectedGC == gcMarkAndSweep
  198. of "generational": result = false
  199. of "destructors": result = conf.selectedGC == gcDestructors
  200. of "go": result = conf.selectedGC == gcGo
  201. of "none": result = conf.selectedGC == gcNone
  202. of "stack", "regions": result = conf.selectedGC == gcRegions
  203. else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
  204. of "opt":
  205. case arg.normalize
  206. of "speed": result = contains(conf.options, optOptimizeSpeed)
  207. of "size": result = contains(conf.options, optOptimizeSize)
  208. of "none": result = conf.options * {optOptimizeSpeed, optOptimizeSize} == {}
  209. else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
  210. of "verbosity": result = $conf.verbosity == arg
  211. of "app":
  212. case arg.normalize
  213. of "gui": result = contains(conf.globalOptions, optGenGuiApp)
  214. of "console": result = not contains(conf.globalOptions, optGenGuiApp)
  215. of "lib": result = contains(conf.globalOptions, optGenDynLib) and
  216. not contains(conf.globalOptions, optGenGuiApp)
  217. of "staticlib": result = contains(conf.globalOptions, optGenStaticLib) and
  218. not contains(conf.globalOptions, optGenGuiApp)
  219. else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
  220. of "dynliboverride":
  221. result = isDynlibOverride(conf, arg)
  222. else: invalidCmdLineOption(conf, passCmd1, switch, info)
  223. proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool =
  224. case switch.normalize
  225. of "debuginfo": result = contains(conf.globalOptions, optCDebug)
  226. of "compileonly", "c": result = contains(conf.globalOptions, optCompileOnly)
  227. of "nolinking": result = contains(conf.globalOptions, optNoLinking)
  228. of "nomain": result = contains(conf.globalOptions, optNoMain)
  229. of "forcebuild", "f": result = contains(conf.globalOptions, optForceFullMake)
  230. of "warnings", "w": result = contains(conf.options, optWarns)
  231. of "hints": result = contains(conf.options, optHints)
  232. of "threadanalysis": result = contains(conf.globalOptions, optThreadAnalysis)
  233. of "stacktrace": result = contains(conf.options, optStackTrace)
  234. of "linetrace": result = contains(conf.options, optLineTrace)
  235. of "debugger": result = contains(conf.options, optEndb)
  236. of "profiler": result = contains(conf.options, optProfiler)
  237. of "memtracker": result = contains(conf.options, optMemTracker)
  238. of "checks", "x": result = conf.options * ChecksOptions == ChecksOptions
  239. of "floatchecks":
  240. result = conf.options * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck}
  241. of "infchecks": result = contains(conf.options, optInfCheck)
  242. of "nanchecks": result = contains(conf.options, optNaNCheck)
  243. of "nilchecks": result = contains(conf.options, optNilCheck)
  244. of "objchecks": result = contains(conf.options, optObjCheck)
  245. of "fieldchecks": result = contains(conf.options, optFieldCheck)
  246. of "rangechecks": result = contains(conf.options, optRangeCheck)
  247. of "boundchecks": result = contains(conf.options, optBoundsCheck)
  248. of "overflowchecks": result = contains(conf.options, optOverflowCheck)
  249. of "movechecks": result = contains(conf.options, optMoveCheck)
  250. of "linedir": result = contains(conf.options, optLineDir)
  251. of "assertions", "a": result = contains(conf.options, optAssert)
  252. of "run", "r": result = contains(conf.globalOptions, optRun)
  253. of "symbolfiles": result = conf.symbolFiles != disabledSf
  254. of "genscript": result = contains(conf.globalOptions, optGenScript)
  255. of "threads": result = contains(conf.globalOptions, optThreads)
  256. of "taintmode": result = contains(conf.globalOptions, optTaintMode)
  257. of "tlsemulation": result = contains(conf.globalOptions, optTlsEmulation)
  258. of "implicitstatic": result = contains(conf.options, optImplicitStatic)
  259. of "patterns": result = contains(conf.options, optPatterns)
  260. of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
  261. of "nilseqs": result = contains(conf.options, optNilSeqs)
  262. else: invalidCmdLineOption(conf, passCmd1, switch, info)
  263. proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
  264. notRelativeToProj = false): AbsoluteDir =
  265. let p = if os.isAbsolute(path) or '$' in path:
  266. path
  267. elif notRelativeToProj:
  268. getCurrentDir() / path
  269. else:
  270. conf.projectPath.string / path
  271. try:
  272. result = AbsoluteDir pathSubs(conf, p, toFullPath(conf, info).splitFile().dir)
  273. except ValueError:
  274. localError(conf, info, "invalid path: " & p)
  275. result = AbsoluteDir p
  276. proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): AbsoluteDir =
  277. let path = if path.len > 0 and path[0] == '"': strutils.unescape(path)
  278. else: path
  279. let basedir = toFullPath(conf, info).splitFile().dir
  280. let p = if os.isAbsolute(path) or '$' in path:
  281. path
  282. else:
  283. basedir / path
  284. try:
  285. result = AbsoluteDir pathSubs(conf, p, basedir)
  286. except ValueError:
  287. localError(conf, info, "invalid path: " & p)
  288. result = AbsoluteDir p
  289. const
  290. errInvalidNumber = "$1 is not a valid number"
  291. proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) =
  292. var a = arg.split(',')
  293. if a.len != 4: localError(conf, info,
  294. "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN expected")
  295. var line, column: int
  296. if parseUtils.parseInt(a[2], line) <= 0:
  297. localError(conf, info, errInvalidNumber % a[1])
  298. if parseUtils.parseInt(a[3], column) <= 0:
  299. localError(conf, info, errInvalidNumber % a[2])
  300. let dirtyOriginalIdx = fileInfoIdx(conf, AbsoluteFile a[1])
  301. if dirtyOriginalIdx.int32 >= 0:
  302. msgs.setDirtyFile(conf, dirtyOriginalIdx, AbsoluteFile a[0])
  303. conf.m.trackPos = newLineInfo(dirtyOriginalIdx, line, column)
  304. proc track(conf: ConfigRef; arg: string, info: TLineInfo) =
  305. var a = arg.split(',')
  306. if a.len != 3: localError(conf, info, "FILE,LINE,COLUMN expected")
  307. var line, column: int
  308. if parseUtils.parseInt(a[1], line) <= 0:
  309. localError(conf, info, errInvalidNumber % a[1])
  310. if parseUtils.parseInt(a[2], column) <= 0:
  311. localError(conf, info, errInvalidNumber % a[2])
  312. conf.m.trackPos = newLineInfo(conf, AbsoluteFile a[0], line, column)
  313. proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
  314. if pass in {passCmd2, passPP}:
  315. expectArg(conf, switch, arg, pass, info)
  316. options.inclDynlibOverride(conf, arg)
  317. proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
  318. conf: ConfigRef) =
  319. var
  320. key, val: string
  321. case switch.normalize
  322. of "path", "p":
  323. expectArg(conf, switch, arg, pass, info)
  324. addPath(conf, if pass == passPP: processCfgPath(conf, arg, info)
  325. else: processPath(conf, arg, info), info)
  326. of "nimblepath", "babelpath":
  327. # keep the old name for compat
  328. if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions:
  329. expectArg(conf, switch, arg, pass, info)
  330. var path = processPath(conf, arg, info, notRelativeToProj=true)
  331. let nimbleDir = AbsoluteDir getEnv("NIMBLE_DIR")
  332. if not nimbleDir.isEmpty and pass == passPP:
  333. path = nimbleDir / RelativeDir"pkgs"
  334. nimblePath(conf, path, info)
  335. of "nonimblepath", "nobabelpath":
  336. expectNoArg(conf, switch, arg, pass, info)
  337. disableNimblePath(conf)
  338. of "excludepath":
  339. expectArg(conf, switch, arg, pass, info)
  340. let path = processPath(conf, arg, info)
  341. conf.searchPaths.keepItIf(it != path)
  342. conf.lazyPaths.keepItIf(it != path)
  343. of "nimcache":
  344. expectArg(conf, switch, arg, pass, info)
  345. conf.nimcacheDir = processPath(conf, arg, info, true)
  346. of "out", "o":
  347. expectArg(conf, switch, arg, pass, info)
  348. conf.outFile = AbsoluteFile arg
  349. of "docseesrcurl":
  350. expectArg(conf, switch, arg, pass, info)
  351. conf.docSeeSrcUrl = arg
  352. of "mainmodule", "m":
  353. discard "allow for backwards compatibility, but don't do anything"
  354. of "define", "d":
  355. expectArg(conf, switch, arg, pass, info)
  356. if {':', '='} in arg:
  357. splitSwitch(conf, arg, key, val, pass, info)
  358. defineSymbol(conf.symbols, key, val)
  359. else:
  360. defineSymbol(conf.symbols, arg)
  361. of "undef", "u":
  362. expectArg(conf, switch, arg, pass, info)
  363. undefSymbol(conf.symbols, arg)
  364. of "symbol":
  365. expectArg(conf, switch, arg, pass, info)
  366. # deprecated, do nothing
  367. of "compile":
  368. expectArg(conf, switch, arg, pass, info)
  369. if pass in {passCmd2, passPP}: processCompile(conf, arg)
  370. of "link":
  371. expectArg(conf, switch, arg, pass, info)
  372. if pass in {passCmd2, passPP}:
  373. addExternalFileToLink(conf, AbsoluteFile arg)
  374. of "debuginfo":
  375. expectNoArg(conf, switch, arg, pass, info)
  376. incl(conf.globalOptions, optCDebug)
  377. of "embedsrc":
  378. expectNoArg(conf, switch, arg, pass, info)
  379. incl(conf.globalOptions, optEmbedOrigSrc)
  380. of "compileonly", "c":
  381. expectNoArg(conf, switch, arg, pass, info)
  382. incl(conf.globalOptions, optCompileOnly)
  383. of "nolinking":
  384. expectNoArg(conf, switch, arg, pass, info)
  385. incl(conf.globalOptions, optNoLinking)
  386. of "nomain":
  387. expectNoArg(conf, switch, arg, pass, info)
  388. incl(conf.globalOptions, optNoMain)
  389. of "forcebuild", "f":
  390. expectNoArg(conf, switch, arg, pass, info)
  391. incl(conf.globalOptions, optForceFullMake)
  392. of "project":
  393. expectNoArg(conf, switch, arg, pass, info)
  394. incl conf.globalOptions, optWholeProject
  395. of "gc":
  396. expectArg(conf, switch, arg, pass, info)
  397. case arg.normalize
  398. of "boehm":
  399. conf.selectedGC = gcBoehm
  400. defineSymbol(conf.symbols, "boehmgc")
  401. of "refc":
  402. conf.selectedGC = gcRefc
  403. of "v2":
  404. message(conf, info, warnDeprecated, "--gc:v2 is deprecated; using default gc")
  405. of "markandsweep":
  406. conf.selectedGC = gcMarkAndSweep
  407. defineSymbol(conf.symbols, "gcmarkandsweep")
  408. of "destructors":
  409. conf.selectedGC = gcDestructors
  410. defineSymbol(conf.symbols, "gcdestructors")
  411. of "go":
  412. conf.selectedGC = gcGo
  413. defineSymbol(conf.symbols, "gogc")
  414. of "none":
  415. conf.selectedGC = gcNone
  416. defineSymbol(conf.symbols, "nogc")
  417. of "stack", "regions":
  418. conf.selectedGC= gcRegions
  419. defineSymbol(conf.symbols, "gcregions")
  420. else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
  421. of "warnings", "w":
  422. if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf)
  423. of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf)
  424. of "hint": processSpecificNote(arg, wHint, pass, info, switch, conf)
  425. of "hints":
  426. if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf)
  427. of "threadanalysis": processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info)
  428. of "stacktrace": processOnOffSwitch(conf, {optStackTrace}, arg, pass, info)
  429. of "excessivestacktrace": processOnOffSwitchG(conf, {optExcessiveStackTrace}, arg, pass, info)
  430. of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info)
  431. of "debugger":
  432. case arg.normalize
  433. of "on", "endb":
  434. conf.options.incl optEndb
  435. defineSymbol(conf.symbols, "endb")
  436. of "off":
  437. conf.options.excl optEndb
  438. undefSymbol(conf.symbols, "endb")
  439. of "native", "gdb":
  440. incl(conf.globalOptions, optCDebug)
  441. conf.options = conf.options + {optLineDir} - {optEndb}
  442. #defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
  443. undefSymbol(conf.symbols, "endb")
  444. else:
  445. localError(conf, info, "expected endb|gdb but found " & arg)
  446. of "profiler":
  447. processOnOffSwitch(conf, {optProfiler}, arg, pass, info)
  448. if optProfiler in conf.options: defineSymbol(conf.symbols, "profiler")
  449. else: undefSymbol(conf.symbols, "profiler")
  450. of "memtracker":
  451. processOnOffSwitch(conf, {optMemTracker}, arg, pass, info)
  452. if optMemTracker in conf.options: defineSymbol(conf.symbols, "memtracker")
  453. else: undefSymbol(conf.symbols, "memtracker")
  454. of "hotcodereloading":
  455. processOnOffSwitch(conf, {optHotCodeReloading}, arg, pass, info)
  456. if optHotCodeReloading in conf.options: defineSymbol(conf.symbols, "hotcodereloading")
  457. else: undefSymbol(conf.symbols, "hotcodereloading")
  458. of "oldnewlines":
  459. case arg.normalize
  460. of "on":
  461. conf.oldNewlines = true
  462. defineSymbol(conf.symbols, "nimOldNewlines")
  463. of "off":
  464. conf.oldNewlines = false
  465. undefSymbol(conf.symbols, "nimOldNewlines")
  466. else:
  467. localError(conf, info, errOnOrOffExpectedButXFound % arg)
  468. of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info)
  469. of "nilseqs": processOnOffSwitch(conf, {optNilSeqs}, arg, pass, info)
  470. of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info)
  471. of "floatchecks":
  472. processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info)
  473. of "infchecks": processOnOffSwitch(conf, {optInfCheck}, arg, pass, info)
  474. of "nanchecks": processOnOffSwitch(conf, {optNaNCheck}, arg, pass, info)
  475. of "nilchecks": processOnOffSwitch(conf, {optNilCheck}, arg, pass, info)
  476. of "objchecks": processOnOffSwitch(conf, {optObjCheck}, arg, pass, info)
  477. of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info)
  478. of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info)
  479. of "boundchecks": processOnOffSwitch(conf, {optBoundsCheck}, arg, pass, info)
  480. of "overflowchecks": processOnOffSwitch(conf, {optOverflowCheck}, arg, pass, info)
  481. of "movechecks": processOnOffSwitch(conf, {optMoveCheck}, arg, pass, info)
  482. of "linedir": processOnOffSwitch(conf, {optLineDir}, arg, pass, info)
  483. of "assertions", "a": processOnOffSwitch(conf, {optAssert}, arg, pass, info)
  484. of "deadcodeelim": discard # deprecated, dead code elim always on
  485. of "threads":
  486. processOnOffSwitchG(conf, {optThreads}, arg, pass, info)
  487. #if optThreads in conf.globalOptions: incl(conf.notes, warnGcUnsafe)
  488. of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
  489. of "taintmode": processOnOffSwitchG(conf, {optTaintMode}, arg, pass, info)
  490. of "implicitstatic":
  491. processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info)
  492. of "patterns":
  493. processOnOffSwitch(conf, {optPatterns}, arg, pass, info)
  494. of "opt":
  495. expectArg(conf, switch, arg, pass, info)
  496. case arg.normalize
  497. of "speed":
  498. incl(conf.options, optOptimizeSpeed)
  499. excl(conf.options, optOptimizeSize)
  500. of "size":
  501. excl(conf.options, optOptimizeSpeed)
  502. incl(conf.options, optOptimizeSize)
  503. of "none":
  504. excl(conf.options, optOptimizeSpeed)
  505. excl(conf.options, optOptimizeSize)
  506. else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
  507. of "app":
  508. expectArg(conf, switch, arg, pass, info)
  509. case arg.normalize
  510. of "gui":
  511. incl(conf.globalOptions, optGenGuiApp)
  512. defineSymbol(conf.symbols, "executable")
  513. defineSymbol(conf.symbols, "guiapp")
  514. of "console":
  515. excl(conf.globalOptions, optGenGuiApp)
  516. defineSymbol(conf.symbols, "executable")
  517. defineSymbol(conf.symbols, "consoleapp")
  518. of "lib":
  519. incl(conf.globalOptions, optGenDynLib)
  520. excl(conf.globalOptions, optGenGuiApp)
  521. defineSymbol(conf.symbols, "library")
  522. defineSymbol(conf.symbols, "dll")
  523. of "staticlib":
  524. incl(conf.globalOptions, optGenStaticLib)
  525. excl(conf.globalOptions, optGenGuiApp)
  526. defineSymbol(conf.symbols, "library")
  527. defineSymbol(conf.symbols, "staticlib")
  528. else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
  529. of "passc", "t":
  530. expectArg(conf, switch, arg, pass, info)
  531. if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(conf, arg)
  532. of "passl", "l":
  533. expectArg(conf, switch, arg, pass, info)
  534. if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(conf, arg)
  535. of "cincludes":
  536. expectArg(conf, switch, arg, pass, info)
  537. if pass in {passCmd2, passPP}: conf.cIncludes.add processPath(conf, arg, info)
  538. of "clibdir":
  539. expectArg(conf, switch, arg, pass, info)
  540. if pass in {passCmd2, passPP}: conf.cLibs.add processPath(conf, arg, info)
  541. of "clib":
  542. expectArg(conf, switch, arg, pass, info)
  543. if pass in {passCmd2, passPP}:
  544. conf.cLinkedLibs.add processPath(conf, arg, info).string
  545. of "header":
  546. if conf != nil: conf.headerFile = arg
  547. incl(conf.globalOptions, optGenIndex)
  548. of "index":
  549. processOnOffSwitchG(conf, {optGenIndex}, arg, pass, info)
  550. of "import":
  551. expectArg(conf, switch, arg, pass, info)
  552. if pass in {passCmd2, passPP}:
  553. conf.implicitImports.add findModule(conf, arg, toFullPath(conf, info)).string
  554. of "include":
  555. expectArg(conf, switch, arg, pass, info)
  556. if pass in {passCmd2, passPP}:
  557. conf.implicitIncludes.add findModule(conf, arg, toFullPath(conf, info)).string
  558. of "listcmd":
  559. expectNoArg(conf, switch, arg, pass, info)
  560. incl(conf.globalOptions, optListCmd)
  561. of "genmapping":
  562. expectNoArg(conf, switch, arg, pass, info)
  563. incl(conf.globalOptions, optGenMapping)
  564. of "os":
  565. expectArg(conf, switch, arg, pass, info)
  566. if pass in {passCmd1, passPP}:
  567. let theOS = platform.nameToOS(arg)
  568. if theOS == osNone: localError(conf, info, "unknown OS: '$1'" % arg)
  569. elif theOS != conf.target.hostOS:
  570. setTarget(conf.target, theOS, conf.target.targetCPU)
  571. of "cpu":
  572. expectArg(conf, switch, arg, pass, info)
  573. if pass in {passCmd1, passPP}:
  574. let cpu = platform.nameToCPU(arg)
  575. if cpu == cpuNone: localError(conf, info, "unknown CPU: '$1'" % arg)
  576. elif cpu != conf.target.hostCPU:
  577. setTarget(conf.target, conf.target.targetOS, cpu)
  578. of "run", "r":
  579. expectNoArg(conf, switch, arg, pass, info)
  580. incl(conf.globalOptions, optRun)
  581. of "errormax":
  582. expectArg(conf, switch, arg, pass, info)
  583. # Note: `nim check` (etc) can overwrite this.
  584. # `0` is meaningless, give it a useful meaning as in clang's -ferror-limit
  585. # If user doesn't set this flag and the code doesn't either, it'd
  586. # have the same effect as errorMax = 1
  587. let ret = parseInt(arg)
  588. conf.errorMax = if ret == 0: high(int) else: ret
  589. of "verbosity":
  590. expectArg(conf, switch, arg, pass, info)
  591. let verbosity = parseInt(arg)
  592. if verbosity notin {0..3}:
  593. localError(conf, info, "invalid verbosity level: '$1'" % arg)
  594. conf.verbosity = verbosity
  595. conf.notes = NotesVerbosity[conf.verbosity]
  596. incl(conf.notes, conf.enableNotes)
  597. excl(conf.notes, conf.disableNotes)
  598. conf.mainPackageNotes = conf.notes
  599. of "parallelbuild":
  600. expectArg(conf, switch, arg, pass, info)
  601. conf.numberOfProcessors = parseInt(arg)
  602. of "version", "v":
  603. expectNoArg(conf, switch, arg, pass, info)
  604. writeVersionInfo(conf, pass)
  605. of "advanced":
  606. expectNoArg(conf, switch, arg, pass, info)
  607. writeAdvancedUsage(conf, pass)
  608. of "fullhelp":
  609. expectNoArg(conf, switch, arg, pass, info)
  610. writeFullhelp(conf, pass)
  611. of "help", "h":
  612. expectNoArg(conf, switch, arg, pass, info)
  613. helpOnError(conf, pass)
  614. of "symbolfiles": discard "ignore for backwards compat"
  615. of "incremental":
  616. when not defined(nimIncremental):
  617. localError(conf, info, "the compiler was not built with " &
  618. "incremental compilation features; bootstrap with " &
  619. "-d:nimIncremental to enable")
  620. case arg.normalize
  621. of "on": conf.symbolFiles = v2Sf
  622. of "off": conf.symbolFiles = disabledSf
  623. of "writeonly": conf.symbolFiles = writeOnlySf
  624. of "readonly": conf.symbolFiles = readOnlySf
  625. of "v2": conf.symbolFiles = v2Sf
  626. else: localError(conf, info, "invalid option for --incremental: " & arg)
  627. of "skipcfg":
  628. expectNoArg(conf, switch, arg, pass, info)
  629. incl(conf.globalOptions, optSkipSystemConfigFile)
  630. of "skipprojcfg":
  631. expectNoArg(conf, switch, arg, pass, info)
  632. incl(conf.globalOptions, optSkipProjConfigFile)
  633. of "skipusercfg":
  634. expectNoArg(conf, switch, arg, pass, info)
  635. incl(conf.globalOptions, optSkipUserConfigFile)
  636. of "skipparentcfg":
  637. expectNoArg(conf, switch, arg, pass, info)
  638. incl(conf.globalOptions, optSkipParentConfigFiles)
  639. of "genscript", "gendeps":
  640. expectNoArg(conf, switch, arg, pass, info)
  641. incl(conf.globalOptions, optGenScript)
  642. incl(conf.globalOptions, optCompileOnly)
  643. of "colors": processOnOffSwitchG(conf, {optUseColors}, arg, pass, info)
  644. of "lib":
  645. expectArg(conf, switch, arg, pass, info)
  646. conf.libpath = processPath(conf, arg, info, notRelativeToProj=true)
  647. of "putenv":
  648. expectArg(conf, switch, arg, pass, info)
  649. splitSwitch(conf, arg, key, val, pass, info)
  650. os.putEnv(key, val)
  651. of "cc":
  652. expectArg(conf, switch, arg, pass, info)
  653. setCC(conf, arg, info)
  654. of "track":
  655. expectArg(conf, switch, arg, pass, info)
  656. track(conf, arg, info)
  657. of "trackdirty":
  658. expectArg(conf, switch, arg, pass, info)
  659. trackDirty(conf, arg, info)
  660. of "suggest":
  661. expectNoArg(conf, switch, arg, pass, info)
  662. conf.ideCmd = ideSug
  663. of "def":
  664. expectNoArg(conf, switch, arg, pass, info)
  665. conf.ideCmd = ideDef
  666. of "eval":
  667. expectArg(conf, switch, arg, pass, info)
  668. conf.evalExpr = arg
  669. of "context":
  670. expectNoArg(conf, switch, arg, pass, info)
  671. conf.ideCmd = ideCon
  672. of "usages":
  673. expectNoArg(conf, switch, arg, pass, info)
  674. conf.ideCmd = ideUse
  675. of "stdout":
  676. expectNoArg(conf, switch, arg, pass, info)
  677. incl(conf.globalOptions, optStdout)
  678. of "listfullpaths":
  679. expectNoArg(conf, switch, arg, pass, info)
  680. incl conf.globalOptions, optListFullPaths
  681. of "dynliboverride":
  682. dynlibOverride(conf, switch, arg, pass, info)
  683. of "dynliboverrideall":
  684. expectNoArg(conf, switch, arg, pass, info)
  685. incl conf.globalOptions, optDynlibOverrideAll
  686. of "cs":
  687. # only supported for compatibility. Does nothing.
  688. expectArg(conf, switch, arg, pass, info)
  689. of "experimental":
  690. if arg.len == 0:
  691. conf.features.incl oldExperimentalFeatures
  692. else:
  693. try:
  694. conf.features.incl parseEnum[Feature](arg)
  695. except ValueError:
  696. localError(conf, info, "unknown experimental feature")
  697. of "nocppexceptions":
  698. expectNoArg(conf, switch, arg, pass, info)
  699. incl(conf.globalOptions, optNoCppExceptions)
  700. defineSymbol(conf.symbols, "noCppExceptions")
  701. of "cppdefine":
  702. expectArg(conf, switch, arg, pass, info)
  703. if conf != nil:
  704. conf.cppDefine(arg)
  705. of "newruntime":
  706. expectNoArg(conf, switch, arg, pass, info)
  707. doAssert(conf != nil)
  708. incl(conf.features, destructor)
  709. defineSymbol(conf.symbols, "nimNewRuntime")
  710. of "stylecheck":
  711. case arg.normalize
  712. of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError}
  713. of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint}
  714. of "error": conf.globalOptions = conf.globalOptions + {optStyleError}
  715. else: localError(conf, info, errOffHintsError % arg)
  716. of "showallmismatches":
  717. processOnOffSwitchG(conf, {optShowAllMismatches}, arg, pass, info)
  718. of "cppcompiletonamespace":
  719. if arg.len > 0:
  720. conf.cppCustomNamespace = arg
  721. else:
  722. conf.cppCustomNamespace = "Nim"
  723. defineSymbol(conf.symbols, "cppCompileToNamespace", conf.cppCustomNamespace)
  724. else:
  725. if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
  726. else: invalidCmdLineOption(conf, pass, switch, info)
  727. template gCmdLineInfo*(): untyped = newLineInfo(config, AbsoluteFile"command line", 1, 1)
  728. proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
  729. var cmd, arg: string
  730. splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)
  731. processSwitch(cmd, arg, pass, gCmdLineInfo, config)
  732. proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) =
  733. # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
  734. # we transform it to (key = hint, val = [X]:off)
  735. var bracketLe = strutils.find(p.key, '[')
  736. if bracketLe >= 0:
  737. var key = substr(p.key, 0, bracketLe - 1)
  738. var val = substr(p.key, bracketLe) & ':' & p.val
  739. processSwitch(key, val, pass, gCmdLineInfo, config)
  740. else:
  741. processSwitch(p.key, p.val, pass, gCmdLineInfo, config)
  742. proc processArgument*(pass: TCmdLinePass; p: OptParser;
  743. argsCount: var int; config: ConfigRef): bool =
  744. if argsCount == 0:
  745. # nim filename.nims is the same as "nim e filename.nims":
  746. if p.key.endswith(".nims"):
  747. config.command = "e"
  748. incl(config.globalOptions, optWasNimscript)
  749. config.projectName = unixToNativePath(p.key)
  750. config.arguments = cmdLineRest(p)
  751. result = true
  752. elif pass != passCmd2:
  753. config.command = p.key
  754. else:
  755. if pass == passCmd1: config.commandArgs.add p.key
  756. if argsCount == 1:
  757. # support UNIX style filenames everywhere for portable build scripts:
  758. config.projectName = unixToNativePath(p.key)
  759. config.arguments = cmdLineRest(p)
  760. result = true
  761. inc argsCount