commands.nim 32 KB

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