Compare commits

...
Sign in to create a new pull request.

30 commits

Author SHA1 Message Date
Joey Yakimowich-Payne
b61d37040f Modify removeStatic to comment out body, then re-comment 2018-07-11 13:41:58 +09:00
Joey Yakimowich-Payne
410977bb71 Move remove static and reset after processing 2018-07-11 07:42:34 +09:00
Joey Yakimowich-Payne
797fa20fca Make static bodies replacement use regex 2018-07-10 20:09:51 +09:00
Joey Yakimowich-Payne
f5110d9da1 Add n.post section 2018-07-10 15:19:58 +09:00
Joey Yakimowich-Payne
d1813414e3 Add check for absolute directories 2018-07-08 22:56:56 +09:00
Joey Yakimowich-Payne
0918f02479 Remove dir sep from replace 2018-07-08 22:51:03 +09:00
Joey Yakimowich-Payne
c96b2f9709 Combine passC and absolute imports 2018-07-08 22:43:40 +09:00
Joey Yakimowich-Payne
cc0999b70b Add section for resetting files 2018-07-08 13:05:09 +09:00
Joey Yakimowich-Payne
e0ea3d09ac Make env vars automatically grab from config 2018-07-08 12:53:12 +09:00
Joey Yakimowich-Payne
2259a51d4e Add test for nim-libnx 2018-07-08 10:07:10 +09:00
Joey Yakimowich-Payne
eca296cf11 Add readme section about remove_static 2018-07-08 10:03:33 +09:00
Joey Yakimowich-Payne
09e5ea8f12 Add preliminary support for removing static funcs 2018-07-07 19:16:16 +09:00
Joey Yakimowich-Payne
8975db2cc9 Rename execute to pipe 2018-06-27 22:24:46 +09:00
Joey Yakimowich-Payne
b148bba4b2 Reset files after processing 2018-06-24 11:26:38 +09:00
Joey Yakimowich-Payne
ea6fa57670 Always do sparse checkout in case new folders are needed in nimgen cfg 2018-06-24 08:37:28 +09:00
Joey Yakimowich-Payne
153591397e Fix issue if cfg file is local gProject dir will be an empty string 2018-06-24 08:22:29 +09:00
Joey Yakimowich-Payne
14d8eca24b Change project dir based on nimgen cfg file 2018-06-24 07:52:36 +09:00
Joey Yakimowich-Payne
941a530885 Add env vars to readme 2018-06-20 14:04:14 +09:00
Joey Yakimowich-Payne
883c79115d Add ability to use environment vars 2018-06-20 13:59:46 +09:00
Joey Yakimowich-Payne
a55d71b02b Version bump 2018-06-18 20:22:47 +09:00
Joey Yakimowich-Payne
a71ddc6478 Fix ctags 2018-06-18 19:56:34 +09:00
Joey Yakimowich-Payne
0449f548dc 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.
2018-06-18 19:53:54 +09:00
Joey Yakimowich-Payne
a3d48fb1ac Use exceptions instead of quitting to get stacktrace 2018-06-18 19:47:13 +09:00
Joey Yakimowich-Payne
acb07ba3e1 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.
2018-06-18 19:44:45 +09:00
Joey Yakimowich-Payne
77e28545ef Add after command that operates on files after nimgen has run 2018-06-18 19:41:12 +09:00
Joey Yakimowich-Payne
0e0eadde37 Merge branch 'configurable_compiler' into all_merged 2018-06-16 15:39:21 +09:00
Joey Yakimowich-Payne
d2e3f41c5f Merge branch 'allow_deeper_output' into all_merged 2018-06-16 15:39:05 +09:00
Joey Yakimowich-Payne
71699332be Allow for deeper than one directory paths 2018-06-16 15:22:16 +09:00
Joey Yakimowich-Payne
f275bc0e35 Update readme with compiler spec 2018-06-16 15:17:51 +09:00
Joey Yakimowich-Payne
0f73ad6d3f Add configurable compiler to global section 2018-06-14 17:13:46 +09:00
4 changed files with 298 additions and 93 deletions

View file

@ -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. 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:- To see examples of nimgen in action check out the following wrappers:-
* Link with a dynamic library * Link with a dynamic library
* [nimbass](https://github.com/genotrance/nimbass) - BASS audio wrapper: [docs](http://nimgen.genotrance.com/nimbass) * [nimbass](https://github.com/genotrance/nimbass) - BASS audio wrapper: [docs](http://nimgen.genotrance.com/nimbass)
@ -71,8 +79,14 @@ _[n.global]_
```quotes``` = pick up any headers included using "" (and not <> which is typically used for standard headers) [default: true] ```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 ```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]_ _[n.include]_
List of all directories, one per line, to include in the search path. This is used by:- List of all directories, one per line, to include in the search path. This is used by:-
@ -103,12 +117,25 @@ 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" ```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]_ _[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. 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.
```wildcard``` = pattern to match against. All keys following the wildcard declaration will apply to matched files ```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]_ _[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 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
@ -123,6 +150,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 ```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 ```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 ```ppflags``` = flags to pass to the preprocessor [default: ""]. -D for gcc and others may be useful
@ -143,7 +172,7 @@ The following keys apply to library source code (before processing) and generate
```search``` = search string providing context for following prepend/append/replace directives ```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 ```prepend``` = string value to prepend into file at beginning or before search

View file

@ -2,16 +2,22 @@ import nre, os, ospaths, osproc, parsecfg, pegs, ropes, sequtils, streams, strut
var var
gDoneRecursive: seq[string] = @[] gDoneRecursive: seq[string] = @[]
gDoneAfter: seq[string] = @[]
gDoneInline: seq[string] = @[] gDoneInline: seq[string] = @[]
gProjectDir = ""
gConfig: Config gConfig: Config
gFilter = "" gFilter = ""
gQuotes = true gQuotes = true
gReset = false
gCppCompiler = "g++"
gCCompiler = "gcc"
gOutput = "" gOutput = ""
gIncludes: seq[string] = @[] gIncludes: seq[string] = @[]
gExcludes: seq[string] = @[] gExcludes: seq[string] = @[]
gRenames = initTable[string, string]() gRenames = initTable[string, string]()
gWildcards = newConfig() gWildcards = newConfig()
gAfter = newConfig()
type type
c2nimConfigObj = object c2nimConfigObj = object
@ -32,6 +38,33 @@ Options:
# ### # ###
# Helpers # Helpers
proc addEnv(str: string): string =
var newStr = str
for pair in envPairs():
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
if newStr.contains("${"):
echo "WARNING: \"", newStr, "\" still contains an uninterpolated value!"
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 = proc execProc(cmd: string): string =
result = "" result = ""
var var
@ -48,18 +81,22 @@ proc execProc(cmd: string): string =
var x = p.peekExitCode() var x = p.peekExitCode()
if x != 0: if x != 0:
echo "Command failed: " & $x raise newException(
echo cmd Exception,
echo result "Command failed: " & $x &
quit(1) "\nCMD: " & $cmd &
"\nRESULT: " & $result
)
proc extractZip(zipfile: string) = proc extractZip(zipfile: string) =
var cmd = "unzip -o $#" var cmd = "unzip -o $#"
if defined(Windows): 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) setCurrentDir(gOutput)
defer: setCurrentDir("..") defer: setCurrentDir(gProjectDir)
echo "Extracting " & zipfile echo "Extracting " & zipfile
discard execProc(cmd % zipfile) discard execProc(cmd % zipfile)
@ -84,10 +121,20 @@ proc gitReset() =
echo "Resetting Git repo" echo "Resetting Git repo"
setCurrentDir(gOutput) setCurrentDir(gOutput)
defer: setCurrentDir("..") defer: setCurrentDir(gProjectDir)
discard execProc("git reset --hard HEAD") discard execProc("git reset --hard HEAD")
proc gitCheckout(filename: string) {.used.} =
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) = proc gitRemotePull(url: string, pull=true) =
if dirExists(gOutput/".git"): if dirExists(gOutput/".git"):
if pull: if pull:
@ -95,7 +142,7 @@ proc gitRemotePull(url: string, pull=true) =
return return
setCurrentDir(gOutput) setCurrentDir(gOutput)
defer: setCurrentDir("..") defer: setCurrentDir(gProjectDir)
echo "Setting up Git repo" echo "Setting up Git repo"
discard execProc("git init .") discard execProc("git init .")
@ -109,10 +156,9 @@ proc gitSparseCheckout(plist: string) =
let sparsefile = ".git/info/sparse-checkout" let sparsefile = ".git/info/sparse-checkout"
if fileExists(gOutput/sparsefile): if fileExists(gOutput/sparsefile):
gitReset() gitReset()
return
setCurrentDir(gOutput) setCurrentDir(gOutput)
defer: setCurrentDir("..") defer: setCurrentDir(gProjectDir)
discard execProc("git config core.sparsecheckout true") discard execProc("git config core.sparsecheckout true")
writeFile(sparsefile, plist) writeFile(sparsefile, plist)
@ -124,9 +170,7 @@ proc doCopy(flist: string) =
for pair in flist.split(","): for pair in flist.split(","):
let spl = pair.split("=") let spl = pair.split("=")
if spl.len() != 2: if spl.len() != 2:
echo "Bad copy syntax: " & flist raise newException(Exception, "Bad copy syntax: " & flist)
quit(1)
let let
lfile = spl[0].strip() lfile = spl[0].strip()
rfile = spl[1].strip() rfile = spl[1].strip()
@ -151,6 +195,9 @@ proc getKey(ukey: string): tuple[key: string, val: bool] =
# File loction # File loction
proc getNimout(file: string, rename=true): string = proc getNimout(file: string, rename=true): string =
if file == "":
return ""
result = file.splitFile().name.replace(re"[\-\.]", "_") & ".nim" result = file.splitFile().name.replace(re"[\-\.]", "_") & ".nim"
if gOutput != "": if gOutput != "":
result = gOutput/result result = gOutput/result
@ -185,9 +232,10 @@ proc search(file: string): string =
found = true found = true
break break
if not found: if not found:
echo "File doesn't exist: " & file raise newException(Exception, "File doesn't exist: " & file)
quit(1)
# Only keep relative directory
result = result.replace(gProjectDir & $DirSep, "")
return result.replace(re"[\\/]", $DirSep) return result.replace(re"[\\/]", $DirSep)
# ### # ###
@ -228,10 +276,11 @@ proc prepend(file: string, data: string, search="") =
if idx != -1: if idx != -1:
content = content[0..<idx] & data & content[idx..<content.len()] content = content[0..<idx] & data & content[idx..<content.len()]
proc execute(file: string, command: string) = proc pipe(file: string, command: string) =
withFile(file):
let cmd = command % ["file", file] let cmd = command % ["file", file]
let commandResult = execProc(cmd) let commandResult = execProc(cmd).strip()
if commandResult != "":
withFile(file):
content = commandResult content = commandResult
proc append(file: string, data: string, search="") = proc append(file: string, data: string, search="") =
@ -283,6 +332,36 @@ proc comment(file: string, pattern: string, numlines: string) =
idx += 1 idx += 1
break break
proc removeStatic(filename: string) =
## Replace static function bodies with a semicolon and commented
## out body
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 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) = proc rename(file: string, renfile: string) =
if file.splitFile().ext == ".nim": if file.splitFile().ext == ".nim":
return return
@ -296,9 +375,7 @@ proc rename(file: string, renfile: string) =
for entry in matches[1].split(","): for entry in matches[1].split(","):
let spl = entry.split("=") let spl = entry.split("=")
if spl.len() != 2: if spl.len() != 2:
echo "Bad replace syntax: " & renfile raise newException(Exception, "Bad replace syntax: " & renfile)
quit(1)
let let
srch = spl[0].strip() srch = spl[0].strip()
repl = spl[1].strip() repl = spl[1].strip()
@ -337,12 +414,20 @@ proc getIncls(file: string, inline=false): seq[string] =
if inline and file in gDoneInline: if inline and file in gDoneInline:
return return
var curPath = splitFile(expandFileName(file))[0]
withFile(file): withFile(file):
for f in content.findIter(re"(?m)^\s*#\s*include\s+(.*?)$"): for f in content.findIter(re"(?m)^\s*#\s*include\s+(.*?)$"):
var inc = f.captures[0].strip() var inc = f.captures[0].strip()
if ((gQuotes and inc.contains("\"")) or (gFilter != "" and gFilter in inc)) and (not exclude(inc)): if ((gQuotes and inc.contains("\"")) or (gFilter != "" and gFilter in inc)) and (not exclude(inc)):
result.add( var addInc = inc.replace(re"""[<>"]""", "").replace(re"\/[\*\/].*$", "").strip()
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() result = result.deduplicate()
@ -375,7 +460,7 @@ proc getDefines(file: string, inline=false): string =
proc runPreprocess(file, ppflags, flags: string, inline: bool): string = proc runPreprocess(file, ppflags, flags: string, inline: bool): string =
var var
pproc = if flags.contains("cpp"): "g++" else: "gcc" pproc = if flags.contains("cpp"): gCppCompiler else: gCCompiler
cmd = "$# -E $# $#" % [pproc, ppflags, file] cmd = "$# -E $# $#" % [pproc, ppflags, file]
for inc in gIncludes: for inc in gIncludes:
@ -415,7 +500,7 @@ proc runPreprocess(file, ppflags, flags: string, inline: bool): string =
proc runCtags(file: string): string = proc runCtags(file: string): string =
var 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) fps = execProc(cmd)
fdata = "" fdata = ""
@ -464,7 +549,9 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) =
for inc in incls: for inc in incls:
runFile(inc, cfg) 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 var cfile = file
if c2nimConfig.preprocess: if c2nimConfig.preprocess:
@ -484,13 +571,24 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) =
outpragma = "" outpragma = ""
passC = "import strutils\n" passC = "import strutils\n"
passC &= "import ospaths\n"
for inc in gIncludes: for inc in gIncludes:
passC &= ("""{.passC: "-I\"" & gorge("nimble path $#").strip() & "/$#\"".}""" % [gOutput, inc]) & "\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: for prag in c2nimConfig.pragma:
outpragma &= "{." & prag & ".}\n" outpragma &= "{." & prag & ".}\n"
let fname = file.splitFile().name.replace(re"[\.\-]", "_") let fname = file.splitFile().name.replace(re"[\.\-]", "_")
let fincl = file.replace(gOutput, "")
if c2nimConfig.dynlib.len() != 0: if c2nimConfig.dynlib.len() != 0:
let let
win = "when defined(Windows):\n" win = "when defined(Windows):\n"
@ -520,7 +618,10 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) =
if outlib != "": if outlib != "":
extflags &= " --dynlib:dynlib$#" % fname extflags &= " --dynlib:dynlib$#" % fname
else: 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 extflags = "--header:header$#" % fname
# Run c2nim on generated file # Run c2nim on generated file
@ -563,29 +664,11 @@ proc c2nim(fl, outfile: string, c2nimConfig: c2nimConfigObj) =
if outlib != "": if outlib != "":
prepend(outfile, 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 var
srch = "" srch = ""
sfile = search(file)
c2nimConfig = c2nimConfigObj(
flags: "--stdcall", ppflags: "",
recurse: false, inline: false, preprocess: false, ctags: false, defines: false,
dynlib: @[], compile: @[], pragma: @[]
)
for act in cfg.keys(): for act in cfg.keys():
let (action, val) = getKey(act) let (action, val) = getKey(act)
@ -593,7 +676,9 @@ proc runFile(file: string, cfgin: OrderedTableRef) =
if action == "create": if action == "create":
createDir(file.splitPath().head) createDir(file.splitPath().head)
writeFile(file, cfg[act]) writeFile(file, cfg[act])
elif action in @["prepend", "append", "replace", "comment", "rename", "compile", "dynlib", "pragma", "execute"] and sfile != "": elif action in @["prepend", "append", "replace", "comment",
"rename", "compile", "dynlib", "pragma",
"pipe"] and sfile != "":
if action == "prepend": if action == "prepend":
if srch != "": if srch != "":
prepend(sfile, cfg[act], cfg[srch]) prepend(sfile, cfg[act], cfg[srch])
@ -618,45 +703,101 @@ proc runFile(file: string, cfgin: OrderedTableRef) =
c2nimConfig.dynlib.add(cfg[act]) c2nimConfig.dynlib.add(cfg[act])
elif action == "pragma": elif action == "pragma":
c2nimConfig.pragma.add(cfg[act]) c2nimConfig.pragma.add(cfg[act])
elif action == "execute": elif action == "pipe":
execute(sfile, cfg[act]) pipe(sfile, cfg[act])
srch = "" srch = ""
elif action == "search": elif action == "search":
srch = act 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]
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": if file.splitFile().ext != ".nim":
var noprocess = false var noprocess = false
for act in cfg.keys(): for act in cfg.keys():
let (action, val) = getKey(act)
if val == true:
if cfg[act] == "true": if cfg[act] == "true":
if act == "recurse": if action == "recurse":
c2nimConfig.recurse = true c2nimConfig.recurse = true
elif act == "inline": elif action == "inline":
c2nimConfig.inline = true c2nimConfig.inline = true
elif act == "preprocess": elif action == "preprocess":
c2nimConfig.preprocess = true c2nimConfig.preprocess = true
elif act == "ctags": elif action == "ctags":
c2nimConfig.ctags = true c2nimConfig.ctags = true
elif act == "defines": elif action == "defines":
c2nimConfig.defines = true c2nimConfig.defines = true
elif act == "noprocess": elif action == "noprocess":
noprocess = true noprocess = true
elif act == "flags": elif action == "flags":
c2nimConfig.flags = cfg[act] c2nimConfig.flags = cfg[act]
elif act == "ppflags": elif action == "ppflags":
c2nimConfig.ppflags = cfg[act] c2nimConfig.ppflags = cfg[act]
if c2nimConfig.recurse and c2nimConfig.inline: if c2nimConfig.recurse and c2nimConfig.inline:
echo "Cannot use recurse and inline simultaneously" echo "Cannot use recurse and inline simultaneously"
quit(1) quit(1)
# Remove static inline function bodies
removeStatic(sfile)
if not noprocess: if not noprocess:
c2nim(file, getNimout(sfile), c2nimConfig) let nimFile = getNimout(sfile)
c2nim(file, nimFile, c2nimConfig)
processAfter(nimFile, c2nimConfig)
# Add them back for compilation
reAddStatic(sfile)
proc runCfg(cfg: string) = proc runCfg(cfg: string) =
if not fileExists(cfg): if not fileExists(cfg):
echo "Config doesn't exist: " & cfg raise newException(Exception, "Config doesn't exist: " & cfg)
quit(1)
gProjectDir = parentDir(cfg.expandFilename())
gConfig = loadConfig(cfg) gConfig = loadConfig(cfg)
@ -668,49 +809,57 @@ proc runCfg(cfg: string) =
try: try:
removeDir(gOutput) removeDir(gOutput)
except OSError: except OSError:
echo "Directory in use: " & gOutput raise newException(Exception, "Directory in use: " & gOutput)
quit(1)
else: else:
for f in walkFiles(gOutput/"*.nim"): for f in walkFiles(gOutput/"*.nim"):
try: try:
removeFile(f) removeFile(f)
except OSError: except OSError:
echo "Unable to delete: " & f raise newException(Exception, "Unable to delete: " & f)
quit(1)
createDir(gOutput) 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"): if gConfig["n.global"].hasKey("filter"):
gFilter = gConfig["n.global"]["filter"] gFilter = gConfig["n.global"]["filter"]
if gConfig["n.global"].hasKey("quotes"): if gConfig["n.global"].hasKey("quotes"):
if gConfig["n.global"]["quotes"] == "false": if gConfig["n.global"]["quotes"] == "false":
gQuotes = false gQuotes = false
if gConfig["n.global"].hasKey("reset"):
if gConfig["n.global"]["reset"] == "true":
gReset = true
if gConfig.hasKey("n.include"): if gConfig.hasKey("n.include"):
for inc in gConfig["n.include"].keys(): for inc in gConfig["n.include"].keys():
gIncludes.add(inc) gIncludes.add(inc.addEnv())
if gConfig.hasKey("n.exclude"): if gConfig.hasKey("n.exclude"):
for excl in gConfig["n.exclude"].keys(): for excl in gConfig["n.exclude"].keys():
gExcludes.add(excl) gExcludes.add(excl.addEnv())
if gConfig.hasKey("n.prepare"): if gConfig.hasKey("n.prepare"):
for prep in gConfig["n.prepare"].keys(): for prep in gConfig["n.prepare"].keys():
let (key, val) = getKey(prep) let (key, val) = getKey(prep)
if val == true: if val == true:
let prepVal = gConfig["n.prepare"][prep]
if key == "download": if key == "download":
downloadUrl(gConfig["n.prepare"][prep]) downloadUrl(prepVal)
elif key == "extract": elif key == "extract":
extractZip(gConfig["n.prepare"][prep]) extractZip(prepVal)
elif key == "git": elif key == "git":
gitRemotePull(gConfig["n.prepare"][prep]) gitRemotePull(prepVal)
elif key == "gitremote": elif key == "gitremote":
gitRemotePull(gConfig["n.prepare"][prep], false) gitRemotePull(prepVal, false)
elif key == "gitsparse": elif key == "gitsparse":
gitSparseCheckout(gConfig["n.prepare"][prep]) gitSparseCheckout(prepVal)
elif key == "execute": elif key == "execute":
discard execProc(gConfig["n.prepare"][prep]) discard execProc(prepVal)
elif key == "copy": elif key == "copy":
doCopy(gConfig["n.prepare"][prep]) doCopy(prepVal)
if gConfig.hasKey("n.wildcard"): if gConfig.hasKey("n.wildcard"):
var wildcard = "" var wildcard = ""
@ -720,14 +869,37 @@ proc runCfg(cfg: string) =
if key == "wildcard": if key == "wildcard":
wildcard = gConfig["n.wildcard"][wild] wildcard = gConfig["n.wildcard"][wild]
else: else:
gWildcards.setSectionKey(wildcard, wild, gConfig["n.wildcard"][wild]) 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(): 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", "n.post"]:
continue continue
runFile(file, gConfig[file]) runFile(file, gConfig[file])
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 # Main loop

View file

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

View file

@ -4,8 +4,12 @@ import strutils
var var
full = false full = false
comps = @["libsvm", "nim7z", "nimarchive", "nimbass", "nimbigwig", "nimfuzz", comps = @[
"nimpcre", "nimrax", "nimssl", "nimssh2"] "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): if detectOs(Windows):
comps.add("nimkerberos") comps.add("nimkerberos")
@ -20,7 +24,7 @@ if paramCount() > 2:
for comp in comps: for comp in comps:
if not dirExists(".."/comp): if not dirExists(".."/comp):
withDir(".."): 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, "", "" exec "nimble uninstall -y " & comp, "", ""
withDir(".."/comp): withDir(".."/comp):