summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorTimothee Cour <timothee.cour2@gmail.com>2020-04-23 01:02:18 -0700
committerGitHub <noreply@github.com>2020-04-23 10:02:18 +0200
commit5c534b2943145106db99212fb9bb75fde289b6f5 (patch)
treec62bed2a203a1cced3b3bee1d7eeafdea95273ea
parent4b43d42b98518e7b6cf66d00932394e7fa0a8ab4 (diff)
downloadNim-5c534b2943145106db99212fb9bb75fde289b6f5.tar.gz
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
-rw-r--r--changelog.md11
-rw-r--r--compiler/main.nim25
-rw-r--r--compiler/nim.nim2
-rw-r--r--compiler/options.nim16
-rw-r--r--doc/basicopt.txt1
5 files changed, 39 insertions, 16 deletions
diff --git a/changelog.md b/changelog.md
index 86d2e181c..35da0381d 100644
--- a/changelog.md
+++ b/changelog.md
@@ -75,6 +75,17 @@
 
 - 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
+  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
 
diff --git a/compiler/main.nim b/compiler/main.nim
index 1a776d516..66ae830d2 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -66,16 +66,22 @@ when not defined(leanCompiler):
     compileProject(graph)
     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) =
   let conf = graph.config
-
-  if conf.outDir.isEmpty:
-    conf.outDir = conf.projectPath
+  setOutDir(conf)
   if conf.outFile.isEmpty:
+    let base = conf.projectName
     let targetName = if optGenDynLib in conf.globalOptions:
-      platform.OS[conf.target.targetOS].dllFrmt % conf.projectName
+      platform.OS[conf.target.targetOS].dllFrmt % base
     else:
-      conf.projectName & platform.OS[conf.target.targetOS].exeExt
+      base & platform.OS[conf.target.targetOS].exeExt
     conf.outFile = RelativeFile targetName
 
   extccomp.initVars(conf)
@@ -181,13 +187,13 @@ proc mainCommand*(graph: ModuleGraph) =
   conf.lastCmdTime = epochTime()
   conf.searchPaths.add(conf.libpath)
   setId(100)
-  case conf.command.normalize
-  of "c", "cc", "compile", "compiletoc":
-    # compile means compileToC currently
+  template handleC() =
     conf.cmd = cmdCompileToC
     if conf.exc == excNone: conf.exc = excSetjmp
     defineSymbol(graph.config.symbols, "c")
     commandCompileToC(graph)
+  case conf.command.normalize
+  of "c", "cc", "compile", "compiletoc": handleC() # compile means compileToC currently
   of "cpp", "compiletocpp":
     conf.cmd = cmdCompileToCpp
     if conf.exc == excNone: conf.exc = excCpp
@@ -197,6 +203,9 @@ proc mainCommand*(graph: ModuleGraph) =
     conf.cmd = cmdCompileToOC
     defineSymbol(graph.config.symbols, "objc")
     commandCompileToC(graph)
+  of "r": # different from `"run"`!
+    conf.globalOptions.incl {optRun, optUseNimcache}
+    handleC()
   of "run":
     conf.cmd = cmdRun
     when hasTinyCBackend:
diff --git a/compiler/nim.nim b/compiler/nim.nim
index 997888cb8..7fe0db5cf 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -63,7 +63,7 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
       if processArgument(pass, p, argsCount, config): break
   if pass == passCmd2:
     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)
 
 proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
diff --git a/compiler/options.nim b/compiler/options.nim
index 6105fcdb3..5f4372177 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -57,6 +57,7 @@ type                          # please make sure we have under 32 options
     optGenScript,             # generate a script file to compile the *.c files
     optGenMapping,            # generate a mapping file
     optRun,                   # run the compiled project
+    optUseNimcache,           # save artifacts (including binary) in $nimcache
     optStyleHint,             # check 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
@@ -524,18 +525,19 @@ proc getOutFile*(conf: ConfigRef; filename: RelativeFile, ext: string): Absolute
   conf.outDir / changeFileExt(filename, ext)
 
 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
   when defined(posix):
-    if dirExists(result.string):
-      result.string.add ".out"
+    if dirExists(result.string): result.string.add ".out"
 
 proc prepareToWriteOutput*(conf: ConfigRef): AbsoluteFile =
   ## Create the output directory and returns a full path to the output file
-  createDir conf.outDir
-  result = conf.outDir / conf.outFile
-  when defined(posix):
-    if dirExists(result.string):
-      result.string.add ".out"
+  result = conf.absOutFile
+  createDir result.string.parentDir
 
 proc getPrefixDir*(conf: ConfigRef): AbsoluteDir =
   ## Gets the prefix dir, usually the parent directory where the binary resides.
diff --git a/doc/basicopt.txt b/doc/basicopt.txt
index 1405e7b01..cc808a077 100644
--- a/doc/basicopt.txt
+++ b/doc/basicopt.txt
@@ -4,6 +4,7 @@
 
 Command:
   //compile, c                compile project with default code generator (C)
+  //r                         compile & run $nimcach/projname [arguments]
   //doc                       generate the documentation for inputfile
 
 Arguments: