- Support for C++ wrapping

- Fix module naming
- Remove file caching
- Fix bug that was deleting .nim file
- Add test case
This commit is contained in:
Ganesh Viswanathan 2017-11-13 16:42:56 -06:00
commit a02cbbeeba
3 changed files with 96 additions and 91 deletions

View file

@ -9,7 +9,6 @@ import streams
import strutils import strutils
import tables import tables
var FILES: TableRef[string, string] = newTable[string, string]()
var DONE: seq[string] = @[] var DONE: seq[string] = @[]
var CONFIG: Config var CONFIG: Config
@ -44,10 +43,9 @@ proc execProc(cmd: string): string =
# File loction # File loction
proc getnimout(file: string): string = proc getnimout(file: string): string =
var nimout = file.splitFile().name & ".nim" var nimout = file.splitFile().name.replace(re"[\-\.]", "_") & ".nim"
if OUTPUT != "": if OUTPUT != "":
nimout = OUTPUT/nimout nimout = OUTPUT/nimout
removeFile(nimout)
return nimout return nimout
@ -80,61 +78,64 @@ proc search(file: string): string =
# ### # ###
# Loading / unloading # Loading / unloading
proc loadfile(file: string) = template withFile(file: string, body: untyped): untyped =
if FILES.hasKey(file): if fileExists(file):
return var f: File
while true:
FILES[file] = readFile(file)
proc savefile(file: string) =
try: try:
if FILES.hasKey(file): f = open(file)
writeFile(file, FILES[file]) break
FILES.del(file)
except: except:
echo "Failed to save " & file sleep(100)
echo getCurrentExceptionMsg()
proc savefiles() = var contentOrig = f.readAll()
for file in FILES.keys(): f.close()
savefile(file) var content {.inject.} = contentOrig
body
if content != contentOrig:
var f = open(file, fmWrite)
write(f, content)
f.close()
else:
echo "Missing file " & file
# ### # ###
# Manipulating content # Manipulating content
proc prepend(file: string, data: string, search="") = proc prepend(file: string, data: string, search="") =
loadfile(file) withFile(file):
if search == "": if search == "":
FILES[file] = data & FILES[file] content = data & content
else: else:
let idx = FILES[file].find(search) let idx = content.find(search)
if idx != -1: if idx != -1:
FILES[file] = FILES[file][0..<idx] & data & FILES[file][idx..<FILES[file].len()] content = content[0..<idx] & data & content[idx..<content.len()]
proc append(file: string, data: string, search="") = proc append(file: string, data: string, search="") =
loadfile(file) withFile(file):
if search == "": if search == "":
FILES[file] &= data content &= data
else: else:
let idx = FILES[file].find(search) let idx = content.find(search)
let idy = idx + search.len() let idy = idx + search.len()
if idx != -1: if idx != -1:
FILES[file] = FILES[file][0..<idy] & data & FILES[file][idy..<FILES[file].len()] content = content[0..<idy] & data & content[idy..<content.len()]
proc freplace(file: string, pattern: string, repl="") = proc freplace(file: string, pattern: string, repl="") =
loadfile(file) withFile(file):
if pattern in FILES[file]: if pattern in content:
FILES[file] = FILES[file].replace(pattern, repl) content = content.replace(pattern, repl)
proc freplace(file: string, pattern: Regex, repl="") = proc freplace(file: string, pattern: Regex, repl="") =
loadfile(file) withFile(file):
if FILES[file].find(pattern).isSome(): if content.find(pattern).isSome():
if "$#" in repl: if "$#" in repl:
for m in FILES[file].findIter(pattern): for m in content.findIter(pattern):
FILES[file] = FILES[file].replace(m.match, repl % m.captures[0]) content = content.replace(m.match, repl % m.captures[0])
else: else:
FILES[file] = FILES[file].replace(pattern, repl) content = content.replace(pattern, repl)
proc compile(dir="", file=""): string = proc compile(dir="", file=""): string =
proc fcompile(file: string): string = proc fcompile(file: string): string =
@ -151,25 +152,19 @@ proc compile(dir="", file=""): string =
return data return data
proc fixfuncprotos(file: string) = proc fixfuncprotos(file: string) =
var data = readFile(file) withFile(file):
for fp in content.findIter(re"(?m)(^.*?)[ ]*\(\*(.*?)\((.*?)\)\)[ \r\n]*\((.*?[\r\n]*.*?)\);"):
var edit = false
for fp in data.findIter(re"(?m)(^.*?)[ ]*\(\*(.*?)\((.*?)\)\)[ \r\n]*\((.*?[\r\n]*.*?)\);"):
var tdout = "typedef $# (*type_$#)($#);\n" % [fp.captures[0], fp.captures[1], fp.captures[3]] & var tdout = "typedef $# (*type_$#)($#);\n" % [fp.captures[0], fp.captures[1], fp.captures[3]] &
"type_$# $#($#);" % [fp.captures[1], fp.captures[1], fp.captures[2]] "type_$# $#($#);" % [fp.captures[1], fp.captures[1], fp.captures[2]]
data = data.replace(fp.match, tdout) content = content.replace(fp.match, tdout)
edit = true
if edit:
writeFile(file, data)
# ### # ###
# Convert to Nim # Convert to Nim
proc getincls(file: string): seq[string] = proc getincls(file: string): seq[string] =
loadfile(file)
result = @[] result = @[]
for f in FILES[file].findIter(re"(?m)^\s*#\s*include\s+(.*?)$"): withFile(file):
for f in content.findIter(re"(?m)^\s*#\s*include\s+(.*?)$"):
var inc = f.captures[0].replace(re"""[<>"]""", "").strip() var inc = f.captures[0].replace(re"""[<>"]""", "").strip()
if FILTER in inc and (not exclude(inc)): if FILTER in inc and (not exclude(inc)):
result.add(inc) result.add(inc)
@ -177,13 +172,16 @@ proc getincls(file: string): seq[string] =
result = result.deduplicate() result = result.deduplicate()
proc getdefines(file: string): string = proc getdefines(file: string): string =
loadfile(file) withFile(file):
result = "" result = ""
for def in FILES[file].findIter(re"(?m)^(\s*#\s*define\s+[\w\d_]+\s+[\d.x]+)(?:\r|//|/*).*?$"): for def in content.findIter(re"(?m)^(\s*#\s*define\s+[\w\d_]+\s+[\d.x]+)(?:\r|//|/*).*?$"):
result &= def.captures[0] & "\n" result &= def.captures[0] & "\n"
proc preprocess(file, ppflags: string): string = proc preprocess(file, ppflags, flags: string): string =
var cmd = "gcc -E $# $#" % [ppflags, file] var pproc = "gcc"
if flags.contains("cpp"):
pproc = "g++"
var cmd = "$# -E $# $#" % [pproc, ppflags, file]
for inc in INCLUDES: for inc in INCLUDES:
cmd &= " -I " & inc cmd &= " -I " & inc
@ -229,7 +227,7 @@ proc ctags(file: string): string =
return fdata return fdata
proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define: bool, compile, dynlib: seq[string] = @[]) = proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define: bool, dynlib, compile: seq[string] = @[]) =
var file = search(fl) var file = search(fl)
if file == "": if file == "":
return return
@ -246,30 +244,27 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define:
if recurse: if recurse:
var incls = getincls(file) var incls = getincls(file)
for inc in incls: for inc in incls:
incout &= "import " & inc.splitFile().name.replace(re"[-_\.]", "") & "\n" incout &= "import " & inc.splitFile().name.replace(re"[\-\.]", "_") & "\n"
c2nim(inc, getnimout(inc), flags, ppflags, recurse, preproc, ctag, define, compile, dynlib) c2nim(inc, getnimout(inc), flags, ppflags, recurse, preproc, ctag, define, dynlib)
var cfile = file var cfile = file
if preproc: if preproc:
cfile = "temp.c" cfile = "temp-$#.c" % [outfile.extractFilename()]
writeFile(cfile, preprocess(file, ppflags)) writeFile(cfile, preprocess(file, ppflags, flags))
elif ctag: elif ctag:
cfile = "temp.c" cfile = "temp-$#.c" % [outfile.extractFilename()]
writeFile(cfile, ctags(file)) writeFile(cfile, ctags(file))
if define and (preproc or ctag): if define and (preproc or ctag):
prepend(cfile, getdefines(file)) prepend(cfile, getdefines(file))
savefile(cfile)
var extflags = "" var extflags = ""
var passC = "" var passC = ""
var outlib = "" var outlib = ""
if compile.len() != 0:
passC = "import strutils\n" passC = "import strutils\n"
for inc in INCLUDES: for inc in INCLUDES:
passC &= ("""{.passC: "-I\"" & gorge("nimble path $#").strip() & "/$#\"".}""" % [OUTPUT, inc]) & "\n" passC &= ("""{.passC: "-I\"" & gorge("nimble path $#").strip() & "/$#\"".}""" % [OUTPUT, inc]) & "\n"
passC &= "{.push importc.}\n{.push header: \"$#\".}\n" % fl
#extflags = "--header:\"$#\"" % fl
if dynlib.len() != 0: if dynlib.len() != 0:
let win = "when defined(Windows):\n" let win = "when defined(Windows):\n"
@ -293,6 +288,9 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define:
if outlib != "": if outlib != "":
extflags &= " --dynlib:dynlib$#" % OUTPUT extflags &= " --dynlib:dynlib$#" % OUTPUT
else:
passC &= "const header$# = \"$#\"\n" % [OUTPUT, fl]
extflags = "--header:header$#" % OUTPUT
# Run c2nim on generated file # Run c2nim on generated file
var cmd = "c2nim $# $# --out:$# $#" % [flags, extflags, outfile, cfile] var cmd = "c2nim $# $# --out:$# $#" % [flags, extflags, outfile, cfile]
@ -300,9 +298,9 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define:
cmd = "cmd /c " & cmd cmd = "cmd /c " & cmd
discard execProc(cmd) discard execProc(cmd)
if preproc: if preproc or ctag:
try: try:
removeFile("temp.c") removeFile(cfile)
except: except:
discard discard
@ -324,7 +322,6 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define:
# Add header file and include paths # Add header file and include paths
if passC != "": if passC != "":
prepend(outfile, passC) prepend(outfile, passC)
append(outfile, "\n{.pop.}\n{.pop.}\n")
# Add dynamic library # Add dynamic library
if outlib != "": if outlib != "":
@ -399,9 +396,6 @@ proc runcfg(cfg: string) =
var flags = "--stdcall" var flags = "--stdcall"
var ppflags = "" var ppflags = ""
# Save C files in case they have changed
savefile(sfile)
for act in CONFIG[file].keys(): for act in CONFIG[file].keys():
if CONFIG[file][act] == "true": if CONFIG[file][act] == "true":
if act == "recurse": if act == "recurse":
@ -420,7 +414,7 @@ proc runcfg(cfg: string) =
ppflags = CONFIG[file][act] ppflags = CONFIG[file][act]
if not noprocess: if not noprocess:
c2nim(file, getnimout(file), flags, ppflags, recurse, preproc, ctag, define, compile, dynlib) c2nim(file, getnimout(file), flags, ppflags, recurse, preproc, ctag, define, dynlib, compile)
# ### # ###
# Main loop # Main loop
@ -431,5 +425,3 @@ if paramCount() == 0:
for i in 1..paramCount(): for i in 1..paramCount():
runcfg(paramStr(i)) runcfg(paramStr(i))
savefiles()

View file

@ -5,8 +5,13 @@ author = "genotrance"
description = "c2nim helper to simpilfy and automate the wrapping of C libraries" description = "c2nim helper to simpilfy and automate the wrapping of C libraries"
license = "MIT" license = "MIT"
skipDirs = @["tests"]
# Dependencies # Dependencies
requires "nim >= 0.16.0", "c2nim >= 0.9.13" requires "nim >= 0.16.0", "c2nim >= 0.9.13"
bin = @["nimgen"] bin = @["nimgen"]
task test, "Test nimgen":
exec "nim e tests/nimgentest.nims"

8
tests/nimgentest.nims Normal file
View file

@ -0,0 +1,8 @@
import ospaths
import strutils
for comp in @["nimbass", "nimfuzz", "nimssl"]:
cd(".."/comp)
exec "nimble install -y"
exec "nimble test"
cd(".."/"nimgen")