{"id":15873802,"url":"https://github.com/phronmophobic/clong","last_synced_at":"2025-04-07T07:11:05.738Z","repository":{"id":62826072,"uuid":"559846041","full_name":"phronmophobic/clong","owner":"phronmophobic","description":"A wrapper for libclang and a generator that can turn c header files into clojure apis.","archived":false,"fork":false,"pushed_at":"2025-02-04T18:01:00.000Z","size":282,"stargazers_count":102,"open_issues_count":5,"forks_count":4,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-31T05:09:03.425Z","etag":null,"topics":["c","clojure","coffi","ffi-wrapper","jna","libclang"],"latest_commit_sha":null,"homepage":"","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/phronmophobic.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2022-10-31T08:09:27.000Z","updated_at":"2025-02-09T05:06:05.000Z","dependencies_parsed_at":"2023-01-23T08:00:31.707Z","dependency_job_id":"230b67ae-6bf4-4ae0-aa01-144aa8069984","html_url":"https://github.com/phronmophobic/clong","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phronmophobic%2Fclong","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phronmophobic%2Fclong/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phronmophobic%2Fclong/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phronmophobic%2Fclong/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phronmophobic","download_url":"https://codeload.github.com/phronmophobic/clong/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247608151,"owners_count":20965952,"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":["c","clojure","coffi","ffi-wrapper","jna","libclang"],"created_at":"2024-10-06T01:06:53.278Z","updated_at":"2025-04-07T07:11:05.715Z","avatar_url":"https://github.com/phronmophobic.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# clong\n\nA wrapper for libclang and a generator that can turn c header files into clojure apis.\n\nSupports jna and dtype-next. Support for other ffi libs is likely.\n\n## Rationale\n\nWriting wrappers for c libraries is tedious and error prone. The goal of clong is to streamline the process of creating wrappers for c libraries. It is a non-goal to make the process 100% automatic. However, it should be possible to do 80-90% of the work and provide tools that are useful for building higher level APIs.\n\n## Usage\n\nLeiningen dependency:\n\n```clojure\n[com.phronemophobic/clong \"1.4.3\"]\n;; only needed for parsing. not needed for generation\n[org.bytedeco/llvm-platform \"16.0.4-1.5.9\"]\n```\n\ndeps.edn dependency:\n\n```clojure\ncom.phronemophobic/clong {:mvn/version \"1.4.3\"}\n;; only needed for parsing. not needed for generation\norg.bytedeco/llvm-platform {:mvn/version \"16.0.4-1.5.9\"}\n```\n\n_Note: If you receive an error like \"Error building classpath. Could not acquire write lock for[...]\" while downloading deps, try deleting the maven dep and retrying with `-Sthreads 1` to workaround this [issue](https://clojure.atlassian.net/browse/TDEPS-244)._\n\n```\nrm -rf ~/.m2/repository/org/bytedeco/\nclj -Sthreads 1 -P\n```\n\n### Parsing\n\n`com.phronemophobic.clong.clang/parse` takes a header filename and the command line args to pass to clang. The most common command line args are `\"-I/my/header/path\"`. If you built clang locally, then you may also need to add system paths. You can see the system paths that you may by running `clang -### empty-file.h` from the command line.\n\n`parse` returns a CXCursor. Further processing can be done via the raw api in `com.phronemophobic.clong.clang.jna.raw`. For basic usage, just use:\n```clojure\n(require '[com.phronemophobic.clong.clang :as clang])\n\n(def results (-\u003e\u003e (clang/parse \"my-header.h\" clang/default-arguments)\n                  clang/get-children\n                  (map clang/cursor-info)))\n```\n\nTo get a flavor of some of the data that can be extracted, check out clong's [datafied version of the libclang API](https://github.com/phronmophobic/clong/blob/18c61d4a20a6d03e47ec49ef65b72c8baf465c39/resources/com/phronemophobic/clong/clang/api.edn).\n\n### Generating APIs\n\nBelow is how clong can be used to generate a wrapper for libz ([full example](https://github.com/phronmophobic/clong/tree/master/examples/libz)):\n\n```clojure\n(require '[clojure.java.io :as io]\n         '[clojure.string :as str]\n         '[clojure.pprint :refer [pprint]]\n         '[clojure.edn :as edn]\n         '[com.phronemophobic.clong.clang :as clang]\n         '[com.phronemophobic.clong.gen.jna :as gen])\n\n(import 'com.sun.jna.ptr.LongByReference)\n\n(def libz\n  (com.sun.jna.NativeLibrary/getInstance \"z\"))\n\n(def api (clang/easy-api \"/opt/local/include/zlib.h\"))\n\n(gen/def-api libz api)\n\n(zlibVersion) ;; \"1.2.11\"\n\n(def source \"clong!\")\n\n(def dest (byte-array 255))\n(def dest-size* (doto (LongByReference.)\n                  (.setValue (alength dest))))\n\n(compress  dest dest-size* source (count source)) ;; 0\n\n(.getValue dest-size*) ;; 14\n\n(def dest2 (byte-array (count source)))\n(def dest2-size* (doto (LongByReference.)\n                   (.setValue (alength dest2))))\n(uncompress dest2 dest2-size* dest (.getValue dest-size*)) ;; 0\n\n(String. dest2) ;; \"clong!\"\n```\n\nThe basic idea is to generate a description of the api with `easy-api` and generate the required structs, functions, and enums with `def-api`.\n\n### Examples\n\nExamples can be found in the [examples directory](https://github.com/phronmophobic/clong/tree/main/examples).\n\n- [libz](https://github.com/phronmophobic/clong/tree/main/examples/libz)\n- [freetype](https://github.com/phronmophobic/clong/tree/main/examples/freetype)\n- [lmdb](https://github.com/phronmophobic/clong/tree/main/examples/lmdb)\n\nOther projects using clong:\n- [clj-graphviz](https://github.com/phronmophobic/clj-graphviz)\n- [clj-libretro](https://github.com/phronmophobic/clj-libretro)\n- [glfw](https://github.com/phronmophobic/clj-glfw)\n- [llama.clj](https://github.com/phronmophobic/llama.clj)\n- [clj-media](https://github.com/phronmophobic/clj-media)\n- [clj-webgpu](https://github.com/phronmophobic/clj-webgpu)\n- [ggml.clj](https://github.com/phronmophobic/ggml.clj)\n- [whisper.clj](https://github.com/phronmophobic/whisper.clj)\n\nFor a more complicated example, clong's [clang interface](https://github.com/phronmophobic/clong/blob/main/src/com/phronemophobic/clong/clang/jna/raw.clj) is [generated](https://github.com/phronmophobic/clong/blob/main/src/com/phronemophobic/clong/clang.clj#L546) by clong itself.\n\nAdditionally, clong was successfully able to generate a complete wrapper for the libav* libraries, ([source](https://github.com/phronmophobic/clj-media/blob/main/src/com/phronemophobic/clj_media/audio.clj#L138)).\n\n### Tips\n\n- Structs will not have any fields reported if _any_ of the struct's fields has an undetermined size. If fields for a struct are missing, you may need to include more headers or make sure the system's standard paths are included (try `clang -### empty-file.h` to see what system paths might be missing).\n- Clong doesn't offer any special support for automatic memory management of ffi data.\n- You can include additional headers using the `-include` argument when parsing\n- Parsing headers can be slow and you probably don't want to ship headers and libclang with your wrapper library. Generate the wrapper ahead of time and save the result as a edn resource that can be loaded. It is also possible to AOT generated interfaces so that the llvm and insn dependencies are required for downstream consumers.\n- JNA has issues with writing to StructureByReference fields. In some cases, it's useful to override structure fields to be raw pointers.\n\n## Future Work\n\n- Improve documentation.\n- Add support for #define values.\n- Add generator that supports project panama.\n- [X] Add support for other ffi libraries besides jna.\n- [-] Implement clojure data interfaces over structs.\n- [X] Support AOT of wrappers.\n- Document AOT of wrappers.\n\n## License\n\nCopyright © 2022-2024 Adrian\n\nDistributed under the Eclipse Public License version 1.0.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphronmophobic%2Fclong","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphronmophobic%2Fclong","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphronmophobic%2Fclong/lists"}