Improve errors - don't point to macros.nim
This commit is contained in:
parent
f543124d7e
commit
a28c3e7cb4
5 changed files with 84 additions and 71 deletions
|
|
@ -33,6 +33,12 @@ https://github.com/nimterop/nimterop/compare/v0.5.9...v0.6.0
|
||||||
|
|
||||||
- `gitPull()` now checks if an existing repository is at the `checkout` value specified. If not, it will pull the latest changes and checkout the specified commit, tag or branch.
|
- `gitPull()` now checks if an existing repository is at the `checkout` value specified. If not, it will pull the latest changes and checkout the specified commit, tag or branch.
|
||||||
|
|
||||||
|
### Other improvements
|
||||||
|
|
||||||
|
- Generated wrappers no longer depend on nimterop being present - no more `import nimterop/types`. Supporting code is directly included in the wrapper output and only when required. E.g. enum macro is only included if wrapper contains enums. [#125](i125) (since v0.6.1)
|
||||||
|
|
||||||
|
- `cImport()` now includes wrapper output from a file rather than inline. Errors in generated wrappers will no longer point to a line in `macros.nim` making debugging easier.
|
||||||
|
|
||||||
|
|
||||||
## Version 0.5.0
|
## Version 0.5.0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Package
|
# Package
|
||||||
|
|
||||||
version = "0.6.0"
|
version = "0.6.1"
|
||||||
author = "genotrance"
|
author = "genotrance"
|
||||||
description = "C/C++ interop for Nim"
|
description = "C/C++ interop for Nim"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@ else:
|
||||||
export sleep
|
export sleep
|
||||||
|
|
||||||
proc execAction*(cmd: string, retry = 0, die = true, cache = false,
|
proc execAction*(cmd: string, retry = 0, die = true, cache = false,
|
||||||
cacheKey = "", onRetry: proc() = nil): tuple[output: string, ret: int] =
|
cacheKey = "", onRetry: proc() = nil,
|
||||||
|
onError: proc(output: string, err: int) = nil): tuple[output: string, ret: int] =
|
||||||
## Execute an external command - supported at compile time
|
## Execute an external command - supported at compile time
|
||||||
##
|
##
|
||||||
## Checks if command exits successfully before returning. If not, an
|
## Checks if command exits successfully before returning. If not, an
|
||||||
|
|
@ -34,6 +35,8 @@ proc execAction*(cmd: string, retry = 0, die = true, cache = false,
|
||||||
## `die = false` - return on errors
|
## `die = false` - return on errors
|
||||||
## `cache = true` - cache results unless cleared with -f
|
## `cache = true` - cache results unless cleared with -f
|
||||||
## `cacheKey` - key to create unique cache entry
|
## `cacheKey` - key to create unique cache entry
|
||||||
|
## `onRetry()` - proc to call before retrying
|
||||||
|
## `onError(output, err)` - proc to call on error
|
||||||
let
|
let
|
||||||
ccmd = fixCmd(cmd)
|
ccmd = fixCmd(cmd)
|
||||||
|
|
||||||
|
|
@ -80,9 +83,12 @@ proc execAction*(cmd: string, retry = 0, die = true, cache = false,
|
||||||
onRetry()
|
onRetry()
|
||||||
sleep(500)
|
sleep(500)
|
||||||
result = execAction(cmd, retry = retry - 1, die, cache, cacheKey)
|
result = execAction(cmd, retry = retry - 1, die, cache, cacheKey)
|
||||||
elif die:
|
else:
|
||||||
doAssert false, "Command failed: " & $result.ret & "\ncmd: " & ccmd &
|
if not onError.isNil:
|
||||||
"\nresult:\n" & result.output
|
onError(result.output, result.ret)
|
||||||
|
|
||||||
|
doAssert not die, "Command failed: " & $result.ret & "\ncmd: " & ccmd &
|
||||||
|
"\nresult:\n" & result.output
|
||||||
|
|
||||||
when not defined(TOAST):
|
when not defined(TOAST):
|
||||||
proc findExe*(exe: string): string =
|
proc findExe*(exe: string): string =
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ All `{.compileTime.}` procs must be used in a compile time context, e.g. using:
|
||||||
|
|
||||||
import hashes, macros, os, strformat, strutils
|
import hashes, macros, os, strformat, strutils
|
||||||
|
|
||||||
import "."/[build, globals, paths]
|
import "."/[globals, paths]
|
||||||
|
import "."/build/[ccompiler, misc, nimconf, shell]
|
||||||
|
|
||||||
proc interpPath(dir: string): string=
|
proc interpPath(dir: string): string=
|
||||||
# TODO: more robust: needs a DirSep after "$projpath"
|
# TODO: more robust: needs a DirSep after "$projpath"
|
||||||
|
|
@ -90,35 +91,30 @@ proc getToastError(output: string): string =
|
||||||
if result.Bl:
|
if result.Bl:
|
||||||
result = "\n\n" & output
|
result = "\n\n" & output
|
||||||
|
|
||||||
proc getNimCheckError(output: string): tuple[tmpFile, errors: string] =
|
proc getNimCheckError(nimFile: string) =
|
||||||
let
|
|
||||||
hash = output.hash().abs()
|
|
||||||
|
|
||||||
result.tmpFile = getProjectCacheDir("failed", forceClean = false) / "nimterop_" & $hash & ".nim"
|
|
||||||
|
|
||||||
if not fileExists(result.tmpFile) or gStateCT.nocache or compileOption("forceBuild"):
|
|
||||||
mkDir(result.tmpFile.parentDir())
|
|
||||||
writeFile(result.tmpFile, output)
|
|
||||||
|
|
||||||
doAssert fileExists(result.tmpFile), "Failed to write to cache dir: " & result.tmpFile
|
|
||||||
|
|
||||||
let
|
let
|
||||||
(check, _) = execAction(
|
(check, _) = execAction(
|
||||||
&"{getCurrentNimCompiler()} check {result.tmpFile.sanitizePath}",
|
&"{getCurrentNimCompiler()} check {nimFile.sanitizePath}",
|
||||||
die = false
|
die = false
|
||||||
)
|
)
|
||||||
|
|
||||||
result.errors = "\n\n" & check
|
doAssert false, &"\n\n{check}\n\n" &
|
||||||
|
"Codegen limitation or error - review 'nim check' output above generated for " & nimFile
|
||||||
|
|
||||||
proc getToast(fullpaths: seq[string], recurse: bool = false, dynlib: string = "",
|
proc getToast(fullpaths: seq[string], recurse: bool = false, dynlib: string = "",
|
||||||
mode = "c", flags = "", noNimout = false): string =
|
mode = "c", flags = "", noNimout = false): string =
|
||||||
var
|
var
|
||||||
ret = 0
|
|
||||||
cmd = when defined(Windows): "cmd /c " else: ""
|
cmd = when defined(Windows): "cmd /c " else: ""
|
||||||
|
ext = "h"
|
||||||
|
|
||||||
|
let
|
||||||
|
toastExe = toastExePath()
|
||||||
|
# see https://github.com/nimterop/nimterop/issues/69
|
||||||
|
cacheKey = getCacheValue(toastExe) & getCacheValue(fullpaths)
|
||||||
|
|
||||||
let toastExe = toastExePath()
|
|
||||||
doAssert fileExists(toastExe), "toast not compiled: " & toastExe.sanitizePath &
|
doAssert fileExists(toastExe), "toast not compiled: " & toastExe.sanitizePath &
|
||||||
" make sure 'nimble build' or 'nimble install' built it"
|
" make sure 'nimble build' or 'nimble install' built it"
|
||||||
|
|
||||||
cmd &= &"{toastExe} --preprocess -m:{mode}"
|
cmd &= &"{toastExe} --preprocess -m:{mode}"
|
||||||
|
|
||||||
if recurse:
|
if recurse:
|
||||||
|
|
@ -147,13 +143,29 @@ proc getToast(fullpaths: seq[string], recurse: bool = false, dynlib: string = ""
|
||||||
if gStateCT.pluginSourcePath.nBl:
|
if gStateCT.pluginSourcePath.nBl:
|
||||||
cmd.add &" --pluginSourcePath={gStateCT.pluginSourcePath.sanitizePath}"
|
cmd.add &" --pluginSourcePath={gStateCT.pluginSourcePath.sanitizePath}"
|
||||||
|
|
||||||
|
ext = "nim"
|
||||||
|
|
||||||
for fullpath in fullpaths:
|
for fullpath in fullpaths:
|
||||||
cmd.add &" {fullpath.sanitizePath}"
|
cmd.add &" {fullpath.sanitizePath}"
|
||||||
|
|
||||||
# see https://github.com/nimterop/nimterop/issues/69
|
# Generate filename for toast output
|
||||||
(result, ret) = execAction(cmd, die = false, cache = (not gStateCT.nocache),
|
let
|
||||||
cacheKey = getCacheValue(toastExe) & getCacheValue(fullpaths))
|
hash = (cmd & cacheKey).hash().abs()
|
||||||
doAssert ret == 0, getToastError(result)
|
cachePath = getNimteropCacheDir() / "toastCache" / "nimterop_" & $hash
|
||||||
|
|
||||||
|
result = cachePath.addFileExt(ext)
|
||||||
|
|
||||||
|
if not fileExists(result) or compileOption("forceBuild"):
|
||||||
|
let
|
||||||
|
dir = cachePath.parentDir()
|
||||||
|
if not dirExists(dir):
|
||||||
|
mkDir(dir)
|
||||||
|
|
||||||
|
cmd.add &" -o {result.sanitizePath}"
|
||||||
|
|
||||||
|
var
|
||||||
|
(_, ret) = execAction(cmd, die = false)
|
||||||
|
doAssert ret == 0, getToastError(result.readFile())
|
||||||
|
|
||||||
macro cOverride*(body): untyped =
|
macro cOverride*(body): untyped =
|
||||||
## When the wrapper code generated by nimterop is missing certain symbols or not
|
## When the wrapper code generated by nimterop is missing certain symbols or not
|
||||||
|
|
@ -567,7 +579,7 @@ macro cImport*(filenames: static seq[string], recurse: static bool = false, dynl
|
||||||
gecho "# Importing " & fullpaths.join(", ").sanitizePath
|
gecho "# Importing " & fullpaths.join(", ").sanitizePath
|
||||||
|
|
||||||
let
|
let
|
||||||
output = getToast(fullpaths, recurse, dynlib, mode, flags)
|
nimFile = getToast(fullpaths, recurse, dynlib, mode, flags)
|
||||||
|
|
||||||
# Reset plugin and overrides for next cImport
|
# Reset plugin and overrides for next cImport
|
||||||
if gStateCT.overrides.nBl:
|
if gStateCT.overrides.nBl:
|
||||||
|
|
@ -575,16 +587,12 @@ macro cImport*(filenames: static seq[string], recurse: static bool = false, dynl
|
||||||
gStateCT.overrides = ""
|
gStateCT.overrides = ""
|
||||||
|
|
||||||
if gStateCT.debug:
|
if gStateCT.debug:
|
||||||
gecho output
|
gecho nimFile.readFile()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
let body = parseStmt(output)
|
result.add parseStmt("include " & nimFile.changeFileExt(""))
|
||||||
|
|
||||||
result.add body
|
|
||||||
except:
|
except:
|
||||||
let
|
getNimCheckError(nimFile)
|
||||||
(tmpFile, errors) = getNimCheckError(output)
|
|
||||||
doAssert false, errors & "\n\nNimterop codegen limitation or error - review 'nim check' output above generated for " & tmpFile
|
|
||||||
|
|
||||||
macro cImport*(filename: static string, recurse: static bool = false, dynlib: static string = "",
|
macro cImport*(filename: static string, recurse: static bool = false, dynlib: static string = "",
|
||||||
mode: static string = "c", flags: static string = ""): untyped =
|
mode: static string = "c", flags: static string = ""): untyped =
|
||||||
|
|
@ -663,49 +671,37 @@ macro c2nImport*(filename: static string, recurse: static bool = false, dynlib:
|
||||||
gecho "# Importing " & fullpath & " with c2nim"
|
gecho "# Importing " & fullpath & " with c2nim"
|
||||||
|
|
||||||
let
|
let
|
||||||
output = getToast(@[fullpath], recurse, dynlib, mode, noNimout = true)
|
hFile = getToast(@[fullpath], recurse, dynlib, mode, noNimout = true)
|
||||||
hash = output.hash().abs()
|
nimFile = hFile.changeFileExt("nim")
|
||||||
hpath = getProjectCacheDir("c2nimCache", forceClean = false) / "nimterop_" & $hash & ".h"
|
|
||||||
npath = hpath[0 .. hpath.rfind('.')] & "nim"
|
|
||||||
header = "header" & fullpath.splitFile().name.split(seps = {'-', '.'}).join()
|
header = "header" & fullpath.splitFile().name.split(seps = {'-', '.'}).join()
|
||||||
|
|
||||||
if not fileExists(hpath) or gStateCT.nocache or compileOption("forceBuild"):
|
if not fileExists(nimFile) or compileOption("forceBuild"):
|
||||||
mkDir(hpath.parentDir())
|
var
|
||||||
writeFile(hpath, output)
|
cmd = when defined(Windows): "cmd /c " else: ""
|
||||||
|
cmd &= &"c2nim {hFile} --header:{header}"
|
||||||
|
|
||||||
doAssert fileExists(hpath), "Unable to write temporary header file: " & hpath
|
if dynlib.nBl:
|
||||||
|
cmd.add &" --dynlib:{dynlib}"
|
||||||
|
if mode.contains("cpp"):
|
||||||
|
cmd.add " --cpp"
|
||||||
|
if flags.nBl:
|
||||||
|
cmd.add &" {flags}"
|
||||||
|
|
||||||
var
|
for i in gStateCT.defines:
|
||||||
cmd = when defined(Windows): "cmd /c " else: ""
|
cmd.add &" --assumedef:{i.quoteShell}"
|
||||||
cmd &= &"c2nim {hpath} --header:{header}"
|
|
||||||
|
|
||||||
if dynlib.nBl:
|
let
|
||||||
cmd.add &" --dynlib:{dynlib}"
|
(c2nimout, ret) = execAction(cmd)
|
||||||
if mode.contains("cpp"):
|
if ret != 0:
|
||||||
cmd.add " --cpp"
|
rmFile(nimFile)
|
||||||
if flags.nBl:
|
doAssert false, "\n\nc2nim codegen limitation or error - " & c2nimout
|
||||||
cmd.add &" {flags}"
|
|
||||||
|
|
||||||
for i in gStateCT.defines:
|
nimFile.writeFile(&"const {header} = \"{fullpath}\"\n\n" & readFile(nimFile))
|
||||||
cmd.add &" --assumedef:{i.quoteShell}"
|
|
||||||
|
|
||||||
let
|
|
||||||
(c2nimout, ret) = execAction(cmd, cache = not gStateCT.nocache,
|
|
||||||
cacheKey = getCacheValue(hpath))
|
|
||||||
|
|
||||||
doAssert ret == 0, "\n\nc2nim codegen limitation or error - " & c2nimout
|
|
||||||
|
|
||||||
var
|
|
||||||
nimout = &"const {header} = \"{fullpath}\"\n\n" & readFile(npath)
|
|
||||||
|
|
||||||
if gStateCT.debug:
|
if gStateCT.debug:
|
||||||
gecho nimout
|
gecho nimFile.readFile()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
let body = parseStmt(nimout)
|
result.add parseStmt("include " & nimFile.changeFileExt(""))
|
||||||
|
|
||||||
result.add body
|
|
||||||
except:
|
except:
|
||||||
let
|
getNimCheckError(nimFile)
|
||||||
(tmpFile, errors) = getNimCheckError(nimout)
|
|
||||||
doAssert false, errors & "\n\nc2nim codegen limitation or error - review 'nim check' output above generated for " & tmpFile
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,10 @@ import "."/toastlib/[ast2, getters, tshelp]
|
||||||
|
|
||||||
import "."/build/[ccompiler, misc]
|
import "."/build/[ccompiler, misc]
|
||||||
|
|
||||||
|
var
|
||||||
|
# Output generated before main() is called
|
||||||
|
preMainOut = ""
|
||||||
|
|
||||||
proc process(gState: State, path: string) =
|
proc process(gState: State, path: string) =
|
||||||
doAssert existsFile(path), &"Invalid path {path}"
|
doAssert existsFile(path), &"Invalid path {path}"
|
||||||
|
|
||||||
|
|
@ -129,6 +133,7 @@ proc main(
|
||||||
if source.nBl:
|
if source.nBl:
|
||||||
# Print source after preprocess or Nim output
|
# Print source after preprocess or Nim output
|
||||||
if gState.pnim:
|
if gState.pnim:
|
||||||
|
gecho preMainOut
|
||||||
gState.initNim()
|
gState.initNim()
|
||||||
for src in source:
|
for src in source:
|
||||||
gState.process(src.expandSymlinkAbs())
|
gState.process(src.expandSymlinkAbs())
|
||||||
|
|
@ -187,7 +192,7 @@ proc mergeParams(cmdNames: seq[string], cmdLine = commandLineParams()): seq[stri
|
||||||
# https://github.com/c-blake/cligen/issues/149
|
# https://github.com/c-blake/cligen/issues/149
|
||||||
for param in cmdLine:
|
for param in cmdLine:
|
||||||
if param.fileExists() and param.splitFile().ext == ".cfg":
|
if param.fileExists() and param.splitFile().ext == ".cfg":
|
||||||
echo &"# Loading flags from '{param}'"
|
preMainOut &= &"# Loading flags from '{param}'\n"
|
||||||
for line in param.readFile().splitLines():
|
for line in param.readFile().splitLines():
|
||||||
let
|
let
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
|
|
@ -197,7 +202,7 @@ proc mergeParams(cmdNames: seq[string], cmdLine = commandLineParams()): seq[stri
|
||||||
result.add param
|
result.add param
|
||||||
|
|
||||||
if result.len != 0 and "-h" notin result and "--help" notin result:
|
if result.len != 0 and "-h" notin result and "--help" notin result:
|
||||||
echo &"""# Generated @ {$now()}
|
preMainOut &= &"""# Generated @ {$now()}
|
||||||
# Command line:
|
# Command line:
|
||||||
# {getAppFilename()} {result.join(" ")}
|
# {getAppFilename()} {result.join(" ")}
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue