Dynlib support
This commit is contained in:
commit
2cdde94635
9 changed files with 126 additions and 41 deletions
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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.currentHeader = getCurrentHeader(fullpath)
|
||||
nimState.impHeader = nimState.currentHeader.replace("header", "imp")
|
||||
nimState.sourceFile = fullpath
|
||||
nimState.constStr &= &"\n {nimState.currentHeader} {{.used.}} = \"{fp}\""
|
||||
|
||||
nimState.gState = gState
|
||||
nimState.currentHeader = getCurrentHeader(fullpath)
|
||||
nimState.impShort = nimState.currentHeader.replace("header", "imp")
|
||||
nimState.sourceFile = fullpath
|
||||
|
||||
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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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":
|
||||
|
|
|
|||
|
|
@ -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]]
|
||||
|
||||
|
|
|
|||
|
|
@ -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}"
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
35
tests/tpcre.nim
Normal file
35
tests/tpcre.nim
Normal file
|
|
@ -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()
|
||||
Loading…
Add table
Add a link
Reference in a new issue