fix some issues with --backend (#14363)

* fix some issues with --backend
* fix https://github.com/timotheecour/Nim/issues/175; improve upon #14306
This commit is contained in:
Timothee Cour
2020-05-16 04:09:18 -07:00
committed by GitHub
parent c32e1378eb
commit c777f2fb60
11 changed files with 125 additions and 59 deletions

View File

@@ -160,8 +160,8 @@ proc mydiv(a, b): int {.raises: [].} =
- Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`.
- The `define` and `undef` pragmas have been de-deprecated.
- New command: `nim r main.nim [args...]` which compiles and runs main.nim, saving
the binary to $nimcache/main$exeExt, using the same logic as `nim c -r` to
- New command: `nim r main.nim [args...]` which compiles and runs main.nim, and implies `--usenimcache`
so that output is saved to $nimcache/main$exeExt, using the same logic as `nim c -r` to
avoid recompiling when sources don't change. This is now the preferred way to
run tests, avoiding the usual pain of clobbering your repo with binaries or
using tricky gitignore rules on posix. Example:
@@ -178,6 +178,12 @@ proc mydiv(a, b): int {.raises: [].} =
- new hint: `--hint:msgOrigin` will show where a compiler msg (hint|warning|error) was generated; this
helps in particular when it's non obvious where it came from either because multiple locations generate
the same message, or because the message involves runtime formatting.
- new flag `--backend:js|c|cpp|objc (or -b:js etc), to change backend; can be used with any command
(eg nim r, doc, check etc); safe to re-assign.
- new flag `--doccmd:cmd` to pass additional flags for runnableExamples, eg: `--doccmd:-d:foo --threads`
use `--doccmd:skip` to skip runnableExamples and rst test snippets.
- new flag `--usenimcache` to output to nimcache (whatever it resolves to after all commands are processed)
and avoids polluting both $pwd and $projectdir. It can be used with any command.
## Tool changes

View File

@@ -75,14 +75,6 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi
# now process command line arguments again, because some options in the
# command line can overwrite the config file's settings
extccomp.initVars(conf)
# XXX This is hacky. We need to find a better way.
case conf.command
of "cpp", "compiletocpp":
conf.backend = backendCpp
conf.cmd = cmdCompileToBackend
else:
discard
self.processCmdLine(passCmd2, "", conf)
if conf.command == "":
rawMessage(conf, errGenerated, "command missing")

View File

@@ -502,8 +502,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
defineSymbol(conf.symbols, "gcmarkandsweep")
of "destructors", "arc":
conf.selectedGC = gcArc
if conf.backend != backendCpp:
conf.exc = excGoto
defineSymbol(conf.symbols, "gcdestructors")
defineSymbol(conf.symbols, "gcarc")
incl conf.globalOptions, optSeqDestructors
@@ -513,8 +511,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
defineSymbol(conf.symbols, "nimV2")
of "orc":
conf.selectedGC = gcOrc
if conf.backend != backendCpp:
conf.exc = excGoto
defineSymbol(conf.symbols, "gcdestructors")
defineSymbol(conf.symbols, "gcorc")
incl conf.globalOptions, optSeqDestructors

View File

@@ -216,13 +216,20 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
# Include the current file if we're parsing a nim file
let importStmt = if d.isPureRst: "" else: "import \"$1\"\n" % [d.filename.replace("\\", "/")]
writeFile(outp, importStmt & content)
let c = if cmd.startsWith("nim <backend> "): os.getAppFilename() & " " & $conf.backend & cmd.substr("nim <backend>".len)
elif cmd.startsWith("nim "): os.getAppFilename() & cmd.substr("nim".len)
else: cmd
let c2 = c % quoteShell(outp)
rawMessage(conf, hintExecuting, c2)
if execShellCmd(c2) != status:
rawMessage(conf, errGenerated, "executing of external program failed: " & c2)
proc interpSnippetCmd(cmd: string): string =
# backward compatibility hacks; interpolation commands should explicitly use `$`
if cmd.startsWith "nim ": result = "$nim " & cmd[4..^1]
else: result = cmd
result = result.replace("$1", "$options") % [
"nim", os.getAppFilename().quoteShell,
"backend", $d.conf.backend,
"options", outp.quoteShell,
]
let cmd = cmd.interpSnippetCmd
rawMessage(conf, hintExecuting, cmd)
if execShellCmd(cmd) != status:
rawMessage(conf, errGenerated, "executing of external program failed: " & cmd)
result.emitted = initIntSet()
result.destFile = getOutFile2(conf, presentationPath(conf, filename),
outExt, htmldocsDir, false)

View File

@@ -306,13 +306,14 @@ proc isVSCompatible*(conf: ConfigRef): bool =
proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
# use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given
# for niminst support
let fullSuffix =
case conf.backend
of backendCpp, backendJs, backendObjc: "." & $conf.backend & suffix
of backendC: suffix
else:
doAssert false
""
var fullSuffix = suffix
case conf.backend
of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix
of backendC: discard
of backendInvalid:
# during parsing of cfg files; we don't know the backend yet, no point in
# guessing wrong thing
return ""
if (conf.target.hostOS != conf.target.targetOS or conf.target.hostCPU != conf.target.targetCPU) and
optCompileOnly notin conf.globalOptions:

View File

@@ -114,8 +114,10 @@ proc commandJsonScript(graph: ModuleGraph) =
let proj = changeFileExt(graph.config.projectFull, "")
extccomp.runJsonBuildInstructions(graph.config, proj)
when not defined(leanCompiler):
proc commandCompileToJS(graph: ModuleGraph) =
proc commandCompileToJS(graph: ModuleGraph) =
when defined(leanCompiler):
globalError(graph.config, unknownLineInfo, "compiler wasn't built with JS code generator")
else:
let conf = graph.config
conf.exc = excCpp
@@ -194,47 +196,65 @@ proc mainCommand*(graph: ModuleGraph) =
when false: setOutDir(conf)
if optUseNimcache in conf.globalOptions: setOutDir(conf)
template handleBackend(backend2: TBackend) =
conf.backend = backend2
conf.cmd = cmdCompileToBackend
defineSymbol(graph.config.symbols, $backend2)
case backend2
proc customizeForBackend(backend: TBackend) =
## Sets backend specific options but don't compile to backend yet in
## case command doesn't require it. This must be called by all commands.
if conf.backend == backendInvalid:
# only set if wasn't already set, to allow override via `nim c -b:cpp`
conf.backend = backend
defineSymbol(graph.config.symbols, $conf.backend)
case conf.backend
of backendC:
if conf.exc == excNone: conf.exc = excSetjmp
commandCompileToC(graph)
of backendCpp:
if conf.exc == excNone: conf.exc = excCpp
commandCompileToC(graph)
of backendObjc:
commandCompileToC(graph)
of backendObjc: discard
of backendJs:
when defined(leanCompiler):
globalError(conf, unknownLineInfo, "compiler wasn't built with JS code generator")
else:
if conf.hcrOn:
# XXX: At the moment, system.nim cannot be compiled in JS mode
# with "-d:useNimRtl". The HCR option has been processed earlier
# and it has added this define implictly, so we must undo that here.
# A better solution might be to fix system.nim
undefSymbol(conf.symbols, "useNimRtl")
commandCompileToJS(graph)
if conf.hcrOn:
# XXX: At the moment, system.nim cannot be compiled in JS mode
# with "-d:useNimRtl". The HCR option has been processed earlier
# and it has added this define implictly, so we must undo that here.
# A better solution might be to fix system.nim
undefSymbol(conf.symbols, "useNimRtl")
of backendInvalid: doAssert false
if conf.selectedGC in {gcArc, gcOrc} and conf.backend != backendCpp:
conf.exc = excGoto
var commandAlreadyProcessed = false
proc compileToBackend(backend: TBackend, cmd = cmdCompileToBackend) =
commandAlreadyProcessed = true
conf.cmd = cmd
customizeForBackend(backend)
case conf.backend
of backendC: commandCompileToC(graph)
of backendCpp: commandCompileToC(graph)
of backendObjc: commandCompileToC(graph)
of backendJs: commandCompileToJS(graph)
of backendInvalid: doAssert false
## process all backend commands
case conf.command.normalize
of "c", "cc", "compile", "compiletoc": handleBackend(backendC) # compile means compileToC currently
of "cpp", "compiletocpp": handleBackend(backendCpp)
of "objc", "compiletooc": handleBackend(backendObjc)
of "js", "compiletojs": handleBackend(backendJs)
of "c", "cc", "compile", "compiletoc": compileToBackend(backendC) # compile means compileToC currently
of "cpp", "compiletocpp": compileToBackend(backendCpp)
of "objc", "compiletooc": compileToBackend(backendObjc)
of "js", "compiletojs": compileToBackend(backendJs)
of "r": # different from `"run"`!
conf.globalOptions.incl {optRun, optUseNimcache}
handleBackend(conf.backend)
compileToBackend(backendC)
of "run":
conf.cmd = cmdRun
when hasTinyCBackend:
extccomp.setCC(conf, "tcc", unknownLineInfo)
commandCompileToC(graph)
if conf.backend notin {backendC, backendInvalid}:
rawMessage(conf, errGenerated, "'run' requires c backend, got: '$1'" % $conf.backend)
compileToBackend(backendC, cmd = cmdRun)
else:
rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc")
else: customizeForBackend(backendC) # fallback for other commands
## process all other commands
case conf.command.normalize
of "doc0":
when defined(leanCompiler):
quit "compiler wasn't built with documentation generator"
@@ -383,6 +403,7 @@ proc mainCommand*(graph: ModuleGraph) =
of "jsonscript":
conf.cmd = cmdJsonScript
commandJsonScript(graph)
elif commandAlreadyProcessed: discard # already handled
else:
rawMessage(conf, errGenerated, "invalid command: " & conf.command)

View File

@@ -223,7 +223,7 @@ type
## fields marked with '*' are subject to
## the incremental compilation mechanisms
## (+) means "part of the dependency"
backend*: TBackend
backend*: TBackend # set via `nim x` or `nim --backend:x`
target*: Target # (+)
linesCompiled*: int # all lines that have been compiled
options*: TOptions # (+)
@@ -419,7 +419,7 @@ proc newConfigRef*(): ConfigRef =
cIncludes: @[], # directories to search for included files
cLibs: @[], # directories to search for lib files
cLinkedLibs: @[], # libraries to link
backend: backendC,
backend: backendInvalid,
externalToLink: @[],
linkOptionsCmd: "",
compileOptionsCmd: @[],

View File

@@ -865,7 +865,7 @@ proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) =
of "test":
params.testCmd = n.getFieldValue.strip
if params.testCmd.len == 0:
params.testCmd = "nim <backend> -r $1" # The nim backend is auto-set in docgen.nim
params.testCmd = "$nim r --backend:$backend $options" # see `interpSnippetCmd`
else:
params.testCmd = unescape(params.testCmd)
of "status", "exitcode":

31
tests/misc/mbackend.nim Normal file
View File

@@ -0,0 +1,31 @@
#[
We can't merge this test inside a `when defined(cpp)` because some bug that was
fixed would not trigger in that case.
]#
import std/compilesettings
import std/unittest
static:
## bugfix 1: this used to CT error with: Error: unhandled exception: mimportcpp.nim(6, 18) `defined(cpp)`
doAssert defined(cpp)
doAssert querySetting(backend) == "cpp"
## checks that `--backend:c` has no side effect (ie, can be overridden by subsequent commands)
doAssert not defined(c)
doAssert not defined(js)
doAssert not defined(js)
type
std_exception {.importcpp: "std::exception", header: "<exception>".} = object
proc what(s: std_exception): cstring {.importcpp: "((char *)#.what())".}
var isThrown = false
try:
## bugfix 2: this used to CT error with: Error: only a 'ref object' can be raised
raise std_exception()
except std_exception as ex:
doAssert ex.what().len > 0
isThrown = true
doAssert isThrown

View File

@@ -1,3 +1,5 @@
# issue #13129
when defined(cpp):
{.push header: "<vector>".}
type

View File

@@ -123,6 +123,16 @@ else: # don't run twice the same test
let cmd = fmt"{nim} r --backend:{mode} --hints:off --nimcache:{nimcache} {file}"
check execCmdEx(cmd) == ("ok3\n", 0)
block: # further issues with `--backend`
let file = testsDir / "misc/mbackend.nim"
var cmd = fmt"{nim} doc -b:cpp --hints:off --nimcache:{nimcache} {file}"
check execCmdEx(cmd) == ("", 0)
cmd = fmt"{nim} check -b:c -b:cpp --hints:off --nimcache:{nimcache} {file}"
check execCmdEx(cmd) == ("", 0)
# issue https://github.com/timotheecour/Nim/issues/175
cmd = fmt"{nim} c -b:js -b:cpp --hints:off --nimcache:{nimcache} {file}"
check execCmdEx(cmd) == ("", 0)
block: # some importc tests
# issue #14314
let file = testsDir / "misc/mimportc.nim"