options.nim 40 KB

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