commands.nim 26 KB

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