Build pre-hook, altNames, uInt, getType() calls, add zlib test
Fix subdir header, static lib name, [u]int[\d]+
This commit is contained in:
parent
3a23953607
commit
b0447677f1
8 changed files with 279 additions and 90 deletions
|
|
@ -20,7 +20,6 @@ cache:
|
|||
- "$HOME/.choosenim/toolchains/nim-0.20.2"
|
||||
|
||||
install:
|
||||
- set -e
|
||||
- export CHOOSENIM_CHOOSE_VERSION=$BRANCH
|
||||
- |
|
||||
curl https://nim-lang.org/choosenim/init.sh -sSf > init.sh
|
||||
|
|
@ -28,7 +27,6 @@ install:
|
|||
- export PATH="$HOME/.nimble/bin:/usr/local/opt/gettext/bin:$PATH"
|
||||
|
||||
script:
|
||||
- set -e
|
||||
- nimble --verbose install -y
|
||||
- nimble --verbose test
|
||||
- nimble --verbose --nimbleDir:`pwd`/build/fakenimble install nimterop -y
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ when not defined(headerStatic):
|
|||
else:
|
||||
cImport(headerPath, recurse = true)
|
||||
```
|
||||
This allows the user to control how the wrapper works - either pass `-d:headerStd` to search for `header.h` in the standard system path, `-d:headerGit` to clone the source from the specified git URL or `-d:headerDL` to get the source from download URL. Further, the `-d:headerVersion=X.Y.Z` flag can be used to specify which version to use. It is used as the tag name for Git whereas for DL, it replaces `$1` in the URL defined.
|
||||
This allows the user to control how the wrapper works - either pass `-d:headerStd` to search for `header.h` in the standard system path, `-d:headerGit` to clone the source from the specified git URL or `-d:headerDL` to get the source from download URL. Further, the `-d:headerSetVer=X.Y.Z` flag can be used to specify which version to use. It is used as the tag name for Git whereas for DL, it replaces `$1` in the URL defined.
|
||||
|
||||
The `-d:headerStatic` attempts to statically link the library. If it is omitted, the library is dynamically linked instead.
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ proc execAction*(cmd: string, nostderr=false): string =
|
|||
doAssert ret == 0, "Command failed: " & $(ret, nostderr) & "\nccmd: " & ccmd & "\nresult:\n" & result
|
||||
|
||||
proc findExe*(exe: string): string =
|
||||
## Find the specified executable using the which/where command - supported
|
||||
## Find the specified executable using the `which`/`where` command - supported
|
||||
## at compile time
|
||||
var
|
||||
cmd =
|
||||
|
|
@ -47,7 +47,7 @@ proc findExe*(exe: string): string =
|
|||
return oup.splitLines()[0].strip()
|
||||
|
||||
proc mkDir*(dir: string) =
|
||||
## Create a directory at cmopile time
|
||||
## Create a directory at compile time
|
||||
##
|
||||
## The `os` module is not available at compile time so a few
|
||||
## crucial helper functions are included with nimterop.
|
||||
|
|
@ -57,7 +57,7 @@ proc mkDir*(dir: string) =
|
|||
discard execAction(&"mkdir {flag} {dir.sanitizePath}")
|
||||
|
||||
proc cpFile*(source, dest: string, move=false) =
|
||||
## Copy a file from source to destination at compile time
|
||||
## Copy a file from `source` to `dest` at compile time
|
||||
let
|
||||
source = source.replace("/", $DirSep)
|
||||
dest = dest.replace("/", $DirSep)
|
||||
|
|
@ -76,7 +76,7 @@ proc cpFile*(source, dest: string, move=false) =
|
|||
discard execAction(&"{cmd} {source.sanitizePath} {dest.sanitizePath}")
|
||||
|
||||
proc mvFile*(source, dest: string) =
|
||||
## Move a file from source to destination at compile time
|
||||
## Move a file from `source` to `dest` at compile time
|
||||
cpFile(source, dest, move=true)
|
||||
|
||||
proc rmFile*(source: string, dir = false) =
|
||||
|
|
@ -99,7 +99,7 @@ proc rmDir*(source: string) =
|
|||
rmFile(source, dir = true)
|
||||
|
||||
proc extractZip*(zipfile, outdir: string) =
|
||||
## Extract a zip file using powershell on Windows and unzip on other
|
||||
## Extract a zip file using `powershell` on Windows and `unzip` on other
|
||||
## systems to the specified output directory
|
||||
var cmd = "unzip -o $#"
|
||||
if defined(Windows):
|
||||
|
|
@ -111,7 +111,7 @@ proc extractZip*(zipfile, outdir: string) =
|
|||
discard execAction(&"cd {outdir.sanitizePath} && {cmd % zipfile}")
|
||||
|
||||
proc extractTar*(tarfile, outdir: string) =
|
||||
## Extract a tar file using tar, 7z or 7za to the specified output directory
|
||||
## Extract a tar file using `tar`, `7z` or `7za` to the specified output directory
|
||||
var
|
||||
cmd = ""
|
||||
name = ""
|
||||
|
|
@ -146,9 +146,9 @@ proc extractTar*(tarfile, outdir: string) =
|
|||
rmFile(outdir / name)
|
||||
|
||||
proc downloadUrl*(url, outdir: string) =
|
||||
## Download a file using curl or wget (or powershell on Windows) to the specified directory
|
||||
## Download a file using `curl` or `wget` (or `powershell` on Windows) to the specified directory
|
||||
##
|
||||
## If a zip file, it is automatically extracted after download.
|
||||
## If an archive file, it is automatically extracted after download.
|
||||
let
|
||||
file = url.extractFilename()
|
||||
ext = file.splitFile().ext.toLowerAscii()
|
||||
|
|
@ -185,7 +185,7 @@ proc gitReset*(outdir: string) =
|
|||
echo "# Retrying ..."
|
||||
|
||||
proc gitCheckout*(file, outdir: string) =
|
||||
## Checkout the specified file in the git repository specified
|
||||
## Checkout the specified `file` in the git repository at `outdir`
|
||||
##
|
||||
## This effectively resets all changes in the file and can be
|
||||
## used to undo any changes that were made to source files to enable
|
||||
|
|
@ -240,13 +240,17 @@ proc gitPull*(url: string, outdir = "", plist = "", checkout = "") =
|
|||
proc findFile*(file: string|Regex, dir: string, recurse = true, first = false): string =
|
||||
## Find the file in the specified directory
|
||||
##
|
||||
## ``file`` can be a string or a regex object
|
||||
## `file` can be a string or a regex object
|
||||
##
|
||||
## Turn off recursive search with ``recurse`` and stop on first match with
|
||||
## ``first``. Without it, the shortest match is returned.
|
||||
## Turn off recursive search with `recurse` and stop on first match with
|
||||
## `first`. Without it, the shortest match is returned.
|
||||
when file is Regex:
|
||||
var
|
||||
rm: RegexMatch
|
||||
else:
|
||||
let
|
||||
dir = dir / file.parentDir()
|
||||
file = file.extractFilename
|
||||
|
||||
for f in walkDirRec(dir, yieldFilter = {pcFile, pcLinkToFile},
|
||||
followFilter = if recurse: {pcDir} else: {}):
|
||||
|
|
@ -311,6 +315,52 @@ proc configure*(path, check: string, flags = "") =
|
|||
|
||||
doAssert (path / check).fileExists(), "# Configure failed"
|
||||
|
||||
proc getCmakePropertyStr(name, property, value: string): string =
|
||||
&"\nset_target_properties({name} PROPERTIES {property} \"{value}\")\n"
|
||||
|
||||
proc setCmakeProperty*(outdir, name, property, value: string) =
|
||||
## Set a `cmake` property in `outdir / CMakeLists.txt` - usable in the `xxxPreBuild` hook
|
||||
## for `getHeader()`
|
||||
##
|
||||
## `set_target_properties(name PROPERTIES property "value")`
|
||||
let
|
||||
cm = outdir / "CMakeLists.txt"
|
||||
if cm.fileExists():
|
||||
cm.writeFile(
|
||||
cm.readFile() & getCmakePropertyStr(name, property, value)
|
||||
)
|
||||
|
||||
proc setCmakeLibName*(outdir, name, prefix = "", oname = "", suffix = "") =
|
||||
## Set a `cmake` property in `outdir / CMakeLists.txt` to specify a custom library output
|
||||
## name - usable in the `xxxPreBuild` hook for `getHeader()`
|
||||
##
|
||||
## `prefix` is typically `lib`
|
||||
## `oname` is the library name
|
||||
## `suffix` is typically `.a`
|
||||
##
|
||||
## Sometimes, `cmake` generates non-standard library names - e.g. zlib compiles to
|
||||
## `libzlibstatic.a` on Windows. This proc can help rename it to `libzlib.a` so that `getHeader()`
|
||||
## can find it after the library is compiled.
|
||||
##
|
||||
## ```
|
||||
## set_target_properties(name PROPERTIES PREFIX "prefix")
|
||||
## set_target_properties(name PROPERTIES OUTPUT_NAME "oname")
|
||||
## set_target_properties(name PROPERTIES SUFFIX "suffix")
|
||||
## ```
|
||||
let
|
||||
cm = outdir / "CMakeLists.txt"
|
||||
if cm.fileExists():
|
||||
var
|
||||
str = ""
|
||||
if prefix.len != 0:
|
||||
str &= getCmakePropertyStr(name, "PREFIX", prefix)
|
||||
if oname.len != 0:
|
||||
str &= getCmakePropertyStr(name, "OUTPUT_NAME", oname)
|
||||
if suffix.len != 0:
|
||||
str &= getCmakePropertyStr(name, "SUFFIX", suffix)
|
||||
if str.len != 0:
|
||||
cm.writeFile(cm.readFile() & str)
|
||||
|
||||
proc cmake*(path, check, flags: string) =
|
||||
## Run the `cmake` command to generate all Makefiles or other
|
||||
## build scripts in the specified path
|
||||
|
|
@ -349,7 +399,7 @@ proc make*(path, check: string|Regex, flags = "") =
|
|||
##
|
||||
## `flags` are any flags that should be passed to the `make` command.
|
||||
##
|
||||
## If make.exe is missing and mingw32-make.exe is available, it will
|
||||
## If `make.exe` is missing and `mingw32-make.exe` is available, it will
|
||||
## be copied over to make.exe in the same location.
|
||||
if findFile(check, path).len != 0:
|
||||
return
|
||||
|
|
@ -394,6 +444,9 @@ proc getGccPaths*(mode = "c"): seq[string] =
|
|||
if path notin result:
|
||||
result.add path
|
||||
|
||||
when defined(osx):
|
||||
result.add execAction("xcrun --show-sdk-path").strip() & "/usr/include"
|
||||
|
||||
proc getGccLibPaths*(mode = "c"): seq[string] =
|
||||
var
|
||||
nul = when defined(Windows): "nul" else: "/dev/null"
|
||||
|
|
@ -416,6 +469,9 @@ proc getGccLibPaths*(mode = "c"): seq[string] =
|
|||
if path notin result:
|
||||
result.add path
|
||||
|
||||
when defined(osx):
|
||||
result.add "/usr/lib"
|
||||
|
||||
proc getStdPath(header: string): string =
|
||||
for inc in getGccPaths():
|
||||
result = findFile(header, inc, recurse = false, first = true)
|
||||
|
|
@ -503,12 +559,19 @@ proc buildLibrary(lname, outdir, conFlags, cmakeFlags, makeFlags: string): strin
|
|||
gen = ""
|
||||
when defined(windows):
|
||||
if findExe("sh").len != 0:
|
||||
gen = "MSYS Makefiles"
|
||||
let
|
||||
uname = execAction("sh -c uname -a").toLowerAscii()
|
||||
if uname.contains("msys"):
|
||||
gen = "MSYS Makefiles".quoteShell
|
||||
elif uname.contains("mingw"):
|
||||
gen = "MinGW Makefiles".quoteShell & " -DCMAKE_SH=\"CMAKE_SH-NOTFOUND\""
|
||||
else:
|
||||
echo "Unsupported system: " & uname
|
||||
else:
|
||||
gen = "MinGW Makefiles"
|
||||
gen = "MinGW Makefiles".quoteShell
|
||||
else:
|
||||
gen = "Unix Makefiles"
|
||||
cmake(outdir / "build", "Makefile", &".. -G {gen.sanitizePath} {cmakeFlags}")
|
||||
gen = "Unix Makefiles".quoteShell
|
||||
cmake(outdir / "build", "Makefile", &".. -G {gen} {cmakeFlags}")
|
||||
cmakeDeps = true
|
||||
makePath = outdir / "build"
|
||||
else:
|
||||
|
|
@ -550,33 +613,54 @@ proc getDynlibExt(): string =
|
|||
result = ".dylib[0-9.]*"
|
||||
|
||||
macro getHeader*(header: static[string], giturl: static[string] = "", dlurl: static[string] = "", outdir: static[string] = "",
|
||||
conFlags: static[string] = "", cmakeFlags: static[string] = "", makeFlags: static[string] = ""): untyped =
|
||||
conFlags: static[string] = "", cmakeFlags: static[string] = "", makeFlags: static[string] = "",
|
||||
altNames: static[string] = ""): untyped =
|
||||
## Get the path to a header file for wrapping with
|
||||
## `cImport() <cimport.html#cImport.m%2C%2Cstring%2Cstring%2Cstring>`_ or
|
||||
## `c2nImport() <cimport.html#c2nImport.m%2C%2Cstring%2Cstring%2Cstring>`_.
|
||||
##
|
||||
## This proc checks -d:xxx defines based on the header name (e.g. lzma from lzma.h),
|
||||
## This proc checks `-d:xxx` defines based on the header name (e.g. lzma from lzma.h),
|
||||
## and accordingly employs different ways to obtain the source.
|
||||
##
|
||||
## ``-d:xxxStd`` - search standard system paths. E.g. ``/usr/include`` and ``/usr/lib`` on Linux
|
||||
## ``-d:xxxGit`` - clone source from a git repo specified in ``giturl``
|
||||
## ``-d:xxxDL`` - download source from ``dlurl`` and extract if required
|
||||
## `-d:xxxStd` - search standard system paths. E.g. `/usr/include` and `/usr/lib` on Linux
|
||||
## `-d:xxxGit` - clone source from a git repo specified in `giturl`
|
||||
## `-d:xxxDL` - download source from `dlurl` and extract if required
|
||||
##
|
||||
## This allows a single wrapper to be used in different ways depending on the user's needs.
|
||||
## If no -d:xxx defines are specified, ``outdir`` will be searched for the header.
|
||||
## If no `-d:xxx` defines are specified, `outdir` will be searched for the header as is.
|
||||
##
|
||||
## The library is then configured (with cmake or autotools if possible) and built
|
||||
## using make, unless using ``-d:xxxStd`` which presumes that the system package
|
||||
## `-d:xxxSetVer=x.y.z` can be used to specify which version to use. It is used as a tag
|
||||
## name for Git whereas for DL, it replaces `$1` in the URL defined.
|
||||
##
|
||||
## The library is then configured (with `cmake` or `autotools` if possible) and built
|
||||
## using `make`, unless using `-d:xxxStd` which presumes that the system package
|
||||
## manager was used to install prebuilt headers and binaries.
|
||||
##
|
||||
## The header path is stored in ``const xxxPath`` and can be used in a ``cImport()`` call
|
||||
## in the calling wrapper. The dynamic library path is stored in ``const xxxLPath`` and can
|
||||
## be used for the ``dynlib`` parameter (within quotes).
|
||||
## The header path is stored in `const xxxPath` and can be used in a `cImport()` call
|
||||
## in the calling wrapper. The dynamic library path is stored in `const xxxLPath` and can
|
||||
## be used for the `dynlib` parameter (within quotes) or with `{.passL.}`.
|
||||
##
|
||||
## ``-d:xxxStatic`` can be specified to statically link with the library instead. This
|
||||
## will automatically add a ``{.passL.}`` call to the static library for convenience.
|
||||
## `-d:xxxStatic` can be specified to statically link with the library instead. This
|
||||
## will automatically add a `{.passL.}` call to the static library for convenience.
|
||||
##
|
||||
## `conFlags`, `cmakeFlags` and `makeFlags` allow sending custom parameters to `configure`,
|
||||
## `cmake` and `make` in case additional configuration is required as part of the build process.
|
||||
##
|
||||
## `altNames` is a list of alternate names for the library - e.g. zlib uses `zlib.h` for the header but
|
||||
## the typical lib name is `libz.so` and not `libzlib.so`. In this case, `altNames = "z"`. Comma
|
||||
## separate for multiple alternate names.
|
||||
##
|
||||
## `xxxPreBuild` is a hook that is called after the source code is pulled from Git or downloaded but
|
||||
## before the library is built. This might be needed if some initial prep needs to be done before
|
||||
## compilation. A few values are provided to the hook to help provide context:
|
||||
##
|
||||
## `outdir` is the same `outdir` passed in and `header` is the discovered header path in the
|
||||
## downloaded source code.
|
||||
##
|
||||
## Simply define `proc xxxPreBuild(outdir, header: string)` in the wrapper and it will get called
|
||||
## prior to the build process.
|
||||
var
|
||||
name = header.split(".")[0]
|
||||
name = header.extractFilename().split(".")[0]
|
||||
|
||||
nameStd = newIdentNode(name & "Std")
|
||||
nameGit = newIdentNode(name & "Git")
|
||||
|
|
@ -586,10 +670,18 @@ macro getHeader*(header: static[string], giturl: static[string] = "", dlurl: sta
|
|||
|
||||
path = newIdentNode(name & "Path")
|
||||
lpath = newIdentNode(name & "LPath")
|
||||
version = newIdentNode(name & "Version")
|
||||
version = newIdentNode(name & "SetVer")
|
||||
lname = newIdentNode(name & "LName")
|
||||
preBuild = newIdentNode(name & "PreBuild")
|
||||
|
||||
lre = "(lib)?$1[0-9.\\-]*\\" % name
|
||||
lre = "(lib)?$1[_]?(static)?[0-9.\\-]*\\"
|
||||
|
||||
if altNames.len != 0:
|
||||
let
|
||||
names = "(" & name & "|" & altNames.replace(",", "|") & ")"
|
||||
lre = lre % names
|
||||
else:
|
||||
lre = lre % name
|
||||
|
||||
result = newNimNode(nnkStmtList)
|
||||
result.add(quote do:
|
||||
|
|
@ -615,6 +707,11 @@ macro getHeader*(header: static[string], giturl: static[string] = "", dlurl: sta
|
|||
else:
|
||||
getLocalPath(`header`, `outdir`)
|
||||
|
||||
when declared(`preBuild`):
|
||||
static:
|
||||
`preBuild`(`outdir`, `path`)
|
||||
|
||||
const
|
||||
`lpath`* = buildLibrary(`lname`, `outdir`, `conFlags`, `cmakeFlags`, `makeFlags`)
|
||||
|
||||
static:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ as a starting point for wrapping a new library. The template can be copied and
|
|||
trimmed down and modified as required. `templite.nim <https://github.com/nimterop/nimterop/blob/master/nimterop/templite.nim>`_ is a shorter
|
||||
version for more experienced users.
|
||||
|
||||
All ``{.compileTime.}`` procs must be used in a compile time context, e.g. using:
|
||||
All `{.compileTime.}` procs must be used in a compile time context, e.g. using:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
|
|
@ -194,7 +194,7 @@ macro cOverride*(body): untyped =
|
|||
## proc svGetCallerInfo(fileName: var cstring; lineNumber: var cint)
|
||||
##
|
||||
## Using the `cOverride() <cimport.html#cOverride.m>`_ block, nimterop
|
||||
## can be instructed to skip over ``svGetCallerInfo()``. This works for procs,
|
||||
## can be instructed to skip over `svGetCallerInfo()`. This works for procs,
|
||||
## consts and types.
|
||||
##
|
||||
## `cOverride() <cimport.html#cOverride.m>`_ only affects calls to
|
||||
|
|
@ -254,7 +254,7 @@ macro cPlugin*(body): untyped =
|
|||
## - `nskEnumField` for enum (field) names, though they are in the global namespace as `nskConst`
|
||||
## - `nskProc` - for proc names
|
||||
##
|
||||
## ``nimterop/plugins`` is implicitly imported to provide access to standard plugin facilities.
|
||||
## `nimterop/plugins` is implicitly imported to provide access to standard plugin facilities.
|
||||
##
|
||||
## `cPlugin() <cimport.html#cPlugin.m>`_ only affects calls to
|
||||
## `cImport() <cimport.html#cImport.m%2C%2Cstring%2Cstring%2Cstring>`_ that follow it.
|
||||
|
|
@ -288,7 +288,7 @@ macro cPlugin*(body): untyped =
|
|||
gStateCT.pluginSourcePath = path
|
||||
|
||||
proc cSearchPath*(path: string): string {.compileTime.}=
|
||||
## Get full path to file or directory ``path`` in search path configured
|
||||
## Get full path to file or directory `path` in search path configured
|
||||
## using `cAddSearchDir() <cimport.html#cAddSearchDir%2Cstring>`_ and
|
||||
## `cAddStdDir() <cimport.html#cAddStdDir,string>`_.
|
||||
##
|
||||
|
|
@ -321,15 +321,15 @@ proc cDisableCaching*() {.compileTime.} =
|
|||
## value will continue to be used . Use `cDisableCaching() <cimport.html#cDisableCaching>`_
|
||||
## to avoid this scenario during development.
|
||||
##
|
||||
## ``nim -f`` was broken prior to 0.19.4 but can also be used to flush the cached content.
|
||||
## `nim -f` was broken prior to 0.19.4 but can also be used to flush the cached content.
|
||||
|
||||
gStateCT.nocache = true
|
||||
|
||||
macro cDefine*(name: static string, val: static string = ""): untyped =
|
||||
## ``#define`` an identifer that is forwarded to the C/C++ preprocessor if
|
||||
## `#define` an identifer that is forwarded to the C/C++ preprocessor if
|
||||
## called within `cImport() <cimport.html#cImport.m%2C%2Cstring%2Cstring%2Cstring>`_
|
||||
## or `c2nImport() <cimport.html#c2nImport.m%2C%2Cstring%2Cstring%2Cstring>`_
|
||||
## as well as to the C/C++ compiler during Nim compilation using ``{.passC: "-DXXX".}``
|
||||
## as well as to the C/C++ compiler during Nim compilation using `{.passC: "-DXXX".}`
|
||||
|
||||
result = newNimNode(nnkStmtList)
|
||||
|
||||
|
|
@ -350,7 +350,7 @@ macro cDefine*(name: static string, val: static string = ""): untyped =
|
|||
echo result.repr & "\n"
|
||||
|
||||
proc cAddSearchDir*(dir: string) {.compileTime.} =
|
||||
## Add directory ``dir`` to the search path used in calls to
|
||||
## Add directory `dir` to the search path used in calls to
|
||||
## `cSearchPath() <cimport.html#cSearchPath,string>`_.
|
||||
runnableExamples:
|
||||
import paths, os
|
||||
|
|
@ -365,7 +365,7 @@ macro cIncludeDir*(dir: static string): untyped =
|
|||
## Add an include directory that is forwarded to the C/C++ preprocessor if
|
||||
## called within `cImport() <cimport.html#cImport.m%2C%2Cstring%2Cstring%2Cstring>`_
|
||||
## or `c2nImport() <cimport.html#c2nImport.m%2C%2Cstring%2Cstring%2Cstring>`_
|
||||
## as well as to the C/C++ compiler during Nim compilation using ``{.passC: "-IXXX".}``.
|
||||
## as well as to the C/C++ compiler during Nim compilation using `{.passC: "-IXXX".}`.
|
||||
|
||||
var dir = interpPath(dir)
|
||||
result = newNimNode(nnkStmtList)
|
||||
|
|
@ -380,7 +380,7 @@ macro cIncludeDir*(dir: static string): untyped =
|
|||
echo result.repr
|
||||
|
||||
proc cAddStdDir*(mode = "c") {.compileTime.} =
|
||||
## Add the standard ``c`` [default] or ``cpp`` include paths to search
|
||||
## Add the standard `c` [default] or `cpp` include paths to search
|
||||
## path used in calls to `cSearchPath() <cimport.html#cSearchPath,string>`_
|
||||
runnableExamples:
|
||||
static: cAddStdDir()
|
||||
|
|
@ -390,24 +390,24 @@ proc cAddStdDir*(mode = "c") {.compileTime.} =
|
|||
cAddSearchDir inc
|
||||
|
||||
macro cCompile*(path: static string, mode = "c", exclude = ""): untyped =
|
||||
## Compile and link C/C++ implementation into resulting binary using ``{.compile.}``
|
||||
## Compile and link C/C++ implementation into resulting binary using `{.compile.}`
|
||||
##
|
||||
## ``path`` can be a specific file or contain wildcards:
|
||||
## `path` can be a specific file or contain wildcards:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
## cCompile("file.c")
|
||||
## cCompile("path/to/*.c")
|
||||
##
|
||||
## ``mode`` recursively searches for code files in ``path``.
|
||||
## `mode` recursively searches for code files in `path`.
|
||||
##
|
||||
## ``c`` searches for ``*.c`` whereas ``cpp`` searches for ``*.C *.cpp *.c++ *.cc *.cxx``
|
||||
## `c` searches for `*.c` whereas `cpp` searches for `*.C *.cpp *.c++ *.cc *.cxx`
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
## cCompile("path/to/dir", "cpp")
|
||||
##
|
||||
## ``exclude`` can be used to exclude files by partial string match. Comma separated to
|
||||
## `exclude` can be used to exclude files by partial string match. Comma separated to
|
||||
## specify multiple exclude strings
|
||||
##
|
||||
## .. code-block:: nim
|
||||
|
|
@ -485,16 +485,16 @@ macro cCompile*(path: static string, mode = "c", exclude = ""): untyped =
|
|||
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
|
||||
## content is cached in ``nimcache`` until ``filename`` changes unless
|
||||
## `cDisableCaching() <cimport.html#cDisableCaching>`_ is set. ``nim -f``
|
||||
## content is cached in `nimcache` until `filename` changes unless
|
||||
## `cDisableCaching() <cimport.html#cDisableCaching>`_ is set. `nim -f`
|
||||
## can also be used after Nim v0.19.4 to flush the cache.
|
||||
##
|
||||
## ``recurse`` can be used to generate Nim wrappers from ``#include`` files
|
||||
## referenced in ``filename``. This is only done for files in the same
|
||||
## directory as ``filename`` or in a directory added using
|
||||
## `recurse` can be used to generate Nim wrappers from `#include` files
|
||||
## 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
|
||||
## `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
|
||||
|
|
@ -513,14 +513,14 @@ macro cImport*(filename: static string, recurse: static bool = false, dynlib: st
|
|||
##
|
||||
## cImport("pcre.h", dynlib="dynpcre")
|
||||
##
|
||||
## If ``dynlib`` is not specified, the C/C++ implementation files can be compiled in
|
||||
## If `dynlib` is not specified, the C/C++ implementation files can be compiled in
|
||||
## with `cCompile() <cimport.html#cCompile.m%2C%2Cstring%2Cstring>`_, or the
|
||||
## ``{.passL.}`` pragma can be used to specify the static lib to link.
|
||||
## `{.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
|
||||
## `mode` is purely for forward compatibility when toast adds C++ support. It can
|
||||
## be ignored for the foreseeable future.
|
||||
##
|
||||
## ``flags`` can be used to pass any other command line arguments to ``toast``.
|
||||
## `flags` can be used to pass any other command line arguments to `toast`.
|
||||
|
||||
result = newNimNode(nnkStmtList)
|
||||
|
||||
|
|
@ -546,24 +546,24 @@ macro cImport*(filename: static string, recurse: static bool = false, dynlib: st
|
|||
|
||||
macro c2nImport*(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 using ``c2nim``
|
||||
## Import all supported definitions from specified header file using `c2nim`
|
||||
##
|
||||
## Similar to `cImport() <cimport.html#cImport.m%2C%2Cstring%2Cstring%2Cstring>`_
|
||||
## but uses ``c2nim`` to generate the Nim wrapper instead of ``toast``. Note that neither
|
||||
## but uses `c2nim` to generate the Nim wrapper instead of `toast`. Note that neither
|
||||
## `cOverride() <cimport.html#cOverride.m>`_, `cSkipSymbol() <cimport.html#cSkipSymbol%2Cseq[T][string]>`_
|
||||
## nor `cPlugin() <cimport.html#cPlugin.m>`_ have any impact on ``c2nim``.
|
||||
## nor `cPlugin() <cimport.html#cPlugin.m>`_ have any impact on `c2nim`.
|
||||
##
|
||||
## ``toast`` is only used to preprocess the header file and recurse
|
||||
## `toast` is only used to preprocess the header file and recurse
|
||||
## if specified.
|
||||
##
|
||||
## ``mode`` should be set to ``cpp`` for c2nim to wrap C++ headers.
|
||||
## `mode` should be set to `cpp` for c2nim to wrap C++ headers.
|
||||
##
|
||||
## ``flags`` can be used to pass other command line arguments to ``c2nim``.
|
||||
## `flags` can be used to pass other command line arguments to `c2nim`.
|
||||
##
|
||||
## ``nimterop`` does not depend on ``c2nim`` as a ``nimble`` dependency so it
|
||||
## `nimterop` does not depend on `c2nim` as a `nimble` dependency so it
|
||||
## does not get installed automatically. Any wrapper or library that requires this proc
|
||||
## needs to install ``c2nim`` with ``nimble install c2nim`` or add it as a dependency in
|
||||
## its own ``.nimble`` file.
|
||||
## needs to install `c2nim` with `nimble install c2nim` or add it as a dependency in
|
||||
## its own `.nimble` file.
|
||||
|
||||
result = newNimNode(nnkStmtList)
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ when while
|
|||
xor
|
||||
yield""".split(Whitespace).toSet()
|
||||
|
||||
const gTypeMap = {
|
||||
const gTypeMap* = {
|
||||
# char
|
||||
"char": "cchar",
|
||||
"signed char": "cschar",
|
||||
|
|
@ -39,6 +39,8 @@ const gTypeMap = {
|
|||
"signed short int": "cshort",
|
||||
"unsigned short": "cushort",
|
||||
"unsigned short int": "cushort",
|
||||
"uShort": "cushort",
|
||||
"u_short": "cushort",
|
||||
|
||||
# int
|
||||
"int": "cint",
|
||||
|
|
@ -47,6 +49,8 @@ const gTypeMap = {
|
|||
"ssize_t": "cint",
|
||||
"unsigned": "cuint",
|
||||
"unsigned int": "cuint",
|
||||
"uInt": "cuint",
|
||||
"u_int": "cuint",
|
||||
"size_t": "cuint",
|
||||
|
||||
# long
|
||||
|
|
@ -57,6 +61,8 @@ const gTypeMap = {
|
|||
"off_t": "clong",
|
||||
"unsigned long": "culong",
|
||||
"unsigned long int": "culong",
|
||||
"uLong": "culong",
|
||||
"u_long": "culong",
|
||||
|
||||
# long long
|
||||
"long long": "clonglong",
|
||||
|
|
@ -79,8 +85,8 @@ proc getType*(str: string): string =
|
|||
|
||||
result = str.strip(chars={'_'}).
|
||||
replace(re"\s+", " ").
|
||||
replace(re"([u]?int[\d]+)_t", "$1").
|
||||
replace(re"([u]?int)ptr_t", "ptr $1")
|
||||
replace(re"^([u]?int[\d]+)_t$", "$1").
|
||||
replace(re"^([u]?int)ptr_t$", "ptr $1")
|
||||
|
||||
if gTypeMap.hasKey(result):
|
||||
result = gTypeMap[result]
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ proc initGrammar(): Grammar =
|
|||
"""
|
||||
|
||||
template funcParamCommon(fname, pname, ptyp, pptr, pout, count, i: untyped): untyped =
|
||||
ptyp = nimState.getIdentifier(nimState.data[i].val, nskType, fname)
|
||||
ptyp = nimState.getIdentifier(nimState.data[i].val, nskType, fname).getType()
|
||||
|
||||
pptr = ""
|
||||
while i+1 < nimState.data.len and nimState.data[i+1].name == "pointer_declarator":
|
||||
|
|
@ -137,7 +137,7 @@ proc initGrammar(): Grammar =
|
|||
|
||||
var
|
||||
i = 0
|
||||
typ = nimState.getIdentifier(nimState.data[i].val, nskType)
|
||||
typ = nimState.getIdentifier(nimState.data[i].val, nskType).getType()
|
||||
name = ""
|
||||
nname = ""
|
||||
tptr = ""
|
||||
|
|
@ -161,7 +161,7 @@ proc initGrammar(): Grammar =
|
|||
let
|
||||
pragma = nimState.getPragma(nimState.getImportC(name, nname))
|
||||
|
||||
if typ.nBl and nname.nBl and nimState.addNewIdentifer(nname):
|
||||
if nname notin gTypeMap and typ.nBl and nname.nBl and nimState.addNewIdentifer(nname):
|
||||
if i < nimState.data.len and nimState.data[^1].name == "function_declarator":
|
||||
var
|
||||
fname = nname
|
||||
|
|
@ -575,7 +575,7 @@ proc initGrammar(): Grammar =
|
|||
|
||||
if fnname.nBl and nimState.addNewIdentifer(fnname):
|
||||
let
|
||||
ftyp = nimState.getIdentifier(nimState.data[0].val, nskType, fnname)
|
||||
ftyp = nimState.getIdentifier(nimState.data[0].val, nskType, fnname).getType()
|
||||
pragma = nimState.getPragma(nimState.getImportC(fname, fnname), "cdecl")
|
||||
|
||||
if fptr.len != 0 or ftyp != "object":
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import strutils
|
|||
proc testCall(cmd, output: string, exitCode: int, delete = true) =
|
||||
if delete:
|
||||
rmDir("build/liblzma")
|
||||
rmDir("build/zlib")
|
||||
echo cmd
|
||||
var
|
||||
ccmd =
|
||||
|
|
@ -17,26 +18,45 @@ proc testCall(cmd, output: string, exitCode: int, delete = true) =
|
|||
|
||||
var
|
||||
cmd = "nim c -f"
|
||||
rcmd = " -r lzma.nim"
|
||||
exp = "liblzma version = "
|
||||
lrcmd = " -r lzma.nim"
|
||||
zrcmd = " -r zlib.nim"
|
||||
lexp = "liblzma version = "
|
||||
zexp = "zlib version = "
|
||||
|
||||
testCall(cmd & lrcmd, "No build files found", 1)
|
||||
|
||||
when defined(posix):
|
||||
testCall(cmd & rcmd, "No build files found", 1)
|
||||
|
||||
# stdlib
|
||||
testCall(cmd & " -d:lzmaStd" & rcmd, exp, 0)
|
||||
testCall(cmd & " -d:lzmaStd -d:lzmaStatic" & rcmd, exp, 0)
|
||||
testCall(cmd & " -d:lzmaStd" & lrcmd, lexp, 0)
|
||||
testCall(cmd & " -d:lzmaStd -d:lzmaStatic" & lrcmd, lexp, 0)
|
||||
|
||||
when not defined(osx):
|
||||
testCall(cmd & " -d:zlibStd" & zrcmd, zexp, 0)
|
||||
testCall(cmd & " -d:zlibStd -d:zlibStatic" & zrcmd, zexp, 0)
|
||||
|
||||
# git
|
||||
testCall(cmd & " -d:lzmaGit" & rcmd, exp, 0)
|
||||
testCall(cmd & " -d:lzmaGit -d:lzmaStatic" & rcmd, exp, 0, delete = false)
|
||||
testCall(cmd & " -d:lzmaGit" & lrcmd, lexp, 0)
|
||||
testCall(cmd & " -d:lzmaGit -d:lzmaStatic" & lrcmd, lexp, 0, delete = false)
|
||||
|
||||
# git tag
|
||||
testCall(cmd & " -d:lzmaGit -d:lzmaVersion=v5.2.0" & rcmd, exp & "5.2.0", 0)
|
||||
testCall(cmd & " -d:lzmaGit -d:lzmaStatic -d:lzmaVersion=v5.2.0" & rcmd, exp & "5.2.0", 0, delete = false)
|
||||
testCall(cmd & " -d:lzmaGit -d:lzmaSetVer=v5.2.0" & lrcmd, lexp & "5.2.0", 0)
|
||||
testCall(cmd & " -d:lzmaGit -d:lzmaStatic -d:lzmaSetVer=v5.2.0" & lrcmd, lexp & "5.2.0", 0, delete = false)
|
||||
testCall("cd build/liblzma && git branch", "v5.2.0", 0, delete = false)
|
||||
|
||||
# git
|
||||
testCall(cmd & " -d:zlibGit" & zrcmd, zexp, 0)
|
||||
testCall(cmd & " -d:zlibGit -d:zlibStatic" & zrcmd, zexp, 0, delete = false)
|
||||
|
||||
# git tag
|
||||
testCall(cmd & " -d:zlibGit -d:zlibSetVer=v1.2.10" & zrcmd, zexp & "1.2.10", 0)
|
||||
testCall(cmd & " -d:zlibGit -d:zlibStatic -d:zlibSetVer=v1.2.10" & zrcmd, zexp & "1.2.10", 0, delete = false)
|
||||
testCall("cd build/zlib && git branch", "v1.2.10", 0, delete = false)
|
||||
|
||||
# dl
|
||||
testCall(cmd & " -d:lzmaDL" & rcmd, "Need version", 1)
|
||||
testCall(cmd & " -d:lzmaDL -d:lzmaVersion=5.2.4" & rcmd, exp & "5.2.4", 0)
|
||||
testCall(cmd & " -d:lzmaDL -d:lzmaStatic -d:lzmaVersion=5.2.4" & rcmd, exp & "5.2.4", 0, delete = false)
|
||||
testCall(cmd & " -d:lzmaDL" & lrcmd, "Need version", 1)
|
||||
testCall(cmd & " -d:lzmaDL -d:lzmaSetVer=5.2.4" & lrcmd, lexp & "5.2.4", 0)
|
||||
testCall(cmd & " -d:lzmaDL -d:lzmaStatic -d:lzmaSetVer=5.2.4" & lrcmd, lexp & "5.2.4", 0, delete = false)
|
||||
|
||||
# dl
|
||||
testCall(cmd & " -d:zlibDL -d:zlibSetVer=1.2.11" & zrcmd, zexp & "1.2.11", 0)
|
||||
testCall(cmd & " -d:zlibDL -d:zlibStatic -d:zlibSetVer=1.2.11" & zrcmd, zexp & "1.2.11", 0, delete = false)
|
||||
|
|
|
|||
68
tests/zlib.nim
Normal file
68
tests/zlib.nim
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import os, strutils
|
||||
|
||||
import nimterop/[build, cimport]
|
||||
|
||||
const
|
||||
baseDir = currentSourcePath.parentDir()/"build"/"zlib"
|
||||
|
||||
static:
|
||||
cDebug()
|
||||
|
||||
proc zlibPreBuild(outdir, path: string) =
|
||||
let
|
||||
mf = outdir / "Makefile"
|
||||
if mf.fileExists():
|
||||
# Delete default Makefile
|
||||
if mf.readFile().contains("configure first"):
|
||||
mf.rmFile()
|
||||
when defined(windows):
|
||||
# Fix static lib name on Windows
|
||||
setCmakeLibName(outdir, "zlibstatic", prefix = "lib", oname = "zlib", suffix = ".a")
|
||||
|
||||
getHeader(
|
||||
"zlib.h",
|
||||
giturl = "https://github.com/madler/zlib",
|
||||
dlurl = "http://zlib.net/zlib-$1.tar.gz",
|
||||
outdir = baseDir,
|
||||
altNames = "z"
|
||||
)
|
||||
|
||||
cPlugin:
|
||||
import regex, strutils
|
||||
|
||||
proc onSymbol*(sym: var Symbol) {.exportc, dynlib.} =
|
||||
sym.name = sym.name.replace(re"_[_]+", "_").strip(chars = {'_'})
|
||||
|
||||
cOverride:
|
||||
type
|
||||
voidpf = ptr object
|
||||
voidpc = ptr object
|
||||
voidp = ptr object
|
||||
uLongf = culong
|
||||
z_size_t = culong
|
||||
z_crc_t = culong
|
||||
alloc_func* {.importc.} = proc(opaque: voidpf, items, size: uint) {.cdecl.}
|
||||
Bytef {.importc.} = object
|
||||
|
||||
when defined(posix):
|
||||
type
|
||||
pthread_mutex_s = object
|
||||
pthread_cond_s = object
|
||||
pthread_rwlock_arch_t = object
|
||||
extension = object
|
||||
fd_set = object
|
||||
|
||||
when defined(posix):
|
||||
static:
|
||||
cSkipSymbol(@["u_int8_t", "u_int16_t", "u_int32_t", "u_int64_t"])
|
||||
|
||||
when defined(zlibGit) or defined(zlibDL):
|
||||
when dirExists(baseDir / "build"):
|
||||
cIncludeDir(baseDir / "build")
|
||||
|
||||
when not defined(zlibStatic):
|
||||
cImport(zlibPath, recurse = true, dynlib = "zlibLPath")
|
||||
else:
|
||||
cImport(zlibPath, recurse = true)
|
||||
|
||||
echo "zlib version = " & $zlibVersion()
|
||||
Loading…
Add table
Add a link
Reference in a new issue