{"id":18841904,"url":"https://github.com/diskuv/dkml-c-probe","last_synced_at":"2025-06-25T09:04:03.839Z","repository":{"id":38457011,"uuid":"489130768","full_name":"diskuv/dkml-c-probe","owner":"diskuv","description":"Cross-compiler friendly characterizations of the OCaml's native C compiler","archived":false,"fork":false,"pushed_at":"2025-03-11T21:05:54.000Z","size":92,"stargazers_count":8,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-25T09:03:07.654Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/diskuv.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.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,"zenodo":null}},"created_at":"2022-05-05T21:28:15.000Z","updated_at":"2025-03-11T20:46:55.000Z","dependencies_parsed_at":"2024-11-08T02:53:07.304Z","dependency_job_id":"a4c47e02-abb7-4d38-9b8b-0144049f8311","html_url":"https://github.com/diskuv/dkml-c-probe","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/diskuv/dkml-c-probe","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diskuv%2Fdkml-c-probe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diskuv%2Fdkml-c-probe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diskuv%2Fdkml-c-probe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diskuv%2Fdkml-c-probe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/diskuv","download_url":"https://codeload.github.com/diskuv/dkml-c-probe/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diskuv%2Fdkml-c-probe/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261841925,"owners_count":23217911,"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":[],"created_at":"2024-11-08T02:52:59.579Z","updated_at":"2025-06-25T09:04:03.764Z","avatar_url":"https://github.com/diskuv.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dkml-c-probe\n\n`dkml-c-probe` simplifies the creation of cross-compiling compatible\n[foreign C stub code](https://dune.readthedocs.io/en/latest/foreign-code.html).\nIt includes two components:\n\n1. **C_abi**: Introspects OCaml's native C compiler, including cross-compilers,\n   to determine the ABI those C compilers will generate\n2. **C_conf**: Supplies flags to C compilers and OCaml tools that specify the locations\n   of C headers and C libraries\n\nIts support for cross-compiling comes from:\n\n- With cross-compilers you will not often be able to run the executables\n  that have been generated. `C_abi` never runs executables created by the C compiler.\n- When compiling on a host ABI and cross-compiling to multiple target ABIs,\n  there must be separate sets of C libraries: one set for the host ABI and\n  one set for each target ABI. `C_conf` can locate C headers and C libraries\n  that are appropriate for the host ABI and target ABIs.\n\nFor example, let's say you had an Apple Intel x86_64 build machine with\na OCaml ocamlfind cross-compiler toolchain for Apple Silicon. *This will\nbe available soon from Opam: https://github.com/diskuv/dkml-compiler/blob/main/dkml-base-compiler.opam*\n\nOCaml will report:\n\n\u003c!-- $MDX non-deterministic=command --\u003e\n```console\n$ ocamlopt -config\n...\nnative_c_compiler: clang -arch x86_64\n\n$ ocamlfind -toolchain darwin_arm64 ocamlopt -config\n...\nnative_c_compiler: clang -arch arm64\n```\n\nwhich would mean using the `C_abi`:\n\n\u003c!-- $MDX non-deterministic=command --\u003e\n```ocaml\nDkml_c_probe.C_abi.V3.get_abi ()\n```\n\nwould result in `Ok Darwin_x86_64` or `Ok Darwin_arm64`, depending on which\nocamlfind toolchain was used.\n\n[Dune Cross Compilation](https://dune.readthedocs.io/en/latest/cross-compilation.html)\ncombined with [Opam Monorepo](https://github.com/ocamllabs/opam-monorepo#opam-monorepo)\nmakes this simpler. On the same example machine you could do:\n\n\u003c!-- $MDX non-deterministic=command --\u003e\n```console\n$ dune build -x darwin_arm64\n```\n\nand it would compile both Apple Intel and Apple Silicon binaries. During the\ncompilation of the Apple Intel binaries (Dune's \"default\" context) the\n`get_abi ()` would give `Ok Darwin_x86_64` while during the compilation of\nthe Apple Silicon binaries (Dune's \"default_arm64\" context) it would give\n`Ok Darwin_arm64`.\n\n---\n\nLet's also say you needed to link your code against the foreign C library \"gmp\".\n\nYour `dune` script would typically look like:\n\n```lisp\n(library\n (name my_library)\n (c_library_flags\n  :standard\n  (:include c_library_flags.sexp))\n (foreign_stubs\n  (language c)\n  (names my_stubs)\n  (flags\n   :standard\n   (:include c_flags.sexp))))\n\n(rule\n (targets c_flags.sexp c_library_flags.sexp)\n (action\n  (run\n   ./config/discover.exe\n   -context_name\n   %{context_name}\n   -ccomp_type\n   %{ocaml-config:ccomp_type})))\n```\n\nIn the above `dune` script the responsibility to supply the C\nflags (ex. `-I/usr/local/include/gmp`) and C library flags\n(ex. `-L/usr/local/lib/gmp -lgmp`) has been delegated\nto `./config/discover.exe`.\n\nYou would use `C_conf` in the\n[Dune Configurator based `config/discover.ml`](https://dune.readthedocs.io/en/stable/dune-libs.html)\nto generate these flags:\n\n```lisp\n; file: config/dune\n(executable\n (name discover)\n (libraries dune-configurator dkml-c-probe))\n```\n\n\u003c!-- $MDX file=samples/discover.ml --\u003e\n```ocaml\n(* file: config/discover.ml *)\n\nmodule C = Configurator.V1\n\nlet () =\n  let ctxname = ref \"\" in\n  let ccomp_type = ref \"\" in\n  let args =\n    [\n      (\"-context_name\", Arg.Set_string ctxname, \"Dune %{context_name} variable\");\n      ( \"-ccomp_type\",\n        Arg.Set_string ccomp_type,\n        \"Dune %{ocaml-config:ccomp_type} variable\" );\n    ]\n  in\n  C.main ~args ~name:\"discover\" (fun _c -\u003e\n      let cflags, clibraryflags =\n        let open Dkml_c_probe.C_conf in\n        match load_from_dune_context_name !ctxname with\n        | Error msg -\u003e\n            failwith (\"Failed loading C_conf in Dune Configurator. \" ^ msg)\n        | Ok conf -\u003e (\n            match\n              compiler_flags_of_ccomp_type conf ~ccomp_type:!ccomp_type\n                ~clibrary:\"ffi\"\n            with\n            | Error msg -\u003e\n                failwith (\"Failed getting compiler flags from C_conf. \" ^ msg)\n            | Ok (Some fl) -\u003e (C_flags.cc_flags fl, C_flags.link_flags fl)\n            | Ok None -\u003e\n                (* We can't find the library! You could fall back\n                   to pkg-config by using C.Pkg_config, or just have\n                   a sane default. *)\n                ([], [ \"-lgmp\" ]))\n      in\n\n      C.Flags.write_sexp \"c_flags.sexp\" cflags;\n      C.Flags.write_sexp \"c_library_flags.sexp\" clibraryflags)\n```\n\n## Usage\n\nInstall it with:\n\n\u003c!-- $MDX non-deterministic=command --\u003e\n```console\n$ opam install dkml-c-probe\n```\n\nThen either:\n* Use the [OCaml Interfaces](#ocaml-interfaces) in your [Dune Configurator](https://dune.readthedocs.io/en/latest/dune-libs.html#configurator-1)\n* Use the [C Header](#c-header) in your [foreign C stub code](https://dune.readthedocs.io/en/latest/foreign-code.html)\n\nOCaml API documentation is at https://diskuv.github.io/dkml-c-probe/dkml-c-probe/Dkml_c_probe/index.html\n\n## OCaml Interfaces\n\n### C_abi\n\n```console\n$ ocaml samples/show_abi_signature.ml\nmodule V3 = Dkml_c_probe.C_abi.V3\nmodule V3 :\n  sig\n    type t_os =\n        UnknownOS\n      | Android\n      | DragonFly\n      | FreeBSD\n      | IOS\n      | Linux\n      | NetBSD\n      | OpenBSD\n      | OSX\n      | Windows\n    type t_abi =\n        Unknown_unknown\n      | Android_arm32v7a\n      | Android_arm64v8a\n      | Android_x86\n      | Android_x86_64\n      | Darwin_arm64\n      | Darwin_x86_64\n      | DragonFly_x86_64\n      | FreeBSD_x86_64\n      | Linux_arm32v6\n      | Linux_arm32v7\n      | Linux_arm64\n      | Linux_x86\n      | Linux_x86_64\n      | NetBSD_x86_64\n      | OpenBSD_x86_64\n      | Windows_arm32\n      | Windows_arm64\n      | Windows_x86\n      | Windows_x86_64\n    val get_os : unit -\u003e (t_os, string) result\n    val get_abi : unit -\u003e (t_abi, string) result\n    val get_abi_name : unit -\u003e (string, string) result\n  end\n```\n\n### C_conf\n\nExtensive documentation is available at the\n[C_conf documentation page](https://diskuv.github.io/dkml-c-probe/dkml-c-probe/Dkml_c_probe/C_conf/index.html)\n\nHere is a quick peek at `C_conf`:\n\n```console\n$ ocaml samples/show_conf_signature.ml\nmodule C_conf = Dkml_c_probe__.C_conf\nmodule C_conf = Dkml_c_probe.C_conf\nmodule C_conf :\n  sig\n    type t\n    type env_getter = string -\u003e string option\n    module C_flags : sig ... end\n    module Ocamlmklib_flags : sig ... end\n    val load : ?getenv:env_getter -\u003e unit -\u003e (t, string) result\n    val load_from_dune_context_name :\n      ?getenv:env_getter -\u003e string -\u003e (t, string) result\n    val load_from_findlib_toolchain :\n      ?getenv:env_getter -\u003e string option -\u003e (t, string) result\n    val compiler_flags_of_ccomp_type :\n      t -\u003e\n      ccomp_type:string -\u003e\n      clibrary:string -\u003e (C_flags.t option, string) result\n    val compiler_flags_msvc :\n      t -\u003e clibrary:string -\u003e (C_flags.t option, string) result\n    val compiler_flags_gcc :\n      t -\u003e clibrary:string -\u003e (C_flags.t option, string) result\n    val tool_flags_ocamlmklib :\n      t -\u003e clibrary:string -\u003e (Ocamlmklib_flags.t option, string) result\n  end\n```\n\n## C Header\n\nThe header file will be available as the following expressions:\n- `%{dkml-c-probe:lib}%/dkml_compiler_probe.h` if you are in an `.opam` file\n- `%{lib:dkml-c-probe:dkml_compiler_probe.h}` if you are in a `dune` file\n\n\u003c!-- $MDX file=dkml_compiler_probe.h --\u003e\n```c\n/******************************************************************************/\n/*  Copyright 2021 Diskuv, Inc.                                               */\n/*                                                                            */\n/*  Licensed under the Apache License, Version 2.0 (the \"License\");           */\n/*  you may not use this file except in compliance with the License.          */\n/*  You may obtain a copy of the License at                                   */\n/*                                                                            */\n/*      http://www.apache.org/licenses/LICENSE-2.0                            */\n/*                                                                            */\n/*  Unless required by applicable law or agreed to in writing, software       */\n/*  distributed under the License is distributed on an \"AS IS\" BASIS,         */\n/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  */\n/*  See the License for the specific language governing permissions and       */\n/*  limitations under the License.                                            */\n/******************************************************************************/\n\n/*\n  For Apple see https://developer.apple.com/documentation/apple-silicon/building-a-universal-macos-binary\n  For Windows see https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-160\n  For Android see https://developer.android.com/ndk/guides/cpu-features\n  For Linux see https://sourceforge.net/p/predef/wiki/Architectures/\n */\n#ifndef DKMLCOMPILERPROBE_H\n#define DKMLCOMPILERPROBE_H\n\n#if __APPLE__\n#   include \u003cTargetConditionals.h\u003e\n#   if TARGET_OS_OSX\n#       define DKML_OS_NAME \"OSX\"\n#       define DKML_OS_OSX\n#       if TARGET_CPU_ARM64\n#           define DKML_ABI \"darwin_arm64\"\n#           define DKML_ABI_darwin_arm64\n#       elif TARGET_CPU_X86_64\n#           define DKML_ABI \"darwin_x86_64\"\n#           define DKML_ABI_darwin_x86_64\n#       elif TARGET_CPU_PPC64\n#           define DKML_ABI \"darwin_ppc64\"\n#           define DKML_ABI_darwin_ppc64\n#       endif /* TARGET_CPU_ARM64, TARGET_CPU_X86_64, TARGET_CPU_PPC64 */\n#   elif TARGET_OS_IOS\n#       define DKML_OS_NAME \"IOS\"\n#       define DKML_OS_IOS\n#       define DKML_ABI \"darwin_arm64\"\n#       define DKML_ABI_darwin_arm64\n#   endif /* TARGET_OS_OSX, TARGET_OS_IOS */\n#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)\n#   if __OpenBSD__\n#       define DKML_OS_NAME \"OpenBSD\"\n#       define DKML_OS_OpenBSD\n#       if __x86_64__\n#           define DKML_ABI \"openbsd_x86_64\"\n#           define DKML_ABI_openbsd_x86_64\n#       endif /* __x86_64__ */\n#   elif __FreeBSD__\n#       define DKML_OS_NAME \"FreeBSD\"\n#       define DKML_OS_FreeBSD\n#       if __x86_64__\n#           define DKML_ABI \"freebsd_x86_64\"\n#           define DKML_ABI_freebsd_x86_64\n#       endif /* __x86_64__ */\n#   elif __NetBSD__\n#       define DKML_OS_NAME \"NetBSD\"\n#       define DKML_OS_NetBSD\n#       if __x86_64__\n#           define DKML_ABI \"netbsd_x86_64\"\n#           define DKML_ABI_netbsd_x86_64\n#       endif /* __x86_64__ */\n#   elif __DragonFly__\n#       define DKML_OS_NAME \"DragonFly\"\n#       define DKML_OS_DragonFly\n#       if __x86_64__\n#           define DKML_ABI \"dragonfly_x86_64\"\n#           define DKML_ABI_dragonfly_x86_64\n#       endif /* __x86_64__ */\n#   endif /* __OpenBSD__, __FreeBSD__, __NetBSD__, __DragonFly__ */\n#elif __linux__\n#   if __ANDROID__\n#       define DKML_OS_NAME \"Android\"\n#       define DKML_OS_Android\n#       if __arm__\n#           define DKML_ABI \"android_arm32v7a\"\n#           define DKML_ABI_android_arm32v7a\n#       elif __aarch64__\n#           define DKML_ABI \"android_arm64v8a\"\n#           define DKML_ABI_android_arm64v8a\n#       elif __i386__\n#           define DKML_ABI \"android_x86\"\n#           define DKML_ABI_android_x86\n#       elif __x86_64__\n#           define DKML_ABI \"android_x86_64\"\n#           define DKML_ABI_android_x86_64\n#       endif /* __arm__, __aarch64__, __i386__, __x86_64__ */\n#   else\n#       define DKML_OS_NAME \"Linux\"\n#       define DKML_OS_Linux\n#       if __aarch64__\n#           define DKML_ABI \"linux_arm64\"\n#           define DKML_ABI_linux_arm64\n#       elif __arm__\n#           if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__)\n#               define DKML_ABI \"linux_arm32v6\"\n#               define DKML_ABI_linux_arm32v6\n#           elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)\n#               define DKML_ABI \"linux_arm32v7\"\n#               define DKML_ABI_linux_arm32v7\n#           endif /* __ARM_ARCH_6__ || ...,  __ARM_ARCH_7__ || ... */\n#       elif __x86_64__\n#           define DKML_ABI \"linux_x86_64\"\n#           define DKML_ABI_linux_x86_64\n#       elif __i386__\n#           define DKML_ABI \"linux_x86\"\n#           define DKML_ABI_linux_x86\n#       elif defined(__ppc64__) || defined(__PPC64__)\n#           define DKML_ABI \"linux_ppc64\"\n#           define DKML_ABI_linux_ppc64\n#       elif __s390x__\n#           define DKML_ABI \"linux_s390x\"\n#           define DKML_ABI_linux_s390x\n#       endif /* __aarch64__, __arm__, __x86_64__, __i386__, __ppc64__ || __PPC64__, __s390x__ */\n#   endif /* __ANDROID__ */\n#elif _WIN32\n#   define DKML_OS_NAME \"Windows\"\n#   define DKML_OS_Windows\n#   if _M_ARM64\n#       define DKML_ABI \"windows_arm64\"\n#       define DKML_ABI_windows_arm64\n#   elif _M_ARM\n#       define DKML_ABI \"windows_arm32\"\n#       define DKML_ABI_windows_arm32\n#   elif _WIN64\n#       define DKML_ABI \"windows_x86_64\"\n#       define DKML_ABI_windows_x86_64\n#   elif _M_IX86\n#       define DKML_ABI \"windows_x86\"\n#       define DKML_ABI_windows_x86\n#   endif /* _M_ARM64, _M_ARM, _WIN64, _M_IX86 */\n#endif\n\n#ifndef DKML_OS_NAME\n#   define DKML_OS_NAME \"UnknownOS\"\n#   define DKML_OS_UnknownOS\n#endif\n#ifndef DKML_ABI\n#   define DKML_ABI \"unknown_unknown\"\n#   define DKML_ABI_unknown_unknown\n#endif\n\n#endif /* DKMLCOMPILERPROBE_H */\n```\n\n## Contributions\n\nWe are always looking for new ABIs! Each new ABI needs to have its own\nmaintainer.\n\nIf you are interested, head over to **[Your Contributions](CONTRIBUTORS.md)**.\n\n## Status\n\n| Status                                                                                                                                                            |\n| ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| [![Syntax check](https://github.com/diskuv/dkml-c-probe/actions/workflows/test.yml/badge.svg)](https://github.com/diskuv/dkml-c-probe/actions/workflows/test.yml) |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiskuv%2Fdkml-c-probe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiskuv%2Fdkml-c-probe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiskuv%2Fdkml-c-probe/lists"}