refs #68; turn some macros to CT procs; fix #112 (doc fixes) (#102)

* refs #68 macro=>proc cSkipSymbol
* refs #68 macro=>proc cDebug
* refs #68 macro=>proc cDisableCaching
* refs #68 notes for cDefine
* refs #68 macro=>proc cAddSearchDir ; improve some runnableExamples
* refs #68 macro=>proc cAddStdDir
* $projpath/include => testsIncludeDir() everywhere
* disable $projpath interpolation (error prone)
* fix tests
* make nim doc part of test suite; fix for 0.19.2
This commit is contained in:
Timothee Cour 2019-02-02 16:03:46 -08:00 • committed by genotrance
commit 9fe45ac32b
11 changed files with 99 additions and 77 deletions

View file

@ -36,7 +36,8 @@ __Usage__
```nim ```nim
import nimterop/cimport import nimterop/cimport
cDebug() static:
cDebug()
cDefine("HAS_ABC") cDefine("HAS_ABC")
cDefine("HAS_ABC", "DEF") cDefine("HAS_ABC", "DEF")
cIncludeDir("clib/include") cIncludeDir("clib/include")

View file

@ -43,14 +43,18 @@ proc testAll() =
if defined(OSX) or defined(Windows) or not existsEnv("TRAVIS"): if defined(OSX) or defined(Windows) or not existsEnv("TRAVIS"):
tsoloud() # requires some libraries on linux, need them installed in TRAVIS tsoloud() # requires some libraries on linux, need them installed in TRAVIS
const htmldocsDir = "build/htmldocs"
proc runNimDoc() =
execCmd &"nim doc -o:{htmldocsDir} --project --index:on nimterop/all.nim"
task test, "Test": task test, "Test":
for options in ["", "-d:release"]: for options in ["", "-d:release"]:
buildToast(options) buildToast(options)
testAll() testAll()
runNimDoc()
task docs, "Generate docs": task docs, "Generate docs":
# Uses: pip install ghp-import # Uses: pip install ghp-import
execCmd "nim doc --project --index:on nimterop/cimport" runNimDoc()
execCmd "nim doc --project --index:on nimterop/git" execCmd &"ghp-import --no-jekyll -fp {htmldocsDir}"
execCmd "nim doc --project --index:on nimterop/plugin"
execCmd "ghp-import --no-jekyll -fp nimterop/htmldocs"

7
nimterop/all.nim Normal file
View file

@ -0,0 +1,7 @@
##[
Module that should import everything so that `nim doc --project nimtero/all` runs docs on everything.
]##
# TODO: make sure it does import everything.
import "."/[cimport,git,plugin]

View file

@ -1,3 +1,13 @@
##[
Main import file to write wrappers.
Each `compileTime` proc must be used in a compile time context, eg using:
```
static:
cAddStdDir()
```
]##
import hashes, macros, os, strformat, strutils import hashes, macros, os, strformat, strutils
const CIMPORT {.used.} = 1 const CIMPORT {.used.} = 1
@ -9,7 +19,10 @@ export types
proc interpPath(dir: string): string= proc interpPath(dir: string): string=
# TODO: more robust: needs a DirSep after "$projpath" # TODO: more robust: needs a DirSep after "$projpath"
result = dir.replace("$projpath", getProjectPath()) # disabling this interpolation as this is error prone, but other less
# interpolations can be added, eg see https://github.com/nim-lang/Nim/pull/10530
# result = dir.replace("$projpath", getProjectPath())
result = dir
proc joinPathIfRel(path1: string, path2: string): string = proc joinPathIfRel(path1: string, path2: string): string =
if path2.isAbsolute: if path2.isAbsolute:
@ -184,18 +197,15 @@ macro cOverride*(body): untyped =
if gStateCT.debug: if gStateCT.debug:
echo "Overriding " & gStateCT.symOverride.join(" ") echo "Overriding " & gStateCT.symOverride.join(" ")
macro cSkipSymbol*(skips: varargs[string]): untyped = proc cSkipSymbol*(skips: seq[string]) {.compileTime.} =
## Similar to `cOverride() <cimport.html#cOverride.m,>`_, this macro allows ## Similar to `cOverride() <cimport.html#cOverride.m,>`_, this macro allows
## filtering out symbols not of interest from the generated output. ## filtering out symbols not of interest from the generated output.
##
runnableExamples: runnableExamples:
cSkipSymbol "proc1", "Type2" static: cSkipSymbol @["proc1", "Type2"]
gStateCT.symOverride.add skips
for skip in skips:
gStateCT.symOverride.add skip.strVal
macro cPlugin*(body): untyped = macro cPlugin*(body): untyped =
## When `cOverride() <cimport.html#cOverride.m,>`_ and `cSkipSymbol() <cimport.html#cSkipSymbol.m%2Cvarargs[string]>`_ ## When `cOverride() <cimport.html#cOverride.m,>`_ and `cSkipSymbol() <cimport.html#cSkipSymbol.m%2Cseq[string]>`_
## are not adequate, the `cPlugin() <cimport.html#cPlugin.m,>`_ macro can be used ## are not adequate, the `cPlugin() <cimport.html#cPlugin.m,>`_ macro can be used
## to customize the generated Nim output. The following callbacks are available at ## to customize the generated Nim output. The following callbacks are available at
## this time. ## this time.
@ -242,8 +252,8 @@ macro cPlugin*(body): untyped =
proc cSearchPath*(path: string): string {.compileTime.}= 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.m,>`_ and ## using `cAddSearchDir() <cimport.html#cAddSearchDir,>`_ and
## `cAddStdDir() <cimport.html#cAddStdDir.m,string>`_. ## `cAddStdDir() <cimport.html#cAddStdDir,string>`_.
## ##
## This can be used to locate files or directories that can be passed onto ## This can be used to locate files or directories that can be passed onto
## `cCompile() <cimport.html#cCompile.m,,string>`_, ## `cCompile() <cimport.html#cCompile.m,,string>`_,
@ -261,23 +271,25 @@ proc cSearchPath*(path: string): string {.compileTime.}=
doAssert found, "File or directory not found: " & path & doAssert found, "File or directory not found: " & path &
" gStateCT.searchDirs: " & $gStateCT.searchDirs " gStateCT.searchDirs: " & $gStateCT.searchDirs
macro cDebug*(): untyped = proc cDebug*() {.compileTime.} =
## Enable debug messages and display the generated Nim code ## Enable debug messages and display the generated Nim code
gStateCT.debug = true gStateCT.debug = true
macro cDisableCaching*(): untyped = proc cDisableCaching*() {.compileTime.} =
## Disable caching of generated Nim code - useful during wrapper development ## Disable caching of generated Nim code - useful during wrapper development
## ##
## If files included by header being processed by `cImport() <cimport.html#cImport.m,>`_ ## If files included by header being processed by `cImport() <cimport.html#cImport.m,>`_
## change and affect the generated content, they will be ignored and the cached ## change and affect the generated content, they will be ignored and the cached
## value will continue to be used . Use `cDisableCaching() <cimport.html#cDisableCaching.m,>`_ ## value will continue to be used . Use `cDisableCaching() <cimport.html#cDisableCaching,>`_
## to avoid this scenario during development. ## 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 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 = macro cDefine*(name: static string, val: static string = ""): untyped =
## ``#define`` an identifer that is forwarded to the C/C++ compiler ## ``#define`` an identifer that is forwarded to the C/C++ compiler
## using ``{.passC: "-DXXX".}`` ## using ``{.passC: "-DXXX".}``
@ -285,6 +297,8 @@ macro cDefine*(name: static string, val: static string = ""): untyped =
result = newNimNode(nnkStmtList) result = newNimNode(nnkStmtList)
var str = name var str = name
# todo: see https://github.com/genotrance/nimterop/issues/100 for
# edge case of empty strings
if val.nBl: if val.nBl:
str &= &"={val.quoteShell}" str &= &"={val.quoteShell}"
@ -292,24 +306,20 @@ macro cDefine*(name: static string, val: static string = ""): untyped =
gStateCT.defines.add(str) gStateCT.defines.add(str)
str = "-D" & str str = "-D" & str
result.add(quote do: result.add quote do:
{.passC: `str`.} {.passC: `str`.}
)
if gStateCT.debug: if gStateCT.debug:
echo result.repr echo result.repr
macro cAddSearchDir*(dir: static string): untyped = 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>`_. ## `cSearchPath() <cimport.html#cSearchPath,string>`_.
## runnableExamples:
## This allows something like this: import paths, os
## static:
## .. code-block:: nim cAddSearchDir testsIncludeDir()
## doAssert cSearchPath("test.h").existsFile
## cAddSearchDir("path/to/includes")
## cImport cSearchPath("file.h")
var dir = interpPath(dir) var dir = interpPath(dir)
if dir notin gStateCT.searchDirs: if dir notin gStateCT.searchDirs:
gStateCT.searchDirs.add(dir) gStateCT.searchDirs.add(dir)
@ -322,46 +332,32 @@ macro cIncludeDir*(dir: static string): untyped =
var dir = interpPath(dir) var dir = interpPath(dir)
result = newNimNode(nnkStmtList) result = newNimNode(nnkStmtList)
let let fullpath = findPath(dir)
fullpath = findPath(dir)
str = &"-I{fullpath.quoteShell}"
if fullpath notin gStateCT.includeDirs: if fullpath notin gStateCT.includeDirs:
gStateCT.includeDirs.add(fullpath) gStateCT.includeDirs.add(fullpath)
let str = &"-I{fullpath.quoteShell}"
result.add(quote do: result.add quote do:
{.passC: `str`.} {.passC: `str`.}
) if gStateCT.debug:
echo result.repr
if gStateCT.debug: proc cAddStdDir*(mode = "c") {.compileTime.} =
echo result.repr
macro cAddStdDir*(mode = "c"): untyped =
## 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>`_ ## path used in calls to `cSearchPath() <cimport.html#cSearchPath,string>`_
##
## This allows something like this:
##
runnableExamples: runnableExamples:
cAddStdDir() static: cAddStdDir()
echo cSearchPath("math.h") import os
doAssert cSearchPath("math.h").existsFile
result = newNimNode(nnkStmtList)
var var
inc = false inc = false
for line in getGccPaths(mode).splitLines():
for line in getGccPaths(mode.strVal()).splitLines():
if "#include <...> search starts here" in line: if "#include <...> search starts here" in line:
inc = true inc = true
continue continue
elif "End of search list" in line: elif "End of search list" in line:
break break
if inc: if inc:
let sline = line.strip() cAddSearchDir line.strip()
result.add quote do:
cAddSearchDir(`sline`)
macro cCompile*(path: static string, mode = "c"): untyped = macro cCompile*(path: static string, mode = "c"): untyped =
## Compile and link C/C++ implementation into resulting binary using ``{.compile.}`` ## Compile and link C/C++ implementation into resulting binary using ``{.compile.}``
@ -430,7 +426,7 @@ macro cCompile*(path: static string, mode = "c"): untyped =
macro cImport*(filename: static string, recurse: static bool = false): untyped = macro cImport*(filename: static string, recurse: static bool = false): untyped =
## Import all supported definitions from specified header file. Generated ## Import all supported definitions from specified header file. Generated
## content is cached in ``nimcache`` until ``filename`` changes unless ## content is cached in ``nimcache`` until ``filename`` changes unless
## `cDisableCaching() <cimport.html#cDisableCaching.m,>`_ is set. ``nim -f`` ## `cDisableCaching() <cimport.html#cDisableCaching,>`_ is set. ``nim -f``
## can also be used after Nim v0.19.4 to flush the cache. ## can also be used after Nim v0.19.4 to flush the cache.
## ##
## ``recurse`` can be used to generate Nim wrappers from ``#include`` files ## ``recurse`` can be used to generate Nim wrappers from ``#include`` files

View file

@ -15,3 +15,7 @@ proc toastExePath*(): string =
proc incDir*(): string = proc incDir*(): string =
nimteropBuildDir() / "inc" nimteropBuildDir() / "inc"
proc testsIncludeDir*(): string =
nimteropRoot() / "tests" / "include"

View file

@ -0,0 +1,7 @@
#[
pending https://github.com/nim-lang/Nim/pull/10530
note: nimble init installs something like this (maybe without src in this case)
switch("path", "$projectDir/../src")
but it doesn't seem robust in case tests have subdirs, so, changing to ../ seems better
]#
switch("path", "..")

2
tests/nim.cfg Normal file
View file

@ -0,0 +1,2 @@
# TODO: pending https://github.com/nimterop/nimterop/issues/110 remove in favor of config.nims
--path:".."

View file

@ -1,15 +1,15 @@
import nimterop/cimport
import unittest import unittest
import nimterop/cimport
type type
locale_t = object locale_t = object
mingw_ldbl_type_t = object mingw_ldbl_type_t = object
mingw_dbl_type_t = object mingw_dbl_type_t = object
cDebug() static:
cDisableCaching() cDebug()
cDisableCaching()
cAddStdDir() cAddStdDir()
cPlugin: cPlugin:
import strutils import strutils
@ -21,4 +21,4 @@ cImport cSearchPath("math.h")
check sin(5) == -0.9589242746631385 check sin(5) == -0.9589242746631385
check abs(-5) == 5 check abs(-5) == 5
check sqrt(4.00) == 2.0 check sqrt(4.00) == 2.0

View file

@ -1,12 +1,14 @@
import std/unittest import std/unittest
import nimterop/cimport import nimterop/cimport
import nimterop/paths
cDebug() static:
cDisableCaching() cDebug()
cDisableCaching()
cAddSearchDir testsIncludeDir()
cDefine("FORCE") cDefine("FORCE")
cIncludeDir "$projpath/include" cIncludeDir testsIncludeDir()
cAddSearchDir "$projpath/include"
cCompile cSearchPath("test.c") cCompile cSearchPath("test.c")
cPlugin: cPlugin:
@ -137,8 +139,6 @@ var
k: uKernel k: uKernel
kp: Kernel kp: Kernel
cAddStdDir()
## failing tests ## failing tests
when false: when false:
static: # Error: undeclared identifier: 'foobar1' static: # Error: undeclared identifier: 'foobar1'

View file

@ -1,11 +1,13 @@
import nimterop/cimport
import unittest import unittest
import nimterop/cimport
import nimterop/paths
cDebug() static:
cDisableCaching() cDebug()
cDisableCaching()
cAddSearchDir testsIncludeDir()
cIncludeDir "$projpath/include" cIncludeDir testsIncludeDir()
cAddSearchDir "$projpath/include"
cCompile cSearchPath "test2.cpp" cCompile cSearchPath "test2.cpp"
cImport cSearchPath "test2.hpp" cImport cSearchPath "test2.hpp"

View file

@ -7,9 +7,8 @@ const
static: static:
gitPull("https://github.com/jarikomppa/soloud", baseDir, "include/*\nsrc/*\n") gitPull("https://github.com/jarikomppa/soloud", baseDir, "include/*\nsrc/*\n")
cDebug()
cDebug() cDisableCaching()
cDisableCaching()
cOverride: cOverride:
type type
@ -18,7 +17,7 @@ cOverride:
proc Soloud_destroy*(aSoloud: ptr Soloud) {.importc: "Soloud_destroy", header: cSearchPath(incl/"soloud_c.h").} proc Soloud_destroy*(aSoloud: ptr Soloud) {.importc: "Soloud_destroy", header: cSearchPath(incl/"soloud_c.h").}
cSkipSymbol("WavStream_stop", "WavStream_setFilter") static: cSkipSymbol @["WavStream_stop", "WavStream_setFilter"]
cIncludeDir(incl) cIncludeDir(incl)