/tutorial-on-swig-in-ceedling

connect c code to python code with the help of ceedling

Primary LanguageC

Interface with swig in ceedling

connect c code to python code with the help of ceedling.

prerequisites

  • getting ceedling ready
    • install ruby by following this websites
    • then install ceedling from command line

      gem install ceedling

Aim

let's assume we have a c code that add 2 numbers and return the results

int result = add(1, 2);

The aim for swig is to convert the c/c++ code to higher level programming language After generating the wrapper for python code, the above function in c then can be use in python by:

>>>import example
>>>example.add(1, 2)
>>>3

step by step on interfacing

  1. create a ceedling project and change directory into it

    ceedling new example
    cd example
  2. create a module call add

    ceedling module:create[add]

    this will create add.c , add.h, and test_add.c

  3. create a function call add that adds 2 numbers

    //add.c
    int add(int v1, int v2){
        return v1 + v2;
    }
    //add.h
    int add(int v1, int v2);
  4. Inorder for swig to generate the wrapper, you need to write an "interface file" which is the input to SWIG.

    //add.i
    %module example
    %{
    /* Includes the header in the wrapper code */
    #include "add.h"
    %}
    
    %include "add.h"
  5. To turn c code to python module, in command line, type the following:

    swig -python add.i

    This will create example_wrap.c and example.py.


  1. With the help with ceedling, building and linking the source and object file with gcc can be very easy. You will only have to modify the project.yml.

    • Enable the release build and modify the name of the release output to _example.so
    :project:
        :release_build: TRUE
    :release_build:
        :output: _example.pyd
        :use_assembly: FALSE
    • you can specify the flags of gcc during compiling and linking. Since compiling the wrapper will require Python.h headers, we need to also include the directory of Python.h. It's inside path-to-python-install-loc/include
    :tools:
    :release_compiler:
        :executable: gcc                  #absolute file path
        :name: 'gcc linker'
        :arguments:
            - -fpic                     #Compiler directive to output position independent code, a characteristic required by shared libraries
            - -I"$": COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE               #expands to -I search paths
            - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR   #expands to -I search paths
            - -IpathToPythonInstallation/include #subtitute with the designated python dir / include
            - -c ${1}                       #source code input file (Ruby method call param list sub)
            - -o ${2}                       #object file output (Ruby method call param li
    • To link all output files to shared library, add in the release_linker blob
          
    :release_linker:
        :executable: gcc                  #absolute file path
        :name: 'gcc linker'
        :arguments:
        - -shared
        - ${1}                          #list of object files to link (Ruby method call param list sub)
        - -o ${2}                       #executable file output (Ruby method call param list sub)
    • build and link the all the source files in command line by :
    ceedling release

    this will generate an output product call _example.so in build/release

    • copy _example.so into directory that contains example.py.

      to simplify the process or copying, you can modify the output of the products by:

      :release_build:
          :output: ../../directory-containing-example.py/_example.pyd 
          :use_assembly: FALSE
  2. Validate the module generated by opening python in that directory and type:

    >>>import example
    >>>example.add(1, 2)
    >>>3

Troubleshooting

Undefined referenced to `__IMP__PY...`

This is usually due to gcc doesn't link the python library eg. python36.a during linking of the shared library. Solve this by including the library of python in release_linker blob:

  :release_linker:
    :executable: gcc                  #absolute file path
    :name: 'gcc linker'
    :arguments:
      - -shared
      - ${1}                          #list of object files to link (Ruby method call param list sub)
      - -LpathToPythonInstallation/libs  #subtitute with the path of your python installation
      - -lpython36                    #subtitue wisely with the version number of the python
      - -o ${2}                       #executable file output (Ruby method call param list sub)

Module not found error : no module name `_module`

  • the shared library name is different from the name from wrapper

eg: in the case of example.py, the shared library must be named _example.so

  • In windows running mingW, change the extension from .so to .pyd

eg: _example.so change to _example.pyd