commands.nim 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  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(usedNoCaas, defined(noCaas), "-d:noCaas")
  18. bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm")
  19. bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
  20. bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
  21. bootSwitch(usedGoGC, defined(gogc), "--gc:go")
  22. bootSwitch(usedNoGC, defined(nogc), "--gc:none")
  23. import
  24. os, msgs, options, nversion, condsyms, strutils, extccomp, platform,
  25. wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils
  26. # but some have deps to imported modules. Yay.
  27. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
  28. bootSwitch(usedAvoidTimeMachine, noTimeMachine, "-d:avoidTimeMachine")
  29. bootSwitch(usedNativeStacktrace,
  30. defined(nativeStackTrace) and nativeStackTraceSupported,
  31. "-d:nativeStackTrace")
  32. bootSwitch(usedFFI, hasFFI, "-d:useFFI")
  33. proc writeCommandLineUsage*()
  34. type
  35. TCmdLinePass* = enum
  36. passCmd1, # first pass over the command line
  37. passCmd2, # second pass over the command line
  38. passPP # preprocessor called processCommand()
  39. proc processCommand*(switch: string, pass: TCmdLinePass)
  40. proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
  41. config: ConfigRef = nil)
  42. # implementation
  43. const
  44. HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
  45. "Copyright (c) 2006-" & CompileDate.substr(0, 3) & " by Andreas Rumpf\n"
  46. const
  47. Usage = slurp"../doc/basicopt.txt".replace("//", "")
  48. AdvancedUsage = slurp"../doc/advopt.txt".replace("//", "")
  49. proc getCommandLineDesc(): string =
  50. result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
  51. CPU[platform.hostCPU].name]) & Usage
  52. proc helpOnError(pass: TCmdLinePass) =
  53. if pass == passCmd1:
  54. msgWriteln(getCommandLineDesc(), {msgStdout})
  55. msgQuit(0)
  56. proc writeAdvancedUsage(pass: TCmdLinePass) =
  57. if pass == passCmd1:
  58. msgWriteln(`%`(HelpMessage, [VersionAsString,
  59. platform.OS[platform.hostOS].name,
  60. CPU[platform.hostCPU].name]) & AdvancedUsage,
  61. {msgStdout})
  62. msgQuit(0)
  63. proc writeVersionInfo(pass: TCmdLinePass) =
  64. if pass == passCmd1:
  65. msgWriteln(`%`(HelpMessage, [VersionAsString,
  66. platform.OS[platform.hostOS].name,
  67. CPU[platform.hostCPU].name]),
  68. {msgStdout})
  69. const gitHash = gorge("git log -n 1 --format=%H").strip
  70. when gitHash.len == 40:
  71. msgWriteln("git hash: " & gitHash, {msgStdout})
  72. msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
  73. usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
  74. usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC,
  75. {msgStdout})
  76. msgQuit(0)
  77. var
  78. helpWritten: bool
  79. proc writeCommandLineUsage() =
  80. if not helpWritten:
  81. msgWriteln(getCommandLineDesc(), {msgStdout})
  82. helpWritten = true
  83. proc addPrefix(switch: string): string =
  84. if len(switch) == 1: result = "-" & switch
  85. else: result = "--" & switch
  86. proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
  87. if switch == " ": localError(info, errInvalidCmdLineOption, "-")
  88. else: localError(info, errInvalidCmdLineOption, addPrefix(switch))
  89. proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
  90. info: TLineInfo) =
  91. cmd = ""
  92. var i = 0
  93. if i < len(switch) and switch[i] == '-': inc(i)
  94. if i < len(switch) and switch[i] == '-': inc(i)
  95. while i < len(switch):
  96. case switch[i]
  97. of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i])
  98. else: break
  99. inc(i)
  100. if i >= len(switch): arg = ""
  101. elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
  102. else: invalidCmdLineOption(pass, switch, info)
  103. proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
  104. info: TLineInfo) =
  105. case arg.normalize
  106. of "on": gOptions = gOptions + op
  107. of "off": gOptions = gOptions - op
  108. else: localError(info, errOnOrOffExpectedButXFound, arg)
  109. proc processOnOffSwitchOrList(op: TOptions, arg: string, pass: TCmdLinePass,
  110. info: TLineInfo): bool =
  111. result = false
  112. case arg.normalize
  113. of "on": gOptions = gOptions + op
  114. of "off": gOptions = gOptions - op
  115. else:
  116. if arg == "list":
  117. result = true
  118. else:
  119. localError(info, errOnOffOrListExpectedButXFound, arg)
  120. proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
  121. info: TLineInfo) =
  122. case arg.normalize
  123. of "on": gGlobalOptions = gGlobalOptions + op
  124. of "off": gGlobalOptions = gGlobalOptions - op
  125. else: localError(info, errOnOrOffExpectedButXFound, arg)
  126. proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
  127. if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch))
  128. proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
  129. if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
  130. var
  131. enableNotes: TNoteKinds
  132. disableNotes: TNoteKinds
  133. proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
  134. info: TLineInfo; orig: string) =
  135. var id = "" # arg = "X]:on|off"
  136. var i = 0
  137. var n = hintMin
  138. while i < len(arg) and (arg[i] != ']'):
  139. add(id, arg[i])
  140. inc(i)
  141. if i < len(arg) and (arg[i] == ']'): inc(i)
  142. else: invalidCmdLineOption(pass, orig, info)
  143. if i < len(arg) and (arg[i] in {':', '='}): inc(i)
  144. else: invalidCmdLineOption(pass, orig, info)
  145. if state == wHint:
  146. var x = findStr(msgs.HintsToStr, id)
  147. if x >= 0: n = TNoteKind(x + ord(hintMin))
  148. else: localError(info, "unknown hint: " & id)
  149. else:
  150. var x = findStr(msgs.WarningsToStr, id)
  151. if x >= 0: n = TNoteKind(x + ord(warnMin))
  152. else: localError(info, "unknown warning: " & id)
  153. case substr(arg, i).normalize
  154. of "on":
  155. incl(gNotes, n)
  156. incl(gMainPackageNotes, n)
  157. incl(enableNotes, n)
  158. of "off":
  159. excl(gNotes, n)
  160. excl(gMainPackageNotes, n)
  161. incl(disableNotes, n)
  162. excl(ForeignPackageNotes, n)
  163. else: localError(info, errOnOrOffExpectedButXFound, arg)
  164. proc processCompile(filename: string) =
  165. var found = findFile(filename)
  166. if found == "": found = filename
  167. extccomp.addExternalFileToCompile(found)
  168. proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
  169. case switch.normalize
  170. of "gc":
  171. case arg.normalize
  172. of "boehm": result = gSelectedGC == gcBoehm
  173. of "refc": result = gSelectedGC == gcRefc
  174. of "v2": result = gSelectedGC == gcV2
  175. of "markandsweep": result = gSelectedGC == gcMarkAndSweep
  176. of "generational": result = gSelectedGC == gcGenerational
  177. of "go": result = gSelectedGC == gcGo
  178. of "none": result = gSelectedGC == gcNone
  179. of "stack", "regions": result = gSelectedGC == gcRegions
  180. else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
  181. of "opt":
  182. case arg.normalize
  183. of "speed": result = contains(gOptions, optOptimizeSpeed)
  184. of "size": result = contains(gOptions, optOptimizeSize)
  185. of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
  186. else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
  187. of "verbosity": result = $gVerbosity == arg
  188. of "app":
  189. case arg.normalize
  190. of "gui": result = contains(gGlobalOptions, optGenGuiApp)
  191. of "console": result = not contains(gGlobalOptions, optGenGuiApp)
  192. of "lib": result = contains(gGlobalOptions, optGenDynLib) and
  193. not contains(gGlobalOptions, optGenGuiApp)
  194. of "staticlib": result = contains(gGlobalOptions, optGenStaticLib) and
  195. not contains(gGlobalOptions, optGenGuiApp)
  196. else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
  197. of "dynliboverride":
  198. result = isDynlibOverride(arg)
  199. else: invalidCmdLineOption(passCmd1, switch, info)
  200. proc testCompileOption*(switch: string, info: TLineInfo): bool =
  201. case switch.normalize
  202. of "debuginfo": result = contains(gGlobalOptions, optCDebug)
  203. of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly)
  204. of "nolinking": result = contains(gGlobalOptions, optNoLinking)
  205. of "nomain": result = contains(gGlobalOptions, optNoMain)
  206. of "forcebuild", "f": result = contains(gGlobalOptions, optForceFullMake)
  207. of "warnings", "w": result = contains(gOptions, optWarns)
  208. of "hints": result = contains(gOptions, optHints)
  209. of "threadanalysis": result = contains(gGlobalOptions, optThreadAnalysis)
  210. of "stacktrace": result = contains(gOptions, optStackTrace)
  211. of "linetrace": result = contains(gOptions, optLineTrace)
  212. of "debugger": result = contains(gOptions, optEndb)
  213. of "profiler": result = contains(gOptions, optProfiler)
  214. of "memtracker": result = contains(gOptions, optMemTracker)
  215. of "checks", "x": result = gOptions * ChecksOptions == ChecksOptions
  216. of "floatchecks":
  217. result = gOptions * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck}
  218. of "infchecks": result = contains(gOptions, optInfCheck)
  219. of "nanchecks": result = contains(gOptions, optNaNCheck)
  220. of "nilchecks": result = contains(gOptions, optNilCheck)
  221. of "objchecks": result = contains(gOptions, optObjCheck)
  222. of "fieldchecks": result = contains(gOptions, optFieldCheck)
  223. of "rangechecks": result = contains(gOptions, optRangeCheck)
  224. of "boundchecks": result = contains(gOptions, optBoundsCheck)
  225. of "overflowchecks": result = contains(gOptions, optOverflowCheck)
  226. of "linedir": result = contains(gOptions, optLineDir)
  227. of "assertions", "a": result = contains(gOptions, optAssert)
  228. of "deadcodeelim": result = contains(gGlobalOptions, optDeadCodeElim)
  229. of "run", "r": result = contains(gGlobalOptions, optRun)
  230. of "symbolfiles": result = contains(gGlobalOptions, optSymbolFiles)
  231. of "genscript": result = contains(gGlobalOptions, optGenScript)
  232. of "threads": result = contains(gGlobalOptions, optThreads)
  233. of "taintmode": result = contains(gGlobalOptions, optTaintMode)
  234. of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation)
  235. of "implicitstatic": result = contains(gOptions, optImplicitStatic)
  236. of "patterns": result = contains(gOptions, optPatterns)
  237. of "experimental": result = gExperimentalMode
  238. of "excessivestacktrace": result = contains(gGlobalOptions, optExcessiveStackTrace)
  239. else: invalidCmdLineOption(passCmd1, switch, info)
  240. proc processPath(path: string, info: TLineInfo,
  241. notRelativeToProj = false): string =
  242. let p = if notRelativeToProj or os.isAbsolute(path) or
  243. '$' in path:
  244. path
  245. else:
  246. options.gProjectPath / path
  247. try:
  248. result = pathSubs(p, info.toFullPath().splitFile().dir)
  249. except ValueError:
  250. localError(info, "invalid path: " & p)
  251. result = p
  252. proc processCfgPath(path: string, info: TLineInfo): string =
  253. let path = if path[0] == '"': strutils.unescape(path) else: path
  254. let basedir = info.toFullPath().splitFile().dir
  255. let p = if os.isAbsolute(path) or '$' in path:
  256. path
  257. else:
  258. basedir / path
  259. try:
  260. result = pathSubs(p, basedir)
  261. except ValueError:
  262. localError(info, "invalid path: " & p)
  263. result = p
  264. proc trackDirty(arg: string, info: TLineInfo) =
  265. var a = arg.split(',')
  266. if a.len != 4: localError(info, errTokenExpected,
  267. "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN")
  268. var line, column: int
  269. if parseUtils.parseInt(a[2], line) <= 0:
  270. localError(info, errInvalidNumber, a[1])
  271. if parseUtils.parseInt(a[3], column) <= 0:
  272. localError(info, errInvalidNumber, a[2])
  273. let dirtyOriginalIdx = a[1].fileInfoIdx
  274. if dirtyOriginalIdx >= 0:
  275. msgs.setDirtyFile(dirtyOriginalIdx, a[0])
  276. gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
  277. proc track(arg: string, info: TLineInfo) =
  278. var a = arg.split(',')
  279. if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN")
  280. var line, column: int
  281. if parseUtils.parseInt(a[1], line) <= 0:
  282. localError(info, errInvalidNumber, a[1])
  283. if parseUtils.parseInt(a[2], column) <= 0:
  284. localError(info, errInvalidNumber, a[2])
  285. gTrackPos = newLineInfo(a[0], line, column)
  286. proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
  287. if pass in {passCmd2, passPP}:
  288. expectArg(switch, arg, pass, info)
  289. options.inclDynlibOverride(arg)
  290. proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
  291. config: ConfigRef = nil) =
  292. var
  293. theOS: TSystemOS
  294. cpu: TSystemCPU
  295. key, val: string
  296. case switch.normalize
  297. of "path", "p":
  298. expectArg(switch, arg, pass, info)
  299. addPath(if pass == passPP: processCfgPath(arg, info) else: processPath(arg, info), info)
  300. of "nimblepath", "babelpath":
  301. # keep the old name for compat
  302. if pass in {passCmd2, passPP} and not options.gNoNimblePath:
  303. expectArg(switch, arg, pass, info)
  304. let path = processPath(arg, info, notRelativeToProj=true)
  305. nimblePath(path, info)
  306. of "nonimblepath", "nobabelpath":
  307. expectNoArg(switch, arg, pass, info)
  308. disableNimblePath()
  309. of "excludepath":
  310. expectArg(switch, arg, pass, info)
  311. let path = processPath(arg, info)
  312. options.searchPaths.keepItIf( cmpPaths(it, path) != 0 )
  313. options.lazyPaths.keepItIf( cmpPaths(it, path) != 0 )
  314. if (len(path) > 0) and (path[len(path) - 1] == DirSep):
  315. let strippedPath = path[0 .. (len(path) - 2)]
  316. options.searchPaths.keepItIf( cmpPaths(it, strippedPath) != 0 )
  317. options.lazyPaths.keepItIf( cmpPaths(it, strippedPath) != 0 )
  318. of "nimcache":
  319. expectArg(switch, arg, pass, info)
  320. options.nimcacheDir = processPath(arg, info, true)
  321. of "out", "o":
  322. expectArg(switch, arg, pass, info)
  323. options.outFile = arg
  324. of "docseesrcurl":
  325. expectArg(switch, arg, pass, info)
  326. options.docSeeSrcUrl = arg
  327. of "mainmodule", "m":
  328. discard "allow for backwards compatibility, but don't do anything"
  329. of "define", "d":
  330. expectArg(switch, arg, pass, info)
  331. if {':', '='} in arg:
  332. splitSwitch(arg, key, val, pass, info)
  333. defineSymbol(key, val)
  334. else:
  335. defineSymbol(arg)
  336. of "undef", "u":
  337. expectArg(switch, arg, pass, info)
  338. undefSymbol(arg)
  339. of "symbol":
  340. expectArg(switch, arg, pass, info)
  341. # deprecated, do nothing
  342. of "compile":
  343. expectArg(switch, arg, pass, info)
  344. if pass in {passCmd2, passPP}: processCompile(arg)
  345. of "link":
  346. expectArg(switch, arg, pass, info)
  347. if pass in {passCmd2, passPP}: addExternalFileToLink(arg)
  348. of "debuginfo":
  349. expectNoArg(switch, arg, pass, info)
  350. incl(gGlobalOptions, optCDebug)
  351. of "embedsrc":
  352. expectNoArg(switch, arg, pass, info)
  353. incl(gGlobalOptions, optEmbedOrigSrc)
  354. of "compileonly", "c":
  355. expectNoArg(switch, arg, pass, info)
  356. incl(gGlobalOptions, optCompileOnly)
  357. of "nolinking":
  358. expectNoArg(switch, arg, pass, info)
  359. incl(gGlobalOptions, optNoLinking)
  360. of "nomain":
  361. expectNoArg(switch, arg, pass, info)
  362. incl(gGlobalOptions, optNoMain)
  363. of "forcebuild", "f":
  364. expectNoArg(switch, arg, pass, info)
  365. incl(gGlobalOptions, optForceFullMake)
  366. of "project":
  367. expectNoArg(switch, arg, pass, info)
  368. gWholeProject = true
  369. of "gc":
  370. expectArg(switch, arg, pass, info)
  371. case arg.normalize
  372. of "boehm":
  373. gSelectedGC = gcBoehm
  374. defineSymbol("boehmgc")
  375. of "refc":
  376. gSelectedGC = gcRefc
  377. of "v2":
  378. gSelectedGC = gcV2
  379. of "markandsweep":
  380. gSelectedGC = gcMarkAndSweep
  381. defineSymbol("gcmarkandsweep")
  382. of "generational":
  383. gSelectedGC = gcGenerational
  384. defineSymbol("gcgenerational")
  385. of "go":
  386. gSelectedGC = gcGo
  387. defineSymbol("gogc")
  388. of "none":
  389. gSelectedGC = gcNone
  390. defineSymbol("nogc")
  391. of "stack", "regions":
  392. gSelectedGC= gcRegions
  393. defineSymbol("gcregions")
  394. else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
  395. of "warnings", "w":
  396. if processOnOffSwitchOrList({optWarns}, arg, pass, info): listWarnings()
  397. of "warning": processSpecificNote(arg, wWarning, pass, info, switch)
  398. of "hint": processSpecificNote(arg, wHint, pass, info, switch)
  399. of "hints":
  400. if processOnOffSwitchOrList({optHints}, arg, pass, info): listHints()
  401. of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
  402. of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
  403. of "excessivestacktrace": processOnOffSwitchG({optExcessiveStackTrace}, arg, pass, info)
  404. of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
  405. of "debugger":
  406. case arg.normalize
  407. of "on", "endb":
  408. gOptions.incl optEndb
  409. defineSymbol("endb")
  410. of "off":
  411. gOptions.excl optEndb
  412. undefSymbol("endb")
  413. of "native", "gdb":
  414. incl(gGlobalOptions, optCDebug)
  415. gOptions = gOptions + {optLineDir} - {optEndb}
  416. defineSymbol("nimTypeNames", nil) # type names are used in gdb pretty printing
  417. undefSymbol("endb")
  418. else:
  419. localError(info, "expected endb|gdb but found " & arg)
  420. of "profiler":
  421. processOnOffSwitch({optProfiler}, arg, pass, info)
  422. if optProfiler in gOptions: defineSymbol("profiler")
  423. else: undefSymbol("profiler")
  424. of "memtracker":
  425. processOnOffSwitch({optMemTracker}, arg, pass, info)
  426. if optMemTracker in gOptions: defineSymbol("memtracker")
  427. else: undefSymbol("memtracker")
  428. of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info)
  429. of "floatchecks":
  430. processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info)
  431. of "infchecks": processOnOffSwitch({optInfCheck}, arg, pass, info)
  432. of "nanchecks": processOnOffSwitch({optNaNCheck}, arg, pass, info)
  433. of "nilchecks": processOnOffSwitch({optNilCheck}, arg, pass, info)
  434. of "objchecks": processOnOffSwitch({optObjCheck}, arg, pass, info)
  435. of "fieldchecks": processOnOffSwitch({optFieldCheck}, arg, pass, info)
  436. of "rangechecks": processOnOffSwitch({optRangeCheck}, arg, pass, info)
  437. of "boundchecks": processOnOffSwitch({optBoundsCheck}, arg, pass, info)
  438. of "overflowchecks": processOnOffSwitch({optOverflowCheck}, arg, pass, info)
  439. of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info)
  440. of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info)
  441. of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
  442. of "threads":
  443. processOnOffSwitchG({optThreads}, arg, pass, info)
  444. #if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
  445. of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info)
  446. of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info)
  447. of "implicitstatic":
  448. processOnOffSwitch({optImplicitStatic}, arg, pass, info)
  449. of "patterns":
  450. processOnOffSwitch({optPatterns}, arg, pass, info)
  451. of "opt":
  452. expectArg(switch, arg, pass, info)
  453. case arg.normalize
  454. of "speed":
  455. incl(gOptions, optOptimizeSpeed)
  456. excl(gOptions, optOptimizeSize)
  457. of "size":
  458. excl(gOptions, optOptimizeSpeed)
  459. incl(gOptions, optOptimizeSize)
  460. of "none":
  461. excl(gOptions, optOptimizeSpeed)
  462. excl(gOptions, optOptimizeSize)
  463. else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
  464. of "app":
  465. expectArg(switch, arg, pass, info)
  466. case arg.normalize
  467. of "gui":
  468. incl(gGlobalOptions, optGenGuiApp)
  469. defineSymbol("executable")
  470. defineSymbol("guiapp")
  471. of "console":
  472. excl(gGlobalOptions, optGenGuiApp)
  473. defineSymbol("executable")
  474. defineSymbol("consoleapp")
  475. of "lib":
  476. incl(gGlobalOptions, optGenDynLib)
  477. excl(gGlobalOptions, optGenGuiApp)
  478. defineSymbol("library")
  479. defineSymbol("dll")
  480. of "staticlib":
  481. incl(gGlobalOptions, optGenStaticLib)
  482. excl(gGlobalOptions, optGenGuiApp)
  483. defineSymbol("library")
  484. defineSymbol("staticlib")
  485. else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
  486. of "passc", "t":
  487. expectArg(switch, arg, pass, info)
  488. if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(arg)
  489. of "passl", "l":
  490. expectArg(switch, arg, pass, info)
  491. if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(arg)
  492. of "cincludes":
  493. expectArg(switch, arg, pass, info)
  494. if pass in {passCmd2, passPP}: cIncludes.add arg.processPath(info)
  495. of "clibdir":
  496. expectArg(switch, arg, pass, info)
  497. if pass in {passCmd2, passPP}: cLibs.add arg.processPath(info)
  498. of "clib":
  499. expectArg(switch, arg, pass, info)
  500. if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info)
  501. of "header":
  502. if config != nil: config.headerFile = arg
  503. incl(gGlobalOptions, optGenIndex)
  504. of "index":
  505. processOnOffSwitchG({optGenIndex}, arg, pass, info)
  506. of "import":
  507. expectArg(switch, arg, pass, info)
  508. if pass in {passCmd2, passPP}: implicitImports.add arg
  509. of "include":
  510. expectArg(switch, arg, pass, info)
  511. if pass in {passCmd2, passPP}: implicitIncludes.add arg
  512. of "listcmd":
  513. expectNoArg(switch, arg, pass, info)
  514. incl(gGlobalOptions, optListCmd)
  515. of "genmapping":
  516. expectNoArg(switch, arg, pass, info)
  517. incl(gGlobalOptions, optGenMapping)
  518. of "os":
  519. expectArg(switch, arg, pass, info)
  520. if pass in {passCmd1, passPP}:
  521. theOS = platform.nameToOS(arg)
  522. if theOS == osNone: localError(info, errUnknownOS, arg)
  523. elif theOS != platform.hostOS:
  524. setTarget(theOS, targetCPU)
  525. of "cpu":
  526. expectArg(switch, arg, pass, info)
  527. if pass in {passCmd1, passPP}:
  528. cpu = platform.nameToCPU(arg)
  529. if cpu == cpuNone: localError(info, errUnknownCPU, arg)
  530. elif cpu != platform.hostCPU:
  531. setTarget(targetOS, cpu)
  532. of "run", "r":
  533. expectNoArg(switch, arg, pass, info)
  534. incl(gGlobalOptions, optRun)
  535. of "verbosity":
  536. expectArg(switch, arg, pass, info)
  537. gVerbosity = parseInt(arg)
  538. gNotes = NotesVerbosity[gVerbosity]
  539. incl(gNotes, enableNotes)
  540. excl(gNotes, disableNotes)
  541. gMainPackageNotes = gNotes
  542. of "parallelbuild":
  543. expectArg(switch, arg, pass, info)
  544. gNumberOfProcessors = parseInt(arg)
  545. of "version", "v":
  546. expectNoArg(switch, arg, pass, info)
  547. writeVersionInfo(pass)
  548. of "advanced":
  549. expectNoArg(switch, arg, pass, info)
  550. writeAdvancedUsage(pass)
  551. of "help", "h":
  552. expectNoArg(switch, arg, pass, info)
  553. helpOnError(pass)
  554. of "symbolfiles":
  555. processOnOffSwitchG({optSymbolFiles}, arg, pass, info)
  556. of "skipcfg":
  557. expectNoArg(switch, arg, pass, info)
  558. incl(gGlobalOptions, optSkipConfigFile)
  559. of "skipprojcfg":
  560. expectNoArg(switch, arg, pass, info)
  561. incl(gGlobalOptions, optSkipProjConfigFile)
  562. of "skipusercfg":
  563. expectNoArg(switch, arg, pass, info)
  564. incl(gGlobalOptions, optSkipUserConfigFile)
  565. of "skipparentcfg":
  566. expectNoArg(switch, arg, pass, info)
  567. incl(gGlobalOptions, optSkipParentConfigFiles)
  568. of "genscript":
  569. expectNoArg(switch, arg, pass, info)
  570. incl(gGlobalOptions, optGenScript)
  571. of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info)
  572. of "lib":
  573. expectArg(switch, arg, pass, info)
  574. libpath = processPath(arg, info, notRelativeToProj=true)
  575. of "putenv":
  576. expectArg(switch, arg, pass, info)
  577. splitSwitch(arg, key, val, pass, info)
  578. os.putEnv(key, val)
  579. of "cc":
  580. expectArg(switch, arg, pass, info)
  581. setCC(arg)
  582. of "track":
  583. expectArg(switch, arg, pass, info)
  584. track(arg, info)
  585. of "trackdirty":
  586. expectArg(switch, arg, pass, info)
  587. trackDirty(arg, info)
  588. of "suggest":
  589. expectNoArg(switch, arg, pass, info)
  590. gIdeCmd = ideSug
  591. of "def":
  592. expectNoArg(switch, arg, pass, info)
  593. gIdeCmd = ideDef
  594. of "eval":
  595. expectArg(switch, arg, pass, info)
  596. gEvalExpr = arg
  597. of "context":
  598. expectNoArg(switch, arg, pass, info)
  599. gIdeCmd = ideCon
  600. of "usages":
  601. expectNoArg(switch, arg, pass, info)
  602. gIdeCmd = ideUse
  603. of "stdout":
  604. expectNoArg(switch, arg, pass, info)
  605. incl(gGlobalOptions, optStdout)
  606. of "listfullpaths":
  607. expectNoArg(switch, arg, pass, info)
  608. gListFullPaths = true
  609. of "dynliboverride":
  610. dynlibOverride(switch, arg, pass, info)
  611. of "cs":
  612. # only supported for compatibility. Does nothing.
  613. expectArg(switch, arg, pass, info)
  614. of "experimental":
  615. expectNoArg(switch, arg, pass, info)
  616. gExperimentalMode = true
  617. of "nocppexceptions":
  618. expectNoArg(switch, arg, pass, info)
  619. incl(gGlobalOptions, optNoCppExceptions)
  620. defineSymbol("noCppExceptions")
  621. of "cppdefine":
  622. expectArg(switch, arg, pass, info)
  623. if config != nil:
  624. config.cppDefine(arg)
  625. of "newruntime":
  626. expectNoArg(switch, arg, pass, info)
  627. newDestructors = true
  628. defineSymbol("nimNewRuntime")
  629. else:
  630. if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
  631. else: invalidCmdLineOption(pass, switch, info)
  632. proc processCommand(switch: string, pass: TCmdLinePass) =
  633. var cmd, arg: string
  634. splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
  635. processSwitch(cmd, arg, pass, gCmdLineInfo)
  636. var
  637. arguments* = ""
  638. # the arguments to be passed to the program that
  639. # should be run
  640. proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
  641. # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
  642. # we fix this here
  643. var bracketLe = strutils.find(p.key, '[')
  644. if bracketLe >= 0:
  645. var key = substr(p.key, 0, bracketLe - 1)
  646. var val = substr(p.key, bracketLe + 1) & ':' & p.val
  647. processSwitch(key, val, pass, gCmdLineInfo)
  648. else:
  649. processSwitch(p.key, p.val, pass, gCmdLineInfo)
  650. proc processArgument*(pass: TCmdLinePass; p: OptParser;
  651. argsCount: var int): bool =
  652. if argsCount == 0:
  653. # nim filename.nims is the same as "nim e filename.nims":
  654. if p.key.endswith(".nims"):
  655. options.command = "e"
  656. options.gProjectName = unixToNativePath(p.key)
  657. arguments = cmdLineRest(p)
  658. result = true
  659. elif pass != passCmd2:
  660. options.command = p.key
  661. else:
  662. if pass == passCmd1: options.commandArgs.add p.key
  663. if argsCount == 1:
  664. # support UNIX style filenames everywhere for portable build scripts:
  665. options.gProjectName = unixToNativePath(p.key)
  666. arguments = cmdLineRest(p)
  667. result = true
  668. inc argsCount