options.nim 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  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. import
  10. os, strutils, strtabs, sets, lineinfos, platform,
  11. prefixmatches, pathutils, nimpaths, tables
  12. from terminal import isatty
  13. from times import utc, fromUnix, local, getTime, format, DateTime
  14. from std/private/globs import nativeToUnixPath
  15. when defined(nimPreviewSlimSystem):
  16. import std/[syncio, assertions]
  17. const
  18. hasTinyCBackend* = defined(tinyc)
  19. useEffectSystem* = true
  20. useWriteTracking* = false
  21. hasFFI* = defined(nimHasLibFFI)
  22. copyrightYear* = "2023"
  23. nimEnableCovariance* = defined(nimEnableCovariance)
  24. type # please make sure we have under 32 options
  25. # (improves code efficiency a lot!)
  26. TOption* = enum # **keep binary compatible**
  27. optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
  28. optOverflowCheck, optRefCheck,
  29. optNaNCheck, optInfCheck, optStaticBoundsCheck, optStyleCheck,
  30. optAssert, optLineDir, optWarns, optHints,
  31. optOptimizeSpeed, optOptimizeSize,
  32. optStackTrace, # stack tracing support
  33. optStackTraceMsgs, # enable custom runtime msgs via `setFrameMsg`
  34. optLineTrace, # line tracing support (includes stack tracing)
  35. optByRef, # use pass by ref for objects
  36. # (for interfacing with C)
  37. optProfiler, # profiler turned on
  38. optImplicitStatic, # optimization: implicit at compile time
  39. # evaluation
  40. optTrMacros, # en/disable pattern matching
  41. optMemTracker,
  42. optSinkInference # 'sink T' inference
  43. optCursorInference
  44. optImportHidden
  45. TOptions* = set[TOption]
  46. TGlobalOption* = enum
  47. gloptNone, optForceFullMake,
  48. optWasNimscript, # redundant with `cmdNimscript`, could be removed
  49. optListCmd, optCompileOnly, optNoLinking,
  50. optCDebug, # turn on debugging information
  51. optGenDynLib, # generate a dynamic library
  52. optGenStaticLib, # generate a static library
  53. optGenGuiApp, # generate a GUI application
  54. optGenScript, # generate a script file to compile the *.c files
  55. optGenCDeps, # generate a list of *.c files to be read by CMake
  56. optGenMapping, # generate a mapping file
  57. optRun, # run the compiled project
  58. optUseNimcache, # save artifacts (including binary) in $nimcache
  59. optStyleHint, # check that the names adhere to NEP-1
  60. optStyleError, # enforce that the names adhere to NEP-1
  61. optStyleUsages, # only enforce consistent **usages** of the symbol
  62. optSkipSystemConfigFile, # skip the system's cfg/nims config file
  63. optSkipProjConfigFile, # skip the project's cfg/nims config file
  64. optSkipUserConfigFile, # skip the users's cfg/nims config file
  65. optSkipParentConfigFiles, # skip parent dir's cfg/nims config files
  66. optNoMain, # do not generate a "main" proc
  67. optUseColors, # use colors for hints, warnings, and errors
  68. optThreads, # support for multi-threading
  69. optStdout, # output to stdout
  70. optThreadAnalysis, # thread analysis pass
  71. optTlsEmulation, # thread var emulation turned on
  72. optGenIndex # generate index file for documentation;
  73. optGenIndexOnly # generate only index file for documentation
  74. optNoImportdoc # disable loading external documentation files
  75. optEmbedOrigSrc # embed the original source in the generated code
  76. # also: generate header file
  77. optIdeDebug # idetools: debug mode
  78. optIdeTerse # idetools: use terse descriptions
  79. optExcessiveStackTrace # fully qualified module filenames
  80. optShowAllMismatches # show all overloading resolution candidates
  81. optWholeProject # for 'doc': output any dependency
  82. optDocInternal # generate documentation for non-exported symbols
  83. optMixedMode # true if some module triggered C++ codegen
  84. optDeclaredLocs # show declaration locations in messages
  85. optNoNimblePath
  86. optHotCodeReloading
  87. optDynlibOverrideAll
  88. optSeqDestructors # active if the implementation uses the new
  89. # string/seq implementation based on destructors
  90. optTinyRtti # active if we use the new "tiny RTTI"
  91. # implementation
  92. optOwnedRefs # active if the Nim compiler knows about 'owned'.
  93. optMultiMethods
  94. optBenchmarkVM # Enables cpuTime() in the VM
  95. optProduceAsm # produce assembler code
  96. optPanics # turn panics (sysFatal) into a process termination
  97. optNimV1Emulation # emulate Nim v1.0
  98. optNimV12Emulation # emulate Nim v1.2
  99. optNimV16Emulation # emulate Nim v1.6
  100. optSourcemap
  101. optProfileVM # enable VM profiler
  102. optEnableDeepCopy # ORC specific: enable 'deepcopy' for all types.
  103. optShowNonExportedFields # for documentation: show fields that are not exported
  104. TGlobalOptions* = set[TGlobalOption]
  105. const
  106. harmlessOptions* = {optForceFullMake, optNoLinking, optRun, optUseColors, optStdout}
  107. genSubDir* = RelativeDir"nimcache"
  108. NimExt* = "nim"
  109. RodExt* = "rod"
  110. HtmlExt* = "html"
  111. JsonExt* = "json"
  112. TagsExt* = "tags"
  113. TexExt* = "tex"
  114. IniExt* = "ini"
  115. DefaultConfig* = RelativeFile"nim.cfg"
  116. DefaultConfigNims* = RelativeFile"config.nims"
  117. DocConfig* = RelativeFile"nimdoc.cfg"
  118. DocTexConfig* = RelativeFile"nimdoc.tex.cfg"
  119. htmldocsDir* = htmldocsDirname.RelativeDir
  120. docRootDefault* = "@default" # using `@` instead of `$` to avoid shell quoting complications
  121. oKeepVariableNames* = true
  122. spellSuggestSecretSauce* = -1
  123. type
  124. TBackend* = enum
  125. backendInvalid = "" # for parseEnum
  126. backendC = "c"
  127. backendCpp = "cpp"
  128. backendJs = "js"
  129. backendObjc = "objc"
  130. # backendNimscript = "nimscript" # this could actually work
  131. # backendLlvm = "llvm" # probably not well supported; was cmdCompileToLLVM
  132. Command* = enum ## Nim's commands
  133. cmdNone # not yet processed command
  134. cmdUnknown # command unmapped
  135. cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS
  136. cmdCrun # compile and run in nimache
  137. cmdTcc # run the project via TCC backend
  138. cmdCheck # semantic checking for whole project
  139. cmdParse # parse a single file (for debugging)
  140. cmdRod # .rod to some text representation (for debugging)
  141. cmdIdeTools # ide tools (e.g. nimsuggest)
  142. cmdNimscript # evaluate nimscript
  143. cmdDoc0
  144. cmdDoc # convert .nim doc comments to HTML
  145. cmdDoc2tex # convert .nim doc comments to LaTeX
  146. cmdRst2html # convert a reStructuredText file to HTML
  147. cmdRst2tex # convert a reStructuredText file to TeX
  148. cmdMd2html # convert a Markdown file to HTML
  149. cmdMd2tex # convert a Markdown file to TeX
  150. cmdJsondoc0
  151. cmdJsondoc
  152. cmdCtags
  153. cmdBuildindex
  154. cmdGendepend
  155. cmdDump
  156. cmdInteractive # start interactive session
  157. cmdNop
  158. cmdJsonscript # compile a .json build file
  159. cmdNimfix
  160. # old unused: cmdInterpret, cmdDef: def feature (find definition for IDEs)
  161. const
  162. cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS, cmdCrun}
  163. cmdDocLike* = {cmdDoc0, cmdDoc, cmdDoc2tex, cmdJsondoc0, cmdJsondoc,
  164. cmdCtags, cmdBuildindex}
  165. type
  166. NimVer* = tuple[major: int, minor: int, patch: int]
  167. TStringSeq* = seq[string]
  168. TGCMode* = enum # the selected GC
  169. gcUnselected = "unselected"
  170. gcNone = "none"
  171. gcBoehm = "boehm"
  172. gcRegions = "regions"
  173. gcArc = "arc"
  174. gcOrc = "orc"
  175. gcMarkAndSweep = "markAndSweep"
  176. gcHooks = "hooks"
  177. gcRefc = "refc"
  178. gcGo = "go"
  179. # gcRefc and the GCs that follow it use a write barrier,
  180. # as far as usesWriteBarrier() is concerned
  181. IdeCmd* = enum
  182. ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod,
  183. ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols,
  184. ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand
  185. Feature* = enum ## experimental features; DO NOT RENAME THESE!
  186. dotOperators,
  187. callOperator,
  188. parallel,
  189. destructor,
  190. notnil,
  191. dynamicBindSym,
  192. forLoopMacros, # not experimental anymore; remains here for backwards compatibility
  193. caseStmtMacros, # ditto
  194. codeReordering,
  195. compiletimeFFI,
  196. ## This requires building nim with `-d:nimHasLibFFI`
  197. ## which itself requires `nimble install libffi`, see #10150
  198. ## Note: this feature can't be localized with {.push.}
  199. vmopsDanger,
  200. strictFuncs,
  201. views,
  202. strictNotNil,
  203. overloadableEnums, # deadcode
  204. strictEffects,
  205. unicodeOperators, # deadcode
  206. flexibleOptionalParams,
  207. strictDefs,
  208. strictCaseObjects
  209. LegacyFeature* = enum
  210. allowSemcheckedAstModification,
  211. ## Allows to modify a NimNode where the type has already been
  212. ## flagged with nfSem. If you actually do this, it will cause
  213. ## bugs.
  214. checkUnsignedConversions
  215. ## Historically and especially in version 1.0.0 of the language
  216. ## conversions to unsigned numbers were checked. In 1.0.4 they
  217. ## are not anymore.
  218. laxEffects
  219. ## Lax effects system prior to Nim 2.0.
  220. verboseTypeMismatch
  221. SymbolFilesOption* = enum
  222. disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
  223. TSystemCC* = enum
  224. ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccBcc, ccVcc,
  225. ccTcc, ccEnv, ccIcl, ccIcc, ccClangCl
  226. ExceptionSystem* = enum
  227. excNone, # no exception system selected yet
  228. excSetjmp, # setjmp based exception handling
  229. excCpp, # use C++'s native exception handling
  230. excGoto, # exception handling based on goto (should become the new default for C)
  231. excQuirky # quirky exception handling
  232. CfileFlag* {.pure.} = enum
  233. Cached, ## no need to recompile this time
  234. External ## file was introduced via .compile pragma
  235. Cfile* = object
  236. nimname*: string
  237. cname*, obj*: AbsoluteFile
  238. flags*: set[CfileFlag]
  239. customArgs*: string
  240. CfileList* = seq[Cfile]
  241. Suggest* = ref object
  242. section*: IdeCmd
  243. qualifiedPath*: seq[string]
  244. name*: ptr string # not used beyond sorting purposes; name is also
  245. # part of 'qualifiedPath'
  246. filePath*: string
  247. line*: int # Starts at 1
  248. column*: int # Starts at 0
  249. doc*: string # Not escaped (yet)
  250. forth*: string # type
  251. quality*: range[0..100] # matching quality
  252. isGlobal*: bool # is a global variable
  253. contextFits*: bool # type/non-type context matches
  254. prefix*: PrefixMatch
  255. symkind*: byte
  256. scope*, localUsages*, globalUsages*: int # more usages is better
  257. tokenLen*: int
  258. version*: int
  259. endLine*: uint16
  260. endCol*: int
  261. Suggestions* = seq[Suggest]
  262. ProfileInfo* = object
  263. time*: float
  264. count*: int
  265. ProfileData* = ref object
  266. data*: TableRef[TLineInfo, ProfileInfo]
  267. StdOrrKind* = enum
  268. stdOrrStdout
  269. stdOrrStderr
  270. FilenameOption* = enum
  271. foAbs # absolute path, e.g.: /pathto/bar/foo.nim
  272. foRelProject # relative to project path, e.g.: ../foo.nim
  273. foCanonical # canonical module name
  274. foLegacyRelProj # legacy, shortest of (foAbs, foRelProject)
  275. foName # lastPathPart, e.g.: foo.nim
  276. foStacktrace # if optExcessiveStackTrace: foAbs else: foName
  277. ConfigRef* {.acyclic.} = ref object ## every global configuration
  278. ## fields marked with '*' are subject to
  279. ## the incremental compilation mechanisms
  280. ## (+) means "part of the dependency"
  281. backend*: TBackend # set via `nim x` or `nim --backend:x`
  282. target*: Target # (+)
  283. linesCompiled*: int # all lines that have been compiled
  284. options*: TOptions # (+)
  285. globalOptions*: TGlobalOptions # (+)
  286. macrosToExpand*: StringTableRef
  287. arcToExpand*: StringTableRef
  288. m*: MsgConfig
  289. filenameOption*: FilenameOption # how to render paths in compiler messages
  290. unitSep*: string
  291. evalTemplateCounter*: int
  292. evalMacroCounter*: int
  293. exitcode*: int8
  294. cmd*: Command # raw command parsed as enum
  295. cmdInput*: string # input command
  296. projectIsCmd*: bool # whether we're compiling from a command input
  297. implicitCmd*: bool # whether some flag triggered an implicit `command`
  298. selectedGC*: TGCMode # the selected GC (+)
  299. exc*: ExceptionSystem
  300. hintProcessingDots*: bool # true for dots, false for filenames
  301. verbosity*: int # how verbose the compiler is
  302. numberOfProcessors*: int # number of processors
  303. lastCmdTime*: float # when caas is enabled, we measure each command
  304. symbolFiles*: SymbolFilesOption
  305. spellSuggestMax*: int # max number of spelling suggestions for typos
  306. cppDefines*: HashSet[string] # (*)
  307. headerFile*: string
  308. features*: set[Feature]
  309. legacyFeatures*: set[LegacyFeature]
  310. arguments*: string ## the arguments to be passed to the program that
  311. ## should be run
  312. ideCmd*: IdeCmd
  313. oldNewlines*: bool
  314. cCompiler*: TSystemCC # the used compiler
  315. modifiedyNotes*: TNoteKinds # notes that have been set/unset from either cmdline/configs
  316. cmdlineNotes*: TNoteKinds # notes that have been set/unset from cmdline
  317. foreignPackageNotes*: TNoteKinds
  318. notes*: TNoteKinds # notes after resolving all logic(defaults, verbosity)/cmdline/configs
  319. warningAsErrors*: TNoteKinds
  320. mainPackageNotes*: TNoteKinds
  321. mainPackageId*: int
  322. errorCounter*: int
  323. hintCounter*: int
  324. warnCounter*: int
  325. errorMax*: int
  326. maxLoopIterationsVM*: int ## VM: max iterations of all loops
  327. isVmTrace*: bool
  328. configVars*: StringTableRef
  329. symbols*: StringTableRef ## We need to use a StringTableRef here as defined
  330. ## symbols are always guaranteed to be style
  331. ## insensitive. Otherwise hell would break lose.
  332. packageCache*: StringTableRef
  333. nimblePaths*: seq[AbsoluteDir]
  334. searchPaths*: seq[AbsoluteDir]
  335. lazyPaths*: seq[AbsoluteDir]
  336. outFile*: RelativeFile
  337. outDir*: AbsoluteDir
  338. jsonBuildFile*: AbsoluteFile
  339. prefixDir*, libpath*, nimcacheDir*: AbsoluteDir
  340. nimStdlibVersion*: NimVer
  341. dllOverrides, moduleOverrides*, cfileSpecificOptions*: StringTableRef
  342. projectName*: string # holds a name like 'nim'
  343. projectPath*: AbsoluteDir # holds a path like /home/alice/projects/nim/compiler/
  344. projectFull*: AbsoluteFile # projectPath/projectName
  345. projectIsStdin*: bool # whether we're compiling from stdin
  346. lastMsgWasDot*: set[StdOrrKind] # the last compiler message was a single '.'
  347. projectMainIdx*: FileIndex # the canonical path id of the main module
  348. projectMainIdx2*: FileIndex # consider merging with projectMainIdx
  349. command*: string # the main command (e.g. cc, check, scan, etc)
  350. commandArgs*: seq[string] # any arguments after the main command
  351. commandLine*: string
  352. extraCmds*: seq[string] # for writeJsonBuildInstructions
  353. keepComments*: bool # whether the parser needs to keep comments
  354. implicitImports*: seq[string] # modules that are to be implicitly imported
  355. implicitIncludes*: seq[string] # modules that are to be implicitly included
  356. docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \
  357. # The string uses the formatting variables `path` and `line`.
  358. docRoot*: string ## see nim --fullhelp for --docRoot
  359. docCmd*: string ## see nim --fullhelp for --docCmd
  360. configFiles*: seq[AbsoluteFile] # config files (cfg,nims)
  361. cIncludes*: seq[AbsoluteDir] # directories to search for included files
  362. cLibs*: seq[AbsoluteDir] # directories to search for lib files
  363. cLinkedLibs*: seq[string] # libraries to link
  364. externalToLink*: seq[string] # files to link in addition to the file
  365. # we compiled (*)
  366. linkOptionsCmd*: string
  367. compileOptionsCmd*: seq[string]
  368. linkOptions*: string # (*)
  369. compileOptions*: string # (*)
  370. cCompilerPath*: string
  371. toCompile*: CfileList # (*)
  372. suggestionResultHook*: proc (result: Suggest) {.closure.}
  373. suggestVersion*: int
  374. suggestMaxResults*: int
  375. lastLineInfo*: TLineInfo
  376. writelnHook*: proc (output: string) {.closure, gcsafe.}
  377. structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string;
  378. severity: Severity) {.closure, gcsafe.}
  379. cppCustomNamespace*: string
  380. nimMainPrefix*: string
  381. vmProfileData*: ProfileData
  382. expandProgress*: bool
  383. expandLevels*: int
  384. expandNodeResult*: string
  385. expandPosition*: TLineInfo
  386. proc parseNimVersion*(a: string): NimVer =
  387. # could be moved somewhere reusable
  388. if a.len > 0:
  389. let b = a.split(".")
  390. assert b.len == 3, a
  391. template fn(i) = result[i] = b[i].parseInt # could be optimized if needed
  392. fn(0)
  393. fn(1)
  394. fn(2)
  395. proc assignIfDefault*[T](result: var T, val: T, def = default(T)) =
  396. ## if `result` was already assigned to a value (that wasn't `def`), this is a noop.
  397. if result == def: result = val
  398. template setErrorMaxHighMaybe*(conf: ConfigRef) =
  399. ## do not stop after first error (but honor --errorMax if provided)
  400. assignIfDefault(conf.errorMax, high(int))
  401. proc setNoteDefaults*(conf: ConfigRef, note: TNoteKind, enabled = true) =
  402. template fun(op) =
  403. conf.notes.op note
  404. conf.mainPackageNotes.op note
  405. conf.foreignPackageNotes.op note
  406. if enabled: fun(incl) else: fun(excl)
  407. proc setNote*(conf: ConfigRef, note: TNoteKind, enabled = true) =
  408. # see also `prepareConfigNotes` which sets notes
  409. if note notin conf.cmdlineNotes:
  410. if enabled: incl(conf.notes, note) else: excl(conf.notes, note)
  411. proc hasHint*(conf: ConfigRef, note: TNoteKind): bool =
  412. # ternary states instead of binary states would simplify logic
  413. if optHints notin conf.options: false
  414. elif note in {hintConf, hintProcessing}:
  415. # could add here other special notes like hintSource
  416. # these notes apply globally.
  417. note in conf.mainPackageNotes
  418. else: note in conf.notes
  419. proc hasWarn*(conf: ConfigRef, note: TNoteKind): bool {.inline.} =
  420. optWarns in conf.options and note in conf.notes
  421. proc hcrOn*(conf: ConfigRef): bool = return optHotCodeReloading in conf.globalOptions
  422. when false:
  423. template depConfigFields*(fn) {.dirty.} = # deadcode
  424. fn(target)
  425. fn(options)
  426. fn(globalOptions)
  427. fn(selectedGC)
  428. const oldExperimentalFeatures* = {dotOperators, callOperator, parallel}
  429. const
  430. ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck,
  431. optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck,
  432. optStyleCheck}
  433. DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck,
  434. optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck,
  435. optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs`
  436. optTrMacros, optStyleCheck, optCursorInference}
  437. DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace}
  438. proc getSrcTimestamp(): DateTime =
  439. try:
  440. result = utc(fromUnix(parseInt(getEnv("SOURCE_DATE_EPOCH",
  441. "not a number"))))
  442. except ValueError:
  443. # Environment variable malformed.
  444. # https://reproducible-builds.org/specs/source-date-epoch/: "If the
  445. # value is malformed, the build process SHOULD exit with a non-zero
  446. # error code", which this doesn't do. This uses local time, because
  447. # that maintains compatibility with existing usage.
  448. result = utc getTime()
  449. proc getDateStr*(): string =
  450. result = format(getSrcTimestamp(), "yyyy-MM-dd")
  451. proc getClockStr*(): string =
  452. result = format(getSrcTimestamp(), "HH:mm:ss")
  453. template newPackageCache*(): untyped =
  454. newStringTable(when FileSystemCaseSensitive:
  455. modeCaseInsensitive
  456. else:
  457. modeCaseSensitive)
  458. proc newProfileData(): ProfileData =
  459. ProfileData(data: newTable[TLineInfo, ProfileInfo]())
  460. const foreignPackageNotesDefault* = {
  461. hintProcessing, warnUnknownMagic, hintQuitCalled, hintExecuting, hintUser, warnUser}
  462. proc isDefined*(conf: ConfigRef; symbol: string): bool
  463. when defined(nimDebugUtils):
  464. # this allows inserting debugging utilties in all modules that import `options`
  465. # with a single switch, which is useful when debugging compiler.
  466. import debugutils
  467. export debugutils
  468. proc initConfigRefCommon(conf: ConfigRef) =
  469. conf.selectedGC = gcUnselected
  470. conf.verbosity = 1
  471. conf.hintProcessingDots = true
  472. conf.options = DefaultOptions
  473. conf.globalOptions = DefaultGlobalOptions
  474. conf.filenameOption = foAbs
  475. conf.foreignPackageNotes = foreignPackageNotesDefault
  476. conf.notes = NotesVerbosity[1]
  477. conf.mainPackageNotes = NotesVerbosity[1]
  478. proc newConfigRef*(): ConfigRef =
  479. result = ConfigRef(
  480. cCompiler: ccGcc,
  481. macrosToExpand: newStringTable(modeStyleInsensitive),
  482. arcToExpand: newStringTable(modeStyleInsensitive),
  483. m: initMsgConfig(),
  484. cppDefines: initHashSet[string](),
  485. headerFile: "", features: {}, legacyFeatures: {},
  486. configVars: newStringTable(modeStyleInsensitive),
  487. symbols: newStringTable(modeStyleInsensitive),
  488. packageCache: newPackageCache(),
  489. searchPaths: @[],
  490. lazyPaths: @[],
  491. outFile: RelativeFile"",
  492. outDir: AbsoluteDir"",
  493. prefixDir: AbsoluteDir"",
  494. libpath: AbsoluteDir"", nimcacheDir: AbsoluteDir"",
  495. dllOverrides: newStringTable(modeCaseInsensitive),
  496. moduleOverrides: newStringTable(modeStyleInsensitive),
  497. cfileSpecificOptions: newStringTable(modeCaseSensitive),
  498. projectName: "", # holds a name like 'nim'
  499. projectPath: AbsoluteDir"", # holds a path like /home/alice/projects/nim/compiler/
  500. projectFull: AbsoluteFile"", # projectPath/projectName
  501. projectIsStdin: false, # whether we're compiling from stdin
  502. projectMainIdx: FileIndex(0'i32), # the canonical path id of the main module
  503. command: "", # the main command (e.g. cc, check, scan, etc)
  504. commandArgs: @[], # any arguments after the main command
  505. commandLine: "",
  506. keepComments: true, # whether the parser needs to keep comments
  507. implicitImports: @[], # modules that are to be implicitly imported
  508. implicitIncludes: @[], # modules that are to be implicitly included
  509. docSeeSrcUrl: "",
  510. cIncludes: @[], # directories to search for included files
  511. cLibs: @[], # directories to search for lib files
  512. cLinkedLibs: @[], # libraries to link
  513. backend: backendInvalid,
  514. externalToLink: @[],
  515. linkOptionsCmd: "",
  516. compileOptionsCmd: @[],
  517. linkOptions: "",
  518. compileOptions: "",
  519. ccompilerpath: "",
  520. toCompile: @[],
  521. arguments: "",
  522. suggestMaxResults: 10_000,
  523. maxLoopIterationsVM: 10_000_000,
  524. vmProfileData: newProfileData(),
  525. spellSuggestMax: spellSuggestSecretSauce,
  526. )
  527. initConfigRefCommon(result)
  528. setTargetFromSystem(result.target)
  529. # enable colors by default on terminals
  530. if terminal.isatty(stderr):
  531. incl(result.globalOptions, optUseColors)
  532. when defined(nimDebugUtils):
  533. onNewConfigRef(result)
  534. proc newPartialConfigRef*(): ConfigRef =
  535. ## create a new ConfigRef that is only good enough for error reporting.
  536. when defined(nimDebugUtils):
  537. result = getConfigRef()
  538. else:
  539. result = ConfigRef()
  540. initConfigRefCommon(result)
  541. proc cppDefine*(c: ConfigRef; define: string) =
  542. c.cppDefines.incl define
  543. proc getStdlibVersion*(conf: ConfigRef): NimVer =
  544. if conf.nimStdlibVersion == (0,0,0):
  545. let s = conf.symbols.getOrDefault("nimVersion", "")
  546. conf.nimStdlibVersion = s.parseNimVersion
  547. result = conf.nimStdlibVersion
  548. proc isDefined*(conf: ConfigRef; symbol: string): bool =
  549. if conf.symbols.hasKey(symbol):
  550. result = true
  551. elif cmpIgnoreStyle(symbol, CPU[conf.target.targetCPU].name) == 0:
  552. result = true
  553. elif cmpIgnoreStyle(symbol, platform.OS[conf.target.targetOS].name) == 0:
  554. result = true
  555. else:
  556. case symbol.normalize
  557. of "x86": result = conf.target.targetCPU == cpuI386
  558. of "itanium": result = conf.target.targetCPU == cpuIa64
  559. of "x8664": result = conf.target.targetCPU == cpuAmd64
  560. of "posix", "unix":
  561. result = conf.target.targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
  562. osQnx, osAtari, osAix,
  563. osHaiku, osVxWorks, osSolaris, osNetbsd,
  564. osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos,
  565. osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos, osZephyr, osNuttX}
  566. of "linux":
  567. result = conf.target.targetOS in {osLinux, osAndroid}
  568. of "bsd":
  569. result = conf.target.targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osCrossos}
  570. of "freebsd":
  571. result = conf.target.targetOS in {osFreebsd, osCrossos}
  572. of "emulatedthreadvars":
  573. result = platform.OS[conf.target.targetOS].props.contains(ospLacksThreadVars)
  574. of "msdos": result = conf.target.targetOS == osDos
  575. of "mswindows", "win32": result = conf.target.targetOS == osWindows
  576. of "macintosh":
  577. result = conf.target.targetOS in {osMacos, osMacosx, osIos}
  578. of "osx", "macosx":
  579. result = conf.target.targetOS in {osMacosx, osIos}
  580. of "sunos": result = conf.target.targetOS == osSolaris
  581. of "nintendoswitch":
  582. result = conf.target.targetOS == osNintendoSwitch
  583. of "freertos", "lwip":
  584. result = conf.target.targetOS == osFreeRTOS
  585. of "zephyr":
  586. result = conf.target.targetOS == osZephyr
  587. of "nuttx":
  588. result = conf.target.targetOS == osNuttX
  589. of "littleendian": result = CPU[conf.target.targetCPU].endian == littleEndian
  590. of "bigendian": result = CPU[conf.target.targetCPU].endian == bigEndian
  591. of "cpu8": result = CPU[conf.target.targetCPU].bit == 8
  592. of "cpu16": result = CPU[conf.target.targetCPU].bit == 16
  593. of "cpu32": result = CPU[conf.target.targetCPU].bit == 32
  594. of "cpu64": result = CPU[conf.target.targetCPU].bit == 64
  595. of "nimrawsetjmp":
  596. result = conf.target.targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd,
  597. osDragonfly, osMacosx}
  598. else: discard
  599. template quitOrRaise*(conf: ConfigRef, msg = "") =
  600. # xxx in future work, consider whether to also intercept `msgQuit` calls
  601. if conf.isDefined("nimDebug"):
  602. doAssert false, msg
  603. else:
  604. quit(msg) # quits with QuitFailure
  605. proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in cmdDocLike + {cmdIdeTools}
  606. proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
  607. template compilationCachePresent*(conf: ConfigRef): untyped =
  608. false
  609. # conf.symbolFiles in {v2Sf, writeOnlySf}
  610. template optPreserveOrigSource*(conf: ConfigRef): untyped =
  611. optEmbedOrigSrc in conf.globalOptions
  612. proc mainCommandArg*(conf: ConfigRef): string =
  613. ## This is intended for commands like check or parse
  614. ## which will work on the main project file unless
  615. ## explicitly given a specific file argument
  616. if conf.commandArgs.len > 0:
  617. result = conf.commandArgs[0]
  618. else:
  619. result = conf.projectName
  620. proc existsConfigVar*(conf: ConfigRef; key: string): bool =
  621. result = hasKey(conf.configVars, key)
  622. proc getConfigVar*(conf: ConfigRef; key: string, default = ""): string =
  623. result = conf.configVars.getOrDefault(key, default)
  624. proc setConfigVar*(conf: ConfigRef; key, val: string) =
  625. conf.configVars[key] = val
  626. proc getOutFile*(conf: ConfigRef; filename: RelativeFile, ext: string): AbsoluteFile =
  627. # explains regression https://github.com/nim-lang/Nim/issues/6583#issuecomment-625711125
  628. # Yet another reason why "" should not mean "."; `""/something` should raise
  629. # instead of implying "" == "." as it's bug prone.
  630. doAssert conf.outDir.string.len > 0
  631. result = conf.outDir / changeFileExt(filename, ext)
  632. proc absOutFile*(conf: ConfigRef): AbsoluteFile =
  633. doAssert not conf.outDir.isEmpty
  634. doAssert not conf.outFile.isEmpty
  635. result = conf.outDir / conf.outFile
  636. when defined(posix):
  637. if dirExists(result.string): result.string.add ".out"
  638. proc prepareToWriteOutput*(conf: ConfigRef): AbsoluteFile =
  639. ## Create the output directory and returns a full path to the output file
  640. result = conf.absOutFile
  641. createDir result.string.parentDir
  642. proc getPrefixDir*(conf: ConfigRef): AbsoluteDir =
  643. ## Gets the prefix dir, usually the parent directory where the binary resides.
  644. ##
  645. ## This is overridden by some tools (namely nimsuggest) via the ``conf.prefixDir``
  646. ## field.
  647. ## This should resolve to root of nim sources, whether running nim from a local
  648. ## clone or using installed nim, so that these exist: `result/doc/advopt.txt`
  649. ## and `result/lib/system.nim`
  650. if not conf.prefixDir.isEmpty: result = conf.prefixDir
  651. else:
  652. let binParent = AbsoluteDir splitPath(getAppDir()).head
  653. when defined(posix):
  654. if binParent == AbsoluteDir"/usr":
  655. result = AbsoluteDir"/usr/lib/nim"
  656. elif binParent == AbsoluteDir"/usr/local":
  657. result = AbsoluteDir"/usr/local/lib/nim"
  658. else:
  659. result = binParent
  660. else:
  661. result = binParent
  662. proc setDefaultLibpath*(conf: ConfigRef) =
  663. # set default value (can be overwritten):
  664. if conf.libpath.isEmpty:
  665. # choose default libpath:
  666. var prefix = getPrefixDir(conf)
  667. conf.libpath = prefix / RelativeDir"lib"
  668. # Special rule to support other tools (nimble) which import the compiler
  669. # modules and make use of them.
  670. let realNimPath = findExe("nim")
  671. # Find out if $nim/../../lib/system.nim exists.
  672. let parentNimLibPath = realNimPath.parentDir.parentDir / "lib"
  673. if not fileExists(conf.libpath.string / "system.nim") and
  674. fileExists(parentNimLibPath / "system.nim"):
  675. conf.libpath = AbsoluteDir parentNimLibPath
  676. proc canonicalizePath*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile =
  677. result = AbsoluteFile path.string.expandFilename
  678. proc setFromProjectName*(conf: ConfigRef; projectName: string) =
  679. try:
  680. conf.projectFull = canonicalizePath(conf, AbsoluteFile projectName)
  681. except OSError:
  682. conf.projectFull = AbsoluteFile projectName
  683. let p = splitFile(conf.projectFull)
  684. let dir = if p.dir.isEmpty: AbsoluteDir getCurrentDir() else: p.dir
  685. conf.projectPath = AbsoluteDir canonicalizePath(conf, AbsoluteFile dir)
  686. conf.projectName = p.name
  687. proc removeTrailingDirSep*(path: string): string =
  688. if (path.len > 0) and (path[^1] == DirSep):
  689. result = substr(path, 0, path.len - 2)
  690. else:
  691. result = path
  692. proc disableNimblePath*(conf: ConfigRef) =
  693. incl conf.globalOptions, optNoNimblePath
  694. conf.lazyPaths.setLen(0)
  695. conf.nimblePaths.setLen(0)
  696. proc clearNimblePath*(conf: ConfigRef) =
  697. conf.lazyPaths.setLen(0)
  698. conf.nimblePaths.setLen(0)
  699. include packagehandling
  700. proc getOsCacheDir(): string =
  701. when defined(posix):
  702. result = getEnv("XDG_CACHE_HOME", getHomeDir() / ".cache") / "nim"
  703. else:
  704. result = getHomeDir() / genSubDir.string
  705. proc getNimcacheDir*(conf: ConfigRef): AbsoluteDir =
  706. proc nimcacheSuffix(conf: ConfigRef): string =
  707. if conf.cmd == cmdCheck: "_check"
  708. elif isDefined(conf, "release") or isDefined(conf, "danger"): "_r"
  709. else: "_d"
  710. # XXX projectName should always be without a file extension!
  711. result = if not conf.nimcacheDir.isEmpty:
  712. conf.nimcacheDir
  713. elif conf.backend == backendJs:
  714. if conf.outDir.isEmpty:
  715. conf.projectPath / genSubDir
  716. else:
  717. conf.outDir / genSubDir
  718. else:
  719. AbsoluteDir(getOsCacheDir() / splitFile(conf.projectName).name &
  720. nimcacheSuffix(conf))
  721. proc pathSubs*(conf: ConfigRef; p, config: string): string =
  722. let home = removeTrailingDirSep(os.getHomeDir())
  723. result = unixToNativePath(p % [
  724. "nim", getPrefixDir(conf).string,
  725. "lib", conf.libpath.string,
  726. "home", home,
  727. "config", config,
  728. "projectname", conf.projectName,
  729. "projectpath", conf.projectPath.string,
  730. "projectdir", conf.projectPath.string,
  731. "nimcache", getNimcacheDir(conf).string]).expandTilde
  732. iterator nimbleSubs*(conf: ConfigRef; p: string): string =
  733. let pl = p.toLowerAscii
  734. if "$nimblepath" in pl or "$nimbledir" in pl:
  735. for i in countdown(conf.nimblePaths.len-1, 0):
  736. let nimblePath = removeTrailingDirSep(conf.nimblePaths[i].string)
  737. yield p % ["nimblepath", nimblePath, "nimbledir", nimblePath]
  738. else:
  739. yield p
  740. proc toGeneratedFile*(conf: ConfigRef; path: AbsoluteFile,
  741. ext: string): AbsoluteFile =
  742. ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
  743. result = getNimcacheDir(conf) / RelativeFile path.string.splitPath.tail.changeFileExt(ext)
  744. proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile,
  745. createSubDir: bool = true): AbsoluteFile =
  746. ## Return an absolute path of a generated intermediary file.
  747. ## Optionally creates the cache directory if `createSubDir` is `true`.
  748. let subdir = getNimcacheDir(conf)
  749. if createSubDir:
  750. try:
  751. createDir(subdir.string)
  752. except OSError:
  753. conf.quitOrRaise "cannot create directory: " & subdir.string
  754. result = subdir / RelativeFile f.string.splitPath.tail
  755. proc rawFindFile(conf: ConfigRef; f: RelativeFile; suppressStdlib: bool): AbsoluteFile =
  756. for it in conf.searchPaths:
  757. if suppressStdlib and it.string.startsWith(conf.libpath.string):
  758. continue
  759. result = it / f
  760. if fileExists(result):
  761. return canonicalizePath(conf, result)
  762. result = AbsoluteFile""
  763. proc rawFindFile2(conf: ConfigRef; f: RelativeFile): AbsoluteFile =
  764. for i, it in conf.lazyPaths:
  765. result = it / f
  766. if fileExists(result):
  767. # bring to front
  768. for j in countdown(i, 1):
  769. swap(conf.lazyPaths[j], conf.lazyPaths[j-1])
  770. return canonicalizePath(conf, result)
  771. result = AbsoluteFile""
  772. template patchModule(conf: ConfigRef) {.dirty.} =
  773. if not result.isEmpty and conf.moduleOverrides.len > 0:
  774. let key = getPackageName(conf, result.string) & "_" & splitFile(result).name
  775. if conf.moduleOverrides.hasKey(key):
  776. let ov = conf.moduleOverrides[key]
  777. if ov.len > 0: result = AbsoluteFile(ov)
  778. when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo):
  779. proc isRelativeTo(path, base: string): bool =
  780. # pending #13212 use os.isRelativeTo
  781. let path = path.normalizedPath
  782. let base = base.normalizedPath
  783. let ret = relativePath(path, base)
  784. result = path.len > 0 and not ret.startsWith ".."
  785. const stdlibDirs* = [
  786. "pure", "core", "arch",
  787. "pure/collections",
  788. "pure/concurrency",
  789. "pure/unidecode", "impure",
  790. "wrappers", "wrappers/linenoise",
  791. "windows", "posix", "js",
  792. "deprecated/pure"]
  793. const
  794. pkgPrefix = "pkg/"
  795. stdPrefix = "std/"
  796. proc getRelativePathFromConfigPath*(conf: ConfigRef; f: AbsoluteFile, isTitle = false): RelativeFile =
  797. let f = $f
  798. if isTitle:
  799. for dir in stdlibDirs:
  800. let path = conf.libpath.string / dir / f.lastPathPart
  801. if path.cmpPaths(f) == 0:
  802. return RelativeFile(stdPrefix & f.splitFile.name)
  803. template search(paths) =
  804. for it in paths:
  805. let it = $it
  806. if f.isRelativeTo(it):
  807. return relativePath(f, it).RelativeFile
  808. search(conf.searchPaths)
  809. search(conf.lazyPaths)
  810. proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile =
  811. if f.isAbsolute:
  812. result = if f.fileExists: AbsoluteFile(f) else: AbsoluteFile""
  813. else:
  814. result = rawFindFile(conf, RelativeFile f, suppressStdlib)
  815. if result.isEmpty:
  816. result = rawFindFile(conf, RelativeFile f.toLowerAscii, suppressStdlib)
  817. if result.isEmpty:
  818. result = rawFindFile2(conf, RelativeFile f)
  819. if result.isEmpty:
  820. result = rawFindFile2(conf, RelativeFile f.toLowerAscii)
  821. patchModule(conf)
  822. proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFile =
  823. # returns path to module
  824. var m = addFileExt(modulename, NimExt)
  825. if m.startsWith(pkgPrefix):
  826. result = findFile(conf, m.substr(pkgPrefix.len), suppressStdlib = true)
  827. else:
  828. if m.startsWith(stdPrefix):
  829. let stripped = m.substr(stdPrefix.len)
  830. for candidate in stdlibDirs:
  831. let path = (conf.libpath.string / candidate / stripped)
  832. if fileExists(path):
  833. result = AbsoluteFile path
  834. break
  835. else: # If prefixed with std/ why would we add the current module path!
  836. let currentPath = currentModule.splitFile.dir
  837. result = AbsoluteFile currentPath / m
  838. if not fileExists(result):
  839. result = findFile(conf, m)
  840. patchModule(conf)
  841. proc findProjectNimFile*(conf: ConfigRef; pkg: string): string =
  842. const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"]
  843. var
  844. candidates: seq[string] = @[]
  845. dir = pkg
  846. prev = dir
  847. nimblepkg = ""
  848. let pkgname = pkg.lastPathPart()
  849. while true:
  850. for k, f in os.walkDir(dir, relative = true):
  851. if k == pcFile and f != "config.nims":
  852. let (_, name, ext) = splitFile(f)
  853. if ext in extensions:
  854. let x = changeFileExt(dir / name, ".nim")
  855. if fileExists(x):
  856. candidates.add x
  857. if ext == ".nimble":
  858. if nimblepkg.len == 0:
  859. nimblepkg = name
  860. # Since nimble packages can have their source in a subfolder,
  861. # check the last folder we were in for a possible match.
  862. if dir != prev:
  863. let x = prev / x.extractFilename()
  864. if fileExists(x):
  865. candidates.add x
  866. else:
  867. # If we found more than one nimble file, chances are that we
  868. # missed the real project file, or this is an invalid nimble
  869. # package. Either way, bailing is the better choice.
  870. return ""
  871. let pkgname = if nimblepkg.len > 0: nimblepkg else: pkgname
  872. for c in candidates:
  873. if pkgname in c.extractFilename(): return c
  874. if candidates.len > 0:
  875. return candidates[0]
  876. prev = dir
  877. dir = parentDir(dir)
  878. if dir == "": break
  879. return ""
  880. proc canonicalImportAux*(conf: ConfigRef, file: AbsoluteFile): string =
  881. ##[
  882. Shows the canonical module import, e.g.:
  883. system, std/tables, fusion/pointers, system/assertions, std/private/asciitables
  884. ]##
  885. var ret = getRelativePathFromConfigPath(conf, file, isTitle = true)
  886. let dir = getNimbleFile(conf, $file).parentDir.AbsoluteDir
  887. if not dir.isEmpty:
  888. let relPath = relativeTo(file, dir)
  889. if not relPath.isEmpty and (ret.isEmpty or relPath.string.len < ret.string.len):
  890. ret = relPath
  891. if ret.isEmpty:
  892. ret = relativeTo(file, conf.projectPath)
  893. result = ret.string
  894. proc canonicalImport*(conf: ConfigRef, file: AbsoluteFile): string =
  895. let ret = canonicalImportAux(conf, file)
  896. result = ret.nativeToUnixPath.changeFileExt("")
  897. proc canonDynlibName(s: string): string =
  898. let start = if s.startsWith("lib"): 3 else: 0
  899. let ende = strutils.find(s, {'(', ')', '.'})
  900. if ende >= 0:
  901. result = s.substr(start, ende-1)
  902. else:
  903. result = s.substr(start)
  904. proc inclDynlibOverride*(conf: ConfigRef; lib: string) =
  905. conf.dllOverrides[lib.canonDynlibName] = "true"
  906. proc isDynlibOverride*(conf: ConfigRef; lib: string): bool =
  907. result = optDynlibOverrideAll in conf.globalOptions or
  908. conf.dllOverrides.hasKey(lib.canonDynlibName)
  909. proc showNonExportedFields*(conf: ConfigRef) =
  910. incl(conf.globalOptions, optShowNonExportedFields)
  911. proc expandDone*(conf: ConfigRef): bool =
  912. result = conf.ideCmd == ideExpand and conf.expandLevels == 0 and conf.expandProgress
  913. proc parseIdeCmd*(s: string): IdeCmd =
  914. case s:
  915. of "sug": ideSug
  916. of "con": ideCon
  917. of "def": ideDef
  918. of "use": ideUse
  919. of "dus": ideDus
  920. of "chk": ideChk
  921. of "chkFile": ideChkFile
  922. of "mod": ideMod
  923. of "highlight": ideHighlight
  924. of "outline": ideOutline
  925. of "known": ideKnown
  926. of "msg": ideMsg
  927. of "project": ideProject
  928. of "globalSymbols": ideGlobalSymbols
  929. of "recompile": ideRecompile
  930. of "changed": ideChanged
  931. of "type": ideType
  932. else: ideNone
  933. proc `$`*(c: IdeCmd): string =
  934. case c:
  935. of ideSug: "sug"
  936. of ideCon: "con"
  937. of ideDef: "def"
  938. of ideUse: "use"
  939. of ideDus: "dus"
  940. of ideChk: "chk"
  941. of ideChkFile: "chkFile"
  942. of ideMod: "mod"
  943. of ideNone: "none"
  944. of ideHighlight: "highlight"
  945. of ideOutline: "outline"
  946. of ideKnown: "known"
  947. of ideMsg: "msg"
  948. of ideProject: "project"
  949. of ideGlobalSymbols: "globalSymbols"
  950. of ideDeclaration: "declaration"
  951. of ideExpand: "expand"
  952. of ideRecompile: "recompile"
  953. of ideChanged: "changed"
  954. of ideType: "type"
  955. proc floatInt64Align*(conf: ConfigRef): int16 =
  956. ## Returns either 4 or 8 depending on reasons.
  957. if conf != nil and conf.target.targetCPU == cpuI386:
  958. #on Linux/BSD i386, double are aligned to 4bytes (except with -malign-double)
  959. if conf.target.targetOS != osWindows:
  960. # on i386 for all known POSIX systems, 64bits ints are aligned
  961. # to 4bytes (except with -malign-double)
  962. return 4
  963. return 8