Ring CFFI — Call C Libraries Directly from Ring

207 views
Skip to first unread message

Youssef Saeed

unread,
Apr 9, 2026, 3:26:01 PMApr 9
to The Ring Programming Language
Hello everyone,

I'm excited to announce the release of Ring CFFI — a powerful Foreign Function Interface library for the Ring programming language!

Built on libffi, Ring CFFI allows you to call C functions, manipulate C memory, work with structs/unions/enums, and pass Ring functions as C callbacks — all directly from Ring, without writing any C extension code.

Key Features:
  • Dynamic Library Loading: Load shared libraries (.so, .dll, .dylib) at runtime
  • C Function Calls: Call C functions directly from Ring with automatic type conversion
  • Pointer Operations: Pointer arithmetic, dereferencing, read/write access
  • Struct Support: Define and manipulate C structs with named field access
  • Union & Enum Support: Define and use C unions and enumerations
  • Callbacks: Pass Ring functions as C callbacks
  • Memory Management: Allocate and manage C memory directly
  • C String Handling: Seamless conversion between Ring and C strings
  • Cross-Platform: Works on Windows, Linux, macOS, and FreeBSD
  • High-Level OOP API: Clean FFI class with intuitive method names
Code Example:

Calling C functions from Ring is straightforward:

load "cffi.ring"

new FFI("libc.so.6") { # or msvcrt.dll on Windows
oPrintf = varFunc("printf", "int", ["string"])
varcall(oPrintf, ["Hello from Ring! Value: %d", 42])
}

You can also define and use C structs:

load "cffi.ring"

new FFI {
# Define a Point struct
point = defineStruct("Point", [
:x = "int",
:y = "int"
])

# Allocate and set fields
pPoint = structNew(point)
ptrSet(fieldPtr(pPoint, point, :x), "int", 10)
ptrSet(fieldPtr(pPoint, point, :y), "int", 20)

# Read fields
? "x = " + ptrGet(field(pPoint, point, :x), "int") # 10
? "y = " + ptrGet(field(pPoint, point, :y), "int") # 20
}

Installation

Install easily via RingPM:

ringpm install ring-cffi from ysdragon

Learn MoreNote: Ring CFFI is currently in beta. The API may change as the library evolves. Your testing and feedback are especially valuable at this stage!

Contributions are welcome!

Have ideas or found a bug? Please open an issue or submit a pull request on GitHub.

Your feedback is greatly appreciated!

Hope you find Ring CFFI useful!

Best regards,
Youssef

Mahmoud Fayed

unread,
Apr 9, 2026, 4:21:13 PMApr 9
to The Ring Programming Language
Hello Youssef

This is a very useful and important extension

Thanks for the development & sharing :D

Greetings,
Mahmoud

Bert Mariani

unread,
Apr 9, 2026, 4:52:54 PMApr 9
to The Ring Programming Language
Hello Youssef the Dragon

This is Tremendous with a Capital "T"
This will add some Fire Breathing performance to our Code !!

Best Regards
Bert Mariani

Youssef Saeed

unread,
Apr 9, 2026, 4:59:45 PMApr 9
to The Ring Programming Language
Hello Mahmoud,

Thank you very much for your kind words!

Best regards,
Youssef

Youssef Saeed

unread,
Apr 9, 2026, 5:11:01 PMApr 9
to The Ring Programming Language
Hello Bert,

Thank you for the "Tremendous" response! I love the "Fire Breathing" analogy—unlocking that level of performance seamlessly is exactly what I was aiming for with Ring CFFI.

Please feel free to share your feedback or any "fire" you create once you have the chance to try it out!

Best regards,
Youssef

Mahmoud Fayed

unread,
Apr 10, 2026, 7:24:00 AMApr 10
to The Ring Programming Language
Hello Youssef

You are welcome :D

Greetings,
Mahmoud

Mansour Ayouni

unread,
Apr 10, 2026, 8:04:34 AMApr 10
to Mahmoud Fayed, The Ring Programming Language
Hello Youssef,

I tested all the 23 test examples and they all work.

Is this output correct (I'm on Windows):
image.png

All the best,
Mansour

--

---
You received this message because you are subscribed to the Google Groups "The Ring Programming Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ring-lang+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/ring-lang/1079bff2-0c78-4e9b-81c0-a12bd693664en%40googlegroups.com.

Youssef Saeed

unread,
Apr 10, 2026, 10:06:34 AMApr 10
to The Ring Programming Language
Hello Mansour,

Thank you for the feedback and for testing all 23 examples!

The output you're seeing (Parsed 0 definitions) was indeed a bug in the C Definition Parser (cffi_cdef). It has been fixed in the latest commit.

Please run:
  1. ringpm remove ring-cffi
  2. ringpm install ring-cffi
Then test example 13 again — it should now correctly report the number of parsed definitions.

Best regards,
Youssef

Bert Mariani

unread,
Apr 22, 2026, 4:51:00 PMApr 22
to The Ring Programming Language
Hello Youssef, Mahmoud  et ALL

Attached: combo for CFFI
     Queens-N.ring
     nqueens_solver.c

423 X Faster than pure Ring version

===========================================
Results:  CFFI Version
C:\MyStuff\AA-Queens-CFFI>ring.exe Queens-N.ring
Enter value of n : 12
Counting N-Queens solutions for n = 12 ...
Total solutions : 14200
End   millisec  : 2792
Start millisec  : 2695
Total millisec  : 97
Total seconds   : 0.10

===========================
Results: Ring code version

Enter value of n : 12
Possible placements are :

End   millisec: 44639
Start millisec: 3617
Total millisec: 41022
Total Seconds : 41.02
Exiting of the program...
Enter to Exit :


// ===========================================
// SETUP (one-time):
//   1. ringpm install ring-cffi from ysdragon   (already done)
//   2. Compile the C solver DLL in this same folder:
//        A.  gcc -O2 -shared -o nqueens.dll nqueens_solver.c
//        --------------------------------------------------------
//        B.  Use Visual Studio 2026 - 64 Bit
//
// The full working setup for anyone to replicate:
// # 1. Install ring-cffi
//   ringpm install ring-cffi from ysdragon
//
// # 2. Set up MSVC (64-bit)
//   call C:\ring\language\build\locatevc.bat x64
//
// # 3. Create the export definition
//   echo EXPORTS > nqueens.def
//   echo nqueens_count >> nqueens.def
//
// # 4. Compile the DLL
//   cl /O2 /LD nqueens_solver.c /Fe:nqueens.dll /link /DEF:nqueens.def
//
// # 5. Run
//   ring.exe Queens-N.ring
//==========================================

FILES generated
 nqueens.def
 nqueens.dll
 nqueens.exp
 nqueens.lib
 nqueens_solver.c
 nqueens_solver.obj
 Queens-N.ring

=============================

Regards
Bert Marini

nqueens_solver.c
Queens-N.ring

Mahmoud Fayed

unread,
Apr 22, 2026, 5:15:52 PMApr 22
to The Ring Programming Language
Hello Bert

Thanks for sharing

>> "Results:  CFFI Version"

This version is not attached, please attach it.

Greetings,
Mahmoud

Bert Mariani

unread,
Apr 22, 2026, 5:40:33 PMApr 22
to The Ring Programming Language
Sorry this is the CFFI version

Attached
     Queens-N.ring         (71 lines )
     nqueens_solver.c   (59 lines )

================================
================================

// Queens-N.ring  (ring-cffi accelerated version)
// Bert Mariani with Claude AI assistance
// 2026-04-22
//
// The hot N-Queens backtracking logic runs entirely in C via ring-cffi.
// Ring handles user I/O and timing only.
//
// ---------------------------------------------------------------

// SETUP (one-time):
//   1. ringpm install ring-cffi from ysdragon   (already done)
//   2. Compile the C solver DLL in this same folder:
//        A.  gcc -O2 -shared -o nqueens.dll nqueens_solver.c
//        --------------------------------------------------------
//        B.  Use Visual Studio 2026 - 64 Bit
//
// The full working setup for anyone to replicate:
// # 1. Install ring-cffi
// ringpm install ring-cffi from ysdragon
//
// # 2. Set up MSVC (64-bit)
//   call C:\ring\language\build\locatevc.bat x64
//
// # 3. Create the export definition
//   echo EXPORTS > nqueens.def
//   echo nqueens_count >> nqueens.def
//
// # 4. Compile the DLL
//   cl /O2 /LD nqueens_solver.c /Fe:nqueens.dll /link /DEF:nqueens.def
//
// # 5. Run
//   ring.exe Queens-N.ring
//==========================================

load "cffi.ring"

// --------------- load the shared C library ----------------------
oFfi = new FFI("nqueens.dll")

// Wrap the one C function we need:
//   long nqueens_count(int n)
oNQueens = oFfi.cFunc("nqueens_count", "int", ["int"])

// --------------- user input -------------------------------------
See "Enter value of n : "
Give n
n = 0 + n

See "Counting N-Queens solutions for n = " + n + " ..." + nl

// --------------- timed solve via C FFI --------------------------
start_t = clock()

    nSolutions = oFfi.invoke(oNQueens, [n])   // runs in compiled C

end_t   = clock()
total_t = end_t - start_t

// --------------- results ----------------------------------------
See nl
See "Total solutions : " + nSolutions + nl
See nl
See "End   millisec  : " + end_t   + nl
See "Start millisec  : " + start_t + nl
See "Total millisec  : " + total_t + nl

timeF = total_t / ClocksPerSecond()
See "Total seconds   : " + timeF   + nl

See nl + "Exiting of the program..." + nl
See "Enter to Exit : "
Give m

=====================================
=====================================
=====================================

/*
 * nqueens_solver.c
 * Fast N-Queens solver written in C.
 * Compile as a shared library for use with ring-cffi.
 *
 * Linux/macOS:
 *   gcc -O2 -shared -fPIC -o libnqueens.so nqueens_solver.c
 * Windows:
 *   gcc -O2 -shared -o nqueens.dll nqueens_solver.c
 */

#include <stdlib.h>
#include <string.h>

static int  *col;        /* column of queen in row i       */
static long  solution_count;

/* Inline safe absolute-value to avoid math.h dependency */
static inline int iabs(int v) { return v < 0 ? -v : v; }

/* Returns 1 if placing a queen at column i in row k is safe */
static int place(int k, int i) {
    int j;
    for (j = 0; j < k; j++) {
        if (col[j] == i || iabs(col[j] - i) == iabs(j - k))
            return 0;
    }
    return 1;
}

/* Recursive backtracking solver (0-based rows) */
static void solve(int k, int n) {
    int i;
    for (i = 0; i < n; i++) {
        if (place(k, i)) {
            col[k] = i;
            if (k == n - 1)
                solution_count++;
            else
                solve(k + 1, n);
        }
    }
}

/*
 * nqueens_count(n)
 *   Returns the total number of solutions for an n×n board.
 *   Exported for ring-cffi to call directly.
 */
long nqueens_count(int n) {
    if (n <= 0) return 0;
    col = (int *)malloc(n * sizeof(int));
    if (!col) return -1;
    solution_count = 0;
    solve(0, n);
    free(col);
    col = NULL;
    return solution_count;
}

============================
============================
============================
Queens-N.ring
nqueens_solver.c

Mahmoud Fayed

unread,
Apr 22, 2026, 5:44:11 PMApr 22
to The Ring Programming Language
Hello Bert

Thank you very much for sharing :D
This is a beautiful example about using C code and RingCFFI

By the way, attached: Fast N-Queens using Bitmask Backtracking
Written 100% in Ring and finish execution in around 1 second for (n=12)

Enter N: 12
Total solutions: 14200
Time (ms): 1123
Time (sec): 1.12

Time for other values

Enter N: 13
Total solutions: 73712
Time (ms): 6171
Time (sec): 6.17

Enter N: 14
Total solutions: 365596
Time (ms): 36016
Time (sec): 36.02

Greetings,
Mahmoud
nqueens_bitmask_backtracking.ring

Youssef Saeed

unread,
Apr 22, 2026, 8:08:20 PMApr 22
to The Ring Programming Language
Hello Bert,

Thank you so much for putting this fantastic example together!

A 423x speedup is an incredible real-world demonstration of what RingCFFI was designed for. I truly appreciate you creating such a clear and powerful benchmark.

Best regards,
Youssef

Youssef Saeed

unread,
Apr 22, 2026, 8:09:03 PMApr 22
to The Ring Programming Language
Hello Mahmoud,

Thank you for sharing your bitmask implementation!

Best regards,
Youssef

Mahmoud Fayed

unread,
Apr 22, 2026, 8:29:28 PMApr 22
to The Ring Programming Language
Hello Youssef

You are welcome :D

Greetings,
Mahmoud

Bert Mariani

unread,
Apr 23, 2026, 10:51:56 AMApr 23
to The Ring Programming Language
Hello Youssef, Mahmoud et ALL

The Bit Mask solution is quicker than the Back Tracker
Would you believe 5860 X faster than the Ring-Original

Attached
     Queens-N.ring         -- no change
     nqueens_solver.c    -- Bit Mask version

CFFI Bit Mask:                   7 msec   5860 X      160 X
CFFI Back Tracker:         97 msec     423 X        14 X   
Ring-Bit Mask:            1123 msec       36 X          1 X
Ring-Original         :  41022 msec          1 X

==============================
C:\MyStuff\AA-Queens-CFFI>ring.exe Queens-N.ring
Enter value of n : 12
Counting N-Queens solutions for n = 12 ...
Total solutions : 14200
End   millisec  : 3025
Start millisec  : 3018
Total millisec  : 7         <<<===
Total seconds   : 0.01

Exiting of the program...

==============================
Different Approach

___________________Old (backtracking)___________________New (bitmask)

Conflict check   Loop over all previous queens       Zero — bitmasks do it instantly
Memory   malloc array of columns       None — 3 integers on the stack
Operations per step   O(k) comparisons       2 bitwise ops (&, ~)
Expected speedup   baseline      ~3–5× faster

============================
============================
// Queens-N.ring  (ring-cffi accelerated version)
//  nqueens_solver.c  -  Bitmask backtracking N-Queens solver

#ifdef _MSC_VER
  #define EXPORT __declspec(dllexport)
#else
  #define EXPORT
#endif

static long solution_count;

/*
 * backtrack(colMask, diag1, diag2, all)
 *   Direct C translation of the Ring bitmask backtrack() function.
 */
static void backtrack(unsigned int colMask,
                      unsigned int diag1,
                      unsigned int diag2,
                      unsigned int all)
{
    unsigned int free_bits, bit;

    /* colMask == all means every column has a queen -> solution */
    if (colMask == all) {
        solution_count++;
        return;
    }

    /* available positions: free columns with no diagonal conflict */
    free_bits = all & ~(colMask | diag1 | diag2);

    while (free_bits) {
        /* pick the lowest set bit */
        bit = free_bits & (-(int)free_bits);

        /* remove this bit from free_bits */
        free_bits -= bit;

        /* recurse with updated column and diagonal masks */
        backtrack(
            colMask | bit,
            (diag1  | bit) << 1,
            (diag2  | bit) >> 1,
            all
        );
    }
}

/*
 * nqueens_count(n)
 *   Returns the total number of solutions for an n x n board.
 *   Called from Ring via ring-cffi.
 */
EXPORT long nqueens_count(int n)
{
    unsigned int all;

    if (n <= 0 || n > 31) return 0;

    all = (1u << n) - 1u;   /* n bits set, same as Ring: (1 << n) - 1 */

    solution_count = 0;
    backtrack(0, 0, 0, all);

    return solution_count;
}


=============================

Regards
Bert Mariani
Queens-N.ring
nqueens_solver.c

Mahmoud Fayed

unread,
Apr 23, 2026, 11:00:55 AMApr 23
to The Ring Programming Language
Hello Bert

>> "The Bit Mask solution is quicker than the Back Tracker"
>> "Would you believe 5860 X faster than the Ring-Original"

Thanks for sharing the updated code & benchmarks

Greetings,
Mahmoud

Robin

unread,
Apr 26, 2026, 8:52:05 AMApr 26
to The Ring Programming Language
Hi everyone,

I have a question about extending Ring.

When should I use CFFI versus writing a native extension using the extension tutorial? In which situations is one preferred over the other?

Also, how do they compare in terms of performance? Is using a native extension significantly faster than CFFI, or is the difference usually negligible?

Thanks in advance for your guidance.

Ilir Liburn

unread,
Apr 26, 2026, 11:57:31 AMApr 26
to The Ring Programming Language
Hello Robin,

here is the simple answer from the AI which explains basics:

FFI (Foreign Function Interface) is the general term for the mechanism that allows any two different languages to talk to each other.
The "C" in CFFI specifically stands for C, because C is the "lingua franca" of computing. Most high-level languages (Python, Rust, Java, Go) don't talk to each other directly; they both speak "C" as a middle ground.
How the Translation Works (The "Bridge")
When you pass data from a high-level language (like Python or JavaScript) to a low-level language (like C or Rust), the translation happens via two main concepts:
1. Data Marshalling (The Packaging)
High-level languages use "heavy" objects. For example, a Python integer isn't just a number; it's a structure containing a reference count, type info, and size. C only understands "raw" bytes.
  • The Translation: The FFI layer extracts the raw value (e.g., 42) from the Python object and places it into a specific memory slot (like a 4-byte int) that the C function expects.
2. The Calling Convention (The Handshake)
Different languages have different rules for how to actually run a function (e.g., "Do I put the arguments in CPU registers or on the Stack?").
  • The Translation: The FFI acts as a traffic controller. It rearranges the arguments to match the Application Binary Interface (ABI) of the target language so the CPU doesn't crash when it jumps from one language's code to the other.
Why Lists don't just "become" Arrays
This is where the friction lies.
  • High-level List: Usually a dynamic collection of pointers scattered in memory.
  • Low-level Array: A single, contiguous block of memory.
To "translate" a list to an array, the FFI must loop through the list, extract every single value, and copy them into a brand-new contiguous block of memory. This is why it isn't "automatic"—it’s a performance-heavy operation, so FFI tools usually make you do it explicitly.
Greetings,
Ilir

Bert Mariani

unread,
Apr 26, 2026, 4:35:30 PMApr 26
to The Ring Programming Language
Hello Robin, Mahmoud, Illir, Youssef et ALL

Using Ring API C Interface calls  -  Back-Track version
Attached:  Queens-N.ring
                   nqueens_solver-RingAPI.c

CFFI        Back Tracker:         97  msec    1 X   <<<  CFFI interface
Ring-API Back Track :         298   msec   3 X   <<<   Ring API C interface

---------------------------
Previous comparisons
CFFI Bit Mask:                   7 msec   5860 X      160 X
CFFI Back Tracker:         97 msec     423 X        14 X   
Ring-Bit Mask:            1123 msec       36 X          1 X
Ring-Original         :  41022 msec          1 X
------------------------------


=======================================
BATCH FILE to Run

cls

call C:\ring\language\build\locatevc.bat x64
cl /c /DEBUG nqueens_solver-RingAPI.c -I"C:\ring\language\include"
link /DEBUG nqueens_solver-RingAPI.obj C:\ring\lib\ring.lib /DLL /OUT:nqueens_ext.dll
del nqueens_solver-RingAPI.obj
=====================================


=========================================
c:\MyStuff\AA-Quuens-Ring-API>ring Queens-N.ring
Loading N-Queens native extension...


Enter value of n : 12

Counting N-Queens solutions for n = 12 ...

Total solutions : 14200

End   millisec  : 3500
Start millisec  : 3202
Total millisec  : 298    <<<<   Ring API C interface
Total seconds   : 0.30

Exiting the program...
---------------------------------------
Regards
Bert Mariani

Queens-N.ring
nqueens_solver-RingAPI.c

Ilir Liburn

unread,
Apr 26, 2026, 6:36:23 PMApr 26
to The Ring Programming Language
Hello Bert,

Ring C API version should be faster. On my Ring2C debug build + MSVC DLL release build:

Loading N-Queens native extension...

Enter value of n : 12

Counting N-Queens solutions for n = 12 ...

Total solutions : 14200

End   millisec  : 1305
Start millisec  : 1221
Total millisec  : 84
Total seconds   : 0.08

Exiting the program...

Anyway, I built faster DLL version which cuts total time to 30 millisec.

Greetings,
Ilir
nqueens_solver-RingAPI.c

Bert Mariani

unread,
Apr 26, 2026, 6:43:13 PMApr 26
to Ilir Liburn, The Ring Programming Language
Hello Ilir

Ok ... I see your faster speed with Ring 2C and Ring API

Now build the CFFI version I posted earlier to compare on your Ring 2C on your machine.

Regards 
Bert Mariani

Ilir Liburn

unread,
Apr 26, 2026, 6:54:51 PMApr 26
to The Ring Programming Language
Hello Bert,

I can't. I'm using Ring version 1.24 for development. CFFI requires 1.25, but decided to wait for 1.26 before merging it to Ring2C.

Once it is done later I can inform you about the results.

Greetings,
Ilir
Reply all
Reply to author
Forward
0 new messages