diff options
Diffstat (limited to 'koch.nim')
-rw-r--r-- | koch.nim | 296 |
1 files changed, 115 insertions, 181 deletions
diff --git a/koch.nim b/koch.nim index 2f936fc4e..d8004b3e6 100644 --- a/koch.nim +++ b/koch.nim @@ -15,6 +15,11 @@ when defined(gcc) and defined(windows): 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 os, strutils, parseopt, osproc, streams @@ -35,7 +40,6 @@ Options: --help, -h shows this help and quits Possible Commands: boot [options] bootstraps with given command line options - finish setup PATH and check for a valid GCC installation distrohelper [bindir] helper for distro packagers geninstall generate ./install.sh; Unix only! testinstall test tar.xz package; Unix only! Only for devs! @@ -50,6 +54,9 @@ Possible Commands: tests [options] run the testsuite temp options creates a temporary compiler for testing winrelease creates a release (for coredevs only) + nimble builds the Nimble tool + tools builds Nim related tools + pushcsource push generated C sources to its repo! Only for devs! Boot options: -d:release produce a release version of the compiler -d:tinyc include the Tiny C backend (not supported on Windows) @@ -89,6 +96,9 @@ proc exec(cmd: string, errorcode: int = QuitFailure, additionalPath = "") = if execShellCmd(cmd) != 0: quit("FAILURE", errorcode) putEnv("PATH", prevPath) +proc nimexec(cmd: string) = + exec findNim() & " " & cmd + proc execCleanPath(cmd: string, additionalPath = ""; errorcode: int = QuitFailure) = # simulate a poor man's virtual environment @@ -145,10 +155,13 @@ const compileNimInst = "tools/niminst/niminst" proc csource(args: string) = - exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=none csource --main:compiler/nim.nim compiler/installer.ini $1" % - [args, VersionAsString, compileNimInst, findNim()]) + nimexec(("cc $1 -r $3 --var:version=$2 --var:mingw=none csource " & + "--main:compiler/nim.nim compiler/installer.ini $1") % + [args, VersionAsString, compileNimInst]) proc bundleNimbleSrc() = + ## bunldeNimbleSrc() bundles a specific Nimble commit with the tarball. We + ## always bundle the latest official release. if dirExists("dist/nimble/.git"): exec("git --git-dir dist/nimble/.git pull") else: @@ -161,41 +174,77 @@ proc bundleNimbleExe() = bundleNimbleSrc() # now compile Nimble and copy it to $nim/bin for the installer.ini # to pick it up: - exec(findNim() & " c dist/nimble/src/nimble.nim") + nimexec("c dist/nimble/src/nimble.nim") copyExe("dist/nimble/src/nimble".exe, "bin/nimble".exe) -proc bundleNimsuggest(buildExe: bool) = - if dirExists("dist/nimsuggest/.git"): - exec("git --git-dir dist/nimsuggest/.git pull") +proc buildNimble() = + ## buildNimble() builds Nimble for the building via "github". As such, we + ## choose the most recent commit of Nimble too. + var installDir = "dist/nimble" + if dirExists("dist/nimble/.git"): + exec("git --git-dir dist/nimble/.git pull") else: - exec("git clone https://github.com/nim-lang/nimsuggest.git dist/nimsuggest") + # if dist/nimble exist, but is not a git repo, don't mess with it: + if dirExists(installDir): + var id = 0 + while dirExists("dist/nimble" & $id): + inc id + installDir = "dist/nimble" & $id + exec("git clone https://github.com/nim-lang/nimble.git " & installDir) + nimexec("c " & installDir / "src/nimble.nim") + copyExe(installDir / "src/nimble".exe, "bin/nimble".exe) + +proc bundleNimsuggest(buildExe: bool) = if buildExe: - exec(findNim() & " c --noNimblePath -p:compiler dist/nimsuggest/nimsuggest.nim") - copyExe("dist/nimsuggest/nimsuggest".exe, "bin/nimsuggest".exe) + nimexec("c --noNimblePath -d:release -p:compiler tools/nimsuggest/nimsuggest.nim") + copyExe("tools/nimsuggest/nimsuggest".exe, "bin/nimsuggest".exe) + removeFile("tools/nimsuggest/nimsuggest".exe) + +proc bundleWinTools() = + nimexec("c tools/finish.nim") + copyExe("tools/finish".exe, "finish".exe) + removeFile("tools/finish".exe) + nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe") proc zip(args: string) = bundleNimbleSrc() bundleNimsuggest(false) - exec("$3 cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" % - [VersionAsString, compileNimInst, findNim()]) + bundleWinTools() + nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" % + [VersionAsString, compileNimInst]) exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim zip compiler/installer.ini" % ["tools/niminst/niminst".exe, VersionAsString]) proc xz(args: string) = bundleNimbleSrc() bundleNimsuggest(false) - exec("$3 cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" % - [VersionAsString, compileNimInst, findNim()]) + nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" % + [VersionAsString, compileNimInst]) exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim xz compiler/installer.ini" % ["tools" / "niminst" / "niminst".exe, VersionAsString]) proc buildTool(toolname, args: string) = - exec("$# cc $# $#" % [findNim(), args, toolname]) + nimexec("cc $# $#" % [args, toolname]) copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe) +proc buildTools() = + let nimsugExe = "bin/nimsuggest".exe + nimexec "c --noNimblePath -p:compiler -d:release -o:" & nimsugExe & + " tools/nimsuggest/nimsuggest.nim" + + let nimgrepExe = "bin/nimgrep".exe + nimexec "c -o:" & nimgrepExe & " tools/nimgrep.nim" + if dirExists"dist/nimble": + let nimbleExe = "bin/nimble".exe + nimexec "c --noNimblePath -p:compiler -o:" & nimbleExe & + " dist/nimble/src/nimble.nim" + else: + buildNimble() + proc nsis(args: string) = bundleNimbleExe() bundleNimsuggest(true) + bundleWinTools() # make sure we have generated the niminst executables: buildTool("tools/niminst/niminst", args) #buildTool("tools/nimgrep", args) @@ -206,17 +255,21 @@ proc nsis(args: string) = " nsis compiler/installer.ini") % [VersionAsString, $(sizeof(pointer)*8)]) proc geninstall(args="") = - exec("$# cc -r $# --var:version=$# --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini $#" % - [findNim(), compileNimInst, VersionAsString, args]) + nimexec("cc -r $# --var:version=$# --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini $#" % + [compileNimInst, VersionAsString, args]) + +proc install(args: string) = + geninstall() + exec("sh ./install.sh $#" % args) proc web(args: string) = - exec("$# js tools/dochack/dochack.nim" % findNim()) - exec("$# cc -r tools/nimweb.nim $# web/website.ini --putenv:nimversion=$#" % - [findNim(), args, VersionAsString]) + nimexec("js tools/dochack/dochack.nim") + nimexec("cc -r tools/nimweb.nim $# web/website.ini --putenv:nimversion=$#" % + [args, VersionAsString]) proc website(args: string) = - exec("$# cc -r tools/nimweb.nim $# --website web/website.ini --putenv:nimversion=$#" % - [findNim(), args, VersionAsString]) + nimexec("cc -r tools/nimweb.nim $# --website web/website.ini --putenv:nimversion=$#" % + [args, VersionAsString]) proc pdf(args="") = exec("$# cc -r tools/nimweb.nim $# --pdf web/website.ini --putenv:nimversion=$#" % @@ -255,7 +308,7 @@ proc boot(args: string) = var finalDest = "bin" / "nim".exe # default to use the 'c' command: let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: "" - let smartNimcache = if "release" in args: "rnimcache" else: "dnimcache" + let smartNimcache = if "release" in args: "nimcache/release" else: "nimcache/debug" copyExe(findStartNim(), 0.thVersion) for i in 0..2: @@ -306,7 +359,6 @@ proc removePattern(pattern: string) = removeFile(f) proc clean(args: string) = - if existsFile("koch.dat"): removeFile("koch.dat") removePattern("web/*.html") removePattern("doc/*.html") cleanAux(getCurrentDir()) @@ -320,159 +372,6 @@ proc clean(args: string) = proc winRelease() = exec(r"call ci\nsis_build.bat " & VersionAsString) -# -------------- post unzip steps --------------------------------------------- - -when defined(windows): - import registry - - proc askBool(m: string): bool = - stdout.write m - while true: - let answer = stdin.readLine().normalize - case answer - of "y", "yes": - return true - of "n", "no": - return false - else: - echo "Please type 'y' or 'n'" - - proc askNumber(m: string; a, b: int): int = - stdout.write m - stdout.write " [" & $a & ".." & $b & "] " - while true: - let answer = stdin.readLine() - try: - result = parseInt answer - if result < a or result > b: - raise newException(ValueError, "number out of range") - break - except ValueError: - echo "Please type in a number between ", a, " and ", b - - proc patchConfig(mingw: string) = - const - cfgFile = "config/nim.cfg" - lookFor = """#gcc.path = r"$nim\dist\mingw\bin"""" - replacePattern = """gcc.path = r"$1"""" - try: - let cfg = readFile(cfgFile) - let newCfg = cfg.replace(lookFor, replacePattern % mingw) - if newCfg == cfg: - echo "Could not patch 'config/nim.cfg' [Error]" - echo "Reason: patch substring not found:" - echo lookFor - else: - writeFile(cfgFile, newCfg) - except IOError: - echo "Could not access 'config/nim.cfg' [Error]" - - proc addToPathEnv(e: string) = - let p = getUnicodeValue(r"Environment", "Path", HKEY_CURRENT_USER) - let x = if e.contains(Whitespace): "\"" & e & "\"" else: e - setUnicodeValue(r"Environment", "Path", p & ";" & x, HKEY_CURRENT_USER) - - proc createShortcut(src, dest: string; icon = "") = - var cmd = "bin\\makelink.exe \"" & src & "\" \"\" \"" & dest & - ".lnk\" \"\" 1 \"" & splitFile(src).dir & "\"" - if icon.len != 0: - cmd.add " \"" & icon & "\" 0" - discard execShellCmd(cmd) - - proc createStartMenuEntry() = - let appdata = getEnv("APPDATA") - if appdata.len == 0: return - let dest = appdata & r"\Microsoft\Windows\Start Menu\Programs\Nim-" & - VersionAsString - if dirExists(dest): return - if askBool("Would like to add Nim-" & VersionAsString & - " to your start menu? (y/n) "): - createDir(dest) - createShortcut(getCurrentDir() / "start.bat", dest / "Nim", - getCurrentDir() / r"icons\nim.ico") - if fileExists("doc/overview.html"): - createShortcut(getCurrentDir() / "doc" / "overview.html", - dest / "Overview") - if dirExists(r"dist\aporia-0.4.0"): - createShortcut(getCurrentDir() / r"dist\aporia-0.4.0\bin\aporia.exe", - dest / "Aporia") - - proc checkGccArch(mingw: string): bool = - let gccExe = mingw / r"gcc.exe" - if fileExists(gccExe): - try: - let arch = execProcess(gccExe, ["-dumpmachine"], nil, {poStdErrToStdOut, - poUsePath}) - when hostCPU == "i386": - result = arch.startsWith("i686-") - elif hostCPU == "amd64": - result = arch.startsWith("x86_64-") - else: - {.error: "Unknown CPU for Windows.".} - except OSError, IOError: - result = false - - proc tryDirs(dirs: varargs[string]): string = - let bits = $(sizeof(pointer)*8) - for d in dirs: - if dirExists d: - let x = expandFilename(d / "bin") - if checkGccArch(x): return x - elif dirExists(d & bits): - let x = expandFilename((d & bits) / "bin") - if checkGccArch(x): return x - -proc finish() = - when defined(windows): - let desiredPath = expandFilename(getCurrentDir() / "bin") - let p = getUnicodeValue(r"Environment", "Path", - HKEY_CURRENT_USER) - var alreadyInPath = false - var mingWchoices: seq[string] = @[] - for x in p.split(';'): - let y = expandFilename(if x[0] == '"' and x[^1] == '"': - substr(x, 1, x.len-2) else: x) - if y == desiredPath: alreadyInPath = true - if y.toLowerAscii.contains("mingw"): - if dirExists(y) and checkGccArch(y): - mingWchoices.add y - - if alreadyInPath: - echo "bin/nim.exe is already in your PATH [Skipping]" - else: - if askBool("nim.exe is not in your PATH environment variable.\n" & - " Should it be added permanently? (y/n) "): - addToPathEnv(desiredPath) - if mingWchoices.len == 0: - # No mingw in path, so try a few locations: - let alternative = tryDirs("dist/mingw", "../mingw", r"C:\mingw") - if alternative.len == 0: - echo "No MingW found in PATH and no candidate found " & - " in the standard locations [Error]" - else: - if askBool("Found a MingW directory that is not in your PATH.\n" & - alternative & - "\nShould it be added to your PATH permanently? (y/n) "): - addToPathEnv(alternative) - elif askBool("Do you want to patch Nim's config to use this? (y/n) "): - patchConfig(alternative) - elif mingWchoices.len == 1: - if askBool("MingW installation found at " & mingWchoices[0] & "\n" & - "Do you want to patch Nim's config to use this?\n" & - "(Not required since it's in your PATH!) (y/n) "): - patchConfig(mingWchoices[0]) - else: - echo "Multiple MingW installations found: " - for i in 0..high(mingWchoices): - echo "[", i, "] ", mingWchoices[i] - if askBool("Do you want to patch Nim's config to use one of these? (y/n) "): - let idx = askNumber("Which one do you want to use for Nim? ", - 1, len(mingWchoices)) - patchConfig(mingWchoices[idx-1]) - createStartMenuEntry() - else: - echo("Add ", getCurrentDir(), "/bin to your PATH...") - # -------------- tests -------------------------------------------------------- template `|`(a, b): string = (if a.len > 0: a else: b) @@ -480,11 +379,10 @@ template `|`(a, b): string = (if a.len > 0: a else: b) proc tests(args: string) = # we compile the tester with taintMode:on to have a basic # taint mode test :-) - let nimexe = findNim() - exec nimexe & " cc --taintMode:on tests/testament/tester" + nimexec "cc --taintMode:on tests/testament/tester" # Since tests take a long time (on my machine), and we want to defy Murhpys # law - lets make sure the compiler really is freshly compiled! - exec nimexe & " c --lib:lib -d:release --opt:speed compiler/nim.nim" + nimexec "c --lib:lib -d:release --opt:speed compiler/nim.nim" let tester = quoteShell(getCurrentDir() / "tests/testament/tester".exe) let success = tryExec tester & " " & (args|"all") if not existsEnv("TRAVIS") and not existsEnv("APPVEYOR"): @@ -501,6 +399,38 @@ proc temp(args: string) = copyExe(output, finalDest) if args.len > 0: exec(finalDest & " " & args) +proc copyDir(src, dest: string) = + for kind, path in walkDir(src, relative=true): + case kind + of pcDir: copyDir(dest / path, src / path) + of pcFile: + createDir(dest) + copyFile(src / path, dest / path) + else: discard + +proc pushCsources() = + if not dirExists("../csources/.git"): + quit "[Error] no csources git repository found" + csource("-d:release") + let cwd = getCurrentDir() + try: + copyDir("build/c_code", "../csources/c_code") + copyFile("build/build.sh", "../csources/build.sh") + copyFile("build/build.bat", "../csources/build.bat") + copyFile("build/build64.bat", "../csources/build64.bat") + copyFile("build/makefile", "../csources/makefile") + + setCurrentDir("../csources") + for kind, path in walkDir("c_code"): + if kind == pcDir: + exec("git add " & path / "*.c") + exec("git commit -am \"updated csources to version " & NimVersion & "\"") + exec("git push origin master") + exec("git tag -am \"Version $1\" v$1" % NimVersion) + exec("git push origin v$1" % NimVersion) + finally: + setCurrentDir(cwd) + proc showHelp() = quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)), CompileDate, CompileTime], QuitSuccess) @@ -512,9 +442,9 @@ of cmdLongOption, cmdShortOption: showHelp() of cmdArgument: case normalize(op.key) of "boot": boot(op.cmdLineRest) - of "finish": finish() of "clean": clean(op.cmdLineRest) of "web": web(op.cmdLineRest) + of "doc", "docs": web("--onlyDocs " & op.cmdLineRest) of "json2": web("--json2 " & op.cmdLineRest) of "website": website(op.cmdLineRest & " --googleAnalytics:UA-48159761-1") of "web0": @@ -527,9 +457,13 @@ of cmdArgument: of "nsis": nsis(op.cmdLineRest) of "geninstall": geninstall(op.cmdLineRest) of "distrohelper": geninstall() + of "install": install(op.cmdLineRest) of "testinstall": testUnixInstall() of "test", "tests": tests(op.cmdLineRest) of "temp": temp(op.cmdLineRest) of "winrelease": winRelease() + of "nimble": buildNimble() + of "tools": buildTools() + of "pushcsource", "pushcsources": pushCsources() else: showHelp() of cmdEnd: showHelp() |