1
0
Fork
You've already forked ngn-k-ffi-example
0
No description
  • C 66%
  • Makefile 33.4%
  • Shell 0.6%
Find a file
2025年04月06日 12:44:03 -06:00
example2d update readme 2025年04月06日 12:26:02 -06:00
example3d update readme 2025年04月06日 12:26:02 -06:00
external added fixed make file, user no longer needs to install k independently 2024年10月13日 22:32:52 -06:00
.gitignore raylib runs 2024年10月13日 21:43:45 -06:00
camera.k update readme 2025年04月06日 12:26:02 -06:00
colors.k forgot to add these files 2025年03月30日 18:42:38 -06:00
ffi.k update readme 2025年04月06日 12:29:22 -06:00
input.k update readme 2025年04月06日 12:26:02 -06:00
libffi.c add explanations 2025年04月06日 11:36:09 -06:00
LICENSE added license as required per AGPL usage of ngn/k 2025年04月06日 12:44:03 -06:00
main.k update readme 2025年04月06日 12:26:02 -06:00
makefile update readme 2025年04月06日 12:26:02 -06:00
project.k add explanations 2025年04月06日 11:36:09 -06:00
README.md readme 2025年04月06日 12:42:34 -06:00
run update readme 2024年10月06日 19:36:45 -06:00

KFFI Example

  1. clone
  2. checkout raylib
  3. make
  4. read post script in main.k to learn more

Purpose

This project illustrates successful linking, compiling, and execution of external c libraries from ngn/k.

This repository is for instructional and illustrative purposes, and may be used and transformed by anyone for any reason.

Examples

The following 2 raylib examples were ported for illustration purposes. Example3D is selected in main.k by default

Example 2D

example 2D

Example 3D

example 3D

Instructions

$ make

If there are any errors, you can start over with make clean, then make again

make clones, links and compiles all libraries.

./run will run the program without triggering the compilation step.

When the C library in libffi.c is modified, run make libffi.so

$ make # link and compile all things
$ make clean # get rid of anything not in the git repo
$ ./run # run main.k without the compilation step
$ make libffi.so # build only changes from libffi.c, then simply use ./run again

Comments in ./makefile are illustrative to anyone wishing to understand how to link libraries.

Explanation

Why this architecture

This project contains the following files:

./project.k # describes library interface and include statements
./example3d # k code porting raylib 3d example
./example2d # k code porting raylib 2d example
./external # a directory storing some external library source code
./makefile # describes how to build the project and dependencies
./main.k # entry point to the primary k program
./run # script to run the main k program without the build step
./ffi.k # load library functions (from main) and generate c code

But core files the user should expect to modify are limited to the following:

./project.k # describes library interface and include statements
./main.k # entry point to the primary k program
./makefile # link your external libraries in the libffi.so step

Since the ngn/k ffi only works with k-values, it is necessary to wrap any call to external C code by first converting the k-values to c-values. The interface for this is provided in ngn/k/k.c

For atomic conversions, the convention of a lower-case letter is used. For list conversions, upper cased naming convention is used.

char cK(K); // convert from k-char to c-char
K Kc(char); // convert from c-char to k-char

int iK(K); // convert from k-int to c-int
K Ki(int); // convert from c-int to k-int
K Ks(char *); // convert from c-string to k-string

K Kf(double); // convert from c-double to k-double
double fK(K); // convert from k-double to c-double

With this FFI, a simple call to an addition function would look like this:

#include<stddef.h>#include<k.h>K add(K x,K y){
 int a = iK(x); // convert from k-int to c-int
 int b = iK(y);
 return Ki(a + b); // return the value a+b as a k-int
}

The goal of this project was to require a user to edit as few files necessary to generate this middleware easily and without fuss.

To that end, ./project.k describes the C library interface, which is imported by ./ffi.k, while ./main.k is the application entry point.

./project.k # define imports
./ffi.k # do importing
./main # entry point which calls example3d/main.k

How to import libraries

The ./project.k should define 2 variables: includes and lib.

These are important, since the ./ffi.k does important argument parsing before being passed to C functions.

Any additions or subtractions to ./libffi.c should be preceeded by adding/removing those functions in ./project.k

Any changes to ./libffi.c should be followed by make libffi.so

Any new libraries you wish to add, flags adding those libraries must be added to the libffi.so step in the ./makefile

  1. place lib<libname>.so files in ./obj
  2. include headers in ./project.k
  3. add -l<libname> compiler flags to the libffi.so:$(FILE) step in ./makefile

lib (./project.k)

includes is a list of lists, each containing (function name;argument types;return type)

lib:((`plus ;`int`int;`int)
 (`minus ;`int`int;`int)
 (`mulx ;`int`int;`int)
 (`intdiv ;`int`int;`int))

Attributions

Thanks to @ktye @DiscoDoug @rak1507 @mlochbaum in the APLFarm discord for information regarding existing functionality, for the existing writeups about the ffi, for work designing and exposing the K internals so that an FFI is possible at all, and help debugging the object code so I could successfully link external libraries at all.