From 4f2fb983189c1dfef0cad4dd12d86296517fff4c Mon Sep 17 00:00:00 2001 From: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> Date: Mon, 3 Aug 2026 12:27:26 -0700 Subject: [PATCH 1/4] Add linux_x86_musl and linux_arm64_musl to V4 Linux x86 (32-bit) and arm64 hosts with a musl libc need ABIs distinct from their glibc forms, for the same reason Linux_x86_64_musl was introduced: fully static musl builds need their own distribution slot. + replicate the / __GLIBC__ musl test in the __i386__ and __aarch64__ branches of the C header, hoisting the include so one test covers all the Linux arms + add Linux_x86_musl and Linux_arm64_musl to module V4 + degrade the new ABIs to Linux_x86 / Linux_arm64 in V1-V3; in V1 an x86 musl host then gets the pre-existing Result.error since V1 never had Linux_x86 + make C_conf.load use V4 so musl hosts read ABI-specific environment variables like CP_GMP_CC_DEFAULT_LINUX_X86_64_MUSL + delete the unused top-level t_abi in discover.ml Signed-off-by: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> --- src/c_conf.ml | 2 +- src/config/discover.ml | 42 +++++++++++++++----------------- src/config/dkml_compiler_probe.h | 38 ++++++++++++++++++----------- 3 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/c_conf.ml b/src/c_conf.ml index bae74bd..8ce3db5 100644 --- a/src/c_conf.ml +++ b/src/c_conf.ml @@ -89,7 +89,7 @@ let load_from_dune_context_name ?(getenv = default_env_getter) ctxname = else create_error () let load ?(getenv = default_env_getter) () = - let abi_name_res = C_abi.V3.get_abi_name () in + let abi_name_res = C_abi.V4.get_abi_name () in match abi_name_res with | Ok abi_name -> load_from_findlib_toolchain ~getenv (Some abi_name) | Error msg -> Error msg diff --git a/src/config/discover.ml b/src/config/discover.ml index c8e0b79..227210a 100644 --- a/src/config/discover.ml +++ b/src/config/discover.ml @@ -17,21 +17,6 @@ open Configurator.V1 open Flags -type t_abi = - | Android_arm64v8a - | Android_arm32v7a - | Android_x86 - | Android_x86_64 - | Darwin_arm64 - | Darwin_x86_64 - | Linux_arm64 - | Linux_arm32v6 - | Linux_arm32v7 - | Linux_x86_64 - | Linux_x86 - | Windows_x86_64 - | Windows_x86 - type osinfo = { ostypename : (string, string) result; osname: (string, string) result; @@ -95,6 +80,8 @@ let get_osinfo t = (Result.ok "Unknown_unknown") | [ (_, String ("linux_arm64")) ] -> (Result.ok "Linux_arm64") + | [ (_, String ("linux_arm64_musl")) ] -> + (Result.ok "Linux_arm64_musl") | [ (_, String ("linux_arm32v6")) ] -> (Result.ok "Linux_arm32v6") | [ (_, String ("linux_arm32v7")) ] -> @@ -104,6 +91,8 @@ let get_osinfo t = | [ (_, String ("linux_x86_64_musl")) ] -> (Result.ok "Linux_x86_64_musl") | [ (_, String ("linux_x86")) ] -> (Result.ok "Linux_x86") + | [ (_, String ("linux_x86_musl")) ] -> + (Result.ok "Linux_x86_musl") | [ (_, String "linux_ppc64") ] -> (Result.ok "Unknown_unknown") | [ (_, String "linux_s390x") ] -> @@ -144,15 +133,21 @@ let result_to_quoted_string = function | Result.Error e -> "Result.error (\"" ^ String.escaped e ^ "\")" (* Unlike the pre-V2/pre-V3 adjusters which downgrade newer ABIs to - Result.error, the musl ABI degrades to plain Linux_x86_64 in V1-V3. A musl - host is a Linux x86_64 host, and V1-V3 consumers compiled before musl - detection existed always saw Linux_x86_64 on musl (the probe could not tell - the difference), so reporting Linux_x86_64 preserves their behavior instead - of turning working consumers into runtime errors. *) + Result.error, the musl ABIs degrade to their glibc counterparts in V1-V3. + A musl host is still the same Linux machine architecture, and V1-V3 + consumers compiled before musl detection existed always saw the glibc name + there (the probe could not tell the difference), so keeping the glibc name + preserves their behavior instead of turning working consumers into runtime + errors. In V1 the degraded Linux_x86 then hits adjust_pre_v2_abi's + Result.error, since V1 never had Linux_x86. *) let adjust_pre_v4_abi ~abitypename ~abiname = match (abitypename, abiname) with + | Result.Ok "Linux_arm64_musl", _ | _, Result.Ok "linux_arm64_musl" -> + (Result.ok "Linux_arm64", Result.ok "linux_arm64") | Result.Ok "Linux_x86_64_musl", _ | _, Result.Ok "linux_x86_64_musl" -> (Result.ok "Linux_x86_64", Result.ok "linux_x86_64") + | Result.Ok "Linux_x86_musl", _ | _, Result.Ok "linux_x86_musl" -> + (Result.ok "Linux_x86", Result.ok "linux_x86") | Result.Ok tn, Result.Ok n -> (Result.ok tn, Result.ok n) | Result.Error e, _ | _, Result.Error e -> (Result.error e, Result.error e) @@ -365,8 +360,9 @@ let () = (* V4. - Adds Linux_x86_64_musl: a Linux x86_64 host whose C compiler targets - a non-glibc libc (musl). V1-V3 report such a host as Linux_x86_64 + Adds the musl ABIs Linux_arm64_musl, Linux_x86_64_musl and + Linux_x86_musl: Linux hosts whose C compiler targets a non-glibc + libc (musl). V1-V3 report such hosts under the glibc ABI names (see adjust_pre_v4_abi). *) let lines = lines @@ -398,9 +394,11 @@ let () = | Linux_arm32v6 | Linux_arm32v7 | Linux_arm64 + | Linux_arm64_musl | Linux_x86 | Linux_x86_64 | Linux_x86_64_musl + | Linux_x86_musl | NetBSD_x86_64 | OpenBSD_x86_64 | Windows_arm32 diff --git a/src/config/dkml_compiler_probe.h b/src/config/dkml_compiler_probe.h index f5c737b..6098b97 100644 --- a/src/config/dkml_compiler_probe.h +++ b/src/config/dkml_compiler_probe.h @@ -94,9 +94,24 @@ # else # define DKML_OS_NAME "Linux" # define DKML_OS_Linux + /* musl does not define an identifying macro. Pull in + (glibc and uclibc define __GLIBC__ there; musl defines nothing) + and treat a hosted Linux without __GLIBC__ as musl. */ +# if defined(__has_include) +# if __has_include() +# include +# endif +# else +# include +# endif # if __aarch64__ -# define DKML_ABI "linux_arm64" -# define DKML_ABI_linux_arm64 +# if defined(__GLIBC__) +# define DKML_ABI "linux_arm64" +# define DKML_ABI_linux_arm64 +# else +# define DKML_ABI "linux_arm64_musl" +# define DKML_ABI_linux_arm64_musl +# endif /* __GLIBC__ */ # elif __arm__ # 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__) # define DKML_ABI "linux_arm32v6" @@ -106,16 +121,6 @@ # define DKML_ABI_linux_arm32v7 # endif /* __ARM_ARCH_6__ || ..., __ARM_ARCH_7__ || ... */ # elif __x86_64__ - /* musl does not define an identifying macro. Pull in - (glibc and uclibc define __GLIBC__ there; musl defines nothing) - and treat a hosted Linux x86_64 without __GLIBC__ as musl. */ -# if defined(__has_include) -# if __has_include() -# include -# endif -# else -# include -# endif # if defined(__GLIBC__) # define DKML_ABI "linux_x86_64" # define DKML_ABI_linux_x86_64 @@ -124,8 +129,13 @@ # define DKML_ABI_linux_x86_64_musl # endif /* __GLIBC__ */ # elif __i386__ -# define DKML_ABI "linux_x86" -# define DKML_ABI_linux_x86 +# if defined(__GLIBC__) +# define DKML_ABI "linux_x86" +# define DKML_ABI_linux_x86 +# else +# define DKML_ABI "linux_x86_musl" +# define DKML_ABI_linux_x86_musl +# endif /* __GLIBC__ */ # elif defined(__ppc64__) || defined(__PPC64__) # define DKML_ABI "linux_ppc64" # define DKML_ABI_linux_ppc64 From 887b16533f3b7ec278c9f4462feb9cd7308194cb Mon Sep 17 00:00:00 2001 From: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> Date: Mon, 3 Aug 2026 12:27:28 -0700 Subject: [PATCH 2/4] Rework the Tests workflow: musl coverage, fit the Actions allowlist The workflow had rotted (macos-12 retired, actions/*-artifact@v3 disabled) and its actions were not on this repository's curated Actions allowlist, so every run failed at startup once Actions was enabled. It also had no musl coverage at all. Rebuild it as one workflow with four jobs: + c-header-probe: compile the C header on musl (Alpine) and glibc (Debian) for x86_64 / x86 / arm64 and assert DKML_ABI and its companion define. Uses only `docker run` (+ actions/checkout); arm64 emulation is registered with `docker run tonistiigi/binfmt` rather than a non-allowlisted setup-qemu action + ocaml-alpine-musl: the full dune-configurator -> c_abi.ml path on a real musl host, asserting Ok Linux_x86_64_musl + Cross-Platform-Action: FreeBSD 14.2 and OpenBSD 7.6 guests via cross-platform-actions v1.3.0 (SHA-pinned). Install ocaml + opam + git + ocamlfind from the BSD packages and use the packaged OCaml via ocaml-system after an opam update, so nothing is compiled from source in the emulated VM. `ocaml` reading a script on stdin exits 0 even on a toplevel error, so grep the output for the expected Ok rather than trusting the exit code + test-with-setup-ocaml: Windows/macOS/Linux glibc on ocaml/setup-ocaml (SHA-pinned, OCaml 4.14.x), replacing the former DkML MSVC/MSYS2 + manylinux reusable-workflow matrix whose actions are not allowlisted Triggers add pull_request and workflow_dispatch alongside push to main. Signed-off-by: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> --- .github/workflows/test.yml | 502 ++++++++++++------------------------- 1 file changed, 163 insertions(+), 339 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 79664ad..12e6c14 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,143 +4,186 @@ on: push: branches: - "main" + pull_request: + workflow_dispatch: + +# This repository restricts GitHub Actions to a curated allowlist +# (Settings > Actions > General > Allow select actions). Every `uses:` here +# must reference an allowlisted action, pinned as the allowlist requires. +# +# Coverage: +# * c-header-probe -- Linux musl/glibc ABI detection at the C +# preprocessor level (Alpine + Debian, x86_64 +# / x86 / arm64), using only `docker run`. +# * ocaml-alpine-musl -- the full dune-configurator -> c_abi.ml path +# on a real musl host. +# * Cross-Platform-Action -- FreeBSD and OpenBSD guests. +# * test-with-setup-ocaml -- Windows/macOS/Linux glibc via ocaml/setup-ocaml +# (not the DkML MSVC/MSYS2 + manylinux reusable +# workflow, whose actions are not allowlisted). jobs: + # Compile the C probe header on musl (Alpine) and glibc (Debian) for each + # Linux architecture that has a musl ABI variant, and assert the DKML_ABI + # string and its companion define. The OCaml layer above the header is + # architecture-independent string templating, so the full toolchain only + # needs to run once on a musl host (see ocaml-alpine-musl below). + c-header-probe: + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - platform: linux/amd64 + image: alpine:3.21 + expected: linux_x86_64_musl + setup: apk add --no-cache gcc musl-dev + - platform: linux/386 + image: alpine:3.21 + expected: linux_x86_musl + setup: apk add --no-cache gcc musl-dev + - platform: linux/arm64 + image: alpine:3.21 + expected: linux_arm64_musl + setup: apk add --no-cache gcc musl-dev + - platform: linux/amd64 + image: debian:bookworm + expected: linux_x86_64 + setup: apt-get update -qq && apt-get install -y -qq gcc + - platform: linux/386 + image: debian:bookworm + expected: linux_x86 + setup: apt-get update -qq && apt-get install -y -qq gcc + - platform: linux/arm64 + image: debian:bookworm + expected: linux_arm64 + setup: apt-get update -qq && apt-get install -y -qq gcc + name: c-probe / ${{ matrix.image }} ${{ matrix.platform }} + steps: + - name: Checkout code + uses: actions/checkout@v6 + + # Register binfmt_misc handlers for cross-architecture emulation. This + # is what docker/setup-qemu-action does internally; run the image + # directly so no non-allowlisted GitHub Action is required. + - name: Enable qemu emulation + if: matrix.platform == 'linux/arm64' + run: docker run --privileged --rm tonistiigi/binfmt --install arm64 + + - name: Probe DKML_ABI + run: | + cat > probe.c <<'EOF' + #include + #include "src/config/dkml_compiler_probe.h" + int main(void) { printf("%s\n", DKML_ABI); return 0; } + EOF + cat > check.c < generated c_abi.ml path reports Linux_x86_64_musl. + ocaml-alpine-musl: + runs-on: ubuntu-latest + timeout-minutes: 60 + name: ocaml / alpine (musl x86_64) + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Build, test and probe on Alpine + run: | + docker run --rm -v "$PWD:/src" ocaml/opam:alpine-ocaml-4.14 sh -ec ' + sudo cp -r /src /home/opam/work + sudo chown -R opam /home/opam/work + cd /home/opam/work + opam update + opam install . --deps-only --with-test --yes + opam exec -- dune build --display=short + opam exec -- dune runtest --display=short + opam exec -- dune install + opam exec -- sh -c "cat samples/show_abi.ml | ocaml" | tee /tmp/show_abi.out + grep -q "Linux_x86_64_musl" /tmp/show_abi.out' + test-with-Cross-Platform-Action: - # macOS-12 is only GitHub CI runner that supports VirtualBox - # - the suggested 10.15 from https://stackoverflow.com/questions/66261101/using-vagrant-on-github-actions-ideally-incl-virtualbox - # is deprecated (https://github.com/actions/runner-images/issues/5583) - # - virtualbox added to macOS-12 in https://github.com/actions/runner-images/pull/5594 - runs-on: macos-12 + # BSD guests in QEMU virtual machines on the Linux runners. (Historically + # this ran VirtualBox on macos-12, the only runner that supported it; + # macos-12 was retired in December 2024 and cross-platform-actions runs + # on ubuntu runners now.) + runs-on: ubuntu-latest timeout-minutes: 90 strategy: fail-fast: false matrix: os: + - name: freebsd + version: '14.2' - name: openbsd - version: '6.8' - - name: openbsd - version: '7.1' - # 6.9 gives ... - # <><> Fetching repository information ><><><><><><><><><><><><><><><><><><><><><> - # Error: Could not update repository "default": OpamDownload.Download_fail(_, "Download command failed: \"/usr/bin/ftp -o /tmp/opam-87092-8f3a45/index.tar.gz.part -U opam/2.1.2 -- https://opam.ocaml.org/index.tar.gz\" exited with code 1 \"TLS handshake failure: certificate verification failed: certificate has expired\"") - # because a syspatch has not been applied to the Cross-Platform-Action OpenBSD 6.9. - # See https://marc.info/?l=openbsd-misc&m=163303405028215&w=2 - # It would be nice to run syspatch at startup, but it complains of `syspatch: cannot apply patches while reorder_kernel is running` - # and `run_as_root rcctl disable library_aslr` (https://www.facebook.com/groups/2210554563/posts/10157117341779564/) is ineffective + version: '7.6' + # OpenBSD guests have historically been the flakiest; do not + # block the Tests on them. continue-on-error: yes - - name: freebsd - version: '13.0' - # netbsd 9.2 does not start in VirtualBox as of 2022-06-05 - # - name: netbsd - # version: '9.2' name: Cross-Platform-Action / ${{ matrix.os.name }}-${{ matrix.os.version }} continue-on-error: ${{ matrix.os.continue-on-error == 'yes' }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v6 - - name: Cache Opam root - uses: actions/cache@v3 - with: - path: _opamroot - key: ${{ matrix.os.name }}-${{ matrix.os.version }} - - - name: Cache Opam binaries - uses: actions/cache@v3 - with: - path: _opambin - key: ${{ matrix.os.name }}-${{ matrix.os.version }} - - - name: Test in VirtualBox - uses: cross-platform-actions/action@v0.6.2 + - name: Test in virtual machine + uses: cross-platform-actions/action@5ea7e8e4677bd726033a10b094ba1c5762b15dee # v1.3.0 with: operating_system: ${{ matrix.os.name }} version: ${{ matrix.os.version }} - shell: bash + shell: sh run: | - uname -a - usys=$(uname -s) - workspace_root=$(pwd) - export OPAMROOT="$workspace_root/_opamroot" - - run_as_root() { - # doas on OpenBSD is not enabled (yet) - sudo "$@" - } - - set -x - - case "$usys" in - OpenBSD) - run_as_root pkg_add curl - run_as_root pkg_add gmake bzip2 - run_as_root pkg_add gpatch - # 6.8 - run_as_root pkg_add gtar-1.32p1 unzip-6.0p13 || true - # 6.9 and 7.1 - run_as_root pkg_add gtar-1.34 unzip-6.0p14 || true - run_as_root pkg_add git - ;; + set -eux + # opam is available from the BSD package repositories; use the + # pkg-installed OCaml as the switch compiler (ocaml-system) so no + # compiler is built from source inside the (emulated) VM. The BSD + # opam ships a stale package index, so `opam update` is needed + # before ocaml-system can resolve against the current repository. + # `opam install .` (without --with-test) builds the package in + # release mode, which skips the ounit2/mdx test stanzas -- those + # are exercised on the setup-ocaml matrix below. Here we just + # confirm the BSD ABI is detected and the library builds/installs. + # git is required by `opam install .` to read the pinned local + # directory's VCS state; it is not in the OpenBSD base system. + case "$(uname -s)" in FreeBSD) - run_as_root pkg upgrade --yes pkg - run_as_root pkg install --yes curl - run_as_root pkg install --yes gmake bzip2 - run_as_root pkg install --yes patch gtar unzip - run_as_root pkg install --yes git + sudo pkg install --yes ocaml ocaml-opam git + expected=FreeBSD_x86_64 + ;; + OpenBSD) + sudo pkg_add -I ocaml opam git + expected=OpenBSD_x86_64 ;; esac - # bin/opam cache miss? - opamver="2.1.2" - opamsha256="de1e3efffd5942e0101ef83dcdead548cc65a93e13986aecb4a264a059457ede" - opamcachemiss=OFF - if [ ! -x "$workspace_root/_opambin/bin/opam" ]; then - opamcachemiss=ON - else - opamactualver=$("$workspace_root/_opambin/bin/opam" --version || true) - if [ ! "$opamactualver" = "$opamver" ]; then - opamcachemiss=ON - fi - fi - if [ "$opamcachemiss" = ON ]; then - # curl - curl -fsSL https://github.com/ocaml/opam/releases/download/$opamver/opam-full-$opamver.tar.gz > opam-full-$opamver.tar.gz - case "$usys" in - OpenBSD) - echo "SHA256 (opam-full-$opamver.tar.gz) = de1e3efffd5942e0101ef83dcdead548cc65a93e13986aecb4a264a059457ede" | sha256 -c - ;; - FreeBSD) - sha256 -c 'de1e3efffd5942e0101ef83dcdead548cc65a93e13986aecb4a264a059457ede' opam-full-$opamver.tar.gz - ;; - esac - tar xfz opam-full-$opamver.tar.gz - rm -f opam-full-$opamver.tar.gz - - # gmake bzip2 - cd opam-full-$opamver - gmake cold CONFIGURE_ARGS="--prefix '$workspace_root/_opambin'" - gmake cold-install - cd "$workspace_root" - rm -rf opam-full-$opamver - fi - PATH="$workspace_root/_opambin/bin:$PATH" + opam init --bare --auto-setup --yes --disable-sandboxing + opam update + opam switch create dcp ocaml-system --yes + eval "$(opam env)" - # minimize cross-platform-actions/action post-step 'rsync' that - # transfers files out of virtual machine - install -d "$workspace_root/_build" - trap 'rm -rf $workspace_root/_build' EXIT + # ocamlfind provides topfind, which samples/show_abi.ml loads via + # `#use "topfind"` before it can `#require` the package. + opam install . ocamlfind --yes - # gpatch gtar unzip - opam init --auto-setup - - # git - opam install . --deps-only --with-test --yes - - opam exec -- dune build --root "$workspace_root" --display=short - opam exec -- dune runtest --root "$workspace_root" --display=short - opam exec -- dune install --root "$workspace_root" - opam exec -- sh -c 'cat samples/show_abi.ml | ocaml' + # `ocaml` reading a script on stdin exits 0 even when the toplevel + # errors (e.g. an unbound module), so assert on the output rather + # than trusting the exit code. + opam exec -- sh -c 'cat samples/show_abi.ml | ocaml' | tee /tmp/abi.out + grep -qF "Ok Dkml_c_probe.C_abi.V4.$expected" /tmp/abi.out test-with-setup-ocaml: strategy: @@ -151,51 +194,21 @@ jobs: - ubuntu-latest - macos-latest ocaml-compiler: - - "4.13.x" + - "4.14.x" runs-on: ${{ matrix.os }} name: test-ocaml / ${{ matrix.os }}-${{ matrix.ocaml-compiler }} - # Windows on ocaml/setup-ocaml has been flaky ... let's not stop the Tests simply because it is flaky. - # Confer: ocaml/setup-ocaml issue no. 529 - # Also: - # -> installed opam-depext.1.1.5 - - # #===ERRORwhile compiling depext-cygwinports.0.0.9===========================# - # #context 2.0.10 | win32/x86_64 | ocaml-variants.4.13.1+mingw64c | git+https://github.com/fdopen/opam-repository-mingw.git#opam2 - # #path D:/a/dkml-c-probe/dkml-c-probe/_opam/.opam-switch/build/depext-cygwinports.0.0.9 - # #command D:\cygwin\bin\make.exe -j2 all - # #exit-code 2 - # #env-file D:/.opam/log/depext-cygwinports-1604-d2d111.env - # #output-file D:/.opam/log/depext-cygwinports-1604-d2d111.out - # ### output ### - # # ocamlopt -g str.cmxa unix.cmxa config_file.mli config_file.ml run.mli run.ml cygwin.mli cygwin.ml -o cygwin-install.exe - # # x86_64-w64-mingw32-gcc -O2 -fno-strict-aliasing -fwrapv -mms-bitfields -s symlink.c -o pkg-config.exe - # # ** Fatal error: Cannot run cygpath -m "libmsvcrt" "libmsvcrt.lib" "libmsvcrt.dll.a" "libmsvcrt.a" "D:/a/dkml-c-probe/dkml-c-probe/_opam/lib/ocaml\libmsvcrt" "D:/a/dkml-c-probe/dkml-c-probe/_opam/lib/ocaml\libmsvcrt.lib" "D:/a/dkml-c-probe/dkml-c-probe/_opam/lib/ocaml\libmsvcrt.dll.a" "D:/a/dkml-c-probe/dkml-c-probe/_opam/lib/ocaml\libmsvcrt.a" "D:/a/dkml-c-probe/dkml-c-probe/_opam/lib/ocaml\flexdll\libmsvcrt" "D:/a/dkml-c-probe/dkml-c-probe/_opam/lib/ocaml\flexdll\libmsvcrt.lib" "D:/a/dkml-c-probe/dkml-c-probe/_opam/lib/ocaml\flexdll\libmsvcrt.dll.a" "D:/a/dkml-c-probe/dkml-c-probe/_opam/lib/ocaml\flexdll\libmsvcrt.a" "/usr/lib/gcc/x86_64-w64-mingw32/11/libmsvcrt" "/usr/lib/gcc/x86_64-w64-mingw32/11/libmsvcrt.lib" "/usr/lib/gcc/x86_64-w64-mingw32/11/libmsvcrt.dll.a" "/usr/lib/gcc/x86_64-w64-mingw32/11/libmsvcrt.a" "/usr/x86_64-w64-mingw32/lib/x86_64-w64-mingw32/11/libmsvcrt" "/usr/x86_64-w64-mingw32/lib/x86_64-w64-mingw32/11/libmsvcrt.lib" "/usr/x86_64-w64-mingw32/lib/x86_64-w64-mingw32/11/libmsvcrt.dll.a" "/usr/x86_64-w64-mingw32/lib/x86_64-w64-mingw32/11/libmsvcrt.a" "/usr/x86_64-w64-mingw32/lib/libmsvcrt" "/usr/x86_64-w64-mingw32/lib/libmsvcrt.lib" "/usr/x86_64-w64-mingw32/lib/libmsvcrt.dll.a" "/usr/x86_64-w64-mingw32/lib/libmsvcrt.a" "/usr/x86_64-w64-mingw32/sys-root/mingw/lib/x86_64-w64-mingw32/11/libmsvcrt" "/usr/x86_64-w64-mingw32/sys-root/mingw/lib/x86_64-w64-mingw32/11/libmsvcrt.lib" "/usr/x86_64-w64-mingw32/sys-root/mingw/lib/x86_64-w64-mingw32/11/libmsvcrt.dll.a" "/usr/x86_64-w64-mingw32/sys-root/mingw/lib/x86_64-w64-mingw32/11/libmsvcrt.a" "/usr/x86_64-w64-mingw32/sys-root/mingw/lib/libmsvcrt" "/usr/x86_64-w64-mingw32/sys-root/mingw/lib/libmsvcrt.lib" "/usr/x86_64-w64-mingw32/sys-root/mingw/lib/libmsvcrt.dll.a" "/usr/x86_64-w64-mingw32/sys-root/mingw/lib/libmsvcrt.a" - # # File "caml_startup", line 1: - # # Error: Error during linking (exit code 2) - # # make: *** [Makefile:24: cygwin-install.exe] Error 2 + # Windows on ocaml/setup-ocaml has been flaky ... let's not stop the + # Tests simply because it is flaky. continue-on-error: ${{ startsWith(matrix.os, 'windows-') }} steps: - name: Checkout code - uses: actions/checkout@v3 - - - name: Hack Git CRLF for ocaml/setup-ocaml issue no. 529 - if: ${{ startsWith(matrix.os, 'windows-') }} - run: | - & "C:\Program Files\Git\bin\git.exe" config --system core.autocrlf input + uses: actions/checkout@v6 - name: OCaml ${{ matrix.ocaml-compiler }} with Dune cache - uses: ocaml/setup-ocaml@v2 - if: ${{ !startsWith(matrix.os, 'windows-') }} + uses: ocaml/setup-ocaml@57d9aa353e8d39677b1b9fc39637d48f27fe4a91 # v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} dune-cache: true - - name: OCaml ${{ matrix.ocaml-compiler }} without Dune cache - uses: ocaml/setup-ocaml@v2 - if: ${{ startsWith(matrix.os, 'windows-') }} - with: - ocaml-compiler: ${{ matrix.ocaml-compiler }} - dune-cache: false - cache-prefix: v3 - name: Install Opam dependencies run: opam install . --deps-only --with-test --yes - name: Build OCaml @@ -205,196 +218,7 @@ jobs: - name: Install dkml-c-probe run: opam exec -- dune install - name: Display probe - run: opam exec -- sh -c 'cat samples/show_abi.ml | ocaml' - - setup-dkml: - uses: "diskuv/dkml-workflows/.github/workflows/setup-dkml.yml@v0" - permissions: - # By explicitly setting at least one permission, all other permissions - # are set to none. setup-dkml.yml does not need access to your code! - # Verify in 'Set up job > GITHUB_TOKEN permissions'. - actions: none - with: - ocaml-compiler: 4.12.1 - - test-with-setup-dkml: - needs: setup-dkml - strategy: - fail-fast: false - matrix: - include: - - os: windows-2019 - abi-pattern: win32-windows_x86 - dkml-host-abi: windows_x86 - opam-root: D:/.opam - default_shell: msys2 {0} - msys2_system: MINGW32 - msys2_packages: mingw-w64-i686-pkg-config - bits: "32" - - os: windows-2019 - abi-pattern: win32-windows_x86_64 - dkml-host-abi: windows_x86_64 - opam-root: D:/.opam - default_shell: msys2 {0} - msys2_system: CLANG64 - msys2_packages: mingw-w64-clang-x86_64-pkg-config - bits: "64" - - os: macos-latest - abi-pattern: macos-darwin_all - dkml-host-abi: darwin_x86_64 - crosscompile-toolchain: darwin_arm64 - crosscompile-dune-context: | - (context (default (targets native darwin_arm64))) - default_shell: sh - opam-root: /Users/runner/.opam - bits: "64" - - os: ubuntu-latest - abi-pattern: manylinux2014-linux_x86 - bits: "32" - default_shell: sh - dkml-host-abi: linux_x86 - opam-root: .ci/opamroot # local directory of $GITHUB_WORKSPACE so available to dockcross - - os: ubuntu-latest - abi-pattern: manylinux2014-linux_x86_64 - bits: "64" - default_shell: sh - dkml-host-abi: linux_x86_64 - opam-root: .ci/opamroot # local directory of $GITHUB_WORKSPACE so available to dockcross - runs-on: ${{ matrix.os }} - name: test-dkml / ${{ matrix.abi-pattern }} - defaults: - run: - shell: ${{ matrix.default_shell }} - env: - OPAMROOT: ${{ matrix.opam-root }} - COMPONENT: dkml-component-staging-opam${{ matrix.bits }} - steps: - - name: Checkout - uses: actions/checkout@v3 - - - uses: actions/download-artifact@v3 - with: - path: .ci/dist - - - name: Install MSYS2 (Windows) - if: startsWith(matrix.dkml-host-abi, 'windows_') - uses: msys2/setup-msys2@v2 - with: - msystem: ${{ matrix.msys2_system }} - update: true - install: >- - ${{ matrix.msys2_packages }} - wget - make - rsync - diffutils - patch - unzip - git - tar - - - name: Import build environments from setup-dkml - run: | - ${{ needs.setup-dkml.outputs.import_func }} - import ${{ matrix.abi-pattern }} - - - name: Cache Opam downloads by host - uses: actions/cache@v3 - with: - path: ${{ matrix.opam-root }}/download-cache - key: ${{ matrix.dkml-host-abi }} - - - name: Dune-ify non-Dune Opam dependencies - run: | - opamrun repository add dune-universe git+https://github.com/dune-universe/opam-overlays.git#master - opamrun pin astring --no-action --yes -k version 0.8.5+dune - opamrun pin cmdliner --no-action --yes -k version 1.1.1+dune - opamrun pin fmt --no-action --yes -k version 0.8.9+dune - opamrun pin logs --no-action --yes -k version 0.7.0+dune2 - opamrun pin seq --no-action --yes -k version base+dune - - - name: Cache Opam binaries - uses: actions/cache@v3 - with: - path: _opambin - key: ${{ matrix.dkml-host-abi }} - - - name: Configure Opam for cross-compilation - if: matrix.crosscompile-dune-context - run: | - projectrundir=$(opamrun exec -- pwd) - - # Create / cache opam-installer which is not always present from setup-dkml.yml - if [ ! -x _opambin/bin/opam-installer ] && [ ! -x _opambin/bin/opam-installer.exe ]; then - # Get the binary - opamrun install opam-installer --yes - opaminstaller="$(opamrun var opam-installer:bin)/opam-installer" - # Copy the binary - install -d _opambin/bin - if [ -x "$opaminstaller.exe" ]; then - install "$opaminstaller.exe" _opambin/bin/opam-installer.exe - else - install "$opaminstaller" _opambin/bin/opam-installer - fi - # Remove all packages which just got installed (is there any easy way to do that?); - # technically we only need to remove those that should cross-compiled later. - # But for consistency between cache hit and cache miss, better to remove everything - # installed during `opam install opam-installer`. - opamrun remove cmdliner cppo ocamlgraph opam-file-format re seq stdlib-shims --yes - opamrun list - fi - opaminstaller=$projectrundir/_opambin/bin/opam-installer - - # Install ocamlfind since without it opam-installer can give errors trying - # to find the `ocamlfind` executable - opamrun install ocamlfind --yes - opamrun remove cmdliner seq --yes - - # Inject [dune-workspace] into almost all Opam packages - dunecontext='${{ matrix.crosscompile-dune-context }}' - option_args=$(printf 'pre-build-commands=["%s" "%s" "%s" "%s"]' \ - "$projectrundir/samples/crosscompiling-workspace-generator.sh" \ - '%{name}%' \ - '%{_:build}%/dune-workspace' \ - "$dunecontext" \ - ) - opamrun option "$option_args" - - # Add [dune-workspace] to dkml-c-probe (this package) - "$projectrundir/samples/crosscompiling-workspace-generator.sh" \ - "dkml-c-probe" \ - "dune-workspace" \ - "$dunecontext" - - # Each Opam package must install its cross-compiled libraries into Opam switch - option_args=$(printf 'post-install-commands=["%s" "%s" "%s" "%s" "%s" "%s" "%s" "%s" "%s"]' \ - "$projectrundir/samples/crosscompiling-opam-installer.sh" \ - "$opaminstaller" \ - "%{name}%-${{ matrix.crosscompile-toolchain }}.install" \ - "%{name}%" \ - "%{lib}%" \ - "%{man}%" \ - "%{prefix}%" \ - "%{stublibs}%" \ - "%{toplevel}%" \ - ) - opamrun option "$option_args" - - # Diagnostics: Show the options - opamrun option - - - name: Install Opam dependencies - run: opamrun install . --deps-only --with-test --yes - - name: Build OCaml - run: opamrun exec -- dune build --display=short - - name: Test OCaml - run: opamrun exec -- dune runtest --display=short - - name: Install dkml-c-probe - run: opamrun install . --yes - - name: Display probe of default toolchain - run: opamrun exec -- sh -c 'cat samples/show_abi.ml | ocaml' - - name: Display source for cross-compiled toolchain - if: matrix.crosscompile-toolchain + # `ocaml` on stdin exits 0 even on a toplevel error, so assert that a + # successful `Ok ` result was actually printed. run: | - prefix=$(opamrun var prefix) - opamrun exec -- cat "$prefix/${{ matrix.crosscompile-toolchain }}-sysroot/lib/dkml-c-probe/c_abi.ml" + opam exec -- sh -c 'cat samples/show_abi.ml | ocaml | tee abi.out; grep -qF "Ok Dkml_c_probe.C_abi.V4." abi.out' From 0dac90045b2c5c09bd26e25c1797db2e09f9d963 Mon Sep 17 00:00:00 2001 From: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> Date: Mon, 3 Aug 2026 12:27:30 -0700 Subject: [PATCH 3/4] Pin syntax.yml actions for the Actions allowlist The markdown-link-check and shellcheck actions were referenced by floating tags (@v1, @master) that are not on the repository's curated Actions allowlist, so the workflow failed at startup once Actions was enabled. + pin gaurav-nelson/github-action-markdown-link-check to v1.0.17 (SHA) + pin ludeeus/action-shellcheck to v2.0.0 (SHA) + bump actions/checkout from @master to the allowlisted @v6 Signed-off-by: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> --- .github/workflows/syntax.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/syntax.yml b/.github/workflows/syntax.yml index 404ed06..e1deee2 100644 --- a/.github/workflows/syntax.yml +++ b/.github/workflows/syntax.yml @@ -6,10 +6,10 @@ jobs: syntax-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v6 - name: Check Markdown links - uses: gaurav-nelson/github-action-markdown-link-check@v1 + uses: gaurav-nelson/github-action-markdown-link-check@3c3b66f1f7d0900e37b71eca45b63ea9eedfce31 # v1.0.17 with: use-verbose-mode: 'yes' - name: Run ShellCheck - uses: ludeeus/action-shellcheck@master + uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0 From 804a56534094f71333338a32d28ed180ea08f205 Mon Sep 17 00:00:00 2001 From: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> Date: Mon, 3 Aug 2026 12:27:32 -0700 Subject: [PATCH 4/4] Prepare 4.0.0 release `dune build @runtest @runmarkdown --auto-promote` An interface module V ships in opam major version n: V4 belongs to 4.0.0, restoring the correspondence broken when the 3.3.0 tag shipped V4 under a 3.x version. 3.3.0 was never published to opam and is superseded by this release. Signed-off-by: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> --- CHANGES.md | 34 +++++++++++++++++++++++++++++++- CONTRIBUTORS.md | 8 +++++++- README.md | 40 +++++++++++++++++++++++++------------- dkml-c-probe.opam | 8 ++++---- dkml-c-probe.opam.template | 6 +++--- dune-project | 2 +- 6 files changed, 74 insertions(+), 24 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 1b9b9f1..b9ba690 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,36 @@ -## 3.3.0 +## 4.0.0 + +* `V4` gains full musl parity on Linux: new ABIs `Linux_x86_musl` and + `Linux_arm64_musl` join `Linux_x86_64_musl`. The `` / + `__GLIBC__` test now covers the `__i386__` and `__aarch64__` branches of + the C header (new macros `DKML_ABI_linux_x86_musl` and + `DKML_ABI_linux_arm64_musl`). +* `V1`-`V3` report the new musl ABIs under their glibc names (`Linux_x86`, + `Linux_arm64`), matching the existing `Linux_x86_64_musl` -> `Linux_x86_64` + behavior. In `V1`, an x86 musl host gets the pre-existing `Result.error` + because `V1` never had `Linux_x86`. +* BREAKING (relative to the unpublished 3.3.0 git tag): the `V4.t_abi` + constructor list stays alphabetical, so the insertions change the ranks of + later constructors. Rebuild anything that marshalled `V4.t_abi` values. + 3.3.0 was tagged but never published to opam; use 4.0.0 instead. +* `C_conf.load ()` now uses `V4` (was `V3`): on musl hosts the ABI-specific + environment variable suffix is now e.g. `DEFAULT_LINUX_X86_64_MUSL` instead + of `DEFAULT_LINUX_X86_64`. glibc, Windows, and macOS hosts are unchanged. +* Versioning policy restored: interface module `V` ships in major version + `n` (`V4` <-> 4.0.0, as `V3` <-> 3.0.0 and `V2` <-> 2.0.0). +* Known gap: the Linux arm32 ABIs (`linux_arm32v6`, `linux_arm32v7`) have no + musl variants yet. +* CI: GitHub Actions re-enabled and every workflow brought onto the + repository's curated Actions allowlist (third-party actions SHA-pinned). + The `Tests` workflow now also covers musl: a C-header probe on Alpine + (musl) and Debian (glibc) across x86_64, x86 and arm64, and the full + dune-configurator path on a real musl host, alongside the BSD guests + (upgraded `cross-platform-actions`) and the Windows/macOS/Linux matrix on + `ocaml/setup-ocaml` (replacing the former DkML MSVC/MSYS2 + manylinux + reusable-workflow matrix, whose actions are not allowlisted). `syntax.yml` + upgraded to pinned `markdown-link-check` and `action-shellcheck`. + +## 3.3.0 (git tag only; never published to opam — superseded by 4.0.0) * Add `V4` with the new ABI `Linux_x86_64_musl`: a Linux x86_64 host whose C compiler targets a non-glibc libc (musl). Detection pulls in `` diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 8fcc5c4..dc0f69a 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -25,7 +25,13 @@ If you would like to add a new ABI, you will need to: * Add the ABI introspection test to the C header at [src/config/dkml_compiler_probe.h](src/config/dkml_compiler_probe.h). * Create a new versioned module (ex. `module V123`) of the ABI enumeration in [src/config/discover.ml](src/config/discover.ml). See how `module V2` extends `module V1` in a backwards-compatible way. -* Update the `(version xxx)` in [dune-project](dune-project) +* Extend `adjust_pre_v_abi` in [src/config/discover.ml](src/config/discover.ml) + so the older modules degrade the new ABI: to the closest pre-existing ABI if + older consumers always saw that value on such hosts (like the musl ABIs), or + to `Result.error` if the ABI is genuinely new to them (like the BSDs). +* Update the `(version xxx)` in [dune-project](dune-project). A new + `module V` must ship as major version `n.0.0`: the interface module + version matches the opam major version. Before submitting your PR make sure you have: 1. Run `dune build` diff --git a/README.md b/README.md index e208580..2cca521 100644 --- a/README.md +++ b/README.md @@ -195,9 +195,11 @@ module V4 : | Linux_arm32v6 | Linux_arm32v7 | Linux_arm64 + | Linux_arm64_musl | Linux_x86 | Linux_x86_64 | Linux_x86_64_musl + | Linux_x86_musl | NetBSD_x86_64 | OpenBSD_x86_64 | Windows_arm32 @@ -350,9 +352,24 @@ The header file will be available as the following expressions: # else # define DKML_OS_NAME "Linux" # define DKML_OS_Linux + /* musl does not define an identifying macro. Pull in + (glibc and uclibc define __GLIBC__ there; musl defines nothing) + and treat a hosted Linux without __GLIBC__ as musl. */ +# if defined(__has_include) +# if __has_include() +# include +# endif +# else +# include +# endif # if __aarch64__ -# define DKML_ABI "linux_arm64" -# define DKML_ABI_linux_arm64 +# if defined(__GLIBC__) +# define DKML_ABI "linux_arm64" +# define DKML_ABI_linux_arm64 +# else +# define DKML_ABI "linux_arm64_musl" +# define DKML_ABI_linux_arm64_musl +# endif /* __GLIBC__ */ # elif __arm__ # 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__) # define DKML_ABI "linux_arm32v6" @@ -362,16 +379,6 @@ The header file will be available as the following expressions: # define DKML_ABI_linux_arm32v7 # endif /* __ARM_ARCH_6__ || ..., __ARM_ARCH_7__ || ... */ # elif __x86_64__ - /* musl does not define an identifying macro. Pull in - (glibc and uclibc define __GLIBC__ there; musl defines nothing) - and treat a hosted Linux x86_64 without __GLIBC__ as musl. */ -# if defined(__has_include) -# if __has_include() -# include -# endif -# else -# include -# endif # if defined(__GLIBC__) # define DKML_ABI "linux_x86_64" # define DKML_ABI_linux_x86_64 @@ -380,8 +387,13 @@ The header file will be available as the following expressions: # define DKML_ABI_linux_x86_64_musl # endif /* __GLIBC__ */ # elif __i386__ -# define DKML_ABI "linux_x86" -# define DKML_ABI_linux_x86 +# if defined(__GLIBC__) +# define DKML_ABI "linux_x86" +# define DKML_ABI_linux_x86 +# else +# define DKML_ABI "linux_x86_musl" +# define DKML_ABI_linux_x86_musl +# endif /* __GLIBC__ */ # elif defined(__ppc64__) || defined(__PPC64__) # define DKML_ABI "linux_ppc64" # define DKML_ABI_linux_ppc64 diff --git a/dkml-c-probe.opam b/dkml-c-probe.opam index c672d21..ec040f9 100644 --- a/dkml-c-probe.opam +++ b/dkml-c-probe.opam @@ -1,6 +1,6 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -version: "3.3.0" +version: "4.0.0" synopsis: "Cross-compiler friendly ABI and library discovery for OCaml's native C compilers" description: """ @@ -32,8 +32,8 @@ build: [ ["dune" "build" "-p" name "-j" jobs "@doc"] {with-doc} ] # dkml-c-probe has strong backwards-compatibility. -# Any 3.x minor version is maintained for the latest patch version. +# Any 3.x or 4.x minor version is maintained for the latest patch version. # Please upgrade if there is a patch version for a minor release; # the patch generally means there was an important bug fix. -# Also the latest version is maintained, in case it gets to 4.x.x. -x-maintenance-intent: ["latest" "3.(any).(latest)"] +# Also the latest version is maintained. +x-maintenance-intent: ["latest" "4.(any).(latest)" "3.(any).(latest)"] diff --git a/dkml-c-probe.opam.template b/dkml-c-probe.opam.template index 87386ab..0b56a44 100644 --- a/dkml-c-probe.opam.template +++ b/dkml-c-probe.opam.template @@ -8,8 +8,8 @@ build: [ ["dune" "build" "-p" name "-j" jobs "@doc"] {with-doc} ] # dkml-c-probe has strong backwards-compatibility. -# Any 3.x minor version is maintained for the latest patch version. +# Any 3.x or 4.x minor version is maintained for the latest patch version. # Please upgrade if there is a patch version for a minor release; # the patch generally means there was an important bug fix. -# Also the latest version is maintained, in case it gets to 4.x.x. -x-maintenance-intent: ["latest" "3.(any).(latest)"] +# Also the latest version is maintained. +x-maintenance-intent: ["latest" "4.(any).(latest)" "3.(any).(latest)"] diff --git a/dune-project b/dune-project index 3db96c8..0d83b8d 100644 --- a/dune-project +++ b/dune-project @@ -2,7 +2,7 @@ (name dkml-c-probe) -(version 3.3.0) +(version 4.0.0) (using mdx 0.1)