{"id":15776060,"url":"https://github.com/igjoshua/coffi","last_synced_at":"2025-04-05T06:10:21.896Z","repository":{"id":43262216,"uuid":"406506833","full_name":"IGJoshua/coffi","owner":"IGJoshua","description":"A Foreign Function Interface in Clojure for JDK 19.","archived":false,"fork":false,"pushed_at":"2024-01-29T12:23:14.000Z","size":584,"stargazers_count":250,"open_issues_count":1,"forks_count":3,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-04-25T10:21:51.501Z","etag":null,"topics":["clojure","ffi","jdk17","jdk18","jdk19","native","project-panama"],"latest_commit_sha":null,"homepage":"https://igjoshua.github.io/coffi/","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IGJoshua.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-14T20:06:51.000Z","updated_at":"2024-06-11T03:39:08.166Z","dependencies_parsed_at":"2024-06-11T03:52:43.349Z","dependency_job_id":null,"html_url":"https://github.com/IGJoshua/coffi","commit_stats":{"total_commits":331,"total_committers":3,"mean_commits":"110.33333333333333","dds":0.09667673716012082,"last_synced_commit":"830bb746d19cc582fcefb1515b1f637dd5ffa1b0"},"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IGJoshua%2Fcoffi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IGJoshua%2Fcoffi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IGJoshua%2Fcoffi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IGJoshua%2Fcoffi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IGJoshua","download_url":"https://codeload.github.com/IGJoshua/coffi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247294541,"owners_count":20915340,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","ffi","jdk17","jdk18","jdk19","native","project-panama"],"created_at":"2024-10-04T17:04:43.104Z","updated_at":"2025-04-05T06:10:21.873Z","avatar_url":"https://github.com/IGJoshua.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# coffi\n[![Clojars Project](https://img.shields.io/clojars/v/org.suskalo/coffi.svg)](https://clojars.org/org.suskalo/coffi)\n[![cljdoc badge](https://cljdoc.org/badge/org.suskalo/coffi)](https://cljdoc.org/d/org.suskalo/coffi)\n\nCoffi is a foreign function interface library for Clojure, using the [Foreign\nFunction \u0026 Memory API](https://openjdk.org/jeps/454) in JDK 22 and later. This\nallows calling native code directly from Clojure without the need for either\nJava or native code specific to the library, as e.g. the JNI does. Coffi focuses\non ease of use, including functions and macros for creating wrappers to allow\nthe resulting native functions to act just like Clojure ones, however this\ndoesn't remove the ability to write systems which minimize the cost of\nmarshaling data and optimize for performance, to make use of the low-level\naccess the FF\u0026M API gives us.\n\n- [Getting Started](https://cljdoc.org/d/org.suskalo/coffi/CURRENT/doc/getting-started)\n- [API Documentation](https://cljdoc.org/d/org.suskalo/coffi/CURRENT/api/coffi)\n- [Recent Changes](CHANGELOG.md)\n\n## Installation\nThis library is available on Clojars, or as a git dependency. Add one of the\nfollowing entries to the `:deps` key of your `deps.edn`:\n\n```clojure\norg.suskalo/coffi {:mvn/version \"1.0.486\"}\nio.github.IGJoshua/coffi {:git/tag \"v1.0.486\" :git/sha \"c61090c\"}\n```\n\nIf you use this library as a git dependency, you will need to prepare the\nlibrary.\n\n```sh\n$ clj -X:deps prep\n```\n\nCoffi requires usage of the package `java.lang.foreign`, and most of the\noperations are considered unsafe by the JDK, and are therefore unavailable to\nyour code without passing some command line flags. In order to use coffi, add\nthe following JVM arguments to your application.\n\n```sh\n--enable-native-access=ALL-UNNAMED\n```\n\nYou can specify JVM arguments in a particular invocation of the Clojure CLI with\nthe `-J` flag like so:\n\n``` sh\nclj -J--enable-native-access=ALL-UNNAMED\n```\n\nYou can also specify them in an alias in your `deps.edn` file under the\n`:jvm-opts` key (see the next example) and then invoking the CLI with that alias\nusing `-M`, `-A`, or `-X`.\n\n``` clojure\n{:aliases {:dev {:jvm-opts [\"--enable-native-access=ALL-UNNAMED\"]}}}\n```\n\nOther build tools should provide similar functionality if you check their\ndocumentation.\n\nWhen creating an executable jar file, you can avoid the need to pass this\nargument by adding the manifest attribute `Enable-Native-Access: ALL-UNNAMED` to\nyour jar. See your build tool's documentation for how to add this.\n\nCoffi also includes support for the linter clj-kondo. If you use clj-kondo and\nthis library's macros are not linting correctly, you may need to install the\nconfig bundled with the library. You can do so with the following shell command,\nrun from your project directory:\n\n```sh\n$ clj-kondo --copy-configs --dependencies --lint \"$(clojure -Spath)\"\n```\n\n## Usage\nThe two main namespaces are `coffi.mem` which provides functions for allocating\nand manipulating off-heap memory and (de)serializing values, and `coffi.ffi`\nwhich can load native libraries, declare native function wrappers, and\n(de)serialize functions as callbacks.\n\n```clojure\n(require '[coffi.mem :as mem])\n(require '[coffi.ffi :as ffi :refer [defcfn]])\n\n(defcfn strlen\n  \"Given a string, measures its length in bytes.\"\n  strlen [::mem/c-string] ::mem/long)\n\n(strlen \"hello\")\n;; =\u003e 5\n\n(ffi/load-system-library \"z\")\n```\n\nIn the `coffi.mem` namespace there are types for all the signed primitive\nnumeric types in C, plus `::mem/pointer` and `::mem/c-string`, and ways to use\nmalli-like type declarations to define structs, unions, arrays, enums, and\nflagsets.\n\n## Alternatives\nThis library is not the only Clojure library providing access to native code. In\naddition the following libraries (among others) exist:\n\n- [dtype-next](https://github.com/cnuernber/dtype-next)\n- [tech.jna](https://github.com/techascent/tech.jna)\n- [clojure-jna](https://github.com/Chouser/clojure-jna)\n\nDtype-next has support for Java versions 8-15, 17+, and GraalVM, but is focused\nstrongly on array-based programming, as well as being focused on keeping memory\nin the native side rather than marshaling data to and from Clojure-native\nstructures. In Java 17+, this uses the Foreign Function \u0026 Memory API (a part of\nProject Panama until stabilization in JDK 22), while in other Java versions it\nuses JNA.\n\nTech.jna and clojure-jna both use the JNA library in all cases, and neither\nprovide explicit support for callbacks. JNA allows the use of\n`java.nio.ByteBuffer`s to pass structs by value, and both libraries provide ways\nto use this by-value construction to call by-reference apis.\n\nAn additional alternative to coffi is to directly use the JNI, which is the\nlongest-standing method of wrapping native code in the JVM, but comes with the\ndownside that it requires you to write both native and Java code to use, even if\nyou only intend to use it from Clojure.\n\nIf your application needs to be able to run in earlier versions of the JVM than\n22, you should consider these other options. Dtype-next provides the most robust\nsupport for native code, but if you are wrapping a simple library then the other\nlibraries may be more appealing, as they have a smaller API surface area and\nit's easier to wrap functions.\n\nThere is also a [third party round up](https://docs.google.com/spreadsheets/d/1ViLHNUgrO2osh2AH0h7MaCaXz8g0UpLbyWojY5f10kk/edit?gid=332155605#gid=332155605)\nof FFI options for Clojure.\n\n## Known Issues\nThe project author is aware of these issues and plans to fix them in a future\nrelease:\n\n- When generating docs with codox in a library that depends on coffi, the below error will be produced. A temporary workaround is to add an explicit dependency in your codox build on insn at version 0.2.1\n  ```\n  Unable to find static field: ACC_OPEN in interface org.objectweb.asm.Opcodes\n  ```\n\n## Future Plans\nThese features are planned for future releases.\n\n- Support for va_args type\n- Header parsing tool for generating a data model? (maybe just work with [clong](https://github.com/phronmophobic/clong)?)\n- Generic type aliases\n- Unsigned integer types\n- Record-based struct types\n- Helper macro for out arguments\n- Improve error messages from defcfn macro\n- Mapped memory\n- Helper macros for custom serde implementations for composite data types (this is in progress [for structs](https://github.com/IGJoshua/coffi/issues/12)!)\n\n## License\n\nCopyright © 2023 Joshua Suskalo\n\nDistributed under the Eclipse Public License version 1.0.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figjoshua%2Fcoffi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Figjoshua%2Fcoffi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figjoshua%2Fcoffi/lists"}