# # # Maintenance program for Nim # (c) Copyright 2017 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # See doc/koch.txt for documentation. # const NimbleStableCommit = "d13f3b8ce288b4dc8c34c219a4e050aaeaf43fc9" # master # examples of possible values: #head, #ea82b54, 1.2.3 FusionStableHash = "#372ee4313827ef9f2ea388840f7d6b46c2b1b014" HeadHash = "#head" when not defined(windows): const Z3StableCommit = "65de3f748a6812eecd7db7c478d5fc54424d368b" # the version of Z3 that DrNim uses when defined(gcc) and defined(windows): when defined(x86): {.link: "icons/koch.res".} else: {.link: "icons/koch_icon.o".} when defined(amd64) and defined(windows) and defined(vcc): {.link: "icons/koch-amd64-windows-vcc.res".} when defined(i386) and defined(windows) and defined(vcc): {.link: "icons/koch-i386-windows-vcc.res".} import std/[os, strutils, parseopt, osproc] # Using `std/os` instead of `os` to fail early if config isn't set up properly. # If this fails with: `Error: cannot open file: std/os`, see # https://github.com/nim-lang/Nim/pull/14291 for explanation + how to fix. import tools / kochdocs import tools / deps const VersionAsString = system.NimVersion const HelpText = """ +-----------------------------------------------------------------+ | Maintenance program for Nim | | Version $1| | (c) 2017 Andreas Rumpf | +-----------------------------------------------------------------+ Build time: $2, $3 Usage: koch [options] command [options for command] Options: --help, -h shows this help and quits --latest bundle the installers with bleeding edge versions of external components. --stable bundle the installers with stable versions of external components (default). --nim:path use specified path for nim binary --localdocs[:path] only build local documentations. If a path is not specified (or empty), the default is used. Possible Commands: boot [options] bootstraps with given command line options distrohelper [bindir] helper for distro packagers tools builds Nim related tools toolsNoExternal builds Nim related tools (except external tools, e.g. nimble) doesn't require network connectivity nimble builds the Nimble tool fusion installs fusion via Nimble Boot options: -d:release produce a release version of the compiler -d:nimUseLinenoise use the linenoise library for interactive mode `nim secret` (not needed on Windows) -d:leanCompiler produce a compiler without JS codegen or documentation generator in order to use less RAM for bootstrapping Commands for core developers: runCI runs continuous integration (CI), e.g. from travis docs [options] generates the full documentation csource -d:danger builds the C sources for installation pdf builds the PDF documentation zip builds the installation zip package xz builds the installation tar.xz package testinstall test tar.xz package; Unix only! installdeps [options] installs external dependency (e.g. tinyc) to dist/ tests [options] run the testsuite (run a subset of tests by specifying a category, e.g. `tests cat async`) temp options creates a temporary compiler for testing pushcsource push generated C sources to its repo Web options: --googleAnalytics:UA-... add the given google analytics code to the docs. To build the official docs, use UA-48159761-1 """ let kochExe* = when isMainModule: os.getAppFilename() # always correct when koch is main program, even if `koch` exe renamed e.g.: `nim c -o:koch_debug koch.nim` else: getAppDir() / "koch".exe # works for winrelease proc kochExec*(cmd: string) = exec kochExe.quoteShell & " " & cmd proc kochExecFold*(desc, cmd: string) = execFold(desc, kochExe.quoteShell & " " & cmd) template withDir(dir, body) = let old = getCurrentDir() try: setCurrentDir(dir) body finally: setCurrentDir(old) let origDir = getCurrentDir() setCurrentDir(getAppDir()) proc tryExec(cmd: string): bool = echo(cmd) result = execShellCmd(cmd) == 0 proc safeRemove(filename: string) = if fileExists(filename): removeFile(filename) proc overwriteFile(source, dest: string) = safeRemove(dest) moveFile(source, dest) proc copyExe(source, dest: string) = safeRemove(dest) copyFile(dest=dest, source=source) inclFilePermissions(dest, {fpUserExec, fpGroupExec, fpOthersExec}) const compileNimInst = "tools/niminst/niminst" distDir = "dist" proc csource(args: string) = nimexec(("cc $1 -r $3 --var:version=$2 --var:mingw=none csource " & "--main:compiler/nim.nim compiler/installer.ini $1") % [args, VersionAsString, compileNimInst]) proc bundleC2nim(args: string) = cloneDependency(distDir, "https://github.com/nim-lang/c2nim.
//: So far the recipes we define can't run each other. Let's change that.
:(scenario "calling_recipe")
recipe main [
f
]
recipe f [
3:integer <- add 2:literal, 2:literal
]
+mem: storing 4 in location 3
:(before "struct routine {")
// Everytime a recipe runs another, we interrupt it and start running the new
// recipe. When that finishes, we continue this one where we left off.
// This requires maintaining a 'stack' of interrupted recipes or 'calls'.
struct call {
recipe_number running_recipe;
size_t pc;
// End call Fields
call(recipe_number r) :running_recipe(r), pc(0) {}
};
typedef stack<call> call_stack;
:(replace{} "struct routine")
struct routine {
call_stack calls;
// End routine Fields
routine(recipe_number r);
};
:(code)
routine::routine(recipe_number r) {
calls.push(call(r));
}
//: now update routine's helpers
:(replace{} "inline size_t& running_at(routine& rr)")
inline size_t& running_at(routine& rr) {
return rr.calls.top().pc;
}
:(replace{} "inline string recipe_name(routine& rr)")
inline string recipe_name(routine& rr) {
return Recipe[rr.calls.top().running_recipe].name;
}
:(replace{} "inline vector<instruction>& steps(routine& rr)")
inline vector<instruction>& steps(routine& rr) {
return Recipe[rr.calls.top().running_recipe].steps;
}
:(replace{} "default:" following "End Primitive Recipe Implementations")
default: {
// not a primitive; try to look for a matching recipe
if (Recipe.find(instructions[pc].operation) == Recipe.end()) {
raise << "undefined operation " << instructions[pc].operation << ": " << instructions[pc].name << '\n';
break;
}
rr.calls.push(call(instructions[pc].operation));
continue; // not done with caller; don't increment pc
}
//: finally, we need to fix the termination conditions for the run loop
:(replace{} "inline bool done(routine& rr)")
inline bool done(routine& rr) {
return rr.calls.empty();
}
:(before "Running one instruction")
// when we reach the end of one call, we may reach the end of the one below
// it, and the one below that, and so on
while (running_at(rr) >= steps(rr).size()) {
rr.calls.pop();
if (rr.calls.empty()) return;
// todo: no results returned warning
++running_at(rr);
}
:(before "End Includes")
#include <stack>
using std::stack;