Compare commits
30 commits
master
...
master_bac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b61d37040f | ||
|
|
410977bb71 | ||
|
|
797fa20fca | ||
|
|
f5110d9da1 | ||
|
|
d1813414e3 | ||
|
|
0918f02479 | ||
|
|
c96b2f9709 | ||
|
|
cc0999b70b | ||
|
|
e0ea3d09ac | ||
|
|
2259a51d4e | ||
|
|
eca296cf11 | ||
|
|
09e5ea8f12 | ||
|
|
8975db2cc9 | ||
|
|
b148bba4b2 | ||
|
|
ea6fa57670 | ||
|
|
153591397e | ||
|
|
14d8eca24b | ||
|
|
941a530885 | ||
|
|
883c79115d | ||
|
|
a55d71b02b | ||
|
|
a71ddc6478 | ||
|
|
0449f548dc | ||
|
|
a3d48fb1ac | ||
|
|
acb07ba3e1 | ||
|
|
77e28545ef | ||
|
|
0e0eadde37 | ||
|
|
d2e3f41c5f | ||
|
|
71699332be | ||
|
|
f275bc0e35 | ||
|
|
0f73ad6d3f |
4 changed files with 298 additions and 93 deletions
31
README.md
31
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.
|
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
|
||||||
|
|
||||||
|
|
|
||||||
326
nimgen.nim
326
nimgen.nim
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue