commands.nim 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  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 = conf.selectedGC == gcV2
  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. conf.selectedGC = gcV2
  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}: conf.implicitImports.add arg
  553. of "include":
  554. expectArg(conf, switch, arg, pass, info)
  555. if pass in {passCmd2, passPP}: conf.implicitIncludes.add arg
  556. of "listcmd":
  557. expectNoArg(conf, switch, arg, pass, info)
  558. incl(conf.globalOptions, optListCmd)
  559. of "genmapping":
  560. expectNoArg(conf, switch, arg, pass, info)
  561. incl(conf.globalOptions, optGenMapping)
  562. of "os":
  563. expectArg(conf, switch, arg, pass, info)
  564. if pass in {passCmd1, passPP}:
  565. let theOS = platform.nameToOS(arg)
  566. if theOS == osNone: localError(conf, info, "unknown OS: '$1'" % arg)
  567. elif theOS != conf.target.hostOS:
  568. setTarget(conf.target, theOS, conf.target.targetCPU)
  569. of "cpu":
  570. expectArg(conf, switch, arg, pass, info)
  571. if pass in {passCmd1, passPP}:
  572. let cpu = platform.nameToCPU(arg)
  573. if cpu == cpuNone: localError(conf, info, "unknown CPU: '$1'" % arg)
  574. elif cpu != conf.target.hostCPU:
  575. setTarget(conf.target, conf.target.targetOS, cpu)
  576. of "run", "r":
  577. expectNoArg(conf, switch, arg, pass, info)
  578. incl(conf.globalOptions, optRun)
  579. of "verbosity":
  580. expectArg(conf, switch, arg, pass, info)
  581. let verbosity = parseInt(arg)
  582. if verbosity notin {0..3}:
  583. localError(conf, info, "invalid verbosity level: '$1'" % arg)
  584. conf.verbosity = verbosity
  585. conf.notes = NotesVerbosity[conf.verbosity]
  586. incl(conf.notes, conf.enableNotes)
  587. excl(conf.notes, conf.disableNotes)
  588. conf.mainPackageNotes = conf.notes
  589. of "parallelbuild":
  590. expectArg(conf, switch, arg, pass, info)
  591. conf.numberOfProcessors = parseInt(arg)
  592. of "version", "v":
  593. expectNoArg(conf, switch, arg, pass, info)
  594. writeVersionInfo(conf, pass)
  595. of "advanced":
  596. expectNoArg(conf, switch, arg, pass, info)
  597. writeAdvancedUsage(conf, pass)
  598. of "fullhelp":
  599. expectNoArg(conf, switch, arg, pass, info)
  600. writeFullhelp(conf, pass)
  601. of "help", "h":
  602. expectNoArg(conf, switch, arg, pass, info)
  603. helpOnError(conf, pass)
  604. of "symbolfiles", "incremental":
  605. case arg.normalize
  606. of "on": conf.symbolFiles = v2Sf
  607. of "off": conf.symbolFiles = disabledSf
  608. of "writeonly": conf.symbolFiles = writeOnlySf
  609. of "readonly": conf.symbolFiles = readOnlySf
  610. of "v2": conf.symbolFiles = v2Sf
  611. else: localError(conf, info, "invalid option for --symbolFiles: " & arg)
  612. of "skipcfg":
  613. expectNoArg(conf, switch, arg, pass, info)
  614. incl(conf.globalOptions, optSkipSystemConfigFile)
  615. of "skipprojcfg":
  616. expectNoArg(conf, switch, arg, pass, info)
  617. incl(conf.globalOptions, optSkipProjConfigFile)
  618. of "skipusercfg":
  619. expectNoArg(conf, switch, arg, pass, info)
  620. incl(conf.globalOptions, optSkipUserConfigFile)
  621. of "skipparentcfg":
  622. expectNoArg(conf, switch, arg, pass, info)
  623. incl(conf.globalOptions, optSkipParentConfigFiles)
  624. of "genscript", "gendeps":
  625. expectNoArg(conf, switch, arg, pass, info)
  626. incl(conf.globalOptions, optGenScript)
  627. incl(conf.globalOptions, optCompileOnly)
  628. of "colors": processOnOffSwitchG(conf, {optUseColors}, arg, pass, info)
  629. of "lib":
  630. expectArg(conf, switch, arg, pass, info)
  631. conf.libpath = processPath(conf, arg, info, notRelativeToProj=true)
  632. of "putenv":
  633. expectArg(conf, switch, arg, pass, info)
  634. splitSwitch(conf, arg, key, val, pass, info)
  635. os.putEnv(key, val)
  636. of "cc":
  637. expectArg(conf, switch, arg, pass, info)
  638. setCC(conf, arg, info)
  639. of "track":
  640. expectArg(conf, switch, arg, pass, info)
  641. track(conf, arg, info)
  642. of "trackdirty":
  643. expectArg(conf, switch, arg, pass, info)
  644. trackDirty(conf, arg, info)
  645. of "suggest":
  646. expectNoArg(conf, switch, arg, pass, info)
  647. conf.ideCmd = ideSug
  648. of "def":
  649. expectNoArg(conf, switch, arg, pass, info)
  650. conf.ideCmd = ideDef
  651. of "eval":
  652. expectArg(conf, switch, arg, pass, info)
  653. conf.evalExpr = arg
  654. of "context":
  655. expectNoArg(conf, switch, arg, pass, info)
  656. conf.ideCmd = ideCon
  657. of "usages":
  658. expectNoArg(conf, switch, arg, pass, info)
  659. conf.ideCmd = ideUse
  660. of "stdout":
  661. expectNoArg(conf, switch, arg, pass, info)
  662. incl(conf.globalOptions, optStdout)
  663. of "listfullpaths":
  664. expectNoArg(conf, switch, arg, pass, info)
  665. incl conf.globalOptions, optListFullPaths
  666. of "dynliboverride":
  667. dynlibOverride(conf, switch, arg, pass, info)
  668. of "dynliboverrideall":
  669. expectNoArg(conf, switch, arg, pass, info)
  670. incl conf.globalOptions, optDynlibOverrideAll
  671. of "cs":
  672. # only supported for compatibility. Does nothing.
  673. expectArg(conf, switch, arg, pass, info)
  674. of "experimental":
  675. if arg.len == 0:
  676. conf.features.incl oldExperimentalFeatures
  677. else:
  678. try:
  679. conf.features.incl parseEnum[Feature](arg)
  680. except ValueError:
  681. localError(conf, info, "unknown experimental feature")
  682. of "nocppexceptions":
  683. expectNoArg(conf, switch, arg, pass, info)
  684. incl(conf.globalOptions, optNoCppExceptions)
  685. defineSymbol(conf.symbols, "noCppExceptions")
  686. of "cppdefine":
  687. expectArg(conf, switch, arg, pass, info)
  688. if conf != nil:
  689. conf.cppDefine(arg)
  690. of "newruntime":
  691. expectNoArg(conf, switch, arg, pass, info)
  692. doAssert(conf != nil)
  693. incl(conf.features, destructor)
  694. defineSymbol(conf.symbols, "nimNewRuntime")
  695. of "stylecheck":
  696. case arg.normalize
  697. of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError}
  698. of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint}
  699. of "error": conf.globalOptions = conf.globalOptions + {optStyleError}
  700. else: localError(conf, info, errOffHintsError % arg)
  701. of "showallmismatches":
  702. processOnOffSwitchG(conf, {optShowAllMismatches}, arg, pass, info)
  703. of "cppcompiletonamespace":
  704. if arg.len > 0:
  705. conf.cppCustomNamespace = arg
  706. else:
  707. conf.cppCustomNamespace = "Nim"
  708. defineSymbol(conf.symbols, "cppCompileToNamespace", conf.cppCustomNamespace)
  709. else:
  710. if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
  711. else: invalidCmdLineOption(conf, pass, switch, info)
  712. template gCmdLineInfo*(): untyped = newLineInfo(config, AbsoluteFile"command line", 1, 1)
  713. proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
  714. var cmd, arg: string
  715. splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)
  716. processSwitch(cmd, arg, pass, gCmdLineInfo, config)
  717. proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) =
  718. # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
  719. # we transform it to (key = hint, val = [X]:off)
  720. var bracketLe = strutils.find(p.key, '[')
  721. if bracketLe >= 0:
  722. var key = substr(p.key, 0, bracketLe - 1)
  723. var val = substr(p.key, bracketLe) & ':' & p.val
  724. processSwitch(key, val, pass, gCmdLineInfo, config)
  725. else:
  726. processSwitch(p.key, p.val, pass, gCmdLineInfo, config)
  727. proc processArgument*(pass: TCmdLinePass; p: OptParser;
  728. argsCount: var int; config: ConfigRef): bool =
  729. if argsCount == 0:
  730. # nim filename.nims is the same as "nim e filename.nims":
  731. if p.key.endswith(".nims"):
  732. config.command = "e"
  733. incl(config.globalOptions, optWasNimscript)
  734. config.projectName = unixToNativePath(p.key)
  735. config.arguments = cmdLineRest(p)
  736. result = true
  737. elif pass != passCmd2:
  738. config.command = p.key
  739. else:
  740. if pass == passCmd1: config.commandArgs.add p.key
  741. if argsCount == 1:
  742. # support UNIX style filenames everywhere for portable build scripts:
  743. config.projectName = unixToNativePath(p.key)
  744. config.arguments = cmdLineRest(p)
  745. result = true
  746. inc argsCount