aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGanesh Viswanathan <dev@genotrance.com>2020-04-22 22:11:30 -0500
committerGanesh Viswanathan <dev@genotrance.com>2020-04-22 22:11:30 -0500
commitc1f46680f77d077bfc7abebea8b289e9b8bac043 (patch)
treefa01b07d028f058b18cbfe38bd68ff1e11f0222b
parentf17b958f47686f41a20045ea089295841a6845d6 (diff)
downloadnimterop-c1f46680f77d077bfc7abebea8b289e9b8bac043.tar.gz
nimterop-c1f46680f77d077bfc7abebea8b289e9b8bac043.zip
Add cImport for multiple headers
-rw-r--r--nimterop.nimble3
-rw-r--r--nimterop/cimport.nim91
-rw-r--r--tests/rsa.nim42
3 files changed, 99 insertions, 37 deletions
diff --git a/nimterop.nimble b/nimterop.nimble
index 37c395d..9cb79b1 100644
--- a/nimterop.nimble
+++ b/nimterop.nimble
@@ -51,6 +51,9 @@ task test, "Test":
execTest "tests/tpcre.nim"
execTest "tests/tpcre.nim", "-d:FLAGS=\"-f:ast2\""
+ execTest "tests/rsa.nim"
+ execTest "tests/rsa.nim", "-d:FLAGS=\"-H\""
+
# Platform specific tests
when defined(Windows):
execTest "tests/tmath.nim"
diff --git a/nimterop/cimport.nim b/nimterop/cimport.nim
index 52d1892..3e58bc8 100644
--- a/nimterop/cimport.nim
+++ b/nimterop/cimport.nim
@@ -91,6 +91,11 @@ proc getCacheValue(fullpath: string): string =
if not gStateCT.nocache:
result = fullpath.getFileDate()
+proc getCacheValue(fullpaths: seq[string]): string =
+ if not gStateCT.nocache:
+ for fullpath in fullpaths:
+ result &= getCacheValue(fullpath)
+
proc getToastError(output: string): string =
# Filter out preprocessor errors
for line in output.splitLines():
@@ -121,7 +126,7 @@ proc getNimCheckError(output: string): tuple[tmpFile, errors: string] =
result.errors = "\n\n" & check
-proc getToast(fullpath: string, recurse: bool = false, dynlib: string = "",
+proc getToast(fullpaths: seq[string], recurse: bool = false, dynlib: string = "",
mode = "c", flags = "", noNimout = false): string =
var
ret = 0
@@ -158,11 +163,12 @@ proc getToast(fullpath: string, recurse: bool = false, dynlib: string = "",
if gStateCT.pluginSourcePath.nBl:
cmd.add &" --pluginSourcePath={gStateCT.pluginSourcePath.sanitizePath}"
- cmd.add &" {fullpath.sanitizePath}"
+ for fullpath in fullpaths:
+ cmd.add &" {fullpath.sanitizePath}"
# see https://github.com/nimterop/nimterop/issues/69
(result, ret) = execAction(cmd, die = false, cache = (not gStateCT.nocache),
- cacheKey = getCacheValue(fullpath))
+ cacheKey = getCacheValue(fullpaths))
doAssert ret == 0, getToastError(result)
macro cOverride*(body): untyped =
@@ -555,6 +561,46 @@ macro cCompile*(path: static string, mode = "c", exclude = ""): untyped =
if gStateCT.debug:
echo result.repr
+macro cImport*(filenames: static seq[string], recurse: static bool = false, dynlib: static string = "",
+ mode: static string = "c", flags: static string = ""): untyped =
+ ## Import multiple headers in one shot
+ ##
+ ## This macro is preferable over multiple individual `cImport()` calls, especially
+ ## when the headers might `#include` the same headers and result in duplicate symbols.
+ result = newNimNode(nnkStmtList)
+
+ var
+ fullpaths: seq[string]
+
+ for filename in filenames:
+ fullpaths.add findPath(filename)
+
+ # In case cOverride called after cPlugin
+ if gStateCT.pluginSourcePath.Bl:
+ cPluginHelper(gStateCT.pluginSource)
+
+ echo "# Importing " & fullpaths.join(", ").sanitizePath
+
+ let
+ output = getToast(fullpaths, recurse, dynlib, mode, flags)
+
+ # Reset plugin and overrides for next cImport
+ if gStateCT.overrides.nBl:
+ gStateCT.pluginSourcePath = ""
+ gStateCT.overrides = ""
+
+ if gStateCT.debug:
+ echo output
+
+ try:
+ let body = parseStmt(output)
+
+ result.add body
+ except:
+ let
+ (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 = "",
mode: static string = "c", flags: static string = ""): untyped =
## Import all supported definitions from specified header file. Generated
@@ -590,8 +636,8 @@ macro cImport*(filename: static string, recurse: static bool = false, dynlib: st
## with `cCompile() <cimport.html#cCompile.m%2C%2Cstring%2Cstring>`_, or the
## `{.passL.}` pragma can be used to specify the static lib to link.
##
- ## `mode` is purely for forward compatibility when toast adds C++ support. It can
- ## be ignored for the foreseeable future.
+ ## `mode` selects the preprocessor and tree-sitter parser to be used to process
+ ## the header.
##
## `flags` can be used to pass any other command line arguments to `toast`. A
## good example would be `--prefix` and `--suffix` which strip leading and
@@ -600,37 +646,8 @@ macro cImport*(filename: static string, recurse: static bool = false, dynlib: st
## `cImport()` consumes and resets preceding `cOverride()` calls. `cPlugin()`
## is retained for the next `cImport()` call unless a new `cPlugin()` call is
## defined.
-
- result = newNimNode(nnkStmtList)
-
- let
- fullpath = findPath(filename)
-
- # In case cOverride called after cPlugin
- if gStateCT.pluginSourcePath.Bl:
- cPluginHelper(gStateCT.pluginSource)
-
- echo "# Importing " & fullpath.sanitizePath
-
- let
- output = getToast(fullpath, recurse, dynlib, mode, flags)
-
- # Reset plugin and overrides for next cImport
- if gStateCT.overrides.nBl:
- gStateCT.pluginSourcePath = ""
- gStateCT.overrides = ""
-
- if gStateCT.debug:
- echo output
-
- try:
- let body = parseStmt(output)
-
- result.add body
- except:
- let
- (tmpFile, errors) = getNimCheckError(output)
- doAssert false, errors & "\n\nNimterop codegen limitation or error - review 'nim check' output above generated for " & tmpFile
+ return quote do:
+ cImport(@[`filename`], bool(`recurse`), `dynlib`, `mode`, `flags`)
macro c2nImport*(filename: static string, recurse: static bool = false, dynlib: static string = "",
mode: static string = "c", flags: static string = ""): untyped =
@@ -661,7 +678,7 @@ macro c2nImport*(filename: static string, recurse: static bool = false, dynlib:
echo "# Importing " & fullpath & " with c2nim"
let
- output = getToast(fullpath, recurse, dynlib, noNimout = true)
+ output = getToast(@[fullpath], recurse, dynlib, noNimout = true)
hash = output.hash().abs()
hpath = getProjectCacheDir("c2nimCache", forceClean = false) / "nimterop_" & $hash & ".h"
npath = hpath[0 .. hpath.rfind('.')] & "nim"
diff --git a/tests/rsa.nim b/tests/rsa.nim
new file mode 100644
index 0000000..638c490
--- /dev/null
+++ b/tests/rsa.nim
@@ -0,0 +1,42 @@
+import os
+import strutils
+
+import nimterop/[build, cimport]
+
+setDefines(@["cryptoStd"])
+getHeader("openssl/crypto.h")
+
+const
+ basePath = cryptoPath.parentDir
+ FLAGS {.strdefine.} = ""
+
+cPlugin:
+ import strutils
+
+ proc onSymbol*(sym: var Symbol) {.exportc, dynlib.} =
+ sym.name = sym.name.strip(chars = {'_'}).replace("__", "_")
+
+ if sym.name in [
+ "AES_ENCRYPT", "AES_DECRYPT",
+ "BIO_CTRL_PENDING", "BIO_CTRL_WPENDING",
+ "BN_F_BNRAND", "BN_F_BNRAND_RANGE",
+ "CRYPTO_THREADID",
+ "EVP_CIPHER",
+ "OPENSSL_VERSION",
+ "PKCS7_ENCRYPT", "PKCS7_STREAM",
+ "SSL_TXT_ADH", "SSL_TXT_AECDH", "SSL_TXT_kECDHE"
+ ]:
+ sym.name = "C_" & sym.name
+
+cOverride:
+ proc OPENSSL_die*(assertion: cstring; file: cstring; line: cint) {.importc.}
+
+cImport(@[
+ basePath / "rsa.h",
+ basePath / "err.h",
+], recurse = true, flags = "-f:ast2 -s " & FLAGS)
+
+{.passL: cryptoLPath.}
+
+OpensslInit()
+echo $OPENSSL_VERSION_TEXT \ No newline at end of file