new cmd: nim r main [args...] to compile & run, saving binary under $nimcache/main (#13382)

* implement `nim r main` to compile and run, saving binary to $nimcache
* remove outFileAbs for now
This commit is contained in:
Timothee Cour 2020-04-23 01:02:18 -07:00 • committed by GitHub
commit 5c534b2943
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 39 additions and 16 deletions

View file

@ -75,6 +75,17 @@
- Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. - Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`.
- The `define` and `undef` pragmas have been de-deprecated. - 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
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:
```nim
nim r compiler/nim.nim --help # only compiled the first time
echo 'import os; echo getCurrentCompilerExe()' | nim r - # this works too
nim r compiler/nim.nim --fullhelp # no recompilation
nim r --nimcache:/tmp main # binary saved to /tmp/main
```
## Tool changes ## Tool changes

View file

@ -66,16 +66,22 @@ when not defined(leanCompiler):
compileProject(graph) compileProject(graph)
finishDoc2Pass(graph.config.projectName) finishDoc2Pass(graph.config.projectName)
proc setOutDir(conf: ConfigRef) =
if conf.outDir.isEmpty:
if optUseNimcache in conf.globalOptions:
conf.outDir = getNimcacheDir(conf)
else:
conf.outDir = conf.projectPath
proc commandCompileToC(graph: ModuleGraph) = proc commandCompileToC(graph: ModuleGraph) =
let conf = graph.config let conf = graph.config
setOutDir(conf)
if conf.outDir.isEmpty:
conf.outDir = conf.projectPath
if conf.outFile.isEmpty: if conf.outFile.isEmpty:
let base = conf.projectName
let targetName = if optGenDynLib in conf.globalOptions: let targetName = if optGenDynLib in conf.globalOptions:
platform.OS[conf.target.targetOS].dllFrmt % conf.projectName platform.OS[conf.target.targetOS].dllFrmt % base
else: else:
conf.projectName & platform.OS[conf.target.targetOS].exeExt base & platform.OS[conf.target.targetOS].exeExt
conf.outFile = RelativeFile targetName conf.outFile = RelativeFile targetName
extccomp.initVars(conf) extccomp.initVars(conf)
@ -181,13 +187,13 @@ proc mainCommand*(graph: ModuleGraph) =
conf.lastCmdTime = epochTime() conf.lastCmdTime = epochTime()
conf.searchPaths.add(conf.libpath) conf.searchPaths.add(conf.libpath)
setId(100) setId(100)
case conf.command.normalize template handleC() =
of "c", "cc", "compile", "compiletoc":
# compile means compileToC currently
conf.cmd = cmdCompileToC conf.cmd = cmdCompileToC
if conf.exc == excNone: conf.exc = excSetjmp if conf.exc == excNone: conf.exc = excSetjmp
defineSymbol(graph.config.symbols, "c") defineSymbol(graph.config.symbols, "c")
commandCompileToC(graph) commandCompileToC(graph)
case conf.command.normalize
of "c", "cc", "compile", "compiletoc": handleC() # compile means compileToC currently
of "cpp", "compiletocpp": of "cpp", "compiletocpp":
conf.cmd = cmdCompileToCpp conf.cmd = cmdCompileToCpp
if conf.exc == excNone: conf.exc = excCpp if conf.exc == excNone: conf.exc = excCpp
@ -197,6 +203,9 @@ proc mainCommand*(graph: ModuleGraph) =
conf.cmd = cmdCompileToOC conf.cmd = cmdCompileToOC
defineSymbol(graph.config.symbols, "objc") defineSymbol(graph.config.symbols, "objc")
commandCompileToC(graph) commandCompileToC(graph)
of "r": # different from `"run"`!
conf.globalOptions.incl {optRun, optUseNimcache}
handleC()
of "run": of "run":
conf.cmd = cmdRun conf.cmd = cmdRun
when hasTinyCBackend: when hasTinyCBackend:

View file

@ -63,7 +63,7 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
if processArgument(pass, p, argsCount, config): break if processArgument(pass, p, argsCount, config): break
if pass == passCmd2: if pass == passCmd2:
if {optRun, optWasNimscript} * config.globalOptions == {} and if {optRun, optWasNimscript} * config.globalOptions == {} and
config.arguments.len > 0 and config.command.normalize notin ["run", "e"]: config.arguments.len > 0 and config.command.normalize notin ["run", "e", "r"]:
rawMessage(config, errGenerated, errArgsNeedRunOption) rawMessage(config, errGenerated, errArgsNeedRunOption)
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =

View file

@ -57,6 +57,7 @@ type # please make sure we have under 32 options
optGenScript, # generate a script file to compile the *.c files optGenScript, # generate a script file to compile the *.c files
optGenMapping, # generate a mapping file optGenMapping, # generate a mapping file
optRun, # run the compiled project optRun, # run the compiled project
optUseNimcache, # save artifacts (including binary) in $nimcache
optStyleHint, # check that the names adhere to NEP-1 optStyleHint, # check that the names adhere to NEP-1
optStyleError, # enforce that the names adhere to NEP-1 optStyleError, # enforce that the names adhere to NEP-1
optSkipSystemConfigFile, # skip the system's cfg/nims config file optSkipSystemConfigFile, # skip the system's cfg/nims config file
@ -524,18 +525,19 @@ proc getOutFile*(conf: ConfigRef; filename: RelativeFile, ext: string): Absolute
conf.outDir / changeFileExt(filename, ext) conf.outDir / changeFileExt(filename, ext)
proc absOutFile*(conf: ConfigRef): AbsoluteFile = proc absOutFile*(conf: ConfigRef): AbsoluteFile =
if false:
doAssert not conf.outDir.isEmpty
doAssert not conf.outFile.isEmpty
# xxx: fix this pre-existing bug causing `SuccessX` error messages to lie
# for `jsonscript`
result = conf.outDir / conf.outFile result = conf.outDir / conf.outFile
when defined(posix): when defined(posix):
if dirExists(result.string): if dirExists(result.string): result.string.add ".out"
result.string.add ".out"
proc prepareToWriteOutput*(conf: ConfigRef): AbsoluteFile = proc prepareToWriteOutput*(conf: ConfigRef): AbsoluteFile =
## Create the output directory and returns a full path to the output file ## Create the output directory and returns a full path to the output file
createDir conf.outDir result = conf.absOutFile
result = conf.outDir / conf.outFile createDir result.string.parentDir
when defined(posix):
if dirExists(result.string):
result.string.add ".out"
proc getPrefixDir*(conf: ConfigRef): AbsoluteDir = proc getPrefixDir*(conf: ConfigRef): AbsoluteDir =
## Gets the prefix dir, usually the parent directory where the binary resides. ## Gets the prefix dir, usually the parent directory where the binary resides.

View file

@ -4,6 +4,7 @@
Command: Command:
//compile, c compile project with default code generator (C) //compile, c compile project with default code generator (C)
//r compile & run $nimcach/projname [arguments]
//doc generate the documentation for inputfile //doc generate the documentation for inputfile
Arguments: Arguments: