- Added support for wildcard file tasks

- Fixed issue in replacing - with _ in generated modules
- Fixed inconsistent naming of flags and procs
This commit is contained in:
Ganesh Viswanathan 2017-12-04 14:26:20 -06:00
commit 27ea25b901
3 changed files with 132 additions and 89 deletions

View file

@ -94,9 +94,9 @@ Multiple entries for the all following keys are possible by appending any .strin
```dynlib``` = dynamic library to load at runtime for generated .nim procs ```dynlib``` = dynamic library to load at runtime for generated .nim procs
The following keys apply to library source code (before processing) and generated .nim files (after processing) and allow manipulating the files as required to enable successful wrapping. The following keys apply to library source code (before processing) and generated .nim files (after processing) and allow manipulating the files as required to enable successful wrapping. They are not propagated to #include files when ```recurse = true```.
```create``` = create a file at exact location with contents specified ```create``` = create a file at exact location with contents specified. File needs to be in the _[n.exclude]_ list in order to be created.
```search``` = search string providing context for following prepend/append/replace directives ```search``` = search string providing context for following prepend/append/replace directives
@ -106,6 +106,12 @@ The following keys apply to library source code (before processing) and generate
```replace``` = string value to replace search string in file ```replace``` = string value to replace search string in file
_[n.wildcard]_
File wildcards such as *.nim, ssl*.h, etc. can be used to perform tasks across a group of files. This is useful to define common operations such as global text replacements without having to specify an explicit section for every single file. These operations will be performed on every matching file that is defined as a _sourcefile_ or recursed files.
```wildcard``` = pattern to match against. All keys following the wildcard declaration will apply to matched files
__Feedback__ __Feedback__
Nimgen is a work in progress and any feedback or suggestions are welcome. It is hosted on [GitHub](https://github.com/genotrance/nimgen) with an MIT license so issues, forks and PRs are most appreciated. Nimgen is a work in progress and any feedback or suggestions are welcome. It is hosted on [GitHub](https://github.com/genotrance/nimgen) with an MIT license so issues, forks and PRs are most appreciated.

View file

@ -18,6 +18,7 @@ var QUOTES = true
var OUTPUT = "" var OUTPUT = ""
var INCLUDES: seq[string] = @[] var INCLUDES: seq[string] = @[]
var EXCLUDES: seq[string] = @[] var EXCLUDES: seq[string] = @[]
var WILDCARDS = newConfig()
const DOC = """ const DOC = """
Nimgen is a helper for c2nim to simpilfy and automate the wrapping of C libraries Nimgen is a helper for c2nim to simpilfy and automate the wrapping of C libraries
@ -137,7 +138,7 @@ proc getKey(ukey: string): tuple[key: string, val: bool] =
# ### # ###
# File loction # File loction
proc getnimout(file: string): string = proc getNimout(file: string): string =
var nimout = file.splitFile().name.replace(re"[\-\.]", "_") & ".nim" var nimout = file.splitFile().name.replace(re"[\-\.]", "_") & ".nim"
if OUTPUT != "": if OUTPUT != "":
nimout = OUTPUT/nimout nimout = OUTPUT/nimout
@ -156,7 +157,7 @@ proc search(file: string): string =
result = file result = file
if file.splitFile().ext == ".nim": if file.splitFile().ext == ".nim":
result = getnimout(file) result = getNimout(file)
elif not fileExists(result): elif not fileExists(result):
var found = false var found = false
for inc in INCLUDES: for inc in INCLUDES:
@ -246,7 +247,7 @@ proc compile(dir="", file=""): string =
return data return data
proc fixfuncprotos(file: string) = proc fixFuncProtos(file: string) =
withFile(file): withFile(file):
for fp in content.findIter(re"(?m)(^.*?)[ ]*\(\*(.*?)\((.*?)\)\)[ \r\n]*\((.*?[\r\n]*.*?)\);"): for fp in content.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]] &
@ -256,7 +257,7 @@ proc fixfuncprotos(file: string) =
# ### # ###
# Convert to Nim # Convert to Nim
proc getincls(file: string): seq[string] = proc getIncls(file: string): seq[string] =
result = @[] result = @[]
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+(.*?)$"):
@ -266,13 +267,13 @@ proc getincls(file: string): seq[string] =
result = result.deduplicate() result = result.deduplicate()
proc getdefines(file: string): string = proc getDefines(file: string): string =
withFile(file): withFile(file):
result = "" 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.x]+)(?:\r|//|/*).*?$"):
result &= def.captures[0] & "\n" result &= def.captures[0] & "\n"
proc preprocess(file, ppflags, flags: string): string = proc runPreprocess(file, ppflags, flags: string): string =
var pproc = "gcc" var pproc = "gcc"
if flags.contains("cpp"): if flags.contains("cpp"):
pproc = "g++" pproc = "g++"
@ -297,14 +298,15 @@ proc preprocess(file, ppflags, flags: string): string =
if start: if start:
rdata.add( rdata.add(
line.replace("_Noreturn", "") line.replace("_Noreturn", "")
.replace("(())", "")
.replace("WINAPI", "") .replace("WINAPI", "")
.replace("__attribute__", "") .replace("__attribute__", "")
.replace(re"\(\([_a-z]+?\)\)", "") .replace(re"\(\([_a-z]+?\)\)", "")
.replace(re"\(\(__format__\(__printf__, \d, \d\)\)\);", ";") & "\n" .replace(re"\(\(__format__[\s]*\(__[gnu_]*printf__, [\d]+, [\d]+\)\)\);", ";") & "\n"
) )
return $rdata return $rdata
proc ctags(file: string): string = proc runCtags(file: string): string =
var cmd = "ctags -o - --fields=+S+K --c-kinds=p --file-scope=no " & file var cmd = "ctags -o - --fields=+S+K --c-kinds=p --file-scope=no " & file
var fps = execProc(cmd) var fps = execProc(cmd)
@ -321,8 +323,10 @@ proc ctags(file: string): string =
fdata &= fn & "\n" fdata &= fn & "\n"
return fdata return fdata
proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define: bool, dynlib, compile: seq[string] = @[]) = proc runFile(file: string, cfgin: OrderedTableRef)
proc c2nim(fl, outfile, flags, ppflags: string, recurse, preprocess, ctags, defines: bool, dynlib, compile: seq[string] = @[]) =
var file = search(fl) var file = search(fl)
if file == "": if file == "":
return return
@ -333,25 +337,34 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define:
echo "Processing " & file echo "Processing " & file
DONE.add(file) DONE.add(file)
fixfuncprotos(file) fixFuncProtos(file)
var incout = "" var incout = ""
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, dynlib) var cfg = newOrderedTable[string, string]()
if flags != "": cfg["flags"] = flags
if ppflags != "": cfg["ppflags"] = ppflags
if recurse: cfg["recurse"] = $recurse
if preprocess: cfg["preprocess"] = $preprocess
if ctags: cfg["ctags"] = $ctags
if defines: cfg["defines"] = $defines
for i in dynlib:
cfg["dynlib." & i] = i
runFile(inc, cfg)
var cfile = file var cfile = file
if preproc: if preprocess:
cfile = "temp-$#.c" % [outfile.extractFilename()] cfile = "temp-$#.c" % [outfile.extractFilename()]
writeFile(cfile, preprocess(file, ppflags, flags)) writeFile(cfile, runPreprocess(file, ppflags, flags))
elif ctag: elif ctags:
cfile = "temp-$#.c" % [outfile.extractFilename()] cfile = "temp-$#.c" % [outfile.extractFilename()]
writeFile(cfile, ctags(file)) writeFile(cfile, runCtags(file))
if define and (preproc or ctag): if defines and (preprocess or ctags):
prepend(cfile, getdefines(file)) prepend(cfile, getDefines(file))
var extflags = "" var extflags = ""
var passC = "" var passC = ""
@ -361,7 +374,7 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define:
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"
let fname = file.splitFile().name let fname = file.splitFile().name.replace(re"[\.\-]", "_")
if dynlib.len() != 0: if dynlib.len() != 0:
let win = "when defined(Windows):\n" let win = "when defined(Windows):\n"
let lin = "when defined(Linux):\n" let lin = "when defined(Linux):\n"
@ -396,7 +409,7 @@ 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 or ctag: if preprocess or ctags:
try: try:
removeFile(cfile) removeFile(cfile)
except: except:
@ -428,7 +441,78 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define:
# ### # ###
# Processor # Processor
proc runcfg(cfg: string) = proc runFile(file: string, cfgin: OrderedTableRef) =
var cfg = cfgin
var sfile = search(file)
for pattern in WILDCARDS.keys():
let pat = pattern.replace(".", "\\.").replace("*", ".*").replace("?", ".?")
if file.find(re(pat)).isSome():
echo "Appending " & file & " " & pattern
for key in WILDCARDS[pattern].keys():
cfg[key & "." & pattern] = WILDCARDS[pattern][key]
var srch = ""
var compile: seq[string] = @[]
var dynlib: seq[string] = @[]
for act in cfg.keys():
let (action, val) = getKey(act)
if val == true:
if action == "create":
createDir(file.splitPath().head)
writeFile(file, cfg[act])
elif action in @["prepend", "append", "replace", "compile", "dynlib"] and sfile != "":
if action == "prepend":
if srch != "":
prepend(sfile, cfg[act], cfg[srch])
else:
prepend(sfile, cfg[act])
elif action == "append":
if srch != "":
append(sfile, cfg[act], cfg[srch])
else:
append(sfile, cfg[act])
elif action == "replace":
if srch != "":
freplace(sfile, cfg[srch], cfg[act])
elif action == "compile":
compile.add(cfg[act])
elif action == "dynlib":
dynlib.add(cfg[act])
srch = ""
elif action == "search":
srch = act
if file.splitFile().ext != ".nim":
var recurse = false
var preprocess = false
var ctags = false
var defines = false
var noprocess = false
var flags = "--stdcall"
var ppflags = ""
for act in cfg.keys():
if cfg[act] == "true":
if act == "recurse":
recurse = true
elif act == "preprocess":
preprocess = true
elif act == "ctags":
ctags = true
elif act == "defines":
defines = true
elif act == "noprocess":
noprocess = true
elif act == "flags":
flags = cfg[act]
elif act == "ppflags":
ppflags = cfg[act]
if not noprocess:
c2nim(file, getNimout(file), flags, ppflags, recurse, preprocess, ctags, defines, dynlib, compile)
proc runCfg(cfg: string) =
if not fileExists(cfg): if not fileExists(cfg):
echo "Config doesn't exist: " & cfg echo "Config doesn't exist: " & cfg
quit(1) quit(1)
@ -441,6 +525,9 @@ proc runcfg(cfg: string) =
if ARGS["-f"]: if ARGS["-f"]:
removeDir(OUTPUT) removeDir(OUTPUT)
else:
for f in walkFiles(OUTPUT/"*.nim"):
removeFile(f)
if CONFIG["n.global"].hasKey("filter"): if CONFIG["n.global"].hasKey("filter"):
FILTER = CONFIG["n.global"]["filter"] FILTER = CONFIG["n.global"]["filter"]
@ -471,74 +558,24 @@ proc runcfg(cfg: string) =
elif key == "execute": elif key == "execute":
discard execProc(CONFIG["n.prepare"][prep]) discard execProc(CONFIG["n.prepare"][prep])
if CONFIG.hasKey("n.wildcard"):
var wildcard = ""
for wild in CONFIG["n.wildcard"].keys():
let (key, val) = getKey(wild)
if val == true:
if key == "wildcard":
wildcard = CONFIG["n.wildcard"][key]
else:
WILDCARDS.setSectionKey(wildcard, key, CONFIG["n.wildcard"][key])
for file in CONFIG.keys(): for file in CONFIG.keys():
if file in @["n.global", "n.include", "n.exclude", "n.prepare"]: if file in @["n.global", "n.include", "n.exclude", "n.prepare", "n.wildcard"]:
continue continue
var sfile = search(file) runFile(file, CONFIG[file])
var srch = ""
var compile: seq[string] = @[]
var dynlib: seq[string] = @[]
for act in CONFIG[file].keys():
let (action, val) = getKey(act)
if val == true:
if action == "create":
createDir(file.splitPath().head)
writeFile(file, CONFIG[file][act])
elif action in @["prepend", "append", "replace", "compile", "dynlib"] and sfile != "":
if action == "prepend":
if srch != "":
prepend(sfile, CONFIG[file][act], CONFIG[file][srch])
else:
prepend(sfile, CONFIG[file][act])
elif action == "append":
if srch != "":
append(sfile, CONFIG[file][act], CONFIG[file][srch])
else:
append(sfile, CONFIG[file][act])
elif action == "replace":
if srch != "":
freplace(sfile, CONFIG[file][srch], CONFIG[file][act])
elif action == "compile":
compile.add(CONFIG[file][act])
elif action == "dynlib":
dynlib.add(CONFIG[file][act])
srch = ""
elif action == "search":
srch = act
if file.splitFile().ext != ".nim":
var recurse = false
var preproc = false
var ctag = false
var define = false
var noprocess = false
var flags = "--stdcall"
var ppflags = ""
for act in CONFIG[file].keys():
if CONFIG[file][act] == "true":
if act == "recurse":
recurse = true
elif act == "preprocess":
preproc = true
elif act == "ctags":
ctag = true
elif act == "defines":
define = true
elif act == "noprocess":
noprocess = true
elif act == "flags":
flags = CONFIG[file][act]
elif act == "ppflags":
ppflags = CONFIG[file][act]
if not noprocess:
c2nim(file, getnimout(file), flags, ppflags, recurse, preproc, ctag, define, dynlib, compile)
# ### # ###
# Main loop # Main loop
for i in ARGS["<file.cfg>"]: for i in ARGS["<file.cfg>"]:
runcfg(i) runCfg(i)

View file

@ -1,8 +1,8 @@
# Package # Package
version = "0.1.1" version = "0.1.2"
author = "genotrance" author = "genotrance"
description = "c2nim helper to simpilfy and automate the wrapping of C libraries" description = "c2nim helper to simplify and automate the wrapping of C libraries"
license = "MIT" license = "MIT"
skipDirs = @["tests"] skipDirs = @["tests"]