options.nim 40 KB

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