aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgenotrance <dev@genotrance.com>2019-05-08 23:56:30 -0500
committerGitHub <noreply@github.com>2019-05-08 23:56:30 -0500
commit2cdde946359828d724a573f96a1cda01b3b9d8e4 (patch)
tree3cebaccaa8e7646312a8dbde65b566f66e28191c
parentdef527ae6052a707bb61c0cd5e3cdc8be55130a5 (diff)
parentafc9991002fb65c207d0ecf994a941efd5a1384a (diff)
downloadnimterop-2cdde946359828d724a573f96a1cda01b3b9d8e4.tar.gz
nimterop-2cdde946359828d724a573f96a1cda01b3b9d8e4.zip
Dynlib support
-rw-r--r--nimterop.nimble1
-rw-r--r--nimterop/ast.nim12
-rw-r--r--nimterop/cimport.nim35
-rw-r--r--nimterop/getters.nim41
-rw-r--r--nimterop/git.nim2
-rw-r--r--nimterop/globals.nim4
-rw-r--r--nimterop/grammar.nim29
-rw-r--r--nimterop/toast.nim4
-rw-r--r--tests/tpcre.nim35
9 files changed, 124 insertions, 39 deletions
diff --git a/nimterop.nimble b/nimterop.nimble
index a9a99ee..9910444 100644
--- a/nimterop.nimble
+++ b/nimterop.nimble
@@ -34,6 +34,7 @@ task buildToast, "build toast":
proc testAll() =
execTest "tests/tnimterop_c.nim"
execCmd "nim cpp -r tests/tnimterop_cpp.nim"
+ execTest "tests/tpcre.nim"
## platform specific tests
when defined(Windows):
diff --git a/nimterop/ast.nim b/nimterop/ast.nim
index d6b3f76..8efdf6f 100644
--- a/nimterop/ast.nim
+++ b/nimterop/ast.nim
@@ -151,14 +151,16 @@ proc printNim*(gState: State, fullpath: string, root: TSNode, astTable: AstTable
var
nimState = new(NimState)
fp = fullpath.replace("\\", "/")
+
nimState.identifiers = newTable[string, string]()
+ nimState.gState = gState
nimState.currentHeader = getCurrentHeader(fullpath)
- nimState.impHeader = nimState.currentHeader.replace("header", "imp")
+ nimState.impShort = nimState.currentHeader.replace("header", "imp")
nimState.sourceFile = fullpath
- nimState.constStr &= &"\n {nimState.currentHeader} {{.used.}} = \"{fp}\""
- nimState.gState = gState
+ if nimState.gState.dynlib.len == 0:
+ nimState.constStr &= &"\n {nimState.currentHeader} {{.used.}} = \"{fp}\""
root.searchAst(astTable, nimState)
@@ -169,8 +171,8 @@ proc printNim*(gState: State, fullpath: string, root: TSNode, astTable: AstTable
echo &"const{nimState.constStr}\n"
echo &"""
-{{.pragma: {nimState.impHeader}, importc, header: {nimState.currentHeader}.}}
-{{.pragma: {nimState.impHeader}C, {nimState.impHeader}, cdecl.}}
+{{.pragma: {nimState.impShort}, importc{nimState.getHeader()}.}}
+{{.pragma: {nimState.impShort}C, {nimState.impShort}, cdecl{nimState.getDynlib()}.}}
"""
if nimState.typeStr.nBl:
diff --git a/nimterop/cimport.nim b/nimterop/cimport.nim
index 5fade3a..bf5ee79 100644
--- a/nimterop/cimport.nim
+++ b/nimterop/cimport.nim
@@ -112,7 +112,7 @@ proc getNimCheckError(output: string): tuple[tmpFile, errors: string] =
result.errors = "\n\n" & check
-proc getToast(fullpath: string, recurse: bool = false): string =
+proc getToast(fullpath: string, recurse: bool = false, dynlib: string = ""): string =
var
ret = 0
cmd = when defined(Windows): "cmd /c " else: ""
@@ -131,6 +131,9 @@ proc getToast(fullpath: string, recurse: bool = false): string =
for i in gStateCT.includeDirs:
cmd.add &" --includeDirs+={i.quoteShell}"
+ if dynlib.len != 0:
+ cmd.add &" --dynlib={dynlib}"
+
if gStateCT.symOverride.len != 0:
cmd.add &" --symOverride={gStateCT.symOverride.join(\",\")}"
@@ -297,9 +300,6 @@ proc cDisableCaching*() {.compileTime.} =
gStateCT.nocache = true
-# TODO: `passC` should be delayed and inserted inside `cImport`, `cCompile`
-# and this should be made a proc:
-# proc cDefine*(name: string, val = "") {.compileTime.} =
macro cDefine*(name: static string, val: static string = ""): untyped =
## ``#define`` an identifer that is forwarded to the C/C++ compiler
## using ``{.passC: "-DXXX".}``
@@ -462,7 +462,7 @@ macro cCompile*(path: static string, mode = "c", exclude = ""): untyped =
if gStateCT.debug:
echo result.repr
-macro cImport*(filename: static string, recurse: static bool = false): untyped =
+macro cImport*(filename: static string, recurse: static bool = false, dynlib: static string = ""): untyped =
## Import all supported definitions from specified header file. Generated
## content is cached in ``nimcache`` until ``filename`` changes unless
## `cDisableCaching() <cimport.html#cDisableCaching,>`_ is set. ``nim -f``
@@ -472,6 +472,29 @@ macro cImport*(filename: static string, recurse: static bool = false): untyped =
## referenced in ``filename``. This is only done for files in the same
## directory as ``filename`` or in a directory added using
## `cIncludeDir() <cimport.html#cIncludeDir.m,>`_
+ ##
+ ## ``dynlib`` can be used to specify the Nim string to use to specify the dynamic
+ ## library to load the imported symbols from. For example:
+ ##
+ ## .. code-block:: nim
+ ##
+ ## const
+ ## dynpcre =
+ ## when defined(windows):
+ ## when defined(cpu64):
+ ## "pcre64.dll"
+ ## else:
+ ## "pcre32.dll"
+ ## elif hostOS == "macosx":
+ ## "libpcre(.3|.1|).dylib"
+ ## else:
+ ## "libpcre.so(.3|.1|)"
+ ##
+ ## cImport("pcre.h", dynlib="dynpcre")
+ ##
+ ## If ``dynlib`` is not specified, the C/C++ implementation files can be compiled in
+ ## with `cCompile() <cimport.html#cCompile.m,,string>`_, or the `{.passL.}` pragma
+ ## can be used to specify the static lib to link.
result = newNimNode(nnkStmtList)
@@ -481,7 +504,7 @@ macro cImport*(filename: static string, recurse: static bool = false): untyped =
echo "# Importing " & fullpath
let
- output = getToast(fullpath, recurse)
+ output = getToast(fullpath, recurse, dynlib)
if gStateCT.debug:
echo output
diff --git a/nimterop/getters.nim b/nimterop/getters.nim
index ad1cb95..67482d1 100644
--- a/nimterop/getters.nim
+++ b/nimterop/getters.nim
@@ -338,6 +338,47 @@ proc getSplitComma*(joined: seq[string]): seq[string] =
for i in joined:
result = result.concat(i.split(","))
+proc getHeader*(nimState: NimState): string =
+ result =
+ if nimState.gState.dynlib.len == 0:
+ &", header: {nimState.currentHeader}"
+ else:
+ ""
+
+proc getDynlib*(nimState: NimState): string =
+ result =
+ if nimState.gState.dynlib.len != 0:
+ &", dynlib: {nimState.gState.dynlib}"
+ else:
+ ""
+
+proc getImportC*(nimState: NimState, origName, nimName: string): string =
+ if nimName != origName:
+ result = &"importc: \"{origName}\"{nimState.getHeader()}"
+ else:
+ result = nimState.impShort
+
+proc getPragma*(nimState: NimState, pragmas: varargs[string]): string =
+ result = ""
+ for pragma in pragmas.items():
+ if pragma.len != 0:
+ result &= pragma & ", "
+ if result.len != 0:
+ result = " {." & result[0 .. ^3] & ".}"
+
+ result = result.replace(nimState.impShort & ", cdecl", nimState.impShort & "C")
+
+ let
+ dy = nimState.getDynlib()
+
+ if ", cdecl" in result and dy.len != 0:
+ result = result.replace(".}", dy & ".}")
+
+proc getComments*(nimState: NimState): string =
+ if not nimState.gState.nocomments and nimState.commentStr.len != 0:
+ result = "\n" & nimState.commentStr
+ nimState.commentStr = ""
+
proc dll*(path: string): string =
let
(dir, name, _) = path.splitFile()
diff --git a/nimterop/git.nim b/nimterop/git.nim
index 3a0f493..01afa9e 100644
--- a/nimterop/git.nim
+++ b/nimterop/git.nim
@@ -68,7 +68,7 @@ proc downloadUrl*(url, outdir: string) =
var cmd = if defined(Windows):
"powershell [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; wget $# -OutFile $#"
else:
- "curl $# -o $#"
+ "curl -L $# -o $#"
discard execAction(cmd % [url, (outdir/file).quoteShell])
if ext == ".zip":
diff --git a/nimterop/globals.nim b/nimterop/globals.nim
index 1bef589..2db31be 100644
--- a/nimterop/globals.nim
+++ b/nimterop/globals.nim
@@ -57,7 +57,7 @@ type
nocache*, nocomments*, debug*, past*, preprocess*, pnim*, pretty*, recurse*: bool
- code*, mode*, pluginSourcePath*: string
+ code*, dynlib*, mode*, pluginSourcePath*: string
onSymbol*: OnSymbol
@@ -68,7 +68,7 @@ type
gState*: State
- currentHeader*, impHeader*, sourceFile*: string
+ currentHeader*, impShort*, sourceFile*: string
data*: seq[tuple[name, val: string]]
diff --git a/nimterop/grammar.nim b/nimterop/grammar.nim
index 3010966..33399c9 100644
--- a/nimterop/grammar.nim
+++ b/nimterop/grammar.nim
@@ -7,27 +7,6 @@ import "."/[getters, globals, lisp, treesitter/api]
type
Grammar = seq[tuple[grammar: string, call: proc(ast: ref Ast, node: TSNode, nimState: NimState) {.nimcall.}]]
-proc genImportC(nimState: NimState, origName, nimName: string): string =
- if nimName != origName:
- result = &"importc: \"{origName}\", header: {nimState.currentHeader}"
- else:
- result = nimState.impHeader
-
-proc genPragma(nimState: NimState, pragmas: varargs[string]): string =
- result = ""
- for pragma in pragmas.items():
- if pragma.len != 0:
- result &= pragma & ", "
- if result.len != 0:
- result = " {." & result[0 .. ^2] & ".}"
-
- result = result.replace(nimState.impHeader & ", cdecl", nimState.impHeader & "C")
-
-proc getComments(nimState: NimState): string =
- if not nimState.gState.nocomments and nimState.commentStr.len != 0:
- result = "\n" & nimState.commentStr
- nimState.commentStr = ""
-
proc initGrammar(): Grammar =
# #define X Y
result.add(("""
@@ -177,7 +156,7 @@ proc initGrammar(): Grammar =
i += 1
let
- pragma = nimState.genPragma(nimState.genImportC(name, nname))
+ pragma = nimState.getPragma(nimState.getImportC(name, nname))
if typ.nBl and nname.nBl and nimState.addNewIdentifer(nname):
if i < nimState.data.len and nimState.data[^1].name == "function_declarator":
@@ -234,7 +213,7 @@ proc initGrammar(): Grammar =
else:
if nimState.addNewIdentifer(ndname):
let
- pragma = nimState.genPragma(nimState.genImportc(dname, ndname), "bycopy")
+ pragma = nimState.getPragma(nimState.getImportc(dname, ndname), "bycopy")
nimState.typeStr &=
&"{nimState.getComments()}\n {ndname}*{pragma} = {dptr}{nname}"
@@ -274,7 +253,7 @@ proc initGrammar(): Grammar =
nimState.typeStr &= &"{nimState.getComments()}\n {nname}* {{.bycopy.}} = object{union}"
else:
let
- pragma = nimState.genPragma(nimState.genImportC(prefix & name, nname), "bycopy")
+ pragma = nimState.getPragma(nimState.getImportC(prefix & name, nname), "bycopy")
nimState.typeStr &= &"{nimState.getComments()}\n {nname}*{pragma} = object{union}"
var
@@ -586,7 +565,7 @@ proc initGrammar(): Grammar =
if fnname.nBl and nimState.addNewIdentifer(fnname):
let
ftyp = nimState.getIdentifier(nimState.data[0].val, nskType, fnname)
- pragma = nimState.genPragma(nimState.genImportC(fname, fnname), "cdecl")
+ pragma = nimState.getPragma(nimState.getImportC(fname, fnname), "cdecl")
if fptr.len != 0 or ftyp != "object":
nimState.procStr &= &"{nimState.getComments()}\nproc {fnname}*({pout}): {getPtrType(fptr&ftyp)}{pragma}"
diff --git a/nimterop/toast.nim b/nimterop/toast.nim
index eed39d8..da903b0 100644
--- a/nimterop/toast.nim
+++ b/nimterop/toast.nim
@@ -105,6 +105,7 @@ proc main(
nocomments = false,
defines: seq[string] = @[],
includeDirs: seq[string] = @[],
+ dynlib: string = "",
symOverride: seq[string] = @[],
pluginSourcePath: string = "",
debug = false,
@@ -121,6 +122,7 @@ proc main(
nocomments: nocomments,
defines: defines,
includeDirs: includeDirs,
+ dynlib: dynlib,
symOverride: symOverride,
pluginSourcePath: pluginSourcePath,
debug: debug,
@@ -153,6 +155,7 @@ when isMainModule:
"nocomments": "exclude top-level comments from output",
"defines": "definitions to pass to preprocessor",
"includeDirs": "include directory to pass to preprocessor",
+ "dynlib": "Import symbols from library in specified Nim string",
"symOverride": "skip generating specified symbols",
"pluginSourcePath": "Nim file to build and load as a plugin",
"debug": "enable debug output",
@@ -167,6 +170,7 @@ when isMainModule:
"nocomments": 'c',
"defines": 'D',
"includeDirs": 'I',
+ "dynlib": 'l',
"symOverride": 'O',
"debug": 'd',
"pgrammar": 'g'
diff --git a/tests/tpcre.nim b/tests/tpcre.nim
new file mode 100644
index 0000000..705525f
--- /dev/null
+++ b/tests/tpcre.nim
@@ -0,0 +1,35 @@
+import os
+
+import nimterop/[cimport, git, paths]
+
+const
+ baseDir = nimteropBuildDir()/"pcre"
+ pcreH = baseDir/"pcre.h.in"
+
+static:
+ if not pcreH.fileExists():
+ downloadUrl("https://github.com/svn2github/pcre/raw/master/pcre.h.in", baseDir)
+ cDebug()
+ cDisableCaching()
+
+const
+ dynpcre =
+ when defined(windows):
+ when defined(cpu64):
+ "pcre64.dll"
+ else:
+ "pcre32.dll"
+ elif hostOS == "macosx":
+ "libpcre(.3|.1|).dylib"
+ else:
+ "libpcre.so(.3|.1|)"
+
+cPlugin:
+ import strutils
+
+ proc onSymbol*(sym: var Symbol) {.exportc, dynlib.} =
+ sym.name = sym.name.replace("pcre_", "")
+
+cImport(pcreH, dynlib="dynpcre")
+
+echo version() \ No newline at end of file