diff --git a/build.clj b/build.clj index 471cb51..1597ce4 100644 --- a/build.clj +++ b/build.clj @@ -21,12 +21,15 @@ (def source-dirs ["src/"]) +(def c-test-dirs ["test/c/"]) + (def target-dir "target/") (def class-dir (str target-dir "classes/")) (def basis (b/create-basis {:project "deps.edn"})) (def jar-file (str target-dir "coffi.jar")) +(def test-c-library (str target-dir "ffi_test.so")) (defn clean "Deletes the `target/` directory." @@ -76,6 +79,20 @@ :jar-file jar-file})) opts) +(defn compile-test-library + "Compiles the C test code for running the tests." + [opts] + (let [c-files (->> c-test-dirs + (map io/file) + (mapcat file-seq) + (filter #(.isFile %)) + (map #(.getAbsolutePath %)))] + (.mkdirs (io/file target-dir)) + (b/process {:command-args (concat ["clang" "-fpic" "-shared"] + c-files + ["-o" test-c-library])})) + opts) + (defn run-tasks "Runs a series of tasks with a set of options. The `:tasks` key is a list of symbols of other task names to call. The rest of diff --git a/test/c/ffi_test.c b/test/c/ffi_test.c new file mode 100644 index 0000000..e9cb42b --- /dev/null +++ b/test/c/ffi_test.c @@ -0,0 +1,46 @@ +#include + +typedef struct point { + float x; + float y; +} Point; + +Point add_points(Point a, Point b) { + Point res = {}; + + res.x = a.x + b.x; + res.y = a.y + b.y; + + return res; +} + +typedef char *CString; + +typedef CString (*StringFactory)(void); + +void upcall_test(StringFactory fun) { + return fun(); +} + +static int counter = 0; + +static char* responses[] = { "Hello, world!", "Goodbye friend.", "co'oi prenu" }; + +CString get_string1(void) { + return responses[counter++ % 3]; +} + +CString get_string2(void) { + return "Alternate string"; +} + +StringFactory get_downcall(int whichString) { + switch (whichString % 2) { + case 0: + return get_string1; + case 1: + return get_string2; + default: + return 0; + } +}