- 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
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
@ -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
_[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__
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 INCLUDES: seq[string] = @[]
var EXCLUDES: seq[string] = @[]
var WILDCARDS = newConfig()
const DOC = """
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
proc getnimout(file: string): string =
proc getNimout(file: string): string =
var nimout = file.splitFile().name.replace(re"[\-\.]", "_") & ".nim"
if OUTPUT != "":
nimout = OUTPUT/nimout
@ -156,7 +157,7 @@ proc search(file: string): string =
result = file
if file.splitFile().ext == ".nim":
result = getnimout(file)
result = getNimout(file)
elif not fileExists(result):
var found = false
for inc in INCLUDES:
@ -246,7 +247,7 @@ proc compile(dir="", file=""): string =
return data
proc fixfuncprotos(file: string) =
proc fixFuncProtos(file: string) =
withFile(file):
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]] &
@ -256,7 +257,7 @@ proc fixfuncprotos(file: string) =
# ###
# Convert to Nim
proc getincls(file: string): seq[string] =
proc getIncls(file: string): seq[string] =
result = @[]
withFile(file):
for f in content.findIter(re"(?m)^\s*#\s*include\s+(.*?)$"):
@ -266,13 +267,13 @@ proc getincls(file: string): seq[string] =
result = result.deduplicate()
proc getdefines(file: string): string =
proc getDefines(file: string): string =
withFile(file):
result = ""
for def in content.findIter(re"(?m)^(\s*#\s*define\s+[\w\d_]+\s+[\d.x]+)(?:\r|//|/*).*?$"):
result &= def.captures[0] & "\n"
proc preprocess(file, ppflags, flags: string): string =
proc runPreprocess(file, ppflags, flags: string): string =
var pproc = "gcc"
if flags.contains("cpp"):
pproc = "g++"
@ -297,14 +298,15 @@ proc preprocess(file, ppflags, flags: string): string =
if start:
rdata.add(
line.replace("_Noreturn", "")
.replace("(())", "")
.replace("WINAPI", "")
.replace("__attribute__", "")
.replace(re"\(\([_a-z]+?\)\)", "")
.replace(re"\(\(__format__\(__printf__, \d, \d\)\)\);", ";") & "\n"
.replace(re"\(\(__format__[\s]*\(__[gnu_]*printf__, [\d]+, [\d]+\)\)\);", ";") & "\n"
)
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 fps = execProc(cmd)
@ -321,8 +323,10 @@ proc ctags(file: string): string =
fdata &= fn & "\n"
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)
if file == "":
return
@ -333,25 +337,34 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define:
echo "Processing " & file
DONE.add(file)
fixfuncprotos(file)
fixFuncProtos(file)
var incout = ""
if recurse:
var incls = getincls(file)
var incls = getIncls(file)
for inc in incls:
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
if preproc:
if preprocess:
cfile = "temp-$#.c" % [outfile.extractFilename()]
writeFile(cfile, preprocess(file, ppflags, flags))
elif ctag:
writeFile(cfile, runPreprocess(file, ppflags, flags))
elif ctags:
cfile = "temp-$#.c" % [outfile.extractFilename()]
writeFile(cfile, ctags(file))
writeFile(cfile, runCtags(file))
if define and (preproc or ctag):
prepend(cfile, getdefines(file))
if defines and (preprocess or ctags):
prepend(cfile, getDefines(file))
var extflags = ""
var passC = ""
@ -361,7 +374,7 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define:
for inc in INCLUDES:
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:
let win = "when defined(Windows):\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
discard execProc(cmd)
if preproc or ctag:
if preprocess or ctags:
try:
removeFile(cfile)
except:
@ -428,7 +441,78 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define:
# ###
# 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):
echo "Config doesn't exist: " & cfg
quit(1)
@ -441,6 +525,9 @@ proc runcfg(cfg: string) =
if ARGS["-f"]:
removeDir(OUTPUT)
else:
for f in walkFiles(OUTPUT/"*.nim"):
removeFile(f)
if CONFIG["n.global"].hasKey("filter"):
FILTER = CONFIG["n.global"]["filter"]
@ -471,74 +558,24 @@ proc runcfg(cfg: string) =
elif key == "execute":
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():
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
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
for i in ARGS["<file.cfg>"]:
runcfg(i)
runCfg(i)

View file

@ -1,8 +1,8 @@
# Package
version = "0.1.1"
version = "0.1.2"
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"
skipDirs = @["tests"]