rss

HowTo: Swig C to Java: functions that manage an array of int, simple or complex struct (eg. array of objects)

You would like to map a C code from your Java application and you have heard about Swig: this post is for you!

This post is a really simple example to understand how to manage (from Java application) a C array of complex structure.

After reading Swig 3 documentation and searching on the net, I've finally succeed to create a little poc on how to return a list of struct.

proof of concept sample includes 4 functions:
  • a function sumitems that accept an array of integer as parameter to calculate a sum (part of Swig3 documentation)
  • a function populateSampleItem that just write on a given simple structure
  • a function populateItems that update an existing array of struct
  • a function buildItems that create from scratch a result array of struct

source of this poc is available here : https://github.com/boly38/pocswig
this poc is widely inspirated from similar example from "Samuel Jacob's Weblog" post (thanks to him !)


First file to write is the C header poc.h:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* (in) simple int array as parameter */
int sumitems(int *first, int nitems);

/* simple structure */
typedef struct MyItem_t {
      int  id;
      char *name;
} MyItem;

/* (in/out) simple struct as parameter (updated by the function) */
void populateSampleItem(MyItem *item);

/* array of structure */
typedef struct MyItems_t {
      int  count;       // elements count
      MyItem *elements; // array of MyItem
} MyItems;

/* (in/out) array of structure as parameter (updated by the function) */
void populateItems(MyItems *items);

/* (out) array of structure (generated by the function) */
MyItems *buildItems();
The you will then have to write the C implementation. Here is a sample poc.c:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "poc.h"

int sumitems(int *first, int nitems) {
  int i, sum = 0;
  for (i = 0; i < nitems; i++) {
    sum += first[i];
  }
  return sum;
}

void populateSampleItem(MyItem *item) {
  item->id = 1234;
  item->name = strdup("getSampleItem");
}

void populateItems(MyItems *items) {
    int nb = items->count;
    items->elements = malloc(nb * sizeof(MyItem));
    for (int j=nb-1;j>=0;j--) {
        items->elements[j].id = j;
        char elementName[80];
        sprintf(elementName, "populateItems %d", j);
        items->elements[j].name = strdup(elementName);
    }
}

MyItems *buildItems() {
    printf("buildItems 14 elements");
    int nb = 14;
    MyItems *items= malloc(sizeof(MyItems));;
    items->count = nb;
    items->elements = malloc(nb * sizeof(MyItem));
    for (int j=nb-1;j>=0;j--) {
        items->elements[j].id = j;
        char elementName[80];
        sprintf(elementName, "buildItems %d", j);
        items->elements[j].name = strdup(elementName);
    }
    return items;
}

And now to access this function from java, you will have to use Swig.

Swig use a specification file to setup how to map function/types/etc... This file is a .i file. Here is the file poc.i:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
%module swigpoc

%include "arrays_java.i";
%apply int[] {int *};

%{
 #include "poc.h"
%}

%include "poc.h";
%extend MyItems_t{
  MyItem * getElement(int i) {
      return &$self->elements[i];
  }
}
Line 1 define the module name,
Line 3&4 define how to handle int array using swig facility,
Line 6 to 8 to tell to Swig to output include line into the target wrapper file.
Line 10 reuse as is the header file as specification (Swig MUST wrap all header file methods and structs to Java).
Line 11 to 15 to tell to Swig to append an extra function to help Java user to access to array element.

Now you will have to generate Java files! Use Swig :
rm -f *Item.java *.o *.dll swigpoc*
swig -java poc.i
You could look at your directory, there is some new C and Java files: poc_wrap.c, MyItem.java, MyItems.java, swigpoc.java swigpocJNI.java Next step is to build up the DLL (shared library) (exemple under Cygwin):
1
2
3
4
5
6
#!/bin/bash
JAVA_HOME=/cygdrive/c//Programmes/Java/jdk1.8.0_112/
INCLUDES="-I$JAVA_HOME/include/ -I$JAVA_HOME/include/win32/"

x86_64-w64-mingw32-gcc.exe -c poc.c poc_wrap.c $INCLUDES
x86_64-w64-mingw32-gcc.exe $INCLUDES -shared -o poc.dll poc_wrap.o poc.o
Now you can play with your new library from Java; exemple PocExample.java:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class PocExample {

  static {
    System.out.println("load poc ...");
    System.loadLibrary("poc");
    System.out.println("load poc ... OK ");
  }

  public static void  main(String args[]) {
    System.out.println("poc");

    System.out.println("sumitems:");
    int[] arrayB = new int[10000000];          // Array of 10-million integers
    for (int i=0; i<arrayB.length; i++) {      // Set some values
      arrayB[i] = i;
    }
    int sum = swigpoc.sumitems(arrayB, 10000);
    System.out.println("SumB = " + sum);


    System.out.println("MyItem:");
    MyItem myt = new MyItem();
    swigpoc.populateSampleItem(myt);
    System.out.println("myt.name = " + myt.getName());

    MyItems myts = new MyItems();
    myts.setCount(10);
    swigpoc.populateItems(myts);

    for (int j=0; j<myts.getCount(); j++) {
      System.out.println(String.format("myts.element[%d].name = '%s'",j, myts.getElement(j).getName()));
      System.out.println(String.format("myts.element[%d].id = '%s'"  ,j, myts.getElement(j).getId()));
    }


    MyItems rez = swigpoc.buildItems();
    for (int k=0; k<rez.getCount(); k++) {
      System.out.println(String.format("rez.element[%d].name = '%s'",k, rez.getElement(k).getName()));
      System.out.println(String.format("rez.element[%d].id = '%s'"  ,k, rez.getElement(k).getId()));
    }
  }
}

I let you execute that:
1
2
3
#!/bin/bash
JAVA_HOME=/cygdrive/c//Programmes/Java/jdk1.8.0_112/
$JAVA_HOME/bin/javac *.java && $JAVA_HOME/bin/java PocExample


If you see something wrong, please tell me. Else hopes this helps!

Yet another MUSE Best-Of

Let me introduce you to the best-of MUSE songs :p

Muse - 2006 - Starlight [Official Music Video]

Muse - 2009 - Uprising [Official Video]

Muse - 2010 - Hysteria [Official Music Video]

Muse - 2010 - New Born

Muse - 2010 - Plug In Baby

Muse - 2010 - Sunburn

Muse - 2010 - Time Is Running Out (video)
Muse - 2012 - Resistance

Muse - 2013 - Supremacy (Official Video)

Muse - 2015 - Dead Inside [Official Music Video]

Muse - 2015 - Reapers [Official Lyric Video]

Muse - 2015 - The Handler [Official Lyric Video]


Concerts

Muse Live - 2000 - Presqu'île de Malsaucy - Eurockéennes (Belfort)

Muse Live - 2015 - Main Square Festival


NB: year is youtube video publication date. With helps of thetoptens

How to Jenkins : chain jobs with parameters

This post describes How To chain jobs with parameter(s).
- Choose optionA if you're using pipeline plugin.
- OptionB is a little bit deprecated, but usefull if you would like to script your build execution or trigger it remotely.

(option A) Define a post action in first job

First recommended and simple way if your are using "Build Pipeline". Go to the first job configuration to append a post-action :

(option B) Chain it using shell scripts


NB: this option will make loosing your pipeline chain.
I recommend to use 2 small dedicated temp jobs to test it first. That would avoid to run unnecessarely long build...

Steps :
  • Install Build Token Root Plugin
  • Define first job with parameter
  • Define second job ("follower") with parameter
  • Define a trigger for the follower
  • Append a shell script to chain the two jobs
  • Try!

Install Build Token Root Plugin

Ask to your Jenkins administrator to install this plugin : Build Token Root Plugin
Wait that Jenkins reboot (required).

Define first job with parameter

Add "branch" parameter to your first job.

Add a shell script to echo the variable.

Define follower job with parameter

Add "branch" parameter to your second job (same as previously).
Add a shell script to echo the variable(same as previously).

Define a trigger for the follower

Add a trigger for the second job. Set a secret token here.

Append a shell script to chain the two jobs

Open the first job configuration to add the following shell script.
You will need to adapt the jenkins host value corresponding to your environment.

# show job parameter
echo branch=${branch}

#  resources
#  https://wiki.jenkins-ci.org/display/JENKINS/Parameterized+Build
#  https://wiki.jenkins-ci.org/display/JENKINS/Build+Token+Root+Plugin
#  http://curiositedevie.blogspot.nl/2016/02/how-to-jenkins-chain-jobs-with.html
export JENKINS_HOST=https://myjenkins.domain.net
export JOB_TOKEN=THISISWONDERFULL
export JOB_NAME=git_config_follower
export JOB_PARAM1=branch=${branch}
export JOB_CAUSE=Launching_follower_with_branch_set_to_${branch}
export JOB_PING="$JENKINS_HOST/buildByToken/buildWithParameters?job=$JOB_NAME&token=$JOB_TOKEN&$JOB_PARAM1&cause=$JOB_CAUSE"
echo $JOB_PING
curl --verbose --insecure $JOB_PING

Try!

Launch the first job with a parameter.

Go to the Job console to check curl http status.
Go to the follower (second) job logs.
Check the follower result!