summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2017-02-01 15:39:56 +0100
committerAndreas Rumpf <rumpf_a@web.de>2017-02-01 23:39:40 +0100
commitf04d21f2793933f9b9a54ef2d67dc277e53a0c67 (patch)
treec51450738683304898e24a3065e4e9898a43c86e
parent5565b9ef10f5022ea1bdf84fd40c1bca4a6e02e8 (diff)
downloadNim-f04d21f2793933f9b9a54ef2d67dc277e53a0c67.tar.gz
refactoring: explict config state instead of globals
-rw-r--r--compiler/cgen.nim5
-rw-r--r--compiler/cgendata.nim1
-rw-r--r--compiler/commands.nim12
-rw-r--r--compiler/condsyms.nim1
-rw-r--r--compiler/main.nim4
-rw-r--r--compiler/modulegraphs.nim6
-rw-r--r--compiler/nim.nim12
-rw-r--r--compiler/nimconf.nim106
-rw-r--r--compiler/options.nim13
-rw-r--r--compiler/scriptconfig.nim12
-rw-r--r--lib/system/nimscript.nim5
-rw-r--r--tools/nimsuggest/nimsuggest.nim12
12 files changed, 110 insertions, 79 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 476b1362f..94a856773 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1221,7 +1221,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   injectG()
   result = newModule(g, module)
   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,
       changeFileExt(completeCFilePath(f), hExt))
     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)
     genMainProc(m)
 
-proc cgenWriteModules*(backend: RootRef) =
+proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
   let g = BModuleList(backend)
   # we need to process the transitive closure because recursive module
   # deps are allowed (and the system module is processed in the wrong
   # order anyway)
+  g.config = config
   if g.generatedHeader != nil: finishModule(g.generatedHeader)
   while g.forwardedProcsCounter > 0:
     for m in cgenModules(g):
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 94d34c5cf..8446b9db2 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -115,6 +115,7 @@ type
     breakPointId*: int
     breakpoints*: Rope # later the breakpoints are inserted into the main proc
     typeInfoMarker*: TypeCache
+    config*: ConfigRef
 
   TCGen = object of TPassContext # represents a C source file
     s*: TCFileSections        # sections of the C file
diff --git a/compiler/commands.nim b/compiler/commands.nim
index aac740553..74503a414 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -47,7 +47,8 @@ type
     passPP                    # preprocessor called processCommand()
 
 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
 
@@ -312,7 +313,8 @@ proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
     expectArg(switch, arg, pass, info)
     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
     theOS: TSystemOS
     cpu: TSystemCPU
@@ -523,7 +525,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
     expectArg(switch, arg, pass, info)
     if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info)
   of "header":
-    headerFile = arg
+    if config != nil: config.headerFile = arg
     incl(gGlobalOptions, optGenIndex)
   of "index":
     processOnOffSwitchG({optGenIndex}, arg, pass, info)
@@ -646,6 +648,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optNoCppExceptions)
     defineSymbol("noCppExceptions")
+  of "cppdefine":
+    expectArg(switch, arg, pass, info)
+    if config != nil:
+      config.cppDefine(arg)
   else:
     if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
     else: invalidCmdLineOption(pass, switch, info)
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 98c72f862..a738ddb48 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -101,3 +101,4 @@ proc initDefines*() =
   defineSymbol("nimImmediateDeprecated")
   defineSymbol("nimNewShiftOps")
   defineSymbol("nimDistros")
+  defineSymbol("nimHasCppDefine")
diff --git a/compiler/main.nim b/compiler/main.nim
index 888f89ad5..2acb7620c 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -72,7 +72,7 @@ proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
   #registerPass(cleanupPass())
 
   compileProject(graph, cache)
-  cgenWriteModules(graph.backend)
+  cgenWriteModules(graph.backend, graph.config)
   if gCmd != cmdRun:
     let proj = changeFileExt(gProjectFull, "")
     extccomp.callCCompiler(proj)
@@ -294,4 +294,4 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
 
   resetAttributes()
 
-proc mainCommand*() = mainCommand(newModuleGraph(), newIdentCache())
+proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache())
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 466e12e64..0ae7076d9 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -25,7 +25,7 @@
 ## - Its dependent module stays the same.
 ##
 
-import ast, intsets, tables
+import ast, intsets, tables, options
 
 type
   ModuleGraph* = ref object
@@ -39,16 +39,18 @@ type
     importStack*: seq[int32]  # The current import stack. Used for detecting recursive
                               # module dependencies.
     backend*: RootRef # minor hack so that a backend can extend this easily
+    config*: ConfigRef
 
 {.this: g.}
 
-proc newModuleGraph*(): ModuleGraph =
+proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
   result = ModuleGraph()
   initStrTable(result.packageSyms)
   result.deps = initIntSet()
   result.modules = @[]
   result.importStack = @[]
   result.inclToMod = initTable[int32, int32]()
+  result.config = config
 
 proc resetAllModules*(g: ModuleGraph) =
   initStrTable(packageSyms)
diff --git a/compiler/nim.nim b/compiler/nim.nim
index c458f76f9..56885e9f1 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -37,7 +37,7 @@ proc prependCurDir(f: string): string =
   else:
     result = f
 
-proc handleCmdLine(cache: IdentCache) =
+proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
   if paramCount() == 0:
     writeCommandLineUsage()
   else:
@@ -59,22 +59,22 @@ proc handleCmdLine(cache: IdentCache) =
       gProjectName = p.name
     else:
       gProjectPath = canonicalizePath getCurrentDir()
-    loadConfigs(DefaultConfig) # load all config files
+    loadConfigs(DefaultConfig, config) # load all config files
     let scriptFile = gProjectFull.changeFileExt("nims")
     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:
       if scriptFile == gProjectFull: return
     elif fileExists(gProjectPath / "config.nims"):
       # 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
     # command line can overwite the config file's settings
     extccomp.initVars()
     processCmdLine(passCmd2, "")
     if options.command == "":
       rawMessage(errNoCommand, command)
-    mainCommand(newModuleGraph(), cache)
+    mainCommand(newModuleGraph(config), cache)
     if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics())
     #echo(GC_getStatistics())
     if msgs.gErrorCounter == 0:
@@ -118,5 +118,5 @@ when compileOption("gc", "v2") or compileOption("gc", "refc"):
 condsyms.initDefines()
 
 when not defined(selftest):
-  handleCmdLine(newIdentCache())
+  handleCmdLine(newIdentCache(), newConfigRef())
   msgQuit(int8(msgs.gErrorCounter > 0))
diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim
index 4bf2fbc9a..808159b8f 100644
--- a/compiler/nimconf.nim
+++ b/compiler/nimconf.nim
@@ -21,37 +21,37 @@ proc ppGetTok(L: var TLexer, tok: var TToken) =
   rawGetTok(L, tok)
   while tok.tokType in {tkComment}: rawGetTok(L, tok)
 
-proc parseExpr(L: var TLexer, tok: var TToken): bool
-proc parseAtom(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; config: ConfigRef): bool =
   if tok.tokType == tkParLe:
     ppGetTok(L, tok)
-    result = parseExpr(L, tok)
+    result = parseExpr(L, tok, config)
     if tok.tokType == tkParRi: ppGetTok(L, tok)
     else: lexMessage(L, errTokenExpected, "\')\'")
   elif tok.ident.id == ord(wNot):
     ppGetTok(L, tok)
-    result = not parseAtom(L, tok)
+    result = not parseAtom(L, tok, config)
   else:
     result = isDefined(tok.ident)
     ppGetTok(L, tok)
 
-proc parseAndExpr(L: var TLexer, tok: var TToken): bool =
-  result = parseAtom(L, tok)
+proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
+  result = parseAtom(L, tok, config)
   while tok.ident.id == ord(wAnd):
     ppGetTok(L, tok)          # skip "and"
-    var b = parseAtom(L, tok)
+    var b = parseAtom(L, tok, config)
     result = result and b
 
-proc parseExpr(L: var TLexer, tok: var TToken): bool =
-  result = parseAndExpr(L, tok)
+proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
+  result = parseAndExpr(L, tok, config)
   while tok.ident.id == ord(wOr):
     ppGetTok(L, tok)          # skip "or"
-    var b = parseAndExpr(L, tok)
+    var b = parseAndExpr(L, tok, config)
     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'
-  result = parseExpr(L, tok)
+  result = parseExpr(L, tok, config)
   if tok.tokType == tkColon: ppGetTok(L, tok)
   else: lexMessage(L, errTokenExpected, "\':\'")
 
@@ -66,20 +66,20 @@ type
   TJumpDest = enum
     jdEndif, jdElseEndif
 
-proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest)
-proc doElse(L: var TLexer, tok: var TToken) =
+proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef)
+proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef) =
   if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
   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")
-  var res = evalppIf(L, tok)
-  if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif)
+  var res = evalppIf(L, tok, config)
+  if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config)
   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
   while true:
     if tok.ident != nil and tok.ident.s == "@":
@@ -89,11 +89,11 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
         inc(nestedIfs)
       of wElse:
         if dest == jdElseEndif and nestedIfs == 0:
-          doElse(L, tok)
+          doElse(L, tok, config)
           break
       of wElif:
         if dest == jdElseEndif and nestedIfs == 0:
-          doElif(L, tok)
+          doElif(L, tok, config)
           break
       of wEnd:
         if nestedIfs == 0:
@@ -108,16 +108,16 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
     else:
       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 @
   case whichKeyword(tok.ident)
   of wIf:
     setLen(condStack, len(condStack) + 1)
-    let res = evalppIf(L, tok)
+    let res = evalppIf(L, tok, config)
     condStack[high(condStack)] = res
-    if not res: jumpToDirective(L, tok, jdElseEndif)
-  of wElif: doElif(L, tok)
-  of wElse: doElse(L, tok)
+    if not res: jumpToDirective(L, tok, jdElseEndif, config)
+  of wElif: doElif(L, tok, config)
+  of wElse: doElse(L, tok, config)
   of wEnd: doEnd(L, tok)
   of wWrite:
     ppGetTok(L, tok)
@@ -146,58 +146,58 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
       ppGetTok(L, 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)
   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) =
   if tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}:
     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 == "--":
-    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
   checkSymbol(L, tok)
   var s = tokToStr(tok)
-  confTok(L, tok)             # skip symbol
+  confTok(L, tok, config)             # skip symbol
   var val = ""
   while tok.tokType == tkDot:
     add(s, '.')
-    confTok(L, tok)
+    confTok(L, tok, config)
     checkSymbol(L, tok)
     add(s, tokToStr(tok))
-    confTok(L, tok)
+    confTok(L, tok, config)
   if tok.tokType == tkBracketLe:
     # BUGFIX: val, not s!
     # BUGFIX: do not copy '['!
-    confTok(L, tok)
+    confTok(L, tok, config)
     checkSymbol(L, tok)
     add(val, tokToStr(tok))
-    confTok(L, tok)
-    if tok.tokType == tkBracketRi: confTok(L, tok)
+    confTok(L, tok, config)
+    if tok.tokType == tkBracketRi: confTok(L, tok, config)
     else: lexMessage(L, errTokenExpected, "']'")
     add(val, ']')
   let percent = tok.ident != nil and tok.ident.s == "%="
   if tok.tokType in {tkColon, tkEquals} or percent:
     if len(val) > 0: add(val, ':')
-    confTok(L, tok)           # skip ':' or '=' or '%'
+    confTok(L, tok, config)           # skip ':' or '=' or '%'
     checkSymbol(L, tok)
     add(val, tokToStr(tok))
-    confTok(L, tok)           # skip symbol
+    confTok(L, tok, config)           # skip symbol
     while tok.ident != nil and tok.ident.s == "&":
-      confTok(L, tok)
+      confTok(L, tok, config)
       checkSymbol(L, tok)
       add(val, tokToStr(tok))
-      confTok(L, tok)
+      confTok(L, tok, config)
   if percent:
     processSwitch(s, strtabs.`%`(val, options.gConfigVars,
-                                {useEnvironment, useEmpty}), passPP, info)
+                                {useEnvironment, useEmpty}), passPP, info, config)
   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
     L: TLexer
     tok: TToken
@@ -207,8 +207,8 @@ proc readConfigFile(filename: string; cache: IdentCache) =
     initToken(tok)
     openLexer(L, filename, stream, cache)
     tok.tokType = tkEof       # to avoid a pointless warning
-    confTok(L, tok)           # read in the first token
-    while tok.tokType != tkEof: parseAssignment(L, tok)
+    confTok(L, tok, config)           # read in the first token
+    while tok.tokType != tkEof: parseAssignment(L, tok, config)
     if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end")
     closeLexer(L)
     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 = "/etc/" & filename
 
-proc loadConfigs*(cfg: string; cache: IdentCache) =
+proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) =
   setDefaultLibpath()
 
   if optSkipConfigFile notin gGlobalOptions:
-    readConfigFile(getSystemConfigPath(cfg), cache)
+    readConfigFile(getSystemConfigPath(cfg), cache, config)
 
   if optSkipUserConfigFile notin gGlobalOptions:
-    readConfigFile(getUserConfigPath(cfg), cache)
+    readConfigFile(getUserConfigPath(cfg), cache, config)
 
   var pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir()
   if optSkipParentConfigFiles notin gGlobalOptions:
     for dir in parentDirs(pd, fromRoot=true, inclusive=false):
-      readConfigFile(dir / cfg, cache)
+      readConfigFile(dir / cfg, cache, config)
 
   if optSkipProjConfigFile notin gGlobalOptions:
-    readConfigFile(pd / cfg, cache)
+    readConfigFile(pd / cfg, cache, config)
 
     if gProjectName.len != 0:
       # new project wide config file:
@@ -251,8 +251,8 @@ proc loadConfigs*(cfg: string; cache: IdentCache) =
         projectConfig = changeFileExt(gProjectFull, "nimrod.cfg")
         if fileExists(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.
-  loadConfigs(cfg, newIdentCache())
+  loadConfigs(cfg, newIdentCache(), config)
diff --git a/compiler/options.nim b/compiler/options.nim
index 746ee9044..2295bbf93 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -102,6 +102,17 @@ type
     ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
     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
   gIdeCmd*: IdeCmd
 
@@ -122,7 +133,7 @@ var
   outFile*: string = ""
   docSeeSrcUrl*: string = ""  # if empty, no seeSrc will be generated. \
   # The string uses the formatting variables `path` and `line`.
-  headerFile*: string = ""
+  #headerFile*: string = ""
   gVerbosity* = 1             # how verbose the compiler is
   gNumberOfProcessors*: int   # number of processors
   gWholeProject*: bool        # for 'doc2': output any dependency
diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim
index 75ecf4b02..245680eec 100644
--- a/compiler/scriptconfig.nim
+++ b/compiler/scriptconfig.nim
@@ -25,7 +25,8 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) =
     if kind in filter: result.add path
   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'.
   result = newCtx(module, cache)
   result.mode = emRepl
@@ -133,12 +134,15 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext
     gModuleOverrides[key] = val
   cbconf selfExe:
     setResult(a, os.getAppFilename())
+  cbconf cppDefine:
+    if config != nil:
+      options.cppDefine(config, a.getString(0))
 
 proc runNimScript*(cache: IdentCache; scriptName: string;
-                   freshDefines=true) =
+                   freshDefines=true; config: ConfigRef=nil) =
   passes.gIncludeFile = includeModule
   passes.gImportModule = importModule
-  let graph = newModuleGraph()
+  let graph = newModuleGraph(config)
   if freshDefines: initDefines()
 
   defineSymbol("nimscript")
@@ -150,7 +154,7 @@ proc runNimScript*(cache: IdentCache; scriptName: string;
 
   var m = graph.makeModule(scriptName)
   incl(m.flags, sfMainModule)
-  vm.globalCtx = setupVM(m, cache, scriptName)
+  vm.globalCtx = setupVM(m, cache, scriptName, config)
 
   graph.compileSystemModule(cache)
   discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)
diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim
index f675a9472..73bb91fef 100644
--- a/lib/system/nimscript.nim
+++ b/lib/system/nimscript.nim
@@ -293,6 +293,11 @@ template task*(name: untyped; description: string; body: untyped): untyped =
     setCommand "nop"
     `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):
   # nimble has its own implementation for these things.
   var
diff --git a/tools/nimsuggest/nimsuggest.nim b/tools/nimsuggest/nimsuggest.nim
index b5e7b282f..78fc3fd52 100644
--- a/tools/nimsuggest/nimsuggest.nim
+++ b/tools/nimsuggest/nimsuggest.nim
@@ -418,7 +418,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
       options.gProjectName = unixToNativePath(p.key)
       # if processArgument(pass, p, argsCount): break
 
-proc handleCmdLine(cache: IdentCache) =
+proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
   if paramCount() == 0:
     stdout.writeline(Usage)
   else:
@@ -444,23 +444,23 @@ proc handleCmdLine(cache: IdentCache) =
     gPrefixDir = binaryPath.splitPath().head.parentDir()
     #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
     # command line can overwite the config file's settings
     options.command = "nimsuggest"
     let scriptFile = gProjectFull.changeFileExt("nims")
     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:
       if scriptFile == gProjectFull: return
     elif fileExists(gProjectPath / "config.nims"):
       # directory wide NimScript file
-      runNimScript(cache, gProjectPath / "config.nims", freshDefines=false)
+      runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config)
 
     extccomp.initVars()
     processCmdLine(passCmd2, "")
 
-    let graph = newModuleGraph()
+    let graph = newModuleGraph(config)
     graph.suggestMode = true
     mainCommand(graph, cache)
 
@@ -472,4 +472,4 @@ when false:
 
 condsyms.initDefines()
 defineSymbol "nimsuggest"
-handleCmdline(newIdentCache())
+handleCmdline(newIdentCache(), newConfigRef())