I'm not very familiar with NimScript and it uses, so forgive me if I'm totally off.
Let's say we have NimScript with some defined tasks. From what I've read, these are to be triggered like this:
nim mytask myscript.nims
which is already weird imho, since I would expect the more normal nim myscript.nims mytask
What if I'm using a shebang line like #!/usr/bin/env -S nim --hints:off ?
Obviously, in that case I cannot run it like ./myscript.nims mytask.
Any possible workaround so that I am able to do it this way? (What I'm thinking is eliminating the tasks and do it "normally" but I'm still wondering whether there is a more... proper way or if I'm missing something)
I recommend @PMunch's library, nimcr, too.
You can also define tasks in config.nims. You can list them with nim help and run them with nim taskname. You can have a config.nims in a directory (like the root of a project), or have one for your user at ~/.config/nim/config.nims
Or you can add nim e to the shebang line of your script, like:
#!/usr/bin/env nim e
echo "hello world"
I have a question for @PMunch about nimcr: is there a way to control the naming of the produced binaries so that they can be .gitignore'd without adding the filename for every script? For example, say I have a script myscript.nim with the shebang. It produces .myscript when it's compiled, which I .gitignore. Now I add myscript2.nim but then I forget to add it to the .gitignore and accidentally commit it.
If the compiled binary had a naming convention, like prepending the filename with nimcr then I could add nimcr* to the .gitignore, but I don't see a way to do this. This isn't a huge issue, but it is annoying. Is there a simple solution to this that I'm not noticing? I'm otherwise very happy with the library, thank you for it!
@hyl I use this in my gitignore for binary files:
# Ignore all
*
# Unignore all with extensions
!*.*
# Unignore all dirs
!*/
# all of your other rules
@pietroppeter I believe nim r would compile before every run, while nimcr checks whether the source file has changed since the last compilation, and if not, then it just runs the previously compiled binary.
@jyapayne Thanks! I guess that would work. I'd need to explicitly unignore any other hidden files (eg .eslintrc). Or I could put all the nimcr files in a separate dir and do it there:
nimcr/.*
Good idea, but no there is currently no way of doing this I believe. PRs welcome.
@pietroppeter, @hyl is correct here, the benefit of nimcr is that it caches the compiled file so that it doesn't have to recompile if the file hasn't changed. It also consumes all the output of Nim when compiling so stdout and stderr will stay clean and only contain your program output (as long as the compiler doesn't throw an error, at that point all the consumed data is written back to the terminal).
Oh you are right @SolitudeSF! I did not know that. This works:
#!/usr/bin/env nim r --hints:off --warnings:off
echo CompileTime
Something subtle I think I'm noticing is that running using nimcr is faster than nim r after compiling the time. Not sure why.
$ time ./myscript.nim # shebang nimcr
real 0m0.016s
user 0m0.006s
sys 0m0.006s
$ time ./myscriptr.nim # shebang nim r
real 0m0.833s
user 0m0.766s
sys 0m0.057s
Yes nimcr has taken special care to stay out of the way as much as possible. It also supports various shebang weirdness so you can pass both compiler arguments and the script can take program arguments normally.
The other big benefit of nimcr over nim r is of course the standardised output. Even if the script recompiles it doesn't write to stdout or stdin as long as it compiles correctly. This means that if you use your script within a pipe then it won't pollute your output even if you need to recompile.
#!/usr/bin/nim
import std/strutils
task mytask, "":
echo "Hello, world!"
--hints:off
if paramCount() > 1:
if paramStr(1).endsWith("nims"):
exec "nim $1 $2" % [paramStr(2), paramStr(1)]