Overview
PyPi module | N/A |
git repository | https://bitbucket.org/arrizza-public/swig-c |
git command | git clone git@bitbucket.org:arrizza-public/swig-c.git |
Verification Report | https://arrizza.com/web-ver/swig-c-report.html |
Version Info |
|
- installation: see https://arrizza.com/setup-common
Summary
A discussion and project for using SWIG C for Python, Ruby and javascript functions.
I had a need to call the same C functions from multiple scripting languages: python, ruby, javascript. This project is an example of how to set that up in JetBrain's CLion and CMake
Note: the javascript is working but not using the SWIG generated source file (see javascript/index.cpp and nwrap.h for temporary content). It is not generating a working javascript_example.node file that registers the module.
Some of the issues were:
- configuring the individual cmake subprojects for each scripting language
- separating the output files for each scripting language
For C++ version, see https://arrizza.com/swig-c++
Other good sources for SWIG & python:
Next Steps
For SWIG documentation, see https://www.swig.org/Doc3.0/SWIG.html#SWIG
$ swig -version
SWIG Version 4.0.1
Compiled with g++ [x86_64-pc-linux-gnu]
Configured options: +pcre
Please see http://www.swig.org for reporting bugs and further information
- current calls only use simple functions. Need to try on various other data structures:
- strings
- arrays
- structs
- unions
- JSON
- enums (i.e. read-only)
- pointers (is this needed?)
Common
-
The source code is in src directory. The example.c and .h come from (with minor changes) https://valelab4.ucsf.edu/svn/3rdpartypublic/swig/Doc/Manual/Introduction.html
-
example.i
is used across all sub-targets and is used by swig to configure what is made available to the language-
I used #include "../src/example.h" and %include. The assumption is that all and only exported functions and variables are named in the example.h file. This may not be true for all projects or all scripting languages.
-
the functions in example.c are simple. No unions, no structs, no char* or kinds of pointers, no arrays, i.e. simple. Other C constructs may cause some additional definitions to be needed.
-
Do a clean rebuild and test
- ./do_install - insures latest ruby, python, node are installed
- ./do_clean - wipes out all the output directories and the cmake build.
- ./do_build - runs cmake using the CLion command lines
- ./doit - runs scripts for all languages
Overall:
./do_install
./do_clean
./do_build debug all
# expected stdout:
./doit debug all
==== versions
Python 3.10.13
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux-gnu]
v10.19.0
==== run
language : fact my_mod before after
: ------ ------ ------ ------
python : 720 3 3.0 5.1
ruby : 720 3 3.0 5.1
javascript: 720 3 3.0 5.1
Note that ./doit
or ./do_build
defaults to the incorrect target, so you must specify debug all
- fact - factorial, passes in an integer, returns an integer
- my_mod - modulus, passes in two integers, returns an integer
- before - gets the default value of global variable my_variable
- after - sets my_variable and then gets it again
Installation:
Note: I ran this only on Ubuntu 20.04.1 LTS. Things may be different in other Ubuntu versions or other OS.
All installations are handled by the ./do_install script
$ ./do_install
python3.10 is already the newest version (3.10.13-1+focal1).
<snip>
python3.10-venv is already the newest version (3.10.13-1+focal1).
<snip>
ruby-dev is already the newest version (1:2.7+1).
<snip>
nodejs is already the newest version (10.19.0~dfsg-3ubuntu1.3).
<snip>
swig is already the newest version (4.0.1-5build1).
Note: I have not tested a clean installation of these packages. I may have necessary pip, gem, npm global modules already installed that I have not specified here.
Run test.py
Output directory: out/py
The import loads the factorial function, the mod function and cvar. "cvar" is used to access global C variables. Note these are read/write.
from out.py.example import fact, my_mod, cvar
Expected output:
$ python3.10 test.py
# see ./doit output above, line starting with "python"
Run test.rb
Output directory: out/rb
The require
is very simple in ruby, it loads the .so:
require_relative './out/rb/example.so'
Expected output:
$ ruby test.rb
# see ./doit output above, line starting with "ruby"
Run test.js
For good examples of calls in node_wrap.h, see https://github.com/nodejs/node-addon-examples For node_api.h doc & usage: https://nodejs.org/api/n-api.html#n_api_usage
Output directory: out/js
The require
is very simple in javascript, it loads the .node:
const example = require("./out/js/example.node")
Expected output:
$ node test.js
# see ./doit output above, line starting with "javascript"