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
import nimterop/cimport
cDebug()
static:
cDebug()
cDefine("HAS_ABC")
cDefine("HAS_ABC", "DEF")
cIncludeDir("clib/include")

View file

@ -43,14 +43,18 @@ proc testAll() =
if defined(OSX) or defined(Windows) or not existsEnv("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":
for options in ["", "-d:release"]:
buildToast(options)
testAll()
runNimDoc()
task docs, "Generate docs":
# Uses: pip install ghp-import
execCmd "nim doc --project --index:on nimterop/cimport"
execCmd "nim doc --project --index:on nimterop/git"
execCmd "nim doc --project --index:on nimterop/plugin"
execCmd "ghp-import --no-jekyll -fp nimterop/htmldocs"
runNimDoc()
execCmd &"ghp-import --no-jekyll -fp {htmldocsDir}"

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
const CIMPORT {.used.} = 1
@ -9,7 +19,10 @@ export types
proc interpPath(dir: string): string=
# 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 =
if path2.isAbsolute:
@ -184,18 +197,15 @@ macro cOverride*(body): untyped =
if gStateCT.debug:
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
## filtering out symbols not of interest from the generated output.
##
runnableExamples:
cSkipSymbol "proc1", "Type2"
for skip in skips:
gStateCT.symOverride.add skip.strVal
static: cSkipSymbol @["proc1", "Type2"]
gStateCT.symOverride.add skips
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
## to customize the generated Nim output. The following callbacks are available at
## this time.
@ -242,8 +252,8 @@ macro cPlugin*(body): untyped =
proc cSearchPath*(path: string): string {.compileTime.}=
## Get full path to file or directory ``path`` in search path configured
## using `cAddSearchDir() <cimport.html#cAddSearchDir.m,>`_ and
## `cAddStdDir() <cimport.html#cAddStdDir.m,string>`_.
## using `cAddSearchDir() <cimport.html#cAddSearchDir,>`_ and
## `cAddStdDir() <cimport.html#cAddStdDir,string>`_.
##
## This can be used to locate files or directories that can be passed onto
## `cCompile() <cimport.html#cCompile.m,,string>`_,
@ -261,23 +271,25 @@ proc cSearchPath*(path: string): string {.compileTime.}=
doAssert found, "File or directory not found: " & path &
" gStateCT.searchDirs: " & $gStateCT.searchDirs
macro cDebug*(): untyped =
proc cDebug*() {.compileTime.} =
## Enable debug messages and display the generated Nim code
gStateCT.debug = true
macro cDisableCaching*(): untyped =
proc cDisableCaching*() {.compileTime.} =
## Disable caching of generated Nim code - useful during wrapper development
##
## 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
## 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.
##
## ``nim -f`` was broken prior to 0.19.4 but can also be used to flush the cached content.
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".}``
@ -285,6 +297,8 @@ macro cDefine*(name: static string, val: static string = ""): untyped =
result = newNimNode(nnkStmtList)
var str = name
# todo: see https://github.com/genotrance/nimterop/issues/100 for
# edge case of empty strings
if val.nBl:
str &= &"={val.quoteShell}"
@ -292,24 +306,20 @@ macro cDefine*(name: static string, val: static string = ""): untyped =
gStateCT.defines.add(str)
str = "-D" & str
result.add(quote do:
result.add quote do:
{.passC: `str`.}
)
if gStateCT.debug:
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
## `cSearchPath() <cimport.html#cSearchPath,string>`_.
##
## This allows something like this:
##
## .. code-block:: nim
##
## cAddSearchDir("path/to/includes")
## cImport cSearchPath("file.h")
runnableExamples:
import paths, os
static:
cAddSearchDir testsIncludeDir()
doAssert cSearchPath("test.h").existsFile
var dir = interpPath(dir)
if dir notin gStateCT.searchDirs:
gStateCT.searchDirs.add(dir)
@ -322,46 +332,32 @@ macro cIncludeDir*(dir: static string): untyped =
var dir = interpPath(dir)
result = newNimNode(nnkStmtList)
let
fullpath = findPath(dir)
str = &"-I{fullpath.quoteShell}"
let fullpath = findPath(dir)
if fullpath notin gStateCT.includeDirs:
gStateCT.includeDirs.add(fullpath)
result.add(quote do:
let str = &"-I{fullpath.quoteShell}"
result.add quote do:
{.passC: `str`.}
)
if gStateCT.debug:
echo result.repr
if gStateCT.debug:
echo result.repr
macro cAddStdDir*(mode = "c"): untyped =
proc cAddStdDir*(mode = "c") {.compileTime.} =
## Add the standard ``c`` [default] or ``cpp`` include paths to search
## path used in calls to `cSearchPath() <cimport.html#cSearchPath,string>`_
##
## This allows something like this:
##
runnableExamples:
cAddStdDir()
echo cSearchPath("math.h")
result = newNimNode(nnkStmtList)
static: cAddStdDir()
import os
doAssert cSearchPath("math.h").existsFile
var
inc = false
for line in getGccPaths(mode.strVal()).splitLines():
for line in getGccPaths(mode).splitLines():
if "#include <...> search starts here" in line:
inc = true
continue
elif "End of search list" in line:
break
if inc:
let sline = line.strip()
result.add quote do:
cAddSearchDir(`sline`)
cAddSearchDir line.strip()
macro cCompile*(path: static string, mode = "c"): untyped =
## 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 =
## Import all supported definitions from specified header file. Generated
## 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.
##
## ``recurse`` can be used to generate Nim wrappers from ``#include`` files

View file

@ -15,3 +15,7 @@ proc toastExePath*(): string =
proc incDir*(): string =
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 nimterop/cimport
type
locale_t = object
mingw_ldbl_type_t = object
mingw_dbl_type_t = object
cDebug()
cDisableCaching()
cAddStdDir()
static:
cDebug()
cDisableCaching()
cAddStdDir()
cPlugin:
import strutils
@ -21,4 +21,4 @@ cImport cSearchPath("math.h")
check sin(5) == -0.9589242746631385
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 nimterop/cimport
import nimterop/paths
cDebug()
cDisableCaching()
static:
cDebug()
cDisableCaching()
cAddSearchDir testsIncludeDir()
cDefine("FORCE")
cIncludeDir "$projpath/include"
cAddSearchDir "$projpath/include"
cIncludeDir testsIncludeDir()
cCompile cSearchPath("test.c")
cPlugin:
@ -137,8 +139,6 @@ var
k: uKernel
kp: Kernel
cAddStdDir()
## failing tests
when false:
static: # Error: undeclared identifier: 'foobar1'

View file

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

View file

@ -7,9 +7,8 @@ const
static:
gitPull("https://github.com/jarikomppa/soloud", baseDir, "include/*\nsrc/*\n")
cDebug()
cDisableCaching()
cDebug()
cDisableCaching()
cOverride:
type
@ -18,7 +17,7 @@ cOverride:
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)