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

View file

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