Nimgen is a helper for c2nim to simplify and automate the wrapping of C libraries.
Nimgen can be used to automate the process of manipulating C files so that c2nim can be run on them without issues. This includes adding/removing code snippets, removal of complex preprocessor definitions that c2nim doesn't yet comprehend and recursively running on #include files.
Installation
Nimgen can be installed via Nimble:
> nimble install nimgen
This will download, build and install nimgen in the standard Nimble package location, typically ~/.nimble. Once installed, it can be run just like c2nim.
Usage
Nimgen is driven by a simple .cfg file that is read using the Nim parsecfg module. The sections of the file are described further below.
> nimgen package.cfg
A Nimble package for a library that is wrapped with nimgen will have the following:-
- The .cfg file that tells nimgen what exactly to do
- Nimgen defined as a dependency defined in the .nimble file
- Steps within the .nimble file to download the source code that is being wrapped
This way, the library source code doesn't need to get checked into the Nimble package and can evolve independently.
Nimble already requires Git so those commands can be assumed to be present to download source from a repository. Mercurial is also suggested but depends on the user. Downloading arbitrary files depends on the OS. For Linux, wget/curl can be assumed. On Windows, powershell can be used.
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.
To see examples of nimgen in action check out the following wrappers:-
-
Link with a dynamic library
- nimbass - BASS audio wrapper: docs
- download ZIP with headers and binary
- nimlibxlsxwriter - libxlsxwriter wrapper
- git checkout
- nimbass - BASS audio wrapper: docs
-
Compile C code into binary
- nim7z - 7z decoder wrapper: docs
- git sparse checkout
- nimarchive - libarchive wrapper: docs
- git sparse checkout
- nimbigwig - libbigWig wrapper: docs
- git checkout
- nimfuzz - fts_fuzzy_match wrapper: docs
- download header file
- nimkerberos - WinKerberos wrapper: docs
- git sparse checkout
- nimpcre - PCRE wrapper: docs
- git checkout
- nimrax - Radix tree wrapper: docs
- git checkout
- nimssl - OpenSSL wrapper: docs
- git sparse checkout
- libsvm - libsvm wrapper: docs
- git sparse checkout
- nim7z - 7z decoder wrapper: docs
-
Compile in as static binary
Nimgen only supports the gcc
preprocessor at this time. Support for detecting and using other preprocessors will be based on interest.
Config file
[n.global]
output
= name of the Nimble project once installed, also location to place generated .nim files
quotes
= pick up any headers included using "" (and not <> which is typically used for standard headers) [default: true]
filter
= string to identify and recurse into library .h files in #include statements and exclude standard headers
[n.include]
List of all directories, one per line, to include in the search path. This is used by:-
- The preprocessor for #include files
- Nimgen to find #include files that are recursively processed
Nimgen also adds {.passC.} declarations into the generated .nim files for these include paths if compiling source files directly.
[n.exclude]
List of all directories or files to exclude from all parsing. If an entry here matches any portion of a file, it is excluded from recursive processing.
[n.prepare]
The following keys can be used to prepare dependencies such as downloading ZIP files, cloning Git repositories, etc. Multiple entries are possible by appending any .string to the key. E.g. download.file1. -win, -lin and -osx can be used for OS specific tasks. E.g. download-win
download
= url to download to the output directory. ZIP files are automatically extracted. Files are not redownloaded if already present but re-extracted
extract
= ZIP file to extract in case they are local and don't need to be downloaded. Path is relative to output directory.
git
= url of Git repository to clone. Full repo is pulled so gitremote + gitsparse is preferable. Resets to HEAD if already present
gitremote
= url of Git repository to partially checkout. Use with gitsparse to pull only files and dirs of interest
gitsparse
= list of files and/or dirs to include in partial checkout, one per line. Resets to HEAD if already present
execute
= command to run during preparation
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.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.
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
recurse
= find #include files and process them [default: false]
inline
= include #include files into file being processed, alternative method to processing each header file separately with recurse. Multiple source files will get combined into the same .nim output files [default: false]
preprocess
= run preprocessor (gcc -E) on file to remove #defines, etc. [default: false] - this is especially useful when c2nim doesn't support complex preprocessor usage
ctags
= run ctags on file to filter out function definitions [default: false] - this requires the ctags executable and is an alternative to filter out preprocessor complexity
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
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
noprocess
= do not process this source file with c2nim [default: false] - this is useful if a file only needs to be manipulated
Multiple entries for the all following keys are possible by appending any .string to the key. E.g. dynlib.win, compile.dir
compile
= file or dir of files of source code to {.compile.} into generated .nim
pragma
= pragmas to define in generated .nim file. E.g. pragma = "passL: "-lssl"" => {.passL: "-lssl".}
dynlib
= dynamic library to load at runtime for generated .nim procs
The following keys apply to library source code (before processing) and generated .nim files (after processing) and allow manipulating the files as required to enable successful wrapping. They are not propagated to #include files when recurse = true
.
create
= create a file at exact location with contents specified. File needs to be in the [n.exclude] list in order to be created.
search
= search string providing context for following prepend/append/replace directives
prepend
= string value to prepend into file at beginning or before search
append
= string value to append into file at the end or after search
replace
= string value to replace search string in file
comment
= number of lines to comment from search location
The following key only applies before processing and allows renaming the generated .nim files as required to enable successful wrapping. This may be for organizational purposes or to prevent usage of non-nim supported strings in module names (E.g. first letter is a number). Destination is relative to output directory if defined.
rename
= string value to rename generated filename. E.g. rename = "$replace(7=s7)"
/
= create a directory/module hierarchy
$nimout
= refer to the original filename
$replace(srch1=repl1, srch2=reply2)
= rename specific portions in $nimout
Feedback
Nimgen is a work in progress and any feedback or suggestions are welcome. It is hosted on GitHub with an MIT license so issues, forks and PRs are most appreciated.