mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 01:14:41 +00:00
Note that contrary to what docgen.rst currently says, the ids have
to match exactly or else most web browsers will not jump to the
intended symbol.
(cherry picked from commit 93461aee34)
418 lines
13 KiB
Nim
418 lines
13 KiB
Nim
#
|
|
#
|
|
# Nim's Runtime Library
|
|
# (c) Copyright 2015 Andreas Rumpf
|
|
#
|
|
# See the file "copying.txt", included in this
|
|
# distribution, for details about the copyright.
|
|
#
|
|
|
|
## To learn about scripting in Nim see `NimScript<nims.html>`_
|
|
|
|
# Nim's configuration system now uses Nim for scripting. This module provides
|
|
# a few things that are required for this to work.
|
|
|
|
const
|
|
buildOS* {.magic: "BuildOS".}: string = ""
|
|
## The OS this build is running on. Can be different from ``system.hostOS``
|
|
## for cross compilations.
|
|
|
|
buildCPU* {.magic: "BuildCPU".}: string = ""
|
|
## The CPU this build is running on. Can be different from ``system.hostCPU``
|
|
## for cross compilations.
|
|
|
|
template builtin = discard
|
|
|
|
# We know the effects better than the compiler:
|
|
{.push hint[XDeclaredButNotUsed]: off.}
|
|
|
|
proc listDirs*(dir: string): seq[string] =
|
|
## Lists all the subdirectories (non-recursively) in the directory `dir`.
|
|
builtin
|
|
proc listFiles*(dir: string): seq[string] =
|
|
## Lists all the files (non-recursively) in the directory `dir`.
|
|
builtin
|
|
|
|
proc removeDir(dir: string) {.
|
|
tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
|
|
proc removeFile(dir: string) {.
|
|
tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
|
|
proc moveFile(src, dest: string) {.
|
|
tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
|
|
proc moveDir(src, dest: string) {.
|
|
tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
|
|
proc copyFile(src, dest: string) {.
|
|
tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
|
|
proc copyDir(src, dest: string) {.
|
|
tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
|
|
proc createDir(dir: string) {.tags: [WriteIOEffect], raises: [OSError].} =
|
|
builtin
|
|
proc getError: string = builtin
|
|
proc setCurrentDir(dir: string) = builtin
|
|
proc getCurrentDir*(): string =
|
|
## Retrieves the current working directory.
|
|
builtin
|
|
proc rawExec(cmd: string): int {.tags: [ExecIOEffect], raises: [OSError].} =
|
|
builtin
|
|
|
|
proc warningImpl(arg, orig: string) = discard
|
|
proc hintImpl(arg, orig: string) = discard
|
|
|
|
proc paramStr*(i: int): string =
|
|
## Retrieves the ``i``'th command line parameter.
|
|
builtin
|
|
|
|
proc paramCount*(): int =
|
|
## Retrieves the number of command line parameters.
|
|
builtin
|
|
|
|
proc switch*(key: string, val="") =
|
|
## Sets a Nim compiler command line switch, for
|
|
## example ``switch("checks", "on")``.
|
|
builtin
|
|
|
|
proc warning*(name: string; val: bool) =
|
|
## Disables or enables a specific warning.
|
|
let v = if val: "on" else: "off"
|
|
warningImpl(name & ":" & v, "warning:" & name & ":" & v)
|
|
|
|
proc hint*(name: string; val: bool) =
|
|
## Disables or enables a specific hint.
|
|
let v = if val: "on" else: "off"
|
|
hintImpl(name & ":" & v, "hint:" & name & ":" & v)
|
|
|
|
proc patchFile*(package, filename, replacement: string) =
|
|
## Overrides the location of a given file belonging to the
|
|
## passed package.
|
|
## If the ``replacement`` is not an absolute path, the path
|
|
## is interpreted to be local to the Nimscript file that contains
|
|
## the call to ``patchFile``, Nim's ``--path`` is not used at all
|
|
## to resolve the filename!
|
|
##
|
|
## Example:
|
|
##
|
|
## .. code-block:: nim
|
|
##
|
|
## patchFile("stdlib", "asyncdispatch", "patches/replacement")
|
|
discard
|
|
|
|
proc getCommand*(): string =
|
|
## Gets the Nim command that the compiler has been invoked with, for example
|
|
## "c", "js", "build", "help".
|
|
builtin
|
|
|
|
proc setCommand*(cmd: string; project="") =
|
|
## Sets the Nim command that should be continued with after this Nimscript
|
|
## has finished.
|
|
builtin
|
|
|
|
proc cmpIgnoreStyle(a, b: string): int = builtin
|
|
proc cmpIgnoreCase(a, b: string): int = builtin
|
|
|
|
proc cmpic*(a, b: string): int =
|
|
## Compares `a` and `b` ignoring case.
|
|
cmpIgnoreCase(a, b)
|
|
|
|
proc getEnv*(key: string; default = ""): string {.tags: [ReadIOEffect].} =
|
|
## Retrieves the environment variable of name ``key``.
|
|
builtin
|
|
|
|
proc existsEnv*(key: string): bool {.tags: [ReadIOEffect].} =
|
|
## Checks for the existence of an environment variable named ``key``.
|
|
builtin
|
|
|
|
proc putEnv*(key, val: string) {.tags: [WriteIOEffect].} =
|
|
## Sets the value of the environment variable named ``key`` to ``val``.
|
|
builtin
|
|
|
|
proc delEnv*(key: string) {.tags: [WriteIOEffect].} =
|
|
## Deletes the environment variable named ``key``.
|
|
builtin
|
|
|
|
proc fileExists*(filename: string): bool {.tags: [ReadIOEffect].} =
|
|
## Checks if the file exists.
|
|
builtin
|
|
|
|
proc dirExists*(dir: string): bool {.
|
|
tags: [ReadIOEffect].} =
|
|
## Checks if the directory `dir` exists.
|
|
builtin
|
|
|
|
proc existsFile*(filename: string): bool =
|
|
## An alias for ``fileExists``.
|
|
fileExists(filename)
|
|
|
|
proc existsDir*(dir: string): bool =
|
|
## An alias for ``dirExists``.
|
|
dirExists(dir)
|
|
|
|
proc selfExe*(): string =
|
|
## Returns the currently running nim or nimble executable.
|
|
# TODO: consider making this as deprecated alias of `getCurrentCompilerExe`
|
|
builtin
|
|
|
|
proc toExe*(filename: string): string =
|
|
## On Windows adds ".exe" to `filename`, else returns `filename` unmodified.
|
|
(when defined(windows): filename & ".exe" else: filename)
|
|
|
|
proc toDll*(filename: string): string =
|
|
## On Windows adds ".dll" to `filename`, on Posix produces "lib$filename.so".
|
|
(when defined(windows): filename & ".dll" else: "lib" & filename & ".so")
|
|
|
|
proc strip(s: string): string =
|
|
var i = 0
|
|
while s[i] in {' ', '\c', '\L'}: inc i
|
|
result = s.substr(i)
|
|
|
|
template `--`*(key, val: untyped) =
|
|
## A shortcut for ``switch(astToStr(key), astToStr(val))``.
|
|
switch(astToStr(key), strip astToStr(val))
|
|
|
|
template `--`*(key: untyped) =
|
|
## A shortcut for ``switch(astToStr(key)``.
|
|
switch(astToStr(key), "")
|
|
|
|
type
|
|
ScriptMode* {.pure.} = enum ## Controls the behaviour of the script.
|
|
Silent, ## Be silent.
|
|
Verbose, ## Be verbose.
|
|
Whatif ## Do not run commands, instead just echo what
|
|
## would have been done.
|
|
|
|
var
|
|
mode*: ScriptMode ## Set this to influence how mkDir, rmDir, rmFile etc.
|
|
## behave
|
|
|
|
template checkError(exc: untyped): untyped =
|
|
let err = getError()
|
|
if err.len > 0: raise newException(exc, err)
|
|
|
|
template checkOsError =
|
|
checkError(OSError)
|
|
|
|
template log(msg: string, body: untyped) =
|
|
if mode in {ScriptMode.Verbose, ScriptMode.Whatif}:
|
|
echo "[NimScript] ", msg
|
|
if mode != ScriptMode.WhatIf:
|
|
body
|
|
|
|
proc rmDir*(dir: string) {.raises: [OSError].} =
|
|
## Removes the directory `dir`.
|
|
log "rmDir: " & dir:
|
|
removeDir dir
|
|
checkOsError()
|
|
|
|
proc rmFile*(file: string) {.raises: [OSError].} =
|
|
## Removes the `file`.
|
|
log "rmFile: " & file:
|
|
removeFile file
|
|
checkOsError()
|
|
|
|
proc mkDir*(dir: string) {.raises: [OSError].} =
|
|
## Creates the directory `dir` including all necessary subdirectories. If
|
|
## the directory already exists, no error is raised.
|
|
log "mkDir: " & dir:
|
|
createDir dir
|
|
checkOsError()
|
|
|
|
proc mvFile*(`from`, to: string) {.raises: [OSError].} =
|
|
## Moves the file `from` to `to`.
|
|
log "mvFile: " & `from` & ", " & to:
|
|
moveFile `from`, to
|
|
checkOsError()
|
|
|
|
proc mvDir*(`from`, to: string) {.raises: [OSError].} =
|
|
## Moves the dir `from` to `to`.
|
|
log "mvDir: " & `from` & ", " & to:
|
|
moveDir `from`, to
|
|
checkOsError()
|
|
|
|
proc cpFile*(`from`, to: string) {.raises: [OSError].} =
|
|
## Copies the file `from` to `to`.
|
|
log "cpFile: " & `from` & ", " & to:
|
|
copyFile `from`, to
|
|
checkOsError()
|
|
|
|
proc cpDir*(`from`, to: string) {.raises: [OSError].} =
|
|
## Copies the dir `from` to `to`.
|
|
log "cpDir: " & `from` & ", " & to:
|
|
copyDir `from`, to
|
|
checkOsError()
|
|
|
|
proc exec*(command: string) {.
|
|
raises: [OSError], tags: [ExecIOEffect].} =
|
|
## Executes an external process. If the external process terminates with
|
|
## a non-zero exit code, an OSError exception is raised.
|
|
##
|
|
## **Note:** If you need a version of ``exec`` that returns the exit code
|
|
## and text output of the command, you can use `system.gorgeEx
|
|
## <system.html#gorgeEx,string,string,string>`_.
|
|
log "exec: " & command:
|
|
if rawExec(command) != 0:
|
|
raise newException(OSError, "FAILED: " & command)
|
|
checkOsError()
|
|
|
|
proc exec*(command: string, input: string, cache = "") {.
|
|
raises: [OSError], tags: [ExecIOEffect].} =
|
|
## Executes an external process. If the external process terminates with
|
|
## a non-zero exit code, an OSError exception is raised.
|
|
log "exec: " & command:
|
|
let (output, exitCode) = gorgeEx(command, input, cache)
|
|
if exitCode != 0:
|
|
raise newException(OSError, "FAILED: " & command)
|
|
echo output
|
|
|
|
proc selfExec*(command: string) {.
|
|
raises: [OSError], tags: [ExecIOEffect].} =
|
|
## Executes an external command with the current nim/nimble executable.
|
|
## ``Command`` must not contain the "nim " part.
|
|
let c = selfExe() & " " & command
|
|
log "exec: " & c:
|
|
if rawExec(c) != 0:
|
|
raise newException(OSError, "FAILED: " & c)
|
|
checkOsError()
|
|
|
|
proc put*(key, value: string) =
|
|
## Sets a configuration 'key' like 'gcc.options.always' to its value.
|
|
builtin
|
|
|
|
proc get*(key: string): string =
|
|
## Retrieves a configuration 'key' like 'gcc.options.always'.
|
|
builtin
|
|
|
|
proc exists*(key: string): bool =
|
|
## Checks for the existence of a configuration 'key'
|
|
## like 'gcc.options.always'.
|
|
builtin
|
|
|
|
proc nimcacheDir*(): string =
|
|
## Retrieves the location of 'nimcache'.
|
|
builtin
|
|
|
|
proc projectName*(): string =
|
|
## Retrieves the name of the current project
|
|
builtin
|
|
|
|
proc projectDir*(): string =
|
|
## Retrieves the absolute directory of the current project
|
|
builtin
|
|
|
|
proc projectPath*(): string =
|
|
## Retrieves the absolute path of the current project
|
|
builtin
|
|
|
|
proc thisDir*(): string =
|
|
## Retrieves the directory of the current ``nims`` script file. Its path is
|
|
## obtained via ``currentSourcePath`` (although, currently,
|
|
## ``currentSourcePath`` resolves symlinks, unlike ``thisDir``).
|
|
builtin
|
|
|
|
proc cd*(dir: string) {.raises: [OSError].} =
|
|
## Changes the current directory.
|
|
##
|
|
## The change is permanent for the rest of the execution, since this is just
|
|
## a shortcut for `os.setCurrentDir()
|
|
## <os.html#setCurrentDir,string>`_ . Use the `withDir()
|
|
## <#withDir.t,string,untyped>`_ template if you want to perform a temporary change only.
|
|
setCurrentDir(dir)
|
|
checkOsError()
|
|
|
|
proc findExe*(bin: string): string =
|
|
## Searches for bin in the current working directory and then in directories
|
|
## listed in the PATH environment variable. Returns "" if the exe cannot be
|
|
## found.
|
|
builtin
|
|
|
|
template withDir*(dir: string; body: untyped): untyped =
|
|
## Changes the current directory temporarily.
|
|
##
|
|
## If you need a permanent change, use the `cd() <#cd,string>`_ proc. Usage example:
|
|
##
|
|
## .. code-block:: nim
|
|
## withDir "foo":
|
|
## # inside foo
|
|
## #back to last dir
|
|
var curDir = getCurrentDir()
|
|
try:
|
|
cd(dir)
|
|
body
|
|
finally:
|
|
cd(curDir)
|
|
|
|
|
|
proc writeTask(name, desc: string) =
|
|
if desc.len > 0:
|
|
var spaces = " "
|
|
for i in 0 ..< 20 - name.len: spaces.add ' '
|
|
echo name, spaces, desc
|
|
|
|
proc cppDefine*(define: string) =
|
|
## tell Nim that ``define`` is a C preprocessor ``#define`` and so always
|
|
## needs to be mangled.
|
|
builtin
|
|
|
|
proc stdinReadLine(): TaintedString {.
|
|
tags: [ReadIOEffect], raises: [IOError].} =
|
|
builtin
|
|
|
|
proc stdinReadAll(): TaintedString {.
|
|
tags: [ReadIOEffect], raises: [IOError].} =
|
|
builtin
|
|
|
|
proc readLineFromStdin*(): TaintedString {.raises: [IOError].} =
|
|
## Reads a line of data from stdin - blocks until \n or EOF which happens when stdin is closed
|
|
log "readLineFromStdin":
|
|
result = stdinReadLine()
|
|
checkError(EOFError)
|
|
|
|
proc readAllFromStdin*(): TaintedString {.raises: [IOError].} =
|
|
## Reads all data from stdin - blocks until EOF which happens when stdin is closed
|
|
log "readAllFromStdin":
|
|
result = stdinReadAll()
|
|
checkError(EOFError)
|
|
|
|
when not defined(nimble):
|
|
template `==?`(a, b: string): bool = cmpIgnoreStyle(a, b) == 0
|
|
template task*(name: untyped; description: string; body: untyped): untyped =
|
|
## Defines a task. Hidden tasks are supported via an empty description.
|
|
## Example:
|
|
##
|
|
## .. code-block:: nim
|
|
## task build, "default build is via the C backend":
|
|
## setCommand "c"
|
|
proc `name Task`*() =
|
|
setCommand "nop"
|
|
body
|
|
|
|
let cmd = getCommand()
|
|
if cmd.len == 0 or cmd ==? "help":
|
|
setCommand "help"
|
|
writeTask(astToStr(name), description)
|
|
elif cmd ==? astToStr(name):
|
|
`name Task`()
|
|
|
|
# nimble has its own implementation for these things.
|
|
var
|
|
packageName* = "" ## Nimble support: Set this to the package name. It
|
|
## is usually not required to do that, nims' filename is
|
|
## the default.
|
|
version*: string ## Nimble support: The package's version.
|
|
author*: string ## Nimble support: The package's author.
|
|
description*: string ## Nimble support: The package's description.
|
|
license*: string ## Nimble support: The package's license.
|
|
srcDir*: string ## Nimble support: The package's source directory.
|
|
binDir*: string ## Nimble support: The package's binary directory.
|
|
backend*: string ## Nimble support: The package's backend.
|
|
|
|
skipDirs*, skipFiles*, skipExt*, installDirs*, installFiles*,
|
|
installExt*, bin*: seq[string] = @[] ## Nimble metadata.
|
|
requiresData*: seq[string] = @[] ## Exposes the list of requirements for read
|
|
## and write accesses.
|
|
|
|
proc requires*(deps: varargs[string]) =
|
|
## Nimble support: Call this to set the list of requirements of your Nimble
|
|
## package.
|
|
for d in deps: requiresData.add(d)
|
|
|
|
{.pop.}
|