diff options
| author | genotrance <dev@genotrance.com> | 2019-05-08 23:56:30 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-05-08 23:56:30 -0500 |
| commit | 2cdde946359828d724a573f96a1cda01b3b9d8e4 (patch) | |
| tree | 3cebaccaa8e7646312a8dbde65b566f66e28191c | |
| parent | def527ae6052a707bb61c0cd5e3cdc8be55130a5 (diff) | |
| parent | afc9991002fb65c207d0ecf994a941efd5a1384a (diff) | |
| download | nimterop-2cdde946359828d724a573f96a1cda01b3b9d8e4.tar.gz nimterop-2cdde946359828d724a573f96a1cda01b3b9d8e4.zip | |
Dynlib support
| -rw-r--r-- | nimterop.nimble | 1 | ||||
| -rw-r--r-- | nimterop/ast.nim | 12 | ||||
| -rw-r--r-- | nimterop/cimport.nim | 35 | ||||
| -rw-r--r-- | nimterop/getters.nim | 41 | ||||
| -rw-r--r-- | nimterop/git.nim | 2 | ||||
| -rw-r--r-- | nimterop/globals.nim | 4 | ||||
| -rw-r--r-- | nimterop/grammar.nim | 29 | ||||
| -rw-r--r-- | nimterop/toast.nim | 4 | ||||
| -rw-r--r-- | tests/tpcre.nim | 35 |
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 |
