Thursday, September 4, 2025

Going Native - Calling Native Code

For a long time I've been interested in methods to call native code (which I've learned almost always means C and/or C++) from modern languages. Ever since I started working with Java I heard about something called JNI and that it could be used to unlock ancient mysteries hidden away in native code. At the end of this summer I had some time and finally decided to give it a try.

The native code

Another subject I've been interested in for a long time is linear algebra, specifically matrices and their uses. To try to get a better understanding of them I wrote a couple of small C libraries using them. My linear algebra guide is Linear Algebra and Its Applications (3rd ed) by Gilbert Strang.

One is a basic library to handle the arithmetic of rational numbers: Rashunal.

The other is a library to handle matrices of Rashunals and some basic operations on them (add, multiply, row operations, Gauss factoring). Todos include matrix inversion, minors, calculation of determinants. Finding eigenvalues and eigenvectors requires solving high-degree polynmial equations, so I'm not sure I'll get to that. RMatrix.

I wrote these to the best of my ability using CMake, Unity, and Valgrind. They should be cross-platform and installable on any system (Linux,MacOS, Windows). They have basic unit tests and have been checked for memory integrity. However, they should not be used for any production environment. Do not build your great AI model or statistics package on them!

Prerequisites and Setup

  • CMake
  • Make - Installation is different on different systems
    • Linux - almost certainly available on your distribution's package installer
      • Debian - sudo apt update && sudo apt install make
      • Red Hat - sudo yum update && sudo yum install make
    • MacOS - brew install make
    • Windows - choco install make
  • Your favorite C compiler
Clone the repositories above. The READMEs have instructions on how to compile and install the library code. Briefly:

$ cd Rashunal
$ cmake -S . -B build
$ cd build
$ make && make test && make install
$ cd ..
$ cd rmatrix
$ cmake -S . -B build
$ cd build
$ make && make test && make install

Approach

In each language I target, I'd like to write an application that can read a data file representing a matrix of rational numbers, send it to the native code, do something fairly complicated with it, and return it to the caller in some useful form. To demonstrate I wrote a model application in the RMatrix repository. It reads a matrix in a simple space-delimited format, converts it to an RMatrix, factors it into P-1, L, D, and U matrices, and displays the L and U matrices in the terminal window.


$ cd driver
$ cat example.txt
-2  1/3 -3/4
 6 -1    8
 8  3/2 -7
$ make
$ cat example.txt | ./driver
Height is 3
Width is 3
L:
[  1 0 0 ]
[ -3 1 0 ]
[ -4 0 1 ]
U:
[ 1 -1/6  3/8  ]
[ 0  1   60/17 ]
[ 0  0    1    ]

Next steps

In further entries in this series I'll demonstrate calling this library from several modern, widely-used, high-level languages. The ones I'm planning to target include:

  • Java
  • C#
  • Python
  • (maybe) Swift

But who knows how deep this rabbit hole will go?

No comments:

Post a Comment