options.nim 40 KB

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