summary refs log tree commit diff stats
path: root/koch.nim
diff options
context:
space:
mode:
Diffstat (limited to 'koch.nim')
-rw-r--r--koch.nim296
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()