- 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:
parent
9bcabd23e3
commit
27ea25b901
3 changed files with 132 additions and 89 deletions
10
README.md
10
README.md
|
|
@ -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.
|
||||||
|
|
|
||||||
207
nimgen.nim
207
nimgen.nim
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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"]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue