From 63a75bce4ee36ad2e09ff4957408c7f49e319c2a Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Wed, 24 Jun 2020 12:24:15 -0500 Subject: [PATCH] No more includes in build --- nimterop/build.nim | 129 +++++----------------------------- nimterop/build/ccompiler.nim | 2 + nimterop/build/conan.nim | 6 ++ nimterop/build/getheader.nim | 7 +- nimterop/build/jbb.nim | 6 ++ nimterop/build/nimconf.nim | 6 ++ nimterop/build/shell.nim | 85 ++++++++++++++++------ nimterop/build/tools.nim | 22 +++--- nimterop/cimport.nim | 1 - nimterop/globals.nim | 20 ++++-- nimterop/paths.nim | 2 +- nimterop/setup.nim | 3 +- nimterop/toast.nim | 10 ++- nimterop/toastlib/getters.nim | 3 +- nimterop/treesitter/cpp.nim | 3 +- 15 files changed, 144 insertions(+), 161 deletions(-) diff --git a/nimterop/build.nim b/nimterop/build.nim index 672cb58..3a73f56 100644 --- a/nimterop/build.nim +++ b/nimterop/build.nim @@ -1,130 +1,39 @@ -import hashes, osproc, sets, strformat, strutils - when not defined(TOAST): - import macros, tables - -import os except findExe, sleep + import os except findExe, sleep +else: + import os export extractFilename, `/` -# build specific debug since we cannot import globals (yet) -var - gDebug* = false - gDebugCT* {.compileTime.} = false - gNimExe* = "" - # Misc helpers - -proc sanitizePath*(path: string, noQuote = false, sep = $DirSep): string = - result = path.multiReplace([("\\\\", sep), ("\\", sep), ("/", sep)]) - if not noQuote: - result = result.quoteShell - -proc getCurrentNimCompiler*(): string = - when nimvm: - result = getCurrentCompilerExe() - when defined(nimsuggest): - result = result.replace("nimsuggest", "nim") - else: - result = gNimExe - -template fixOutDir() {.dirty, used.} = - let - outdir = if outdir.isAbsolute(): outdir else: getProjectDir() / outdir - -proc compareVersions*(ver1, ver2: string): int = - ## Compare two version strings x.y.z and return -1, 0, 1 - ## - ## ver1 < ver2 = -1 - ## ver1 = ver2 = 0 - ## ver1 > ver2 = 1 - let - ver1seq = ver1.replace("-", "").split('.') - ver2seq = ver2.replace("-", "").split('.') - for i in 0 ..< ver1seq.len: - let - p1 = ver1seq[i] - p2 = if i < ver2seq.len: ver2seq[i] else: "0" - - try: - let - h1 = p1.parseHexInt() - h2 = p2.parseHexInt() - - if h1 < h2: return -1 - elif h1 > h2: return 1 - except ValueError: - if p1 < p2: return -1 - elif p1 > p2: return 1 - -proc fixCmd(cmd: string): string = - when defined(Windows): - # Replace 'cd d:\abc' with 'd: && cd d:\abc` - var filteredCmd = cmd - if cmd.toLower().startsWith("cd"): - var - colonIndex = cmd.find(":") - driveLetter = cmd.substr(colonIndex-1, colonIndex) - if (driveLetter[0].isAlphaAscii() and - driveLetter[1] == ':' and - colonIndex == 4): - filteredCmd = &"{driveLetter} && {cmd}" - result = "cmd /c " & filteredCmd - elif defined(posix): - result = cmd - else: - doAssert false +import "."/build/misc +export misc # Nim cfg file related functionality -include "."/build/nimconf - -proc getNimteropCacheDir(): string = - # Get location to cache all nimterop artifacts - result = getNimcacheDir() / "nimterop" +import "."/build/nimconf +export nimconf # Functionality shelled out to external executables -include "."/build/shell - -proc getProjectCacheDir*(name: string, forceClean = true): string = - ## Get a cache directory where all nimterop artifacts can be stored - ## - ## Projects can use this location to download source code and build binaries - ## that can be then accessed by multiple apps. This is created under the - ## per-user Nim cache directory. - ## - ## Use `name` to specify the subdirectory name for a project. - ## - ## `forceClean` is enabled by default and effectively deletes the folder - ## if Nim is compiled with the `-f` or `--forceBuild` flag. This allows - ## any project to start out with a clean cache dir on a forced build. - ## - ## NOTE: avoid calling `getProjectCacheDir()` multiple times on the same - ## `name` when `forceClean = true` else checked out source might get deleted - ## at the wrong time during build. - ## - ## E.g. - ## `nimgit2` downloads `libgit2` source so `name = "libgit2"` - ## - ## `nimarchive` downloads `libarchive`, `bzlib`, `liblzma` and `zlib` so - ## `name = "nimarchive" / "libarchive"` for `libarchive`, etc. - result = getNimteropCacheDir() / name - - if forceClean and compileOption("forceBuild"): - echo "# Removing " & result - rmDir(result) +import "."/build/shell +export shell # C compiler support -include "."/build/ccompiler +import "."/build/ccompiler +export ccompiler when not defined(TOAST): # configure, cmake, make support - include "."/build/tools + import "."/build/tools + export tools # Conan.io support - include "."/build/conan + import "."/build/conan + export conan # Julia BinaryBuilder.org support - include "."/build/jbb + import "."/build/jbb + export jbb # getHeader support - include "."/build/getheader + import "."/build/getheader + export getheader diff --git a/nimterop/build/ccompiler.nim b/nimterop/build/ccompiler.nim index c33c94a..550e1b2 100644 --- a/nimterop/build/ccompiler.nim +++ b/nimterop/build/ccompiler.nim @@ -1,5 +1,7 @@ import os, strformat, strutils +import "."/shell + proc getCompilerMode*(path: string): string = ## Determines a target language mode from an input filename, if one is not already specified. let file = path.splitFile() diff --git a/nimterop/build/conan.nim b/nimterop/build/conan.nim index 3430752..31e7f26 100644 --- a/nimterop/build/conan.nim +++ b/nimterop/build/conan.nim @@ -1,5 +1,7 @@ import os, strformat, strutils, tables +import "."/[ccompiler, misc, nimconf, shell] + when (NimMajor, NimMinor, NimPatch) < (1, 2, 0): import marshal else: @@ -77,6 +79,10 @@ proc jsonGet(url: string): JsonNode = discard rmFile(file) +template fixOutDir() {.dirty.} = + let + outdir = if outdir.isAbsolute(): outdir else: getProjectDir() / outdir + proc `==`*(pkg1, pkg2: ConanPackage): bool = ## Check if two ConanPackage objects are equal (not pkg1.isNil and not pkg2.isNil and diff --git a/nimterop/build/getheader.nim b/nimterop/build/getheader.nim index 216b599..8bb13fd 100644 --- a/nimterop/build/getheader.nim +++ b/nimterop/build/getheader.nim @@ -1,4 +1,9 @@ -import macros, os, strutils, tables +import macros, strformat, strutils, tables + +import os except findExe + +import ".."/globals +import "."/[ccompiler, conan, jbb, nimconf, shell, tools] var gDefines {.compileTime.} = initTable[string, string]() diff --git a/nimterop/build/jbb.nim b/nimterop/build/jbb.nim index 15bc578..cb48a27 100644 --- a/nimterop/build/jbb.nim +++ b/nimterop/build/jbb.nim @@ -1,5 +1,7 @@ import json, os, strformat, strutils, tables +import "."/[ccompiler, nimconf, shell] + when (NimMajor, NimMinor, NimPatch) < (1, 2, 0): import marshal @@ -27,6 +29,10 @@ var # Reuse dependencies already downloaded gJBBRequires {.compileTime.}: Table[string, JBBPackage] +template fixOutDir() {.dirty.} = + let + outdir = if outdir.isAbsolute(): outdir else: getProjectDir() / outdir + proc `==`*(pkg1, pkg2: JBBPackage): bool = ## Check if two JBBPackage objects are equal (not pkg1.isNil and not pkg2.isNil and diff --git a/nimterop/build/nimconf.nim b/nimterop/build/nimconf.nim index c87a60f..70e47a3 100644 --- a/nimterop/build/nimconf.nim +++ b/nimterop/build/nimconf.nim @@ -1,5 +1,7 @@ import json, os, osproc, sets, strformat, strutils +import "."/misc + when nimvm: when (NimMajor, NimMinor, NimPatch) >= (1, 2, 0): import std/compilesettings @@ -227,3 +229,7 @@ proc getOutDir*(projectDir = ""): string = let cfg = getNimConfig(projectDir) result = cfg.outDir + +proc getNimteropCacheDir*(): string = + ## Get location to cache all nimterop artifacts + result = getNimcacheDir() / "nimterop" diff --git a/nimterop/build/shell.nim b/nimterop/build/shell.nim index bc07285..7f84db3 100644 --- a/nimterop/build/shell.nim +++ b/nimterop/build/shell.nim @@ -1,15 +1,25 @@ -import os, strformat, strutils +import hashes, osproc, sets, strformat, strutils -proc sleep*(milsecs: int) = - ## Sleep at compile time - let - cmd = - when defined(Windows): - "cmd /c timeout " - else: - "sleep " +when not defined(TOAST): + import os except findExe, sleep +else: + import os - discard gorgeEx(cmd & $(milsecs / 1000)) +import "."/[misc, nimconf] + +when not defined(TOAST): + proc sleep*(milsecs: int) = + ## Sleep at compile time + let + cmd = + when defined(Windows): + "cmd /c timeout " + else: + "sleep " + + discard gorgeEx(cmd & $(milsecs / 1000)) +else: + export sleep proc execAction*(cmd: string, retry = 0, die = true, cache = false, cacheKey = "", onRetry: proc() = nil): tuple[output: string, ret: int] = @@ -73,20 +83,23 @@ proc execAction*(cmd: string, retry = 0, die = true, cache = false, doAssert false, "Command failed: " & $result.ret & "\ncmd: " & ccmd & "\nresult:\n" & result.output -proc findExe*(exe: string): string = - ## Find the specified executable using the `which`/`where` command - supported - ## at compile time - var - cmd = - when defined(Windows): - "where " & exe - else: - "which " & exe +when not defined(TOAST): + proc findExe*(exe: string): string = + ## Find the specified executable using the `which`/`where` command - supported + ## at compile time + var + cmd = + when defined(Windows): + "where " & exe + else: + "which " & exe - (output, ret) = execAction(cmd, die = false) + (output, ret) = execAction(cmd, die = false) - if ret == 0: - return output.splitLines()[0].strip().sanitizePath + if ret == 0: + return output.splitLines()[0].strip().sanitizePath +else: + export findExe proc mkDir*(dir: string) = ## Create a directory at compile time @@ -465,3 +478,31 @@ proc getNumProcs*(): string = execAction("sysctl -n hw.ncpu").output.strip() else: "1" + +proc getProjectCacheDir*(name: string, forceClean = true): string = + ## Get a cache directory where all nimterop artifacts can be stored + ## + ## Projects can use this location to download source code and build binaries + ## that can be then accessed by multiple apps. This is created under the + ## per-user Nim cache directory. + ## + ## Use `name` to specify the subdirectory name for a project. + ## + ## `forceClean` is enabled by default and effectively deletes the folder + ## if Nim is compiled with the `-f` or `--forceBuild` flag. This allows + ## any project to start out with a clean cache dir on a forced build. + ## + ## NOTE: avoid calling `getProjectCacheDir()` multiple times on the same + ## `name` when `forceClean = true` else checked out source might get deleted + ## at the wrong time during build. + ## + ## E.g. + ## `nimgit2` downloads `libgit2` source so `name = "libgit2"` + ## + ## `nimarchive` downloads `libarchive`, `bzlib`, `liblzma` and `zlib` so + ## `name = "nimarchive" / "libarchive"` for `libarchive`, etc. + result = getNimteropCacheDir() / name + + if forceClean and compileOption("forceBuild"): + echo "# Removing " & result + rmDir(result) diff --git a/nimterop/build/tools.nim b/nimterop/build/tools.nim index c6a4283..5be1f4b 100644 --- a/nimterop/build/tools.nim +++ b/nimterop/build/tools.nim @@ -1,20 +1,16 @@ -import os, strformat, strutils +import strformat, strutils -type - BuildType* = enum - btAutoconf, btCmake +import os except findExe - BuildStatus = object - built: bool - buildPath: string - error: string +import ".."/globals +import "."/[misc, shell] proc echoDebug(str: string) = let str = "\n# " & str.strip().replace("\n", "\n# ") - when nimvm: - if gDebugCT: echo str + when defined(TOAST): + if gState.debug: echo str else: - if gDebug: echo str + if gStateCT.debug: echo str proc configure*(path, check: string, flags = "") = ## Run the GNU `configure` command to generate all Makefiles or other @@ -208,7 +204,7 @@ proc make*(path, check: string, flags = "", regex = false) = doAssert findFile(check, path, regex = regex).len != 0, "make failed" -proc buildWithCmake(outdir, flags: string): BuildStatus = +proc buildWithCmake*(outdir, flags: string): BuildStatus = if not fileExists(outdir / "Makefile"): if fileExists(outdir / "CMakeLists.txt"): if findExe("cmake").len != 0: @@ -238,7 +234,7 @@ proc buildWithCmake(outdir, flags: string): BuildStatus = else: result.buildPath = outdir -proc buildWithAutoConf(outdir, flags: string): BuildStatus = +proc buildWithAutoConf*(outdir, flags: string): BuildStatus = if not fileExists(outdir / "Makefile"): if findExe("bash").len != 0: for file in @["configure", "configure.ac", "configure.in", "autogen.sh", "build/autogen.sh"]: diff --git a/nimterop/cimport.nim b/nimterop/cimport.nim index c81c35b..38a75e7 100644 --- a/nimterop/cimport.nim +++ b/nimterop/cimport.nim @@ -376,7 +376,6 @@ proc cSearchPath*(path: string): string {.compileTime.}= proc cDebug*() {.compileTime.} = ## Enable debug messages and display the generated Nim code gStateCT.debug = true - build.gDebugCT = true proc cDisableCaching*() {.compileTime.} = ## Disable caching of generated Nim code - useful during wrapper development diff --git a/nimterop/globals.nim b/nimterop/globals.nim index fa8f8de..e8117c8 100644 --- a/nimterop/globals.nim +++ b/nimterop/globals.nim @@ -7,7 +7,7 @@ when defined(TOAST): import compiler/[ast, idents, modulegraphs, options] - import "."/treesitter/api + # import "."/treesitter/api type Feature* = enum @@ -78,6 +78,21 @@ type pluginSource*: string # `cPlugin()` generated code to write to plugin file from searchDirs*: seq[string] # `cSearchPath()` added directories for header search + BuildType* = enum + btAutoconf, btCmake + + BuildStatus* = object + built*: bool + buildPath*: string + error*: string + +when nimvm: + var + gStateCT* {.compileTime, used.} = new(State) +else: + var + gState*: State + when defined(TOAST): const gAtoms* {.used.} = @[ @@ -119,9 +134,6 @@ when defined(TOAST): template decho*(args: varargs[string, `$`]): untyped = if gState.debug: gecho join(args, "").getCommented() -else: - var - gStateCT* {.compileTime, used.} = new(State) template nBl*(s: typed): untyped {.used.} = (s.len != 0) diff --git a/nimterop/paths.nim b/nimterop/paths.nim index fa245b3..b336d46 100644 --- a/nimterop/paths.nim +++ b/nimterop/paths.nim @@ -1,6 +1,6 @@ import os -import "."/build +import "."/build/shell const cacheDir* = getProjectCacheDir("nimterop", forceClean = false) diff --git a/nimterop/setup.nim b/nimterop/setup.nim index 3f16dd7..998d9e9 100644 --- a/nimterop/setup.nim +++ b/nimterop/setup.nim @@ -1,6 +1,7 @@ import os, strutils -import "."/[build, paths] +import "."/[paths] +import "."/build/[shell] proc treesitterSetup*() = gitPull("https://github.com/tree-sitter/tree-sitter", cacheDir / "treesitter", """ diff --git a/nimterop/toast.nim b/nimterop/toast.nim index b7a993a..e888e30 100644 --- a/nimterop/toast.nim +++ b/nimterop/toast.nim @@ -2,10 +2,12 @@ import os, osproc, sets, strformat, strutils, tables, times import "."/treesitter/[api, c, cpp] -import "."/[build, globals] +import "."/[globals] import "."/toastlib/[ast2, getters, tshelp] +import "."/build/[ccompiler, misc] + proc process(gState: State, path: string) = doAssert existsFile(path), &"Invalid path {path}" @@ -54,7 +56,7 @@ proc main( ) = # Setup global state with arguments - var gState = State( + gState = State( convention: convention, debug: debug, defines: defines, @@ -76,10 +78,6 @@ proc main( symOverride: symOverride ) - # Set gDebug in build.nim - build.gDebug = gState.debug - build.gNimExe = gState.nim - # Split some arguments with , gState.symOverride = gState.symOverride.getSplitComma() gState.prefix = gState.prefix.getSplitComma() diff --git a/nimterop/toastlib/getters.nim b/nimterop/toastlib/getters.nim index 0c1b784..c3f48ae 100644 --- a/nimterop/toastlib/getters.nim +++ b/nimterop/toastlib/getters.nim @@ -2,7 +2,8 @@ import dynlib, macros, os, sequtils, sets, strformat, strutils, tables, times import regex -import ".."/[build, globals, plugin] +import ".."/[globals, plugin] +import ".."/build/[ccompiler, misc, nimconf, shell] const gReserved = """ addr and as asm diff --git a/nimterop/treesitter/cpp.nim b/nimterop/treesitter/cpp.nim index 2fe3128..4f5be17 100644 --- a/nimterop/treesitter/cpp.nim +++ b/nimterop/treesitter/cpp.nim @@ -1,6 +1,7 @@ import strutils, os -import ".."/[build, setup, paths] +import ".."/[setup, paths] +import ".."/build/shell static: treesitterCppSetup()