refactoring: explict config state instead of globals

This commit is contained in:
Andreas Rumpf 2017-02-01 15:39:56 +01:00
commit f04d21f279
12 changed files with 110 additions and 79 deletions

View file

@ -1221,7 +1221,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
injectG() injectG()
result = newModule(g, module) result = newModule(g, module)
if optGenIndex in gGlobalOptions and g.generatedHeader == nil: if optGenIndex in gGlobalOptions and g.generatedHeader == nil:
let f = if headerFile.len > 0: headerFile else: gProjectFull let f = if graph.config.headerFile.len > 0: graph.config.headerFile else: gProjectFull
g.generatedHeader = rawNewModule(g, module, g.generatedHeader = rawNewModule(g, module,
changeFileExt(completeCFilePath(f), hExt)) changeFileExt(completeCFilePath(f), hExt))
incl g.generatedHeader.flags, isHeaderFile incl g.generatedHeader.flags, isHeaderFile
@ -1373,11 +1373,12 @@ proc myClose(b: PPassContext, n: PNode): PNode =
for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym) for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
genMainProc(m) genMainProc(m)
proc cgenWriteModules*(backend: RootRef) = proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
let g = BModuleList(backend) let g = BModuleList(backend)
# we need to process the transitive closure because recursive module # we need to process the transitive closure because recursive module
# deps are allowed (and the system module is processed in the wrong # deps are allowed (and the system module is processed in the wrong
# order anyway) # order anyway)
g.config = config
if g.generatedHeader != nil: finishModule(g.generatedHeader) if g.generatedHeader != nil: finishModule(g.generatedHeader)
while g.forwardedProcsCounter > 0: while g.forwardedProcsCounter > 0:
for m in cgenModules(g): for m in cgenModules(g):

View file

@ -115,6 +115,7 @@ type
breakPointId*: int breakPointId*: int
breakpoints*: Rope # later the breakpoints are inserted into the main proc breakpoints*: Rope # later the breakpoints are inserted into the main proc
typeInfoMarker*: TypeCache typeInfoMarker*: TypeCache
config*: ConfigRef
TCGen = object of TPassContext # represents a C source file TCGen = object of TPassContext # represents a C source file
s*: TCFileSections # sections of the C file s*: TCFileSections # sections of the C file

View file

@ -47,7 +47,8 @@ type
passPP # preprocessor called processCommand() passPP # preprocessor called processCommand()
proc processCommand*(switch: string, pass: TCmdLinePass) proc processCommand*(switch: string, pass: TCmdLinePass)
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
config: ConfigRef = nil)
# implementation # implementation
@ -312,7 +313,8 @@ proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
options.inclDynlibOverride(arg) options.inclDynlibOverride(arg)
proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
config: ConfigRef = nil) =
var var
theOS: TSystemOS theOS: TSystemOS
cpu: TSystemCPU cpu: TSystemCPU
@ -523,7 +525,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info) if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info)
of "header": of "header":
headerFile = arg if config != nil: config.headerFile = arg
incl(gGlobalOptions, optGenIndex) incl(gGlobalOptions, optGenIndex)
of "index": of "index":
processOnOffSwitchG({optGenIndex}, arg, pass, info) processOnOffSwitchG({optGenIndex}, arg, pass, info)
@ -646,6 +648,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optNoCppExceptions) incl(gGlobalOptions, optNoCppExceptions)
defineSymbol("noCppExceptions") defineSymbol("noCppExceptions")
of "cppdefine":
expectArg(switch, arg, pass, info)
if config != nil:
config.cppDefine(arg)
else: else:
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
else: invalidCmdLineOption(pass, switch, info) else: invalidCmdLineOption(pass, switch, info)

View file

@ -101,3 +101,4 @@ proc initDefines*() =
defineSymbol("nimImmediateDeprecated") defineSymbol("nimImmediateDeprecated")
defineSymbol("nimNewShiftOps") defineSymbol("nimNewShiftOps")
defineSymbol("nimDistros") defineSymbol("nimDistros")
defineSymbol("nimHasCppDefine")

View file

@ -72,7 +72,7 @@ proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
#registerPass(cleanupPass()) #registerPass(cleanupPass())
compileProject(graph, cache) compileProject(graph, cache)
cgenWriteModules(graph.backend) cgenWriteModules(graph.backend, graph.config)
if gCmd != cmdRun: if gCmd != cmdRun:
let proj = changeFileExt(gProjectFull, "") let proj = changeFileExt(gProjectFull, "")
extccomp.callCCompiler(proj) extccomp.callCCompiler(proj)
@ -294,4 +294,4 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
resetAttributes() resetAttributes()
proc mainCommand*() = mainCommand(newModuleGraph(), newIdentCache()) proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache())

View file

@ -25,7 +25,7 @@
## - Its dependent module stays the same. ## - Its dependent module stays the same.
## ##
import ast, intsets, tables import ast, intsets, tables, options
type type
ModuleGraph* = ref object ModuleGraph* = ref object
@ -39,16 +39,18 @@ type
importStack*: seq[int32] # The current import stack. Used for detecting recursive importStack*: seq[int32] # The current import stack. Used for detecting recursive
# module dependencies. # module dependencies.
backend*: RootRef # minor hack so that a backend can extend this easily backend*: RootRef # minor hack so that a backend can extend this easily
config*: ConfigRef
{.this: g.} {.this: g.}
proc newModuleGraph*(): ModuleGraph = proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
result = ModuleGraph() result = ModuleGraph()
initStrTable(result.packageSyms) initStrTable(result.packageSyms)
result.deps = initIntSet() result.deps = initIntSet()
result.modules = @[] result.modules = @[]
result.importStack = @[] result.importStack = @[]
result.inclToMod = initTable[int32, int32]() result.inclToMod = initTable[int32, int32]()
result.config = config
proc resetAllModules*(g: ModuleGraph) = proc resetAllModules*(g: ModuleGraph) =
initStrTable(packageSyms) initStrTable(packageSyms)

View file

@ -37,7 +37,7 @@ proc prependCurDir(f: string): string =
else: else:
result = f result = f
proc handleCmdLine(cache: IdentCache) = proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
if paramCount() == 0: if paramCount() == 0:
writeCommandLineUsage() writeCommandLineUsage()
else: else:
@ -59,22 +59,22 @@ proc handleCmdLine(cache: IdentCache) =
gProjectName = p.name gProjectName = p.name
else: else:
gProjectPath = canonicalizePath getCurrentDir() gProjectPath = canonicalizePath getCurrentDir()
loadConfigs(DefaultConfig) # load all config files loadConfigs(DefaultConfig, config) # load all config files
let scriptFile = gProjectFull.changeFileExt("nims") let scriptFile = gProjectFull.changeFileExt("nims")
if fileExists(scriptFile): if fileExists(scriptFile):
runNimScript(cache, scriptFile, freshDefines=false) runNimScript(cache, scriptFile, freshDefines=false, config)
# 'nim foo.nims' means to just run the NimScript file and do nothing more: # 'nim foo.nims' means to just run the NimScript file and do nothing more:
if scriptFile == gProjectFull: return if scriptFile == gProjectFull: return
elif fileExists(gProjectPath / "config.nims"): elif fileExists(gProjectPath / "config.nims"):
# directory wide NimScript file # directory wide NimScript file
runNimScript(cache, gProjectPath / "config.nims", freshDefines=false) runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config)
# now process command line arguments again, because some options in the # now process command line arguments again, because some options in the
# command line can overwite the config file's settings # command line can overwite the config file's settings
extccomp.initVars() extccomp.initVars()
processCmdLine(passCmd2, "") processCmdLine(passCmd2, "")
if options.command == "": if options.command == "":
rawMessage(errNoCommand, command) rawMessage(errNoCommand, command)
mainCommand(newModuleGraph(), cache) mainCommand(newModuleGraph(config), cache)
if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics()) if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics())
#echo(GC_getStatistics()) #echo(GC_getStatistics())
if msgs.gErrorCounter == 0: if msgs.gErrorCounter == 0:
@ -118,5 +118,5 @@ when compileOption("gc", "v2") or compileOption("gc", "refc"):
condsyms.initDefines() condsyms.initDefines()
when not defined(selftest): when not defined(selftest):
handleCmdLine(newIdentCache()) handleCmdLine(newIdentCache(), newConfigRef())
msgQuit(int8(msgs.gErrorCounter > 0)) msgQuit(int8(msgs.gErrorCounter > 0))

View file

@ -21,37 +21,37 @@ proc ppGetTok(L: var TLexer, tok: var TToken) =
rawGetTok(L, tok) rawGetTok(L, tok)
while tok.tokType in {tkComment}: rawGetTok(L, tok) while tok.tokType in {tkComment}: rawGetTok(L, tok)
proc parseExpr(L: var TLexer, tok: var TToken): bool proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool
proc parseAtom(L: var TLexer, tok: var TToken): bool = proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
if tok.tokType == tkParLe: if tok.tokType == tkParLe:
ppGetTok(L, tok) ppGetTok(L, tok)
result = parseExpr(L, tok) result = parseExpr(L, tok, config)
if tok.tokType == tkParRi: ppGetTok(L, tok) if tok.tokType == tkParRi: ppGetTok(L, tok)
else: lexMessage(L, errTokenExpected, "\')\'") else: lexMessage(L, errTokenExpected, "\')\'")
elif tok.ident.id == ord(wNot): elif tok.ident.id == ord(wNot):
ppGetTok(L, tok) ppGetTok(L, tok)
result = not parseAtom(L, tok) result = not parseAtom(L, tok, config)
else: else:
result = isDefined(tok.ident) result = isDefined(tok.ident)
ppGetTok(L, tok) ppGetTok(L, tok)
proc parseAndExpr(L: var TLexer, tok: var TToken): bool = proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
result = parseAtom(L, tok) result = parseAtom(L, tok, config)
while tok.ident.id == ord(wAnd): while tok.ident.id == ord(wAnd):
ppGetTok(L, tok) # skip "and" ppGetTok(L, tok) # skip "and"
var b = parseAtom(L, tok) var b = parseAtom(L, tok, config)
result = result and b result = result and b
proc parseExpr(L: var TLexer, tok: var TToken): bool = proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
result = parseAndExpr(L, tok) result = parseAndExpr(L, tok, config)
while tok.ident.id == ord(wOr): while tok.ident.id == ord(wOr):
ppGetTok(L, tok) # skip "or" ppGetTok(L, tok) # skip "or"
var b = parseAndExpr(L, tok) var b = parseAndExpr(L, tok, config)
result = result or b result = result or b
proc evalppIf(L: var TLexer, tok: var TToken): bool = proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
ppGetTok(L, tok) # skip 'if' or 'elif' ppGetTok(L, tok) # skip 'if' or 'elif'
result = parseExpr(L, tok) result = parseExpr(L, tok, config)
if tok.tokType == tkColon: ppGetTok(L, tok) if tok.tokType == tkColon: ppGetTok(L, tok)
else: lexMessage(L, errTokenExpected, "\':\'") else: lexMessage(L, errTokenExpected, "\':\'")
@ -66,20 +66,20 @@ type
TJumpDest = enum TJumpDest = enum
jdEndif, jdElseEndif jdEndif, jdElseEndif
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef)
proc doElse(L: var TLexer, tok: var TToken) = proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if") if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
ppGetTok(L, tok) ppGetTok(L, tok)
if tok.tokType == tkColon: ppGetTok(L, tok) if tok.tokType == tkColon: ppGetTok(L, tok)
if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif) if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config)
proc doElif(L: var TLexer, tok: var TToken) = proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if") if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
var res = evalppIf(L, tok) var res = evalppIf(L, tok, config)
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif) if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config)
else: condStack[high(condStack)] = true else: condStack[high(condStack)] = true
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) = proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef) =
var nestedIfs = 0 var nestedIfs = 0
while true: while true:
if tok.ident != nil and tok.ident.s == "@": if tok.ident != nil and tok.ident.s == "@":
@ -89,11 +89,11 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
inc(nestedIfs) inc(nestedIfs)
of wElse: of wElse:
if dest == jdElseEndif and nestedIfs == 0: if dest == jdElseEndif and nestedIfs == 0:
doElse(L, tok) doElse(L, tok, config)
break break
of wElif: of wElif:
if dest == jdElseEndif and nestedIfs == 0: if dest == jdElseEndif and nestedIfs == 0:
doElif(L, tok) doElif(L, tok, config)
break break
of wEnd: of wEnd:
if nestedIfs == 0: if nestedIfs == 0:
@ -108,16 +108,16 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
else: else:
ppGetTok(L, tok) ppGetTok(L, tok)
proc parseDirective(L: var TLexer, tok: var TToken) = proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) =
ppGetTok(L, tok) # skip @ ppGetTok(L, tok) # skip @
case whichKeyword(tok.ident) case whichKeyword(tok.ident)
of wIf: of wIf:
setLen(condStack, len(condStack) + 1) setLen(condStack, len(condStack) + 1)
let res = evalppIf(L, tok) let res = evalppIf(L, tok, config)
condStack[high(condStack)] = res condStack[high(condStack)] = res
if not res: jumpToDirective(L, tok, jdElseEndif) if not res: jumpToDirective(L, tok, jdElseEndif, config)
of wElif: doElif(L, tok) of wElif: doElif(L, tok, config)
of wElse: doElse(L, tok) of wElse: doElse(L, tok, config)
of wEnd: doEnd(L, tok) of wEnd: doEnd(L, tok)
of wWrite: of wWrite:
ppGetTok(L, tok) ppGetTok(L, tok)
@ -146,58 +146,58 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
ppGetTok(L, tok) ppGetTok(L, tok)
else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok)) else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
proc confTok(L: var TLexer, tok: var TToken) = proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef) =
ppGetTok(L, tok) ppGetTok(L, tok)
while tok.ident != nil and tok.ident.s == "@": while tok.ident != nil and tok.ident.s == "@":
parseDirective(L, tok) # else: give the token to the parser parseDirective(L, tok, config) # else: give the token to the parser
proc checkSymbol(L: TLexer, tok: TToken) = proc checkSymbol(L: TLexer, tok: TToken) =
if tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}: if tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}:
lexMessage(L, errIdentifierExpected, tokToStr(tok)) lexMessage(L, errIdentifierExpected, tokToStr(tok))
proc parseAssignment(L: var TLexer, tok: var TToken) = proc parseAssignment(L: var TLexer, tok: var TToken; config: ConfigRef) =
if tok.ident.s == "-" or tok.ident.s == "--": if tok.ident.s == "-" or tok.ident.s == "--":
confTok(L, tok) # skip unnecessary prefix confTok(L, tok, config) # skip unnecessary prefix
var info = getLineInfo(L, tok) # save for later in case of an error var info = getLineInfo(L, tok) # save for later in case of an error
checkSymbol(L, tok) checkSymbol(L, tok)
var s = tokToStr(tok) var s = tokToStr(tok)
confTok(L, tok) # skip symbol confTok(L, tok, config) # skip symbol
var val = "" var val = ""
while tok.tokType == tkDot: while tok.tokType == tkDot:
add(s, '.') add(s, '.')
confTok(L, tok) confTok(L, tok, config)
checkSymbol(L, tok) checkSymbol(L, tok)
add(s, tokToStr(tok)) add(s, tokToStr(tok))
confTok(L, tok) confTok(L, tok, config)
if tok.tokType == tkBracketLe: if tok.tokType == tkBracketLe:
# BUGFIX: val, not s! # BUGFIX: val, not s!
# BUGFIX: do not copy '['! # BUGFIX: do not copy '['!
confTok(L, tok) confTok(L, tok, config)
checkSymbol(L, tok) checkSymbol(L, tok)
add(val, tokToStr(tok)) add(val, tokToStr(tok))
confTok(L, tok) confTok(L, tok, config)
if tok.tokType == tkBracketRi: confTok(L, tok) if tok.tokType == tkBracketRi: confTok(L, tok, config)
else: lexMessage(L, errTokenExpected, "']'") else: lexMessage(L, errTokenExpected, "']'")
add(val, ']') add(val, ']')
let percent = tok.ident != nil and tok.ident.s == "%=" let percent = tok.ident != nil and tok.ident.s == "%="
if tok.tokType in {tkColon, tkEquals} or percent: if tok.tokType in {tkColon, tkEquals} or percent:
if len(val) > 0: add(val, ':') if len(val) > 0: add(val, ':')
confTok(L, tok) # skip ':' or '=' or '%' confTok(L, tok, config) # skip ':' or '=' or '%'
checkSymbol(L, tok) checkSymbol(L, tok)
add(val, tokToStr(tok)) add(val, tokToStr(tok))
confTok(L, tok) # skip symbol confTok(L, tok, config) # skip symbol
while tok.ident != nil and tok.ident.s == "&": while tok.ident != nil and tok.ident.s == "&":
confTok(L, tok) confTok(L, tok, config)
checkSymbol(L, tok) checkSymbol(L, tok)
add(val, tokToStr(tok)) add(val, tokToStr(tok))
confTok(L, tok) confTok(L, tok, config)
if percent: if percent:
processSwitch(s, strtabs.`%`(val, options.gConfigVars, processSwitch(s, strtabs.`%`(val, options.gConfigVars,
{useEnvironment, useEmpty}), passPP, info) {useEnvironment, useEmpty}), passPP, info, config)
else: else:
processSwitch(s, val, passPP, info) processSwitch(s, val, passPP, info, config)
proc readConfigFile(filename: string; cache: IdentCache) = proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) =
var var
L: TLexer L: TLexer
tok: TToken tok: TToken
@ -207,8 +207,8 @@ proc readConfigFile(filename: string; cache: IdentCache) =
initToken(tok) initToken(tok)
openLexer(L, filename, stream, cache) openLexer(L, filename, stream, cache)
tok.tokType = tkEof # to avoid a pointless warning tok.tokType = tkEof # to avoid a pointless warning
confTok(L, tok) # read in the first token confTok(L, tok, config) # read in the first token
while tok.tokType != tkEof: parseAssignment(L, tok) while tok.tokType != tkEof: parseAssignment(L, tok, config)
if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end") if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end")
closeLexer(L) closeLexer(L)
rawMessage(hintConf, filename) rawMessage(hintConf, filename)
@ -225,22 +225,22 @@ proc getSystemConfigPath(filename: string): string =
if not existsFile(result): result = joinPath([p, "etc", filename]) if not existsFile(result): result = joinPath([p, "etc", filename])
if not existsFile(result): result = "/etc/" & filename if not existsFile(result): result = "/etc/" & filename
proc loadConfigs*(cfg: string; cache: IdentCache) = proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) =
setDefaultLibpath() setDefaultLibpath()
if optSkipConfigFile notin gGlobalOptions: if optSkipConfigFile notin gGlobalOptions:
readConfigFile(getSystemConfigPath(cfg), cache) readConfigFile(getSystemConfigPath(cfg), cache, config)
if optSkipUserConfigFile notin gGlobalOptions: if optSkipUserConfigFile notin gGlobalOptions:
readConfigFile(getUserConfigPath(cfg), cache) readConfigFile(getUserConfigPath(cfg), cache, config)
var pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir() var pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir()
if optSkipParentConfigFiles notin gGlobalOptions: if optSkipParentConfigFiles notin gGlobalOptions:
for dir in parentDirs(pd, fromRoot=true, inclusive=false): for dir in parentDirs(pd, fromRoot=true, inclusive=false):
readConfigFile(dir / cfg, cache) readConfigFile(dir / cfg, cache, config)
if optSkipProjConfigFile notin gGlobalOptions: if optSkipProjConfigFile notin gGlobalOptions:
readConfigFile(pd / cfg, cache) readConfigFile(pd / cfg, cache, config)
if gProjectName.len != 0: if gProjectName.len != 0:
# new project wide config file: # new project wide config file:
@ -251,8 +251,8 @@ proc loadConfigs*(cfg: string; cache: IdentCache) =
projectConfig = changeFileExt(gProjectFull, "nimrod.cfg") projectConfig = changeFileExt(gProjectFull, "nimrod.cfg")
if fileExists(projectConfig): if fileExists(projectConfig):
rawMessage(warnDeprecated, projectConfig) rawMessage(warnDeprecated, projectConfig)
readConfigFile(projectConfig, cache) readConfigFile(projectConfig, cache, config)
proc loadConfigs*(cfg: string) = proc loadConfigs*(cfg: string; config: ConfigRef = nil) =
# for backwards compatibility only. # for backwards compatibility only.
loadConfigs(cfg, newIdentCache()) loadConfigs(cfg, newIdentCache(), config)

View file

@ -102,6 +102,17 @@ type
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod, ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
ideHighlight, ideOutline ideHighlight, ideOutline
ConfigRef* = ref object ## eventually all global configuration should be moved here
cppDefines*: HashSet[string]
headerFile*: string
proc newConfigRef*(): ConfigRef =
result = ConfigRef(cppDefines: initSet[string](),
headerFile: "")
proc cppDefine*(c: ConfigRef; define: string) =
c.cppDefines.incl define
var var
gIdeCmd*: IdeCmd gIdeCmd*: IdeCmd
@ -122,7 +133,7 @@ var
outFile*: string = "" outFile*: string = ""
docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \ docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \
# The string uses the formatting variables `path` and `line`. # The string uses the formatting variables `path` and `line`.
headerFile*: string = "" #headerFile*: string = ""
gVerbosity* = 1 # how verbose the compiler is gVerbosity* = 1 # how verbose the compiler is
gNumberOfProcessors*: int # number of processors gNumberOfProcessors*: int # number of processors
gWholeProject*: bool # for 'doc2': output any dependency gWholeProject*: bool # for 'doc2': output any dependency

View file

@ -25,7 +25,8 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) =
if kind in filter: result.add path if kind in filter: result.add path
setResult(a, result) setResult(a, result)
proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext = proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
config: ConfigRef = nil): PEvalContext =
# For Nimble we need to export 'setupVM'. # For Nimble we need to export 'setupVM'.
result = newCtx(module, cache) result = newCtx(module, cache)
result.mode = emRepl result.mode = emRepl
@ -133,12 +134,15 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext
gModuleOverrides[key] = val gModuleOverrides[key] = val
cbconf selfExe: cbconf selfExe:
setResult(a, os.getAppFilename()) setResult(a, os.getAppFilename())
cbconf cppDefine:
if config != nil:
options.cppDefine(config, a.getString(0))
proc runNimScript*(cache: IdentCache; scriptName: string; proc runNimScript*(cache: IdentCache; scriptName: string;
freshDefines=true) = freshDefines=true; config: ConfigRef=nil) =
passes.gIncludeFile = includeModule passes.gIncludeFile = includeModule
passes.gImportModule = importModule passes.gImportModule = importModule
let graph = newModuleGraph() let graph = newModuleGraph(config)
if freshDefines: initDefines() if freshDefines: initDefines()
defineSymbol("nimscript") defineSymbol("nimscript")
@ -150,7 +154,7 @@ proc runNimScript*(cache: IdentCache; scriptName: string;
var m = graph.makeModule(scriptName) var m = graph.makeModule(scriptName)
incl(m.flags, sfMainModule) incl(m.flags, sfMainModule)
vm.globalCtx = setupVM(m, cache, scriptName) vm.globalCtx = setupVM(m, cache, scriptName, config)
graph.compileSystemModule(cache) graph.compileSystemModule(cache)
discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache) discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)

View file

@ -293,6 +293,11 @@ template task*(name: untyped; description: string; body: untyped): untyped =
setCommand "nop" setCommand "nop"
`name Task`() `name Task`()
proc cppDefine*(define: string) =
## tell Nim that ``define`` is a C preprocessor ``#define`` and so always
## needs to be mangled.
builtin
when not defined(nimble): when not defined(nimble):
# nimble has its own implementation for these things. # nimble has its own implementation for these things.
var var

View file

@ -418,7 +418,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
options.gProjectName = unixToNativePath(p.key) options.gProjectName = unixToNativePath(p.key)
# if processArgument(pass, p, argsCount): break # if processArgument(pass, p, argsCount): break
proc handleCmdLine(cache: IdentCache) = proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
if paramCount() == 0: if paramCount() == 0:
stdout.writeline(Usage) stdout.writeline(Usage)
else: else:
@ -444,23 +444,23 @@ proc handleCmdLine(cache: IdentCache) =
gPrefixDir = binaryPath.splitPath().head.parentDir() gPrefixDir = binaryPath.splitPath().head.parentDir()
#msgs.writelnHook = proc (line: string) = logStr(line) #msgs.writelnHook = proc (line: string) = logStr(line)
loadConfigs(DefaultConfig, cache) # load all config files loadConfigs(DefaultConfig, cache, config) # load all config files
# now process command line arguments again, because some options in the # now process command line arguments again, because some options in the
# command line can overwite the config file's settings # command line can overwite the config file's settings
options.command = "nimsuggest" options.command = "nimsuggest"
let scriptFile = gProjectFull.changeFileExt("nims") let scriptFile = gProjectFull.changeFileExt("nims")
if fileExists(scriptFile): if fileExists(scriptFile):
runNimScript(cache, scriptFile, freshDefines=false) runNimScript(cache, scriptFile, freshDefines=false, config)
# 'nim foo.nims' means to just run the NimScript file and do nothing more: # 'nim foo.nims' means to just run the NimScript file and do nothing more:
if scriptFile == gProjectFull: return if scriptFile == gProjectFull: return
elif fileExists(gProjectPath / "config.nims"): elif fileExists(gProjectPath / "config.nims"):
# directory wide NimScript file # directory wide NimScript file
runNimScript(cache, gProjectPath / "config.nims", freshDefines=false) runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config)
extccomp.initVars() extccomp.initVars()
processCmdLine(passCmd2, "") processCmdLine(passCmd2, "")
let graph = newModuleGraph() let graph = newModuleGraph(config)
graph.suggestMode = true graph.suggestMode = true
mainCommand(graph, cache) mainCommand(graph, cache)
@ -472,4 +472,4 @@ when false:
condsyms.initDefines() condsyms.initDefines()
defineSymbol "nimsuggest" defineSymbol "nimsuggest"
handleCmdline(newIdentCache()) handleCmdline(newIdentCache(), newConfigRef())