Updated with feedback

This commit is contained in:
Ganesh Viswanathan 2019-01-25 16:41:54 -06:00
commit 2d447a317b
3 changed files with 53 additions and 46 deletions

View file

@ -1,4 +1,4 @@
import hashes, macros, os, ospaths, strformat, strutils import hashes, macros, os, strformat, strutils
const CIMPORT {.used.} = 1 const CIMPORT {.used.} = 1
@ -88,24 +88,24 @@ proc getToast(fullpath: string, recurse: bool = false): string =
ret = 0 ret = 0
cmd = when defined(Windows): "cmd /c " else: "" cmd = when defined(Windows): "cmd /c " else: ""
cmd &= "toast --pnim --preprocess " cmd &= "toast --pnim --preprocess"
if recurse: if recurse:
cmd.add "--recurse " cmd.add " --recurse"
for i in gStateCT.defines: for i in gStateCT.defines:
cmd.add &"--defines+={i.quoteShell} " cmd.add &" --defines+={i.quoteShell}"
for i in gStateCT.includeDirs: for i in gStateCT.includeDirs:
cmd.add &"--includeDirs+={i.quoteShell} " cmd.add &" --includeDirs+={i.quoteShell}"
if gStateCT.symOverride.len != 0: if gStateCT.symOverride.len != 0:
cmd.add &"--symOverride={gStateCT.symOverride.join(\",\")} " cmd.add &" --symOverride={gStateCT.symOverride.join(\",\")}"
if gStateCT.pluginFile.nBl and gStateCT.pluginFile.fileExists(): if gStateCT.pluginFile.nBl:
cmd.add &"--pluginFile={gStateCT.pluginFile.quoteShell} " cmd.add &" --pluginFile={gStateCT.pluginFile.quoteShell}"
cmd.add &"{fullpath.quoteShell}" cmd.add &" {fullpath.quoteShell}"
echo cmd echo cmd
(result, ret) = gorgeEx(cmd, cache=getCacheValue(fullpath)) (result, ret) = gorgeEx(cmd, cache=getCacheValue(fullpath))
doAssert ret == 0, getToastError(result) doAssert ret == 0, getToastError(result)
@ -130,7 +130,7 @@ macro cOverride*(body): untyped =
## ##
## int svGetCallerInfo(const char** fileName, int *lineNumber); ## int svGetCallerInfo(const char** fileName, int *lineNumber);
## ##
## This could get mapped to: ## This might mapped to:
## ##
## .. code-block:: nim ## .. code-block:: nim
## ##
@ -166,9 +166,8 @@ macro cSkipSymbol*(skips: varargs[string]): untyped =
## Similar to `cOverride() <cimport.html#cOverride.m,>`_, this macro allows ## Similar to `cOverride() <cimport.html#cOverride.m,>`_, this macro allows
## filtering out symbols not of interest from the generated output. ## filtering out symbols not of interest from the generated output.
## ##
## .. code-block:: nim runnableExamples:
## cSkipSymbol "proc1", "Type2"
## cSkipSymbol "proc1", "Type2"
for skip in skips: for skip in skips:
gStateCT.symOverride.add skip.strVal gStateCT.symOverride.add skip.strVal
@ -178,21 +177,24 @@ macro cPlugin*(body): untyped =
## are not adequate, the `cPlugin() <cimport.html#cPlugin.m,>`_ macro can be used to customize the generated Nim output. ## are not adequate, the `cPlugin() <cimport.html#cPlugin.m,>`_ macro can be used to customize the generated Nim output.
## The following callbacks are available at this time. ## The following callbacks are available at this time.
## ##
## .. code-block:: nim runnableExamples:
## cPlugin:
## cPlugin: import strutils
## import strutils
## proc onSymbol*(sym: string): string {.exportc, dynlib.} =
## proc onSymbol*(sym: string): string {.exportc, dynlib.} = return sym.strip(chars={'_'})
## return sym.strip(chars={'_'})
let let
data = body.repr data = body.repr
path = getTempDir() / "nimterop" & ($data.hash() & ".nim") hash = data.hash()
phash = if hash<0: -hash else: hash
path = getTempDir() / "nimterop_" & $phash & ".nim"
if not fileExists(path): if not fileExists(path) or gStateCT.nocache:
writeFile(path, data) writeFile(path, data)
doAssert fileExists(path), "Unable to write plugin file: " & path
gStateCT.pluginFile = path gStateCT.pluginFile = path
proc cSearchPath*(path: string): string {.compileTime.}= proc cSearchPath*(path: string): string {.compileTime.}=
@ -209,8 +211,8 @@ proc cSearchPath*(path: string): string {.compileTime.}=
if result.len == 0: if result.len == 0:
var found = false var found = false
for inc in gStateCT.searchDirs: for inc in gStateCT.searchDirs:
result = (inc & "/" & path).replace("\\", "/") result = findPath(inc & "/" & path, fail = false)
if fileExists(result) or dirExists(result): if result.len != 0:
found = true found = true
break break
doAssert found, "File or directory not found: " & path & doAssert found, "File or directory not found: " & path &
@ -297,10 +299,9 @@ macro cAddStdDir*(mode = "c"): untyped =
## ##
## This allows something like this: ## This allows something like this:
## ##
## .. code-block:: nim runnableExamples:
## cAddStdDir()
## cAddStdDir() echo cSearchPath("math.h")
## cImport cSearchPath("math.h")
result = newNimNode(nnkStmtList) result = newNimNode(nnkStmtList)

View file

@ -1,4 +1,4 @@
import dynlib, macros, os, sequtils, sets, strformat, strutils, tables import dynlib, macros, os, sequtils, sets, strformat, strutils, tables, times
import regex import regex
@ -87,15 +87,18 @@ proc getType*(str: string): string =
if gTypeMap.hasKey(result): if gTypeMap.hasKey(result):
result = gTypeMap[result] result = gTypeMap[result]
template checkUnderscores(str, errmsg: string): untyped =
doAssert str[0] != '_' and str[^1] != '_', errmsg
proc getIdentifier*(str: string): string = proc getIdentifier*(str: string): string =
doAssert str.len != 0, "Blank identifier error" doAssert str.len != 0, "Blank identifier error"
if gStateRT.onSymbol != nil: if gStateRT.onSymbol != nil:
result = gStateRT.onSymbol(str) result = gStateRT.onSymbol(str)
checkUnderscores(result, &"Identifier '{str}' still contains leading/trailing underscores '_' after 'cPlugin:onSymbol()': result '{result}'")
else: else:
result = str result = str
checkUnderscores(result, &"Identifier '{result}' contains unsupported leading/trailing underscores '_': use 'cPlugin:onSymbol()' to handle")
doAssert result[0] != '_' and result[^1] != '_', &"Identifier '{result}' with leading/trailing underscore '_' not supported: use cPlugin() to handle"
if result in gReserved: if result in gReserved:
result = &"`{result}`" result = &"`{result}`"
@ -317,23 +320,22 @@ proc getSplitComma*(joined: seq[string]): seq[string] =
proc dll*(path: string): string = proc dll*(path: string): string =
let let
(dir, name, ext) = path.splitFile() (dir, name, _) = path.splitFile()
when defined(Windows): result = dir / (DynlibFormat % name)
result = dir/name.addFileExt("dll")
when defined(Linux):
result = dir/"lib" & name.addFileExt("so")
when defined(OSX):
result = dir/"lib" & name.addFileExt("dylib")
proc loadPlugin*(fullpath: string) = proc loadPlugin*(fullpath: string) =
doAssert fileExists(fullpath), "Plugin file does not exist: " & fullpath doAssert fileExists(fullpath), "Plugin file does not exist: " & fullpath
if not fileExists(fullpath.dll):
let
pdll = fullpath.dll
if not fileExists(pdll) or
fullpath.getLastModificationTime() > pdll.getLastModificationTime():
discard execAction("nim c --app:lib " & fullpath) discard execAction("nim c --app:lib " & fullpath)
doAssert fileExists(fullpath.dll), "No plugin binary generated for " & fullpath doAssert fileExists(pdll), "No plugin binary generated for " & fullpath
let lib = loadLib(fullpath.dll) let lib = loadLib(pdll)
doAssert lib != nil, "Plugin load failed" doAssert lib != nil, "Plugin $1 compiled to $2 failed to load" % [fullpath, pdll]
gStateRT.onSymbol = cast[proc(sym: string): string {.cdecl.}](lib.symAddr("onSymbol")) gStateRT.onSymbol = cast[typeof(gStateRT.onSymbol)](lib.symAddr("onSymbol"))
doAssert gStateRT.onSymbol != nil, "onSymbol() load failed" doAssert gStateRT.onSymbol != nil, "onSymbol() load failed from " & pdll

View file

@ -1,4 +1,4 @@
import sequtils, sets, tables import macros, sequtils, sets, tables
import regex import regex
@ -45,6 +45,10 @@ type
tonim*: proc (ast: ref Ast, node: TSNode) tonim*: proc (ast: ref Ast, node: TSNode)
regex*: Regex regex*: Regex
Symbol = object
name: string
kind: NimSymKind
State = object State = object
compile*, defines*, headers*, includeDirs*, searchDirs*, symOverride*: seq[string] compile*, defines*, headers*, includeDirs*, searchDirs*, symOverride*: seq[string]
@ -75,4 +79,4 @@ type CompileMode = enum
const modeDefault {.used.} = $cpp # TODO: USE this everywhere relevant const modeDefault {.used.} = $cpp # TODO: USE this everywhere relevant
when not declared(CIMPORT): when not declared(CIMPORT):
export gAtoms, gExpressions, gEnumVals, Kind, Ast, State, gStateRT, nBl, CompileMode, modeDefault export gAtoms, gExpressions, gEnumVals, Kind, Ast, Symbol, State, gStateRT, nBl, CompileMode, modeDefault