Code Monkey home page Code Monkey logo

nimgen's Introduction

Nimgen has been superseded by nimterop. Existing wrappers are slowly being migrated over to nimterop. No new features will be implemented going forward.

Chat on Gitter Build status Build Status

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 and static libraries as well as loading in dynamic libraries.

To see examples of nimgen in action check out the following wrappers:-

Nimgen only supports the gcc preprocessor at this time. Support for detecting and using other preprocessors will be based on interest.

Config file

In all sections below, 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 $ or ${} around the environment variable name. In addition, the output var from the n.global section is available as ${output}. For example:

[n.global]
c_compiler="$CC"
cpp_compiler="${CPP}-arm"
output="src/path"

[n.include]
"${output}/library/include"
"${MY_INCLUDE_PATH}/include"

Append -win, -lin and -mac/osx for OS specific sections and tasks. E.g. n.global-win, n.post-lin, download-win, execute-lin-mac.unique1. -unix can be used as a shortcut for -lin-mac.

[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

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:-

  • 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.

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.

gitcheckout = branch, commit or tag of repository to checkout in following Git command, resets after each use. Use "-b name" for branches

gitbranch = master/main branch of the repository, defaults to master

gitoutput = directory for all following Git commands relative to n.global:output [default: n.global:output directory]

git = url of Git repository to clone. Full repo is pulled so gitremote + gitsparse is preferable. Resets 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 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.post]

This section is the same as the prepare section, but for performing actions after the project has been processed.

gitoutput = output directory for Git reset [default: n.global:output directory]

reset = 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.

wildcard = pattern to match against. All keys following the wildcard declaration will apply to matched files

[n.sourcefile]

This section allows selection of multiple sourcefiles without requiring a detailed section for each file. Each specific file can be listed one line at a time and file wildcards can be used to include multiple source files. E.g. $output/include/*/h. [n.wildcard] definitions can be used to perform common operations on these source files if required.

[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

nowildcard = ignore any wildcard definitions for this sourcefile

reset = reset the file back to original state after all processing [default: false]

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. If directory, picks *.c if C mode and *.cxx, *.cpp, *.cc, *.c++ and .C for cpp mode. Dir can also include wildcards. e.g. compile = """dir/A.cxx"""

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.

pipe = execute a command on a file and store the output of the command as the new file contents. E.g. pipe = "cat $file | grep 'static inline'"

search = search string providing context for following prepend/append/replace directives

regex = regex search string providing context for the following replace directive. Specify using """ to avoid regex parsing issues

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. Regex captures can be referred to using $1, $2, etc.

move = search string providing context for location to move the results of a preceding search or regex match

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

Command Line

A subset of capabilities are available through the command line to enable quick tests using nimgen. Command line flags only apply to source files specified on the command line and do not influence any cfg files which are expected to be self-sufficient.

Usage:
  nimgen [options] file.cfg|file.h ...

Params:
  -C<compile>  add compile entry       *
  -E<exclude>  add n.exclude entry     *
  -F<flags>    set c2nim flags         *
  -I<include>  add n.include dir       *
  -O<outdir>   set output directory
  -P<ppflags>  set preprocessor flags  *

Options:
  -c           set ctags = true
  -d           set defines = true
  -i           set inline = true
  -n           set noprocess = true
  -p           set preprocess = true
  -r           set recurse = true

Editing:
  -a<append>   append string           *
  -e<prepend>  prepend string          *
  -l<replace>  replace string          *
  -o#lines     comment X lines         *
  -s<search>   search string           *
  -x<regex>    regex search string     *

* supports multiple instances

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. Also join us at https://gitter.im/nimgen/Lobby to chat about nimgen and the future of Nim wrappers.

Credits

Thank you to the following contributors for their hard work!

https://github.com/jyapayne

nimgen's People

Contributors

data-man avatar genotrance avatar juancarlospaco avatar jyapayne avatar oswjk avatar thomastjdev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nimgen's Issues

[Bug] Relative import in source break code processing

If there are any relative imports in source files, they break nimgen. See example file here from trying to port to nim-libnx.

I've implemented a fix that I think works, but it's useful to get your feedback to make sure it works for everyone. I will file a PR and you can check it out when you have time (no rush on any of these PRs by the way).

Add link capability similar to compile

compile => {.compile: "xyz.c".}

Need a similar capability for link.

link => {.link: "xyz.o".}

Typically code is compiled as part of the nim build but if there's something separate, like a resources file compiled using execute = "windres resource.rc resource.o" then need ability to link.

Can currently use pragma for near term but link will allow for wildcards, etc.

[Feature Request] Implement static function removals

As you know, I've been using the pipe command in order to remove static function calls in nim-libnx using vim. However, now that I've verified things work, I'd like to make it a bit more cross platform friendly.

I propose a function called remove_static or similar to apply to .h files that will remove all static function bodies from the file. I've already implemented a basic version that works for my files, however, it is a bit crude and should ideally use regex (right now I just loop through all lines in the file). I'll file the PR and maybe you can suggest some improvements. I'll put the regex that I tried to use as a comment, but I suspect there is a bug with the Nim pcre implementation because it only processes about 7700 characters of the test file's 22000. I tested the regex on https://regex101.com/ and it works fine, so that's why I think it might be a bug.

No place or site for discussion forum?

For needs e.g. asking: Where is the nimgen comprehensive documentation or explanatory tutorial, preferably in PDF if any ?
checked the gitter, it's none

Error: unhandled exception: assignment to discriminant changes object branch

I am getting the following with nimbass.cfg:

$ nimgen nimbass.cfg 
Downloading bass24-linux.zip
Extracting bass24-linux.zip
Downloading bass_fx24-linux.zip
Extracting bass_fx24-linux.zip
Processing nimbass/bass.h
Generating nimbass/bass.nim
Command failed: 1
c2nim --stdcall  --dynlib:dynlibbass --out:nimbass/bass.nim temp-bass.nim.c
/usr/lib/nim/system/fatal.nim(39) sysFatal
Error: unhandled exception: assignment to discriminant changes object branch; compile with -d:nimOldCaseObjects for a transition period [FieldError]

Am I doing something wrong or it is nimgen broken?

#pragma once

I am trying to wrap miniz. I have the following:

[n.global]
output = miniz

[n.include]
miniz
miniz/C

[n.prepare]
download-lin.miniz = "https://github.com/richgel999/miniz/releases/download/2.1.0/miniz-2.1.0.zip"

[miniz.h]
preprocess = true
defines = true
recurse = true

I am getting a file temp-miniz.nim.c and it has something like:

mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
int mz_compress(miniz/miniz.h:478:9: aviso: #pragma una vez en el fichero principal
  478 | #pragma once
      |         ^~~~
unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);

Which is a warning about #pragma once, which appears in the middle of the file. The problem is two folds:

  1. The file miniz.h has several times: #pragma once. How can I avoid that?
  2. Secondly, would it be possible to have that warning somewhere else? (not in the middle of the file)

Best regards

Error when using `main` as master-branch

Currently the branch master is hardcoded, but with recent changes to Github we now see people using the name main instead. This is a problem for my library ThomasTJdev/nimlibxlsxwriter#1.

The hardcoded master is located here.

proc gitPull() =
if gGitCheckout.len() != 0:
echo "Checking out " & gGitCheckout
discard execProc("git pull --tags origin master")
discard execProc("git checkout " & gGitCheckout)
gGitCheckout = ""
else:
echo "Pulling repository"
discard execProc("git pull --depth=1 origin master")

gorge call causes "Too many files open error"

The way headers are included now is silly. For every file, every single include path executes a gorge("nimble path #$") statement, just so that the compiler can reference the included file by it's name (this also pollutes the include namespace, so multiple files can't have the same name and still be referenced)). Since the compiler tries to execute all of these in parallel, for nim-libnx this causes a massive amount of pipes ("files") to be open, which my OS can't handle. I have 12 include paths and 63 files which results in the compiler trying to execute 756 processes at once.

I have tried increasing my ulimit, but even then it does not work. A solution that works for me is to simply include the file itself based on the path the current file is installed in, which has the side effect of making libraries work without being installed via nimble first. I will submit a PR that fixes this issue for me and see what you think about it.

Cache generated nim files for perusal

Per feedback from @mratsim, need to cache the generated nim files on github for perusal, looking at diffs, etc.

Could create a cache directory and copy all nim files there during generation. Just need to figure out how to ensure that files are regenerated and committed every time there's a relevant change or tag.

Change to stdcall only on Windows

Change the calling convention of nimgen to cdecl by default, maybe with a

when defined(vcc): {.push callingConvention: stdcall.} else: {.push callingConvention: cdecl.}```

Use {.reorder: on.} by default

Setting this pragma by default will help all wrapper creators considering C/C++ is capable of forward references.

Need to table this for the near term since it is only working correctly in 0.19.0 devel and nimgen and wrappers need to continue to support older versions of Nim. Perhaps nimgen could do a Nim version test and add the flag if the version of Nim is new enough. Of course, if people go back and forth with choosenim, an installed wrapper might break randomly.

In the near term, the move flag can be used to move things around so that backwards compatibility is maintained. E.g. from nimui

Long term, it is preferable to avoid such complex regexes and rely on {.reorder: on.} instead.

Change rename from $replace(xyz=pqr) to search/rename

Per @data-man's suggestion, change file renaming to be consistent with the rest of nimgen operations.

[sourcefile]
search = 7
rename = svn

Need to figure out how to achieve moving generated files to an alternate location from $output since rename allows that today.

Ctags command not doing anything

With Exuberant Ctags 5.9~svn20110310, your ctags command:

ctags -o - --fields=+S+K --c-kinds=p --file-scope=no file.c

Produces nothing no matter what file I pass in. If I change --c-kinds=p to --c-kinds=+p, then I think it does what it's meant to do. Am I not using it correctly?

Expand command-line to allow wrapping without a .cfg

Flag and corresponding nimgen cfg field as below.

Params
-C = compile [allow multiple]
-E = exclude [allow multiple]
-F = flags [concatenate multiple]
-I = include [allow multiple]
-O = output
-P = ppflags [concatenate multiple]

Flags
-c = ctags
-d = defines
-i = inline
-n = noprocess
-p = preprocess
-r = recurse

Editing
-y = dynlib
-s = search
-x = regex
-e = prepend
-a = append
-l = replace
-m = comment

Need to see if elaborate interface is warranted or to keep it simple.

use gcc as defined in nim.cfg

After debugging some weird errors, I just found out that on my Windows PC, a simple gcc call on command line invokes some ancient 2.x GCC; and that seems to be what nimgen calls on my machine. Whereas the Nim global configuration contains a correct path to a 6.x GCC. IIUC, this is the GCC actually used for compilation of Nim code. Could nimgen reach to the global Nim configuration by default (on my machine, it's \dnload\nim-etc\nim\config\nim.cfg), and retrieve the path to GCC from there? It would seem like a good idea to me, to ensure that the same GCC is used by nimgen as is used by nim?

`download` does not follow links

downloadUrl does not follow links. Using curl -L ${ARGS} will resolve this on Linux and Mac. From the curl man page:

   -L, --location
          (HTTP)  If  the server reports that the requested page has moved
          to a different location (indicated with a Location: header and a
          3XX  response code), this option will make curl redo the request
          on the new place. If used together with  -i,  --include  or  -I,
          --head,  headers  from  all  requested pages will be shown. When
          authentication is used, curl only sends its credentials  to  the
          initial  host.  If a redirect takes curl to a different host, it
          won't be able to intercept the user+password. See  also  --loca-
          tion-trusted  on how to change this. You can limit the amount of
          redirects to follow by using the --max-redirs option.

          When curl follows a redirect and the request is not a plain  GET
          (for example POST or PUT), it will do the following request with
          a GET if the HTTP response was 301, 302, or 303. If the response
          code  was  any  other  3xx code, curl will re-send the following
          request using the same unmodified method.

          You can tell curl to not change the non-GET  request  method  to
          GET  after  a  30x  response  by using the dedicated options for
          that: --post301, --post302 and --post303.

Cache generated nim files for reference

Repos without any nim files or documentation make it hard to see how the lib works without installation. Need to provide a way to cache the generated payload in Github.

how to use with header-only

I am trying to use a header-only library (https://github.com/Genomicsplc/variantkey/blob/master/c/src/variantkey/variantkey.h) .
I have this cfg:

[n.global]
output = src

[n.include]
src/include

[hex.h]
preprocess = true

[variantkey.h]
preprocess = true
defines = true
rename = "variantkey_sys.nim"

[variantkey_sys.nim]
prepend = """
type
  uint8_t* = uint8
  int8_t* = int8
  uint16_t* = uint16
  uint32_t* = uint32
  uint64_t* = uint64
  size_t* = csize
"""

it seems that nimgen is going in and commenting out the actual implementation in the header files. Is there a way to use this with header-only stuff?
thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.