From 0f73ad6d3f9ec081792e03967b49895a1d53b9b8 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Thu, 14 Jun 2018 17:13:46 +0900 Subject: [PATCH 01/28] Add configurable compiler to global section --- nimgen.nim | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nimgen.nim b/nimgen.nim index d804657..397ece4 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -7,6 +7,8 @@ var gConfig: Config gFilter = "" gQuotes = true + gCppCompiler = "g++" + gCCompiler = "gcc" gOutput = "" gIncludes: seq[string] = @[] gExcludes: seq[string] = @[] @@ -369,7 +371,7 @@ proc getDefines(file: string, inline=false): string = proc runPreprocess(file, ppflags, flags: string, inline: bool): string = var - pproc = if flags.contains("cpp"): "g++" else: "gcc" + pproc = if flags.contains("cpp"): gCppCompiler else: gCCompiler cmd = "$# -E $# $#" % [pproc, ppflags, file] for inc in gIncludes: @@ -671,6 +673,11 @@ proc runCfg(cfg: string) = quit(1) createDir(gOutput) + if gConfig["n.global"].hasKey("cpp_compiler"): + gCppCompiler = gConfig["n.global"]["cpp_compiler"] + if gConfig["n.global"].hasKey("c_compiler"): + gCCompiler = gConfig["n.global"]["c_compiler"] + if gConfig["n.global"].hasKey("filter"): gFilter = gConfig["n.global"]["filter"] if gConfig["n.global"].hasKey("quotes"): From f275bc0e352734cf6e8bbe125d56355b7949e432 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sat, 16 Jun 2018 15:17:51 +0900 Subject: [PATCH 02/28] Update readme with compiler spec --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index d47239e..9fc8618 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,10 @@ _[n.global]_ ```filter``` = string to identify and recurse into library .h files in #include statements and exclude standard headers +```cpp_compiler``` = string to specify a CPP compiler executable. [default: g++] + +```c_compiler``` = string to specify a C compiler executable. [default: gcc] + _[n.include]_ List of all directories, one per line, to include in the search path. This is used by:- From 71699332be05b7a5aed93c4d9d80c4333f7692c3 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sat, 16 Jun 2018 15:22:16 +0900 Subject: [PATCH 03/28] Allow for deeper than one directory paths --- nimgen.nim | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/nimgen.nim b/nimgen.nim index d804657..e601153 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -4,6 +4,7 @@ var gDoneRecursive: seq[string] = @[] gDoneInline: seq[string] = @[] + gProjectDir = getCurrentDir() gConfig: Config gFilter = "" gQuotes = true @@ -59,7 +60,7 @@ proc extractZip(zipfile: string) = cmd = "powershell -nologo -noprofile -command \"& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('$#', '.'); }\"" setCurrentDir(gOutput) - defer: setCurrentDir("..") + defer: setCurrentDir(gProjectDir) echo "Extracting " & zipfile discard execProc(cmd % zipfile) @@ -84,7 +85,7 @@ proc gitReset() = echo "Resetting Git repo" setCurrentDir(gOutput) - defer: setCurrentDir("..") + defer: setCurrentDir(gProjectDir) discard execProc("git reset --hard HEAD") @@ -95,7 +96,7 @@ proc gitRemotePull(url: string, pull=true) = return setCurrentDir(gOutput) - defer: setCurrentDir("..") + defer: setCurrentDir(gProjectDir) echo "Setting up Git repo" discard execProc("git init .") @@ -112,7 +113,7 @@ proc gitSparseCheckout(plist: string) = return setCurrentDir(gOutput) - defer: setCurrentDir("..") + defer: setCurrentDir(gProjectDir) discard execProc("git config core.sparsecheckout true") writeFile(sparsefile, plist) From 77e28545efe6d0a4f34283cbdd051d1ce0f4667d Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 18 Jun 2018 19:41:12 +0900 Subject: [PATCH 04/28] Add `after` command that operates on files after nimgen has run --- README.md | 5 ++++ nimgen.nim | 88 ++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 423b706..ff7b2b4 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,11 @@ File wildcards such as *.nim, ssl*.h, etc. can be used to perform tasks across a ```wildcard``` = pattern to match against. All keys following the wildcard declaration will apply to matched files +_[n.after]_ +The same as n.wildcard, but instead of operating on the files before nimgen is done generating, it operates after, so you can modify Nim files or other files that result from nimgen or c2nim. + +```wildcard``` = pattern to match against. All keys following the wildcard declaration will apply to matched files + _[sourcefile]_ The following keys apply to library source code and help with generating the .nim files. -win, -lin and -osx can be used for OS specific tasks. E.g. dynlib-win, pragma-win diff --git a/nimgen.nim b/nimgen.nim index 942afc6..0bdde29 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -2,6 +2,7 @@ import nre, os, ospaths, osproc, parsecfg, pegs, ropes, sequtils, streams, strut var gDoneRecursive: seq[string] = @[] + gDoneAfter: seq[string] = @[] gDoneInline: seq[string] = @[] gProjectDir = getCurrentDir() @@ -15,6 +16,7 @@ var gExcludes: seq[string] = @[] gRenames = initTable[string, string]() gWildcards = newConfig() + gAfter = newConfig() type c2nimConfigObj = object @@ -566,29 +568,11 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) = if outlib != "": prepend(outfile, outlib) -# ### -# Processor - -proc runFile(file: string, cfgin: OrderedTableRef) = - var - cfg = cfgin - sfile = search(file) - - for pattern in gWildcards.keys(): - let pat = pattern.replace(".", "\\.").replace("*", ".*").replace("?", ".?") - if file.find(re(pat)).isSome(): - echo "Appending " & file & " " & pattern - for key in gWildcards[pattern].keys(): - cfg[key & "." & pattern] = gWildcards[pattern][key] +proc doActions(file: string, c2nimConfig: var c2nimConfigObj, cfg: OrderedTableRef) = var srch = "" - - c2nimConfig = c2nimConfigObj( - flags: "--stdcall", ppflags: "", - recurse: false, inline: false, preprocess: false, ctags: false, defines: false, - dynlib: @[], compile: @[], pragma: @[] - ) + sfile = search(file) for act in cfg.keys(): let (action, val) = getKey(act) @@ -627,6 +611,51 @@ proc runFile(file: string, cfgin: OrderedTableRef) = elif action == "search": srch = act +proc processAfter(nimFile: string, c2nimConfig: var c2nimConfigObj) = + var file = search(nimFile) + if file == "": + return + + if file in gDoneAfter: + return + + gDoneAfter.add(file) + + var afterConfig = newOrderedTable[string, string]() + for pattern in gAfter.keys(): + let pat = pattern.replace(".", "\\.").replace("*", ".*").replace("?", ".?") + if nimFile.find(re(pat)).isSome(): + for key in gAfter[pattern].keys(): + let value = gAfter[pattern][key] + #echo key, ": ", "\"", value, "\" in ", nimFile + afterConfig[key & "." & pattern] = value + + doActions(nimFile, c2nimConfig, afterConfig) + +# ### +# Processor + +proc runFile(file: string, cfgin: OrderedTableRef) = + var + cfg = cfgin + sfile = search(file) + + for pattern in gWildcards.keys(): + let pat = pattern.replace(".", "\\.").replace("*", ".*").replace("?", ".?") + if file.find(re(pat)).isSome(): + echo "Appending " & file & " " & pattern + for key in gWildcards[pattern].keys(): + cfg[key & "." & pattern] = gWildcards[pattern][key] + + var + c2nimConfig = c2nimConfigObj( + flags: "--stdcall", ppflags: "", + recurse: false, inline: false, preprocess: false, ctags: false, defines: false, + dynlib: @[], compile: @[], pragma: @[] + ) + + doActions(file, c2nimConfig, cfg) + if file.splitFile().ext != ".nim": var noprocess = false @@ -654,7 +683,10 @@ proc runFile(file: string, cfgin: OrderedTableRef) = quit(1) if not noprocess: - c2nim(file, getNimout(sfile), c2nimConfig) + let nimFile = getNimout(sfile) + c2nim(file, nimFile, c2nimConfig) + + processAfter(nimFile, c2nimConfig) proc runCfg(cfg: string) = if not fileExists(cfg): @@ -730,12 +762,24 @@ proc runCfg(cfg: string) = else: gWildcards.setSectionKey(wildcard, wild, gConfig["n.wildcard"][wild]) + if gConfig.hasKey("n.after"): + var wildcard = "" + for afterKey in gConfig["n.after"].keys(): + let (key, val) = getKey(afterKey) + if val == true: + if key == "wildcard": + wildcard = gConfig["n.after"][afterKey] + else: + gAfter.setSectionKey(wildcard, afterKey, gConfig["n.after"][afterKey]) + + for file in gConfig.keys(): - if file in @["n.global", "n.include", "n.exclude", "n.prepare", "n.wildcard"]: + if file in @["n.global", "n.include", "n.exclude", "n.prepare", "n.wildcard", "n.after"]: continue runFile(file, gConfig[file]) + # ### # Main loop From acb07ba3e1aa2b8c880cf628a484bb60d561421b Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 18 Jun 2018 19:44:45 +0900 Subject: [PATCH 05/28] Implement relative import support in header files. You must currently replace relative imports using nimgen's commands, but relative files don't crash nimgen anymore. --- nimgen.nim | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/nimgen.nim b/nimgen.nim index 0bdde29..a7233ab 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -156,6 +156,9 @@ proc getKey(ukey: string): tuple[key: string, val: bool] = # File loction proc getNimout(file: string, rename=true): string = + if file == "": + return "" + result = file.splitFile().name.replace(re"[\-\.]", "_") & ".nim" if gOutput != "": result = gOutput/result @@ -193,6 +196,8 @@ proc search(file: string): string = echo "File doesn't exist: " & file quit(1) + # Only keep relative directory + result = result.replace(gProjectDir & $DirSep, "") return result.replace(re"[\\/]", $DirSep) # ### @@ -342,12 +347,20 @@ proc getIncls(file: string, inline=false): seq[string] = if inline and file in gDoneInline: return + var curPath = splitFile(expandFileName(file))[0] withFile(file): for f in content.findIter(re"(?m)^\s*#\s*include\s+(.*?)$"): var inc = f.captures[0].strip() if ((gQuotes and inc.contains("\"")) or (gFilter != "" and gFilter in inc)) and (not exclude(inc)): - result.add( - inc.replace(re"""[<>"]""", "").replace(re"\/[\*\/].*$", "").strip()) + var addInc = inc.replace(re"""[<>"]""", "").replace(re"\/[\*\/].*$", "").strip() + try: + # Try searching for a local library + let finc = expandFileName(curPath & "/" & addInc) + let fname = extractFileName(finc) + result.add(fname.search()) + except OSError: + # If it's a system library + result.add(addInc) result = result.deduplicate() @@ -469,7 +482,9 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) = for inc in incls: runFile(inc, cfg) - incout &= "import $#\n" % inc.search().getNimout()[0 .. ^5] + let nimout = inc.search().getNimout() + if nimout.len() > 0: + incout &= "import $#\n" % nimout[0 .. ^5] var cfile = file if c2nimConfig.preprocess: From a3d48fb1acc1e0b0df3e148a5d7965c6ecf35ca4 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 18 Jun 2018 19:47:13 +0900 Subject: [PATCH 06/28] Use exceptions instead of quitting to get stacktrace --- nimgen.nim | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/nimgen.nim b/nimgen.nim index a7233ab..94407cb 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -53,10 +53,12 @@ proc execProc(cmd: string): string = var x = p.peekExitCode() if x != 0: - echo "Command failed: " & $x - echo cmd - echo result - quit(1) + raise newException( + Exception, + "Command failed: " & $x & + "\nCMD: " & $cmd & + "\nRESULT: " & $result + ) proc extractZip(zipfile: string) = var cmd = "unzip -o $#" @@ -129,9 +131,7 @@ proc doCopy(flist: string) = for pair in flist.split(","): let spl = pair.split("=") if spl.len() != 2: - echo "Bad copy syntax: " & flist - quit(1) - + raise newException(Exception, "Bad copy syntax: " & flist) let lfile = spl[0].strip() rfile = spl[1].strip() @@ -193,8 +193,7 @@ proc search(file: string): string = found = true break if not found: - echo "File doesn't exist: " & file - quit(1) + raise newException(Exception, "File doesn't exist: " & file) # Only keep relative directory result = result.replace(gProjectDir & $DirSep, "") @@ -306,9 +305,7 @@ proc rename(file: string, renfile: string) = for entry in matches[1].split(","): let spl = entry.split("=") if spl.len() != 2: - echo "Bad replace syntax: " & renfile - quit(1) - + raise newException(Exception, "Bad replace syntax: " & renfile) let srch = spl[0].strip() repl = spl[1].strip() @@ -694,9 +691,7 @@ proc runFile(file: string, cfgin: OrderedTableRef) = c2nimConfig.ppflags = cfg[act] if c2nimConfig.recurse and c2nimConfig.inline: - echo "Cannot use recurse and inline simultaneously" - quit(1) - + raise newException(Exception, "Cannot use recurse and inline simultaneously") if not noprocess: let nimFile = getNimout(sfile) c2nim(file, nimFile, c2nimConfig) @@ -705,8 +700,7 @@ proc runFile(file: string, cfgin: OrderedTableRef) = proc runCfg(cfg: string) = if not fileExists(cfg): - echo "Config doesn't exist: " & cfg - quit(1) + raise newException(Exception, "Config doesn't exist: " & cfg) gConfig = loadConfig(cfg) @@ -718,15 +712,13 @@ proc runCfg(cfg: string) = try: removeDir(gOutput) except OSError: - echo "Directory in use: " & gOutput - quit(1) + raise newException(Exception, "Directory in use: " & gOutput) else: for f in walkFiles(gOutput/"*.nim"): try: removeFile(f) except OSError: - echo "Unable to delete: " & f - quit(1) + raise newException(Exception, "Unable to delete: " & f) createDir(gOutput) if gConfig["n.global"].hasKey("cpp_compiler"): From 0449f548dc951eca59bb6681709c9d555149e143 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 18 Jun 2018 19:53:54 +0900 Subject: [PATCH 07/28] Only include necessary file for include libs The previous behavior caused a "Too many files open" error when referrencing lots of libs because of the call to "gorge". This modification retains the old behavior and also works if the library is compiled locally. --- nimgen.nim | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/nimgen.nim b/nimgen.nim index 94407cb..7f7c957 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -501,13 +501,14 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) = outpragma = "" passC = "import strutils\n" - for inc in gIncludes: - passC &= ("""{.passC: "-I\"" & gorge("nimble path $#").strip() & "/$#\"".}""" % [gOutput, inc]) & "\n" + passC &= "import ospaths\n" for prag in c2nimConfig.pragma: outpragma &= "{." & prag & ".}\n" let fname = file.splitFile().name.replace(re"[\.\-]", "_") + let fincl = file.replace(gOutput, "") + if c2nimConfig.dynlib.len() != 0: let win = "when defined(Windows):\n" @@ -537,7 +538,10 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) = if outlib != "": extflags &= " --dynlib:dynlib$#" % fname else: - passC &= "const header$# = \"$#\"\n" % [fname, fl] + if file.isAbsolute(): + passC &= "const header$# = \"$#\"\n" % [fname, fincl] + else: + passC &= "const header$# = currentSourcePath().splitPath().head & \"/$#\"\n" % [fname, fincl] extflags = "--header:header$#" % fname # Run c2nim on generated file From a71ddc64788cc6960c6aac5e8d833bd18f77bad1 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 18 Jun 2018 19:56:34 +0900 Subject: [PATCH 08/28] Fix ctags --- nimgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimgen.nim b/nimgen.nim index 7f7c957..219cf86 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -430,7 +430,7 @@ proc runPreprocess(file, ppflags, flags: string, inline: bool): string = proc runCtags(file: string): string = var - cmd = "ctags -o - --fields=+S+K --c-kinds=p --file-scope=no " & file + cmd = "ctags -o - --fields=+S+K --c-kinds=+p --file-scope=no " & file fps = execProc(cmd) fdata = "" From a55d71b02b44d1926e9bb048b39d3b9c1b2218be Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Mon, 18 Jun 2018 20:22:47 +0900 Subject: [PATCH 09/28] Version bump --- nimgen.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimgen.nimble b/nimgen.nimble index 4d7106a..5c0eb1e 100644 --- a/nimgen.nimble +++ b/nimgen.nimble @@ -1,6 +1,6 @@ # Package -version = "0.2.1" +version = "0.2.2" author = "genotrance" description = "c2nim helper to simplify and automate the wrapping of C libraries" license = "MIT" From 883c79115d0e92a7eff5ba638229b55bad136e2a Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Wed, 20 Jun 2018 13:59:46 +0900 Subject: [PATCH 10/28] Add ability to use environment vars --- nimgen.nim | 95 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/nimgen.nim b/nimgen.nim index 219cf86..ee91e97 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -37,6 +37,25 @@ Options: # ### # Helpers +proc addEnv(str: string): string = + var newStr = str + for pair in envPairs(): + try: + newStr = newStr % [pair.key, pair.value.string] + except ValueError: + discard + + try: + newStr = newStr % ["output", gOutput] + except ValueError: + discard + + # if there are still format args, print a warning + if newStr.contains("${"): + echo "WARNING: \"", newStr, "\" still contains an uninterpolated value!" + + return newStr + proc execProc(cmd: string): string = result = "" var @@ -541,7 +560,7 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) = if file.isAbsolute(): passC &= "const header$# = \"$#\"\n" % [fname, fincl] else: - passC &= "const header$# = currentSourcePath().splitPath().head & \"/$#\"\n" % [fname, fincl] + passC &= "const header$# = currentSourcePath().splitPath().head & \"$#\"\n" % [fname, fincl] extflags = "--header:header$#" % fname # Run c2nim on generated file @@ -595,34 +614,36 @@ proc doActions(file: string, c2nimConfig: var c2nimConfigObj, cfg: OrderedTableR if val == true: if action == "create": createDir(file.splitPath().head) - writeFile(file, cfg[act]) - elif action in @["prepend", "append", "replace", "comment", "rename", "compile", "dynlib", "pragma", "execute"] and sfile != "": + writeFile(file, cfg[act].addEnv()) + elif action in @["prepend", "append", "replace", "comment", + "rename", "compile", "dynlib", "pragma", + "execute"] and sfile != "": if action == "prepend": if srch != "": - prepend(sfile, cfg[act], cfg[srch]) + prepend(sfile, cfg[act].addEnv(), cfg[srch].addEnv()) else: - prepend(sfile, cfg[act]) + prepend(sfile, cfg[act].addEnv()) elif action == "append": if srch != "": - append(sfile, cfg[act], cfg[srch]) + append(sfile, cfg[act].addEnv(), cfg[srch].addEnv()) else: - append(sfile, cfg[act]) + append(sfile, cfg[act].addEnv()) elif action == "replace": if srch != "": - freplace(sfile, cfg[srch], cfg[act]) + freplace(sfile, cfg[srch].addEnv(), cfg[act].addEnv()) elif action == "comment": if srch != "": - comment(sfile, cfg[srch], cfg[act]) + comment(sfile, cfg[srch].addEnv(), cfg[act].addEnv()) elif action == "rename": - rename(sfile, cfg[act]) + rename(sfile, cfg[act].addEnv()) elif action == "compile": - c2nimConfig.compile.add(cfg[act]) + c2nimConfig.compile.add(cfg[act].addEnv()) elif action == "dynlib": - c2nimConfig.dynlib.add(cfg[act]) + c2nimConfig.dynlib.add(cfg[act].addEnv()) elif action == "pragma": - c2nimConfig.pragma.add(cfg[act]) + c2nimConfig.pragma.add(cfg[act].addEnv()) elif action == "execute": - execute(sfile, cfg[act]) + execute(sfile, cfg[act].addEnv()) srch = "" elif action == "search": srch = act @@ -643,7 +664,6 @@ proc processAfter(nimFile: string, c2nimConfig: var c2nimConfigObj) = if nimFile.find(re(pat)).isSome(): for key in gAfter[pattern].keys(): let value = gAfter[pattern][key] - #echo key, ": ", "\"", value, "\" in ", nimFile afterConfig[key & "." & pattern] = value doActions(nimFile, c2nimConfig, afterConfig) @@ -661,7 +681,7 @@ proc runFile(file: string, cfgin: OrderedTableRef) = if file.find(re(pat)).isSome(): echo "Appending " & file & " " & pattern for key in gWildcards[pattern].keys(): - cfg[key & "." & pattern] = gWildcards[pattern][key] + cfg[key & "." & pattern] = gWildcards[pattern][key].addEnv() var c2nimConfig = c2nimConfigObj( @@ -690,9 +710,9 @@ proc runFile(file: string, cfgin: OrderedTableRef) = elif act == "noprocess": noprocess = true elif act == "flags": - c2nimConfig.flags = cfg[act] + c2nimConfig.flags = cfg[act].addEnv() elif act == "ppflags": - c2nimConfig.ppflags = cfg[act] + c2nimConfig.ppflags = cfg[act].addEnv() if c2nimConfig.recurse and c2nimConfig.inline: raise newException(Exception, "Cannot use recurse and inline simultaneously") @@ -710,7 +730,7 @@ proc runCfg(cfg: string) = if gConfig.hasKey("n.global"): if gConfig["n.global"].hasKey("output"): - gOutput = gConfig["n.global"]["output"] + gOutput = gConfig["n.global"]["output"].addEnv() if dirExists(gOutput): if "-f" in commandLineParams(): try: @@ -726,42 +746,43 @@ proc runCfg(cfg: string) = createDir(gOutput) if gConfig["n.global"].hasKey("cpp_compiler"): - gCppCompiler = gConfig["n.global"]["cpp_compiler"] + gCppCompiler = gConfig["n.global"]["cpp_compiler"].addEnv() if gConfig["n.global"].hasKey("c_compiler"): - gCCompiler = gConfig["n.global"]["c_compiler"] + gCCompiler = gConfig["n.global"]["c_compiler"].addEnv() if gConfig["n.global"].hasKey("filter"): - gFilter = gConfig["n.global"]["filter"] + gFilter = gConfig["n.global"]["filter"].addEnv() if gConfig["n.global"].hasKey("quotes"): - if gConfig["n.global"]["quotes"] == "false": + if gConfig["n.global"]["quotes"].addEnv() == "false": gQuotes = false if gConfig.hasKey("n.include"): for inc in gConfig["n.include"].keys(): - gIncludes.add(inc) + gIncludes.add(inc.addEnv()) if gConfig.hasKey("n.exclude"): for excl in gConfig["n.exclude"].keys(): - gExcludes.add(excl) + gExcludes.add(excl.addEnv()) if gConfig.hasKey("n.prepare"): for prep in gConfig["n.prepare"].keys(): let (key, val) = getKey(prep) if val == true: + let prepVal = gConfig["n.prepare"][prep].addEnv() if key == "download": - downloadUrl(gConfig["n.prepare"][prep]) + downloadUrl(prepVal) elif key == "extract": - extractZip(gConfig["n.prepare"][prep]) + extractZip(prepVal) elif key == "git": - gitRemotePull(gConfig["n.prepare"][prep]) + gitRemotePull(prepVal) elif key == "gitremote": - gitRemotePull(gConfig["n.prepare"][prep], false) + gitRemotePull(prepVal, false) elif key == "gitsparse": - gitSparseCheckout(gConfig["n.prepare"][prep]) + gitSparseCheckout(prepVal) elif key == "execute": - discard execProc(gConfig["n.prepare"][prep]) + discard execProc(prepVal) elif key == "copy": - doCopy(gConfig["n.prepare"][prep]) + doCopy(prepVal) if gConfig.hasKey("n.wildcard"): var wildcard = "" @@ -769,9 +790,10 @@ proc runCfg(cfg: string) = let (key, val) = getKey(wild) if val == true: if key == "wildcard": - wildcard = gConfig["n.wildcard"][wild] + wildcard = gConfig["n.wildcard"][wild].addEnv() else: - gWildcards.setSectionKey(wildcard, wild, gConfig["n.wildcard"][wild]) + gWildcards.setSectionKey(wildcard, wild, + gConfig["n.wildcard"][wild].addEnv()) if gConfig.hasKey("n.after"): var wildcard = "" @@ -779,9 +801,10 @@ proc runCfg(cfg: string) = let (key, val) = getKey(afterKey) if val == true: if key == "wildcard": - wildcard = gConfig["n.after"][afterKey] + wildcard = gConfig["n.after"][afterKey].addEnv() else: - gAfter.setSectionKey(wildcard, afterKey, gConfig["n.after"][afterKey]) + gAfter.setSectionKey(wildcard, afterKey, + gConfig["n.after"][afterKey].addEnv()) for file in gConfig.keys(): From 941a53088559388973a18f4049033e37531b5479 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Wed, 20 Jun 2018 14:04:14 +0900 Subject: [PATCH 11/28] Add env vars to readme --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index ff7b2b4..5fa79a4 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,14 @@ __Capabilities & Limitations__ Nimgen supports compiling in C/C++ sources as well as loading in dynamic libraries at this time. Support for static libraries (.a, .lib) are still to come. +Environment variables are supported via Nim's string interpolation `%` symbol imported from the `strutils` module. Simply use double quotes to enclose any value and put `${}` around the environment variable name. In addition, the `output` var from the n.global section is available as ${output}. For example: + + [n.global] + output="src/path" + + [n.include] + "${output}/library/include" + To see examples of nimgen in action check out the following wrappers:- * Link with a dynamic library * [nimbass](https://github.com/genotrance/nimbass) - BASS audio wrapper: [docs](http://nimgen.genotrance.com/nimbass) From 14d8eca24b6d3faedbebb07922a955bc230486f6 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 24 Jun 2018 07:50:47 +0900 Subject: [PATCH 12/28] Change project dir based on nimgen cfg file --- nimgen.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nimgen.nim b/nimgen.nim index ee91e97..14e6692 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -5,7 +5,7 @@ var gDoneAfter: seq[string] = @[] gDoneInline: seq[string] = @[] - gProjectDir = getCurrentDir() + gProjectDir = "" gConfig: Config gFilter = "" gQuotes = true @@ -726,6 +726,8 @@ proc runCfg(cfg: string) = if not fileExists(cfg): raise newException(Exception, "Config doesn't exist: " & cfg) + gProjectDir = parentDir(cfg) + gConfig = loadConfig(cfg) if gConfig.hasKey("n.global"): From 153591397eb053f17f6b23cf9673444f95a76d78 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 24 Jun 2018 08:21:50 +0900 Subject: [PATCH 13/28] Fix issue if cfg file is local gProject dir will be an empty string --- nimgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimgen.nim b/nimgen.nim index 14e6692..750f085 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -726,7 +726,7 @@ proc runCfg(cfg: string) = if not fileExists(cfg): raise newException(Exception, "Config doesn't exist: " & cfg) - gProjectDir = parentDir(cfg) + gProjectDir = parentDir(cfg.expandFilename()) gConfig = loadConfig(cfg) From ea6fa57670b121535d3d032aac1725de13e0626f Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 24 Jun 2018 08:37:28 +0900 Subject: [PATCH 14/28] Always do sparse checkout in case new folders are needed in nimgen cfg --- nimgen.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/nimgen.nim b/nimgen.nim index 750f085..f5ba530 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -135,7 +135,6 @@ proc gitSparseCheckout(plist: string) = let sparsefile = ".git/info/sparse-checkout" if fileExists(gOutput/sparsefile): gitReset() - return setCurrentDir(gOutput) defer: setCurrentDir(gProjectDir) From b148bba4b2aef502c65800d0a6106649f0cf1aa9 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 24 Jun 2018 11:26:38 +0900 Subject: [PATCH 15/28] Reset files after processing --- nimgen.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nimgen.nim b/nimgen.nim index f5ba530..2aeb0db 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -814,6 +814,9 @@ proc runCfg(cfg: string) = runFile(file, gConfig[file]) + # Reset files + gitReset() + # ### # Main loop From 8975db2cc9cb7da87099699d82d84cd43fef0c37 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Wed, 27 Jun 2018 22:22:38 +0900 Subject: [PATCH 16/28] Rename execute to pipe --- README.md | 2 +- nimgen.nim | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 5fa79a4..561accf 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ The following keys apply to library source code (before processing) and generate ```search``` = search string providing context for following prepend/append/replace directives -```execute``` = execute a command on a file and store the output of the command as the new file contents. Ex: execute = "cat $file | grep 'static inline'" +```pipe``` = execute a command on a file and store the output of the command as the new file contents. Ex: pipe = "cat $file | grep 'static inline'" ```prepend``` = string value to prepend into file at beginning or before search diff --git a/nimgen.nim b/nimgen.nim index 2aeb0db..f28dd24 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -255,11 +255,12 @@ proc prepend(file: string, data: string, search="") = if idx != -1: content = content[0.. Date: Sat, 7 Jul 2018 19:16:16 +0900 Subject: [PATCH 17/28] Add preliminary support for removing static funcs --- nimgen.nim | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/nimgen.nim b/nimgen.nim index f28dd24..c227f4b 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -21,7 +21,7 @@ var type c2nimConfigObj = object flags, ppflags: string - recurse, inline, preprocess, ctags, defines: bool + recurse, inline, preprocess, ctags, defines, remove_static: bool dynlib, compile, pragma: seq[string] const DOC = """ @@ -82,7 +82,9 @@ proc execProc(cmd: string): string = proc extractZip(zipfile: string) = var cmd = "unzip -o $#" if defined(Windows): - cmd = "powershell -nologo -noprofile -command \"& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('$#', '.'); }\"" + cmd = "powershell -nologo -noprofile -command \"& { Add-Type -A " & + "'System.IO.Compression.FileSystem'; " & + "[IO.Compression.ZipFile]::ExtractToDirectory('$#', '.'); }\"" setCurrentDir(gOutput) defer: setCurrentDir(gProjectDir) @@ -311,6 +313,54 @@ proc comment(file: string, pattern: string, numlines: string) = idx += 1 break +proc removeStatic(filename: string) = + + if not fileExists(filename): + echo "Missing file: " & filename + return + + var + file = open(filename) + stack: seq[string] = @[] + foundBrace = false + foundStatic = false + writeOutput = true + output = newStringofCap(getFileSize(filename)) + + for line in file.lines(): + var modLine = line + + if not foundStatic: + writeOutput = true + if line.startswith("static inline"): + foundStatic = true + let index = modLine.find("{") + if index != -1: + foundBrace = true + modLine.setLen(index) + elif not foundBrace: + writeOutput = true + if modLine.strip().startswith("{"): + foundBrace = true + writeOutput = false + else: + if modLine.startswith("}"): + foundBrace = false + foundStatic = false + output[^1] = ';' + output &= "\n" + + if writeOutput: + output &= modLine + output &= "\n" + writeOutput = false + + file.close() + + var f = open(filename, fmWrite) + write(f, output) + f.close() + proc rename(file: string, renfile: string) = if file.splitFile().ext == ".nim": return @@ -513,6 +563,9 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) = if c2nimConfig.defines and (c2nimConfig.preprocess or c2nimConfig.ctags): prepend(cfile, getDefines(file, c2nimConfig.inline)) + if c2nimConfig.remove_static: + removeStatic(cfile) + var extflags = "" passC = "" @@ -687,6 +740,7 @@ proc runFile(file: string, cfgin: OrderedTableRef) = c2nimConfig = c2nimConfigObj( flags: "--stdcall", ppflags: "", recurse: false, inline: false, preprocess: false, ctags: false, defines: false, + remove_static: false, dynlib: @[], compile: @[], pragma: @[] ) @@ -707,6 +761,8 @@ proc runFile(file: string, cfgin: OrderedTableRef) = c2nimConfig.ctags = true elif act == "defines": c2nimConfig.defines = true + elif act == "remove_static": + c2nimConfig.remove_static = true elif act == "noprocess": noprocess = true elif act == "flags": From eca296cf114bba8b96488f432165e98bd81b731d Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 8 Jul 2018 10:03:33 +0900 Subject: [PATCH 18/28] Add readme section about remove_static --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 561accf..fbfff52 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,8 @@ The following keys apply to library source code and help with generating the .ni ```defines``` = pulls out simple #defines of ints, floats and hex values for separate conversion [default: false] - works only when preprocess or ctags is used and helps include useful definitions in generated .nim file +```remove_static``` = pulls out the bodies of inline static functions [default: false] + ```flags``` = flags to pass to the c2nim process in "quotes" [default: --stdcall]. --cdecl, --assumedef, --assumendef may be useful ```ppflags``` = flags to pass to the preprocessor [default: ""]. -D for gcc and others may be useful From 2259a51d4e8ff7b93b192bdb1654b73ca783c2c7 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 8 Jul 2018 10:07:10 +0900 Subject: [PATCH 19/28] Add test for nim-libnx --- nimgen.nimble | 2 +- tests/nimgentest.nims | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/nimgen.nimble b/nimgen.nimble index 5c0eb1e..0a5545e 100644 --- a/nimgen.nimble +++ b/nimgen.nimble @@ -1,6 +1,6 @@ # Package -version = "0.2.2" +version = "0.2.3" author = "genotrance" description = "c2nim helper to simplify and automate the wrapping of C libraries" license = "MIT" diff --git a/tests/nimgentest.nims b/tests/nimgentest.nims index f5136c6..872bbab 100644 --- a/tests/nimgentest.nims +++ b/tests/nimgentest.nims @@ -4,8 +4,12 @@ import strutils var full = false - comps = @["libsvm", "nim7z", "nimarchive", "nimbass", "nimbigwig", "nimfuzz", - "nimpcre", "nimrax", "nimssl", "nimssh2"] + comps = @[ + "genotrance/libsvm", "genotrance/nim7z", "genotrance/nimarchive", + "genotrance/nimbass", "genotrance/nimbigwig", "genotrance/nimfuzz", + "genotrance/nimpcre", "genotrance/nimrax", "genotrance/nimssl", + "genotrance/nimssh2", "jyapayne/nim-libnx" + ] if detectOs(Windows): comps.add("nimkerberos") @@ -20,7 +24,7 @@ if paramCount() > 2: for comp in comps: if not dirExists(".."/comp): withDir(".."): - exec "git clone --depth=1 https://github.com/genotrance/" & comp + exec "git clone --depth=1 https://github.com/" & comp exec "nimble uninstall -y " & comp, "", "" withDir(".."/comp): From e0ea3d09ac88a3135d28cc393f0f1a0cc8e4069b Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Wed, 20 Jun 2018 13:59:46 +0900 Subject: [PATCH 20/28] Make env vars automatically grab from config --- nimgen.nim | 57 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/nimgen.nim b/nimgen.nim index c227f4b..61ad29d 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -43,11 +43,15 @@ proc addEnv(str: string): string = try: newStr = newStr % [pair.key, pair.value.string] except ValueError: + # Ignore if there are no values to replace. We + # want to continue anyway discard try: newStr = newStr % ["output", gOutput] except ValueError: + # Ignore if there are no values to replace. We + # want to continue anyway discard # if there are still format args, print a warning @@ -56,6 +60,10 @@ proc addEnv(str: string): string = return newStr +proc `[]`(table: OrderedTableRef[string, string], key: string): string = + ## Gets table values with env vars inserted + tables.`[]`(table, key).addEnv + proc execProc(cmd: string): string = result = "" var @@ -673,30 +681,30 @@ proc doActions(file: string, c2nimConfig: var c2nimConfigObj, cfg: OrderedTableR "pipe"] and sfile != "": if action == "prepend": if srch != "": - prepend(sfile, cfg[act].addEnv(), cfg[srch].addEnv()) + prepend(sfile, cfg[act], cfg[srch]) else: - prepend(sfile, cfg[act].addEnv()) + prepend(sfile, cfg[act]) elif action == "append": if srch != "": - append(sfile, cfg[act].addEnv(), cfg[srch].addEnv()) + append(sfile, cfg[act], cfg[srch]) else: - append(sfile, cfg[act].addEnv()) + append(sfile, cfg[act]) elif action == "replace": if srch != "": - freplace(sfile, cfg[srch].addEnv(), cfg[act].addEnv()) + freplace(sfile, cfg[srch], cfg[act]) elif action == "comment": if srch != "": - comment(sfile, cfg[srch].addEnv(), cfg[act].addEnv()) + comment(sfile, cfg[srch], cfg[act]) elif action == "rename": - rename(sfile, cfg[act].addEnv()) + rename(sfile, cfg[act]) elif action == "compile": - c2nimConfig.compile.add(cfg[act].addEnv()) + c2nimConfig.compile.add(cfg[act]) elif action == "dynlib": - c2nimConfig.dynlib.add(cfg[act].addEnv()) + c2nimConfig.dynlib.add(cfg[act]) elif action == "pragma": - c2nimConfig.pragma.add(cfg[act].addEnv()) + c2nimConfig.pragma.add(cfg[act]) elif action == "pipe": - pipe(sfile, cfg[act].addEnv()) + pipe(sfile, cfg[act]) srch = "" elif action == "search": srch = act @@ -734,7 +742,7 @@ proc runFile(file: string, cfgin: OrderedTableRef) = if file.find(re(pat)).isSome(): echo "Appending " & file & " " & pattern for key in gWildcards[pattern].keys(): - cfg[key & "." & pattern] = gWildcards[pattern][key].addEnv() + cfg[key & "." & pattern] = gWildcards[pattern][key] var c2nimConfig = c2nimConfigObj( @@ -766,9 +774,9 @@ proc runFile(file: string, cfgin: OrderedTableRef) = elif act == "noprocess": noprocess = true elif act == "flags": - c2nimConfig.flags = cfg[act].addEnv() + c2nimConfig.flags = cfg[act] elif act == "ppflags": - c2nimConfig.ppflags = cfg[act].addEnv() + c2nimConfig.ppflags = cfg[act] if c2nimConfig.recurse and c2nimConfig.inline: raise newException(Exception, "Cannot use recurse and inline simultaneously") @@ -788,7 +796,7 @@ proc runCfg(cfg: string) = if gConfig.hasKey("n.global"): if gConfig["n.global"].hasKey("output"): - gOutput = gConfig["n.global"]["output"].addEnv() + gOutput = gConfig["n.global"]["output"] if dirExists(gOutput): if "-f" in commandLineParams(): try: @@ -804,14 +812,14 @@ proc runCfg(cfg: string) = createDir(gOutput) if gConfig["n.global"].hasKey("cpp_compiler"): - gCppCompiler = gConfig["n.global"]["cpp_compiler"].addEnv() + gCppCompiler = gConfig["n.global"]["cpp_compiler"] if gConfig["n.global"].hasKey("c_compiler"): - gCCompiler = gConfig["n.global"]["c_compiler"].addEnv() + gCCompiler = gConfig["n.global"]["c_compiler"] if gConfig["n.global"].hasKey("filter"): - gFilter = gConfig["n.global"]["filter"].addEnv() + gFilter = gConfig["n.global"]["filter"] if gConfig["n.global"].hasKey("quotes"): - if gConfig["n.global"]["quotes"].addEnv() == "false": + if gConfig["n.global"]["quotes"] == "false": gQuotes = false if gConfig.hasKey("n.include"): @@ -826,7 +834,7 @@ proc runCfg(cfg: string) = for prep in gConfig["n.prepare"].keys(): let (key, val) = getKey(prep) if val == true: - let prepVal = gConfig["n.prepare"][prep].addEnv() + let prepVal = gConfig["n.prepare"][prep] if key == "download": downloadUrl(prepVal) elif key == "extract": @@ -848,10 +856,10 @@ proc runCfg(cfg: string) = let (key, val) = getKey(wild) if val == true: if key == "wildcard": - wildcard = gConfig["n.wildcard"][wild].addEnv() + wildcard = gConfig["n.wildcard"][wild] else: gWildcards.setSectionKey(wildcard, wild, - gConfig["n.wildcard"][wild].addEnv()) + gConfig["n.wildcard"][wild]) if gConfig.hasKey("n.after"): var wildcard = "" @@ -859,11 +867,10 @@ proc runCfg(cfg: string) = let (key, val) = getKey(afterKey) if val == true: if key == "wildcard": - wildcard = gConfig["n.after"][afterKey].addEnv() + wildcard = gConfig["n.after"][afterKey] else: gAfter.setSectionKey(wildcard, afterKey, - gConfig["n.after"][afterKey].addEnv()) - + gConfig["n.after"][afterKey]) for file in gConfig.keys(): if file in @["n.global", "n.include", "n.exclude", "n.prepare", "n.wildcard", "n.after"]: From cc0999b70bcc08eca205f1a26dd676f6df35f62b Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 8 Jul 2018 13:05:09 +0900 Subject: [PATCH 21/28] Add section for resetting files --- README.md | 2 ++ nimgen.nim | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fbfff52..d2d04b8 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,8 @@ _[n.global]_ ```quotes``` = pick up any headers included using "" (and not <> which is typically used for standard headers) [default: true] +```reset``` = whether or not to reset all files after processing [default: false] + ```filter``` = string to identify and recurse into library .h files in #include statements and exclude standard headers ```cpp_compiler``` = string to specify a CPP compiler executable. [default: g++] diff --git a/nimgen.nim b/nimgen.nim index 61ad29d..5f3b1fb 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -9,6 +9,7 @@ var gConfig: Config gFilter = "" gQuotes = true + gReset = false gCppCompiler = "g++" gCCompiler = "gcc" gOutput = "" @@ -822,6 +823,10 @@ proc runCfg(cfg: string) = if gConfig["n.global"]["quotes"] == "false": gQuotes = false + if gConfig["n.global"].hasKey("reset"): + if gConfig["n.global"]["reset"] == "true": + gReset = true + if gConfig.hasKey("n.include"): for inc in gConfig["n.include"].keys(): gIncludes.add(inc.addEnv()) @@ -878,8 +883,9 @@ proc runCfg(cfg: string) = runFile(file, gConfig[file]) - # Reset files - gitReset() + if gReset: + # Reset files + gitReset() # ### From c96b2f97099d047e152feb09af3410f692794e0b Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 8 Jul 2018 22:43:17 +0900 Subject: [PATCH 22/28] Combine passC and absolute imports --- nimgen.nim | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nimgen.nim b/nimgen.nim index 5f3b1fb..db451fd 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -584,11 +584,18 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) = passC = "import strutils\n" passC &= "import ospaths\n" + for inc in gIncludes: + let relativeInc = inc.replace(gOutput & $DirSep, "") + passC &= ( + """{.passC: "-I\"" & currentSourcePath().splitPath().head & "/$#\"".}""" % + [relativeInc] + ) & "\n" + for prag in c2nimConfig.pragma: outpragma &= "{." & prag & ".}\n" let fname = file.splitFile().name.replace(re"[\.\-]", "_") - let fincl = file.replace(gOutput, "") + let fincl = file.replace(gOutput & $DirSep, "") if c2nimConfig.dynlib.len() != 0: let From 0918f024792f2e220c39d83b883ada8f24367fd3 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 8 Jul 2018 22:50:34 +0900 Subject: [PATCH 23/28] Remove dir sep from replace --- nimgen.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nimgen.nim b/nimgen.nim index db451fd..be066de 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -585,7 +585,7 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) = passC &= "import ospaths\n" for inc in gIncludes: - let relativeInc = inc.replace(gOutput & $DirSep, "") + let relativeInc = inc.replace(gOutput, "") passC &= ( """{.passC: "-I\"" & currentSourcePath().splitPath().head & "/$#\"".}""" % [relativeInc] @@ -595,7 +595,7 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) = outpragma &= "{." & prag & ".}\n" let fname = file.splitFile().name.replace(re"[\.\-]", "_") - let fincl = file.replace(gOutput & $DirSep, "") + let fincl = file.replace(gOutput, "") if c2nimConfig.dynlib.len() != 0: let From d1813414e3d90b09def545aa9183d63eefff12a4 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 8 Jul 2018 22:56:36 +0900 Subject: [PATCH 24/28] Add check for absolute directories --- nimgen.nim | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/nimgen.nim b/nimgen.nim index be066de..63e54d9 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -585,11 +585,14 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) = passC &= "import ospaths\n" for inc in gIncludes: - let relativeInc = inc.replace(gOutput, "") - passC &= ( - """{.passC: "-I\"" & currentSourcePath().splitPath().head & "/$#\"".}""" % - [relativeInc] - ) & "\n" + if inc.isAbsolute: + passC &= ("""{.passC: "-I\"$#\"".}""" % [inc]) & "\n" + else: + let relativeInc = inc.replace(gOutput, "") + passC &= ( + """{.passC: "-I\"" & currentSourcePath().splitPath().head & "/$#\"".}""" % + [relativeInc] + ) & "\n" for prag in c2nimConfig.pragma: outpragma &= "{." & prag & ".}\n" From f5110d9da15207d2af7d2a15bc84723151032205 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 8 Jul 2018 13:05:09 +0900 Subject: [PATCH 25/28] Add n.post section --- README.md | 8 ++++++++ nimgen.nim | 16 +++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d2d04b8..72ea01d 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,14 @@ The following keys can be used to prepare dependencies such as downloading ZIP f ```copy``` = copy a file to another location. Preferred over moving to preserve original. Comma separate for multiple entries. E.g. copy = "output/config.h.in=output/config.h" +_[n.post]_ + +This section is the same as the prepare section, but for performing actions after the project has been processed. + +```reset``` = whether or not to perform a git reset on all files after processing [default: false] + +```execute``` = command to run after processing + _[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. Only applies on source files following the wildcard declarations. diff --git a/nimgen.nim b/nimgen.nim index 63e54d9..50a3849 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -888,15 +888,21 @@ proc runCfg(cfg: string) = gConfig["n.after"][afterKey]) for file in gConfig.keys(): - if file in @["n.global", "n.include", "n.exclude", "n.prepare", "n.wildcard", "n.after"]: + if file in @["n.global", "n.include", "n.exclude", + "n.prepare", "n.wildcard", "n.after", "n.post"]: continue runFile(file, gConfig[file]) - if gReset: - # Reset files - gitReset() - + if gConfig.hasKey("n.post"): + for post in gConfig["n.post"].keys(): + let (key, val) = getKey(post) + if val == true: + let postVal = gConfig["n.post"][post] + if key == "reset": + gitReset() + elif key == "execute": + discard execProc(postVal) # ### # Main loop From 797fa20fcafef361d68bf326d5a7b2f491dd6ac0 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Tue, 10 Jul 2018 20:09:51 +0900 Subject: [PATCH 26/28] Make static bodies replacement use regex --- nimgen.nim | 51 +++++---------------------------------------------- 1 file changed, 5 insertions(+), 46 deletions(-) diff --git a/nimgen.nim b/nimgen.nim index 50a3849..4529230 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -323,52 +323,11 @@ proc comment(file: string, pattern: string, numlines: string) = break proc removeStatic(filename: string) = - - if not fileExists(filename): - echo "Missing file: " & filename - return - - var - file = open(filename) - stack: seq[string] = @[] - foundBrace = false - foundStatic = false - writeOutput = true - output = newStringofCap(getFileSize(filename)) - - for line in file.lines(): - var modLine = line - - if not foundStatic: - writeOutput = true - if line.startswith("static inline"): - foundStatic = true - let index = modLine.find("{") - if index != -1: - foundBrace = true - modLine.setLen(index) - elif not foundBrace: - writeOutput = true - if modLine.strip().startswith("{"): - foundBrace = true - writeOutput = false - else: - if modLine.startswith("}"): - foundBrace = false - foundStatic = false - output[^1] = ';' - output &= "\n" - - if writeOutput: - output &= modLine - output &= "\n" - writeOutput = false - - file.close() - - var f = open(filename, fmWrite) - write(f, output) - f.close() + ## Replace static function bodies with a semicolon + withFile(filename): + content = content.replace( + re"(?m)(static inline.*?\))(\s*\{(\s*?.*?$)*[\n\r]\})", "$1;" + ) proc rename(file: string, renfile: string) = if file.splitFile().ext == ".nim": From 410977bb710fe91663c59cd8652e855d4d6e880f Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Wed, 11 Jul 2018 07:02:36 +0900 Subject: [PATCH 27/28] Move remove static and reset after processing --- nimgen.nim | 58 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/nimgen.nim b/nimgen.nim index 4529230..336020d 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -22,7 +22,7 @@ var type c2nimConfigObj = object flags, ppflags: string - recurse, inline, preprocess, ctags, defines, remove_static: bool + recurse, inline, preprocess, ctags, defines, removeStatic: bool dynlib, compile, pragma: seq[string] const DOC = """ @@ -125,6 +125,16 @@ proc gitReset() = discard execProc("git reset --hard HEAD") +proc gitCheckout(filename: string) = + echo "Resetting file: $#" % [filename] + + setCurrentDir(gOutput) + defer: setCurrentDir(gProjectDir) + + let adjustedFile = filename.replace(gOutput & $DirSep, "") + + discard execProc("git checkout $#" % [adjustedFile]) + proc gitRemotePull(url: string, pull=true) = if dirExists(gOutput/".git"): if pull: @@ -531,7 +541,7 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) = if c2nimConfig.defines and (c2nimConfig.preprocess or c2nimConfig.ctags): prepend(cfile, getDefines(file, c2nimConfig.inline)) - if c2nimConfig.remove_static: + if c2nimConfig.removeStatic: removeStatic(cfile) var @@ -646,6 +656,9 @@ proc doActions(file: string, c2nimConfig: var c2nimConfigObj, cfg: OrderedTableR if action == "create": createDir(file.splitPath().head) writeFile(file, cfg[act]) + elif action == "removestatic": + removeStatic(sfile) + c2nimConfig.removeStatic = true elif action in @["prepend", "append", "replace", "comment", "rename", "compile", "dynlib", "pragma", "pipe"] and sfile != "": @@ -728,25 +741,25 @@ proc runFile(file: string, cfgin: OrderedTableRef) = var noprocess = false for act in cfg.keys(): - if cfg[act] == "true": - if act == "recurse": - c2nimConfig.recurse = true - elif act == "inline": - c2nimConfig.inline = true - elif act == "preprocess": - c2nimConfig.preprocess = true - elif act == "ctags": - c2nimConfig.ctags = true - elif act == "defines": - c2nimConfig.defines = true - elif act == "remove_static": - c2nimConfig.remove_static = true - elif act == "noprocess": - noprocess = true - elif act == "flags": - c2nimConfig.flags = cfg[act] - elif act == "ppflags": - c2nimConfig.ppflags = cfg[act] + let (action, val) = getKey(act) + if val == true: + if cfg[act] == "true": + if action == "recurse": + c2nimConfig.recurse = true + elif action == "inline": + c2nimConfig.inline = true + elif action == "preprocess": + c2nimConfig.preprocess = true + elif action == "ctags": + c2nimConfig.ctags = true + elif action == "defines": + c2nimConfig.defines = true + elif action == "noprocess": + noprocess = true + elif action == "flags": + c2nimConfig.flags = cfg[act] + elif action == "ppflags": + c2nimConfig.ppflags = cfg[act] if c2nimConfig.recurse and c2nimConfig.inline: raise newException(Exception, "Cannot use recurse and inline simultaneously") @@ -756,6 +769,9 @@ proc runFile(file: string, cfgin: OrderedTableRef) = processAfter(nimFile, c2nimConfig) + if c2nimConfig.removeStatic: + gitCheckout(sfile) + proc runCfg(cfg: string) = if not fileExists(cfg): raise newException(Exception, "Config doesn't exist: " & cfg) From b61d37040ff5a7440bf88fbbf8c761424ef4715f Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Wed, 11 Jul 2018 13:36:45 +0900 Subject: [PATCH 28/28] Modify removeStatic to comment out body, then re-comment --- nimgen.nim | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/nimgen.nim b/nimgen.nim index 336020d..4e6ea9d 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -22,7 +22,7 @@ var type c2nimConfigObj = object flags, ppflags: string - recurse, inline, preprocess, ctags, defines, removeStatic: bool + recurse, inline, preprocess, ctags, defines: bool dynlib, compile, pragma: seq[string] const DOC = """ @@ -125,7 +125,7 @@ proc gitReset() = discard execProc("git reset --hard HEAD") -proc gitCheckout(filename: string) = +proc gitCheckout(filename: string) {.used.} = echo "Resetting file: $#" % [filename] setCurrentDir(gOutput) @@ -333,10 +333,33 @@ proc comment(file: string, pattern: string, numlines: string) = break proc removeStatic(filename: string) = - ## Replace static function bodies with a semicolon + ## Replace static function bodies with a semicolon and commented + ## out body withFile(filename): content = content.replace( - re"(?m)(static inline.*?\))(\s*\{(\s*?.*?$)*[\n\r]\})", "$1;" + re"(?m)(static inline.*?\))(\s*\{(\s*?.*?$)*[\n\r]\})", + proc (match: RegexMatch): string = + let funcDecl = match.captures[0] + let body = match.captures[1].strip() + result = "" + + result.add("$#;" % [funcDecl]) + result.add(body.replace(re"(?m)^", "//")) + ) + +proc reAddStatic(filename: string) = + ## Uncomment out the body and remove the semicolon. Undoes + ## removeStatic + withFile(filename): + content = content.replace( + re"(?m)(static inline.*?\));(\/\/\s*\{(\s*?.*?$)*[\n\r]\/\/\})", + proc (match: RegexMatch): string = + let funcDecl = match.captures[0] + let body = match.captures[1].strip() + result = "" + + result.add("$# " % [funcDecl]) + result.add(body.replace(re"(?m)^\/\/", "")) ) proc rename(file: string, renfile: string) = @@ -541,9 +564,6 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) = if c2nimConfig.defines and (c2nimConfig.preprocess or c2nimConfig.ctags): prepend(cfile, getDefines(file, c2nimConfig.inline)) - if c2nimConfig.removeStatic: - removeStatic(cfile) - var extflags = "" passC = "" @@ -656,9 +676,6 @@ proc doActions(file: string, c2nimConfig: var c2nimConfigObj, cfg: OrderedTableR if action == "create": createDir(file.splitPath().head) writeFile(file, cfg[act]) - elif action == "removestatic": - removeStatic(sfile) - c2nimConfig.removeStatic = true elif action in @["prepend", "append", "replace", "comment", "rename", "compile", "dynlib", "pragma", "pipe"] and sfile != "": @@ -731,7 +748,6 @@ proc runFile(file: string, cfgin: OrderedTableRef) = c2nimConfig = c2nimConfigObj( flags: "--stdcall", ppflags: "", recurse: false, inline: false, preprocess: false, ctags: false, defines: false, - remove_static: false, dynlib: @[], compile: @[], pragma: @[] ) @@ -762,15 +778,20 @@ proc runFile(file: string, cfgin: OrderedTableRef) = c2nimConfig.ppflags = cfg[act] if c2nimConfig.recurse and c2nimConfig.inline: - raise newException(Exception, "Cannot use recurse and inline simultaneously") + echo "Cannot use recurse and inline simultaneously" + quit(1) + + # Remove static inline function bodies + removeStatic(sfile) + if not noprocess: let nimFile = getNimout(sfile) c2nim(file, nimFile, c2nimConfig) processAfter(nimFile, c2nimConfig) - if c2nimConfig.removeStatic: - gitCheckout(sfile) + # Add them back for compilation + reAddStatic(sfile) proc runCfg(cfg: string) = if not fileExists(cfg):