Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 289 lines (249 sloc) 9.581 kb
# Maintenance program for Nimrod
# (c) Copyright 2012 Andreas Rumpf
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
when defined(gcc) and defined(windows):
when defined(x86):
{.link: "icons/koch.res".}
{.link: "icons/koch_icon.o".}
os, strutils, parseopt, osproc, streams
when defined(withUpdate):
import httpclient
when defined(haveZipLib):
import zipfiles
HelpText = """
| Maintenance program for Nimrod |
| Version $1|
| (c) 2012 Andreas Rumpf |
Build time: $2, $3
koch [options] command [options for command]
--help, -h shows this help and quits
Possible Commands:
boot [options] bootstraps with given command line options
clean cleans Nimrod project; removes generated files
web generates the website
csource [options] builds the C sources for installation
zip builds the installation ZIP package
inno [options] builds the Inno Setup installer (for Windows)
tests run the testsuite
update updates nimrod to the latest version from github
(compile koch with -d:withUpdate to enable)
Boot options:
-d:release produce a release version of the compiler
-d:tinyc include the Tiny C backend (not supported on Windows)
-d:useGnuReadline use the GNU readline library for interactive mode
(not needed on Windows)
-d:nativeStacktrace use native stack traces (only for Mac OS X or Linux)
proc exe(f: string): string = return addFileExt(f, ExeExt)
proc exec(cmd: string) =
if execShellCmd(cmd) != 0: quit("FAILURE")
proc tryExec(cmd: string): bool =
result = execShellCmd(cmd) == 0
proc csource(args: string) =
exec("nimrod cc $1 -r tools/niminst/niminst --var:version=$2 csource compiler/nimrod.ini $1" %
[args, NimrodVersion])
proc zip(args: string) =
exec("nimrod cc -r tools/niminst/niminst --var:version=$# zip compiler/nimrod.ini" %
proc buildTool(toolname, args: string) =
exec("nimrod cc $# $#" % [args, toolname])
copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe)
proc inno(args: string) =
# make sure we have generated the c2nim and niminst executables:
buildTool("tools/niminst/niminst", args)
buildTool("tools/nimgrep", args)
buildTool("compiler/c2nim/c2nim", args)
exec("tools" / "niminst" / "niminst --var:version=$# inno compiler/nimrod" %
proc install(args: string) =
exec("sh ./")
proc web(args: string) =
exec(("nimrod cc -r tools/nimweb.nim web/nimrod --putenv:nimrodversion=$#" &
" --path:$#") % [NimrodVersion, getCurrentDir()])
# -------------- boot ---------------------------------------------------------
bootOptions = "" # options to pass to the bootstrap process
proc findStartNimrod: string =
# we try several things before giving up:
# * bin/nimrod
# * $PATH/nimrod
# If these fail, we try to build nimrod with the "build.(sh|bat)" script.
var nimrod = "nimrod".exe
result = "bin" / nimrod
if ExistsFile(result): return
for dir in split(getEnv("PATH"), PathSep):
if ExistsFile(dir / nimrod): return nimrod
when defined(Posix):
const buildScript = ""
if ExistsFile(buildScript):
if tryExec("./" & buildScript): return "bin" / nimrod
const buildScript = "build.bat"
if ExistsFile(buildScript):
if tryExec(buildScript): return "bin" / nimrod
echo("Found no nimrod compiler and every attempt to build one failed!")
proc safeRemove(filename: string) =
if existsFile(filename): removeFile(filename)
proc thVersion(i: int): string =
result = ("compiler" / "nimrod" & $i).exe
proc copyExe(source, dest: string) =
copyFile(dest=dest, source=source)
inclFilePermissions(dest, {fpUserExec})
proc boot(args: string) =
var output = "compiler" / "nimrod".exe
var finalDest = "bin" / "nimrod".exe
copyExe(findStartNimrod(), 0.thVersion)
for i in 0..2:
echo "iteration: ", i+1
exec i.thVersion & " cc $# $# compiler" / "nimrod.nim" % [bootOptions, args]
if sameFileContent(output, i.thVersion):
copyExe(output, finalDest)
echo "executables are equal: SUCCESS!"
copyExe(output, (i+1).thVersion)
copyExe(output, finalDest)
when not defined(windows): echo "[Warning] executables are still not equal"
# -------------- clean --------------------------------------------------------
cleanExt = [
".ppu", ".o", ".obj", ".dcu", ".~pas", ".~inc", ".~dsk", ".~dpr",
".map", ".tds", ".err", ".bak", ".pyc", ".exe", ".rod", ".pdb", ".idb"
ignore = [
".bzrignore", "nimrod", "nimrod.exe", "koch", "koch.exe"
proc cleanAux(dir: string) =
for kind, path in walkDir(dir):
case kind
of pcFile:
var (dir, name, ext) = splitFile(path)
if ext == "" or cleanExt.contains(ext):
if not ignore.contains(name):
echo "removing: ", path
of pcDir:
case splitPath(path).tail
of "nimcache":
echo "removing dir: ", path
of "dist", ".git": nil
else: cleanAux(path)
else: nil
proc removePattern(pattern: string) =
for f in WalkFiles(pattern):
echo "removing: ", f
proc clean(args: string) =
if ExistsFile("koch.dat"): removeFile("koch.dat")
for kind, path in walkDir(getCurrentDir() / "build"):
if kind == pcDir:
echo "removing dir: ", path
# -------------- update -------------------------------------------------------
when defined(withUpdate):
when defined(windows):
{.warning: "Windows users: Make sure to run 'koch update' in Bash.".}
proc update(args: string) =
when defined(windows):
echo("Windows users: Make sure to be running this in Bash. ",
"If you aren't, press CTRL+C now.")
var thisDir = getAppDir()
var git = findExe("git")
echo("Checking for git repo and git executable...")
if existsDir(thisDir & "/.git") and git != "":
echo("Git repo found!")
# use git to download latest source
echo("Checking for updates...")
discard startCmd(git & " fetch origin master")
var procs = startCmd(git & " diff origin/master master")
var errcode = procs.waitForExit()
var output = readLine(procs.outputStream)
if errcode == 0:
if output == "":
# No changes
echo("No update. Exiting..")
echo("Fetching updates from repo...")
var pullout = execCmdEx(git & " pull origin master")
if pullout[1] != 0:
quit("An error has occured.")
if pullout[0].startsWith("Already up-to-date."):
quit("No new changes fetched from the repo. " &
"Local branch must be ahead of it. Exiting...")
quit("An error has occured.")
echo("No repo or executable found!")
when defined(haveZipLib):
echo("Falling back.. Downloading source code from repo...")
# use dom96's httpclient to download zip
thisDir / "")
echo("Extracting source code from archive...")
var zip: TZipArchive
discard open(zip, thisDir & "/", fmRead)
extractAll(zip, thisDir & "/")
quit("Error reading archive.")
quit("No failback available. Exiting...")
echo("Starting update...")
echo("Update complete!")
# -------------- tests --------------------------------------------------------
proc tests(args: string) =
# we compile the tester with taintMode:on to have a basic
# taint mode test :-)
exec("nimrod cc --taintMode:on tests/tester")
exec(getCurrentDir() / "tests/tester".exe & " reject")
exec(getCurrentDir() / "tests/tester".exe & " compile")
exec(getCurrentDir() / "tests/tester".exe & " examples")
exec(getCurrentDir() / "tests/tester".exe & " run")
exec(getCurrentDir() / "tests/tester".exe & " merge")
proc showHelp() =
quit(HelpText % [NimrodVersion & repeatChar(44-len(NimrodVersion)),
CompileDate, CompileTime])
var op = initOptParser()
case op.kind
of cmdLongOption, cmdShortOption: showHelp()
of cmdArgument:
case normalize(op.key)
of "boot": boot(op.cmdLineRest)
of "clean": clean(op.cmdLineRest)
of "web": web(op.cmdLineRest)
of "csource": csource(op.cmdLineRest)
of "zip": zip(op.cmdLineRest)
of "inno": inno(op.cmdLineRest)
of "install": install(op.cmdLineRest)
of "test", "tests": tests(op.cmdLineRest)
of "update":
when defined(withUpdate):
quit "this Koch has not been compiled with -d:withUpdate"
else: showHelp()
of cmdEnd: showHelp()
Jump to Line
Something went wrong with that request. Please try again.