Added inlining in place of recursion, extract existing ZIP file without downloading, delete/create output directory error handling

This commit is contained in:
Ganesh Viswanathan 2018-02-02 14:48:59 -06:00
commit 968e89f08e
3 changed files with 67 additions and 19 deletions

View file

@ -74,6 +74,8 @@ The following keys can be used to prepare dependencies such as downloading ZIP f
```download``` = url to download to the output directory. ZIP files are automatically extracted. Files are not redownloaded if already present but re-extracted
```extract``` = ZIP file to extract in case they are local and don't need to be downloaded. Path is relative to output directory.
```git``` = url of Git repository to clone. Full repo is pulled so gitremote + gitsparse is preferable. Resets to HEAD if already present
```gitremote``` = url of Git repository to partially checkout. Use with gitsparse to pull only files and dirs of interest
@ -94,6 +96,8 @@ The following keys apply to library source code and help with generating the .ni
```recurse``` = find #include files and process them [default: false]
```inline``` = include #include files into file being processed, alternative method to processing each header file separately with recurse. Multiple source files will get combined into the same .nim output files [default: false]
```preprocess``` = run preprocessor (gcc -E) on file to remove #defines, etc. [default: false] - this is especially useful when c2nim doesn't support complex preprocessor usage
```ctags``` = run ctags on file to filter out function definitions [default: false] - this requires the ctags executable and is an alternative to filter out preprocessor complexity

View file

@ -11,6 +11,7 @@ import strutils
import tables
var DONE: seq[string] = @[]
var DONE_INLINE: seq[string] = @[]
var CONFIG: Config
var FILTER = ""
@ -75,7 +76,6 @@ proc downloadUrl(url: string) =
if not (ext == ".zip" and fileExists(OUTPUT/file)):
echo "Downloading " & file
createDir(OUTPUT)
discard execProc(cmd % [url, OUTPUT/file])
if ext == ".zip":
@ -95,7 +95,6 @@ proc gitRemotePull(url: string, pull=true) =
gitReset()
return
createDir(OUTPUT)
setCurrentDir(OUTPUT)
defer: setCurrentDir("..")
@ -257,8 +256,11 @@ proc fixFuncProtos(file: string) =
# ###
# Convert to Nim
proc getIncls(file: string): seq[string] =
proc getIncls(file: string, inline=false): seq[string] =
result = @[]
if inline and file in DONE_INLINE:
return
withFile(file):
for f in content.findIter(re"(?m)^\s*#\s*include\s+(.*?)$"):
var inc = f.captures[0].strip()
@ -266,14 +268,35 @@ proc getIncls(file: string): seq[string] =
result.add(inc.replace(re"""[<>"]""", "").strip())
result = result.deduplicate()
DONE_INLINE.add(file)
if inline:
var sres = newSeq[string]()
for incl in result:
let sincl = search(incl)
if sincl == "":
continue
sres.add(getIncls(sincl, inline))
result.add(sres)
proc getDefines(file: string): string =
result = result.deduplicate()
proc getDefines(file: string, inline=false): string =
result = ""
if inline:
var incls = getIncls(file, inline)
for incl in incls:
let sincl = search(incl)
if sincl != "":
echo "Inlining " & sincl
result &= getDefines(sincl)
withFile(file):
result = ""
for def in content.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\-.xf]+)(?:\r|//|/*).*?$"):
result &= def.captures[0] & "\n"
proc runPreprocess(file, ppflags, flags: string): string =
proc runPreprocess(file, ppflags, flags: string, inline: bool): string =
var pproc = "gcc"
if flags.contains("cpp"):
pproc = "g++"
@ -287,7 +310,9 @@ proc runPreprocess(file, ppflags, flags: string): string =
# Include content only from file
var rdata: Rope
var start = false
let sfile = file.replace("\\", "/")
var sfile = file.replace("\\", "/")
if inline:
sfile = sfile.parentDir()
for line in data.splitLines():
if line.strip() != "":
if line[0] == '#' and not line.contains("#pragma"):
@ -301,6 +326,7 @@ proc runPreprocess(file, ppflags, flags: string): string =
.replace("(())", "")
.replace("WINAPI", "")
.replace("__attribute__", "")
.replace("extern \"C\"", "")
.replace(re"\(\([_a-z]+?\)\)", "")
.replace(re"\(\(__format__[\s]*\(__[gnu_]*printf__, [\d]+, [\d]+\)\)\);", ";") & "\n"
)
@ -326,7 +352,7 @@ proc runCtags(file: string): string =
proc runFile(file: string, cfgin: OrderedTableRef)
proc c2nim(fl, outfile, flags, ppflags: string, recurse, preprocess, ctags, defines: bool, dynlib, compile, pragma: seq[string] = @[]) =
proc c2nim(fl, outfile, flags, ppflags: string, recurse, inline, preprocess, ctags, defines: bool, dynlib, compile, pragma: seq[string] = @[]) =
var file = search(fl)
if file == "":
return
@ -358,13 +384,13 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preprocess, ctags, defi
var cfile = file
if preprocess:
cfile = "temp-$#.c" % [outfile.extractFilename()]
writeFile(cfile, runPreprocess(file, ppflags, flags))
writeFile(cfile, runPreprocess(file, ppflags, flags, inline))
elif ctags:
cfile = "temp-$#.c" % [outfile.extractFilename()]
writeFile(cfile, runCtags(file))
if defines and (preprocess or ctags):
prepend(cfile, getDefines(file))
prepend(cfile, getDefines(file, inline))
var extflags = ""
var passC = ""
@ -496,6 +522,7 @@ proc runFile(file: string, cfgin: OrderedTableRef) =
if file.splitFile().ext != ".nim":
var recurse = false
var inline = false
var preprocess = false
var ctags = false
var defines = false
@ -507,6 +534,8 @@ proc runFile(file: string, cfgin: OrderedTableRef) =
if cfg[act] == "true":
if act == "recurse":
recurse = true
elif act == "inline":
inline = true
elif act == "preprocess":
preprocess = true
elif act == "ctags":
@ -520,8 +549,12 @@ proc runFile(file: string, cfgin: OrderedTableRef) =
elif act == "ppflags":
ppflags = cfg[act]
if recurse and inline:
echo "Cannot use recurse and inline simultaneously"
quit(1)
if not noprocess:
c2nim(file, getNimout(file), flags, ppflags, recurse, preprocess, ctags, defines, dynlib, compile, pragma)
c2nim(file, getNimout(file), flags, ppflags, recurse, inline, preprocess, ctags, defines, dynlib, compile, pragma)
proc runCfg(cfg: string) =
if not fileExists(cfg):
@ -533,12 +566,21 @@ proc runCfg(cfg: string) =
if CONFIG.hasKey("n.global"):
if CONFIG["n.global"].hasKey("output"):
OUTPUT = CONFIG["n.global"]["output"]
if ARGS["-f"]:
removeDir(OUTPUT)
else:
for f in walkFiles(OUTPUT/"*.nim"):
removeFile(f)
if dirExists(OUTPUT):
if ARGS["-f"]:
try:
removeDir(OUTPUT)
except OSError:
echo "Directory in use: " & OUTPUT
quit(1)
else:
for f in walkFiles(OUTPUT/"*.nim"):
try:
removeFile(f)
except OSError:
echo "Unable to delete: " & f
quit(1)
createDir(OUTPUT)
if CONFIG["n.global"].hasKey("filter"):
FILTER = CONFIG["n.global"]["filter"]
@ -560,6 +602,8 @@ proc runCfg(cfg: string) =
if val == true:
if key == "download":
downloadUrl(CONFIG["n.prepare"][prep])
elif key == "extract":
extractZip(CONFIG["n.prepare"][prep])
elif key == "git":
gitRemotePull(CONFIG["n.prepare"][prep])
elif key == "gitremote":

View file

@ -1,6 +1,6 @@
# Package
version = "0.1.2"
version = "0.1.3"
author = "genotrance"
description = "c2nim helper to simplify and automate the wrapping of C libraries"
license = "MIT"