dk packages /

CommonsLang_OCaml 0.1.20260910155123

Relocatable OCaml compiler toolchains and developer tools (the OCaml compiler, flexdll, dune, opam, and Diskuv's DkML MSVC track) as dk packages for Windows, Linux, and macOS.

Apache-2.0 AND LGPL-2.1-only WITH OCaml-LGPL-linking-exception AND LGPL-2.0-only WITH OCaml-LGPL-linking-exception AND LGPL-3.0-or-later AND GPL-2.0-only AND Zlib AND MIT AND GPL-3.0-or-later AND BSD-2-Clause AND Info-ZIP Source → Generated

Relocatable OCaml compiler toolchains and developer tools (the OCaml compiler, flexdll, dune, opam, and Diskuv's DkML MSVC track) as dk packages for Windows, Linux, and macOS.

CommonsLang_OCaml builds and redistributes an OCaml developer toolchain (the OCaml compiler, runtime, and standard library at 4.14.3, 5.4.1, and 5.5.0-beta1, the flexdll linker, dune 3.23.1, and opam 2.5.1) across the dk build system's Windows, Linux, and macOS slots. It also ships Diskuv's Apache-2.0 DkML MSVC track and an MSYS2 tree used to build and run the Windows toolchain. Because it is assembled from many upstreams, its redistributed payload carries several licenses in combination.

Resolution of imports

When a workspace drives per-package opam builds through Dk.OpamLock.GenerateDriver + Dk.OpamBuild.F_BuildLockedPackage and declares one or more package-import sources (imports[]), the generated driver reuses a locked opam package that a source already built and distributes, fetching the prebuilt object lazily. Resolution runs per package, against the imports[] sources in precedence order.

  1. Read each source's own opam lock. Every import source ships the exact opam lock it was built from. For a CommonsBase_Dk.Dk0.Pkg source that is the dk-opam-lock.jsonc member of its localsrc (CommonsBase_Dk.Dk0.MlFrontSource@<mv>), fetched from the pinned import. That lock is authoritative for which opam package and version each of the source's objects contains.

  2. Map object id to opam package and version. For an opam package <name>.<opamver> in a source's lock, the source provides the dk object <source-lib>.<Segment(name)>@<module-version>, whose version component is the source's release version (imports[].version, for example @2.4.2). The opam version is recorded only in the source's lock, which is what step 3 matches against.

  3. Match on the opam name, version, and dependency environment. For each opam <name>.<needver> the consumer's (with-test) lock requires, a source matches when its lock pins <name> at the same <needver> and records the same dependency environment for it (step 5). On the first matching source the package is imported: the driver stages it with get-object <source-lib>.<Seg>@<mv>, lazily, fetched when a build needs its install.zip, and emits no local build form. A package that no source provides at the required version and dependency environment is built locally through F_BuildLockedPackage, with its own dependencies resolved the same way.

  4. The compiler matches through the top-level ocaml field. Each lock records the OCaml compiler its packages are built with in a top-level ocaml field, a full module id such as CommonsLang_OCaml.DkML@4.14.3 (or a CommonsLang_OCaml.Base@5.5.x for a 5.5 toolchain); a lock without the field takes the default CommonsLang_OCaml.DkML@4.14.3. Dk.OpamLock.GenerateDriver reads the ocaml field from both the consumer's lock and each source's lock (already fetched in step 1) and passes it to F_BuildLockedPackage as the ocaml= argument, along with dune=CommonsLang_OCaml.Dune@<v> and (Windows) msys2=CommonsLang_OCaml.MSYS2@<v>. An imported package ships compiled .cmi/.cmx/.cmxa, whose magic numbers are fixed by the compiler, so a source is consumable only when its lock's ocaml equals the consumer's. The dune and msys2 ids leave no trace in the compiled artifacts and stay out of the match.

  5. Match on the dependency environment. A package's built install.zip is a function of which of its optional dependencies were present at build time: the opam solver folds each optional dependency that lands in the solved closure into the package's depends name-set, so that set records the environment. A source's package matches only when, for the package and for every package in its dependency closure, the source's lock and the consumer's lock record the same version and the same depends name-set (compared as a set, since the recorded order follows discovery). Adding an optional dependency to the consumer changes that package's depends set and builds it locally, the way opam rebuilds a package when its optional dependencies change; the same holds when a dependency deeper in the closure resolves to a different version or a different depends set. A package built locally for this reason forces every package whose closure contains it to build locally too. A package the compiler builds into the toolchain, or a purely virtual package, stays out of this comparison; the compiler is already fixed by step 4.

Dk.OpamLock.GenerateDriver imports a package P from a source S when each of these variables is equal between the consumer's lock and S's lock:

  • ocaml: the top-level compiler module id (a lock without the field carries CommonsLang_OCaml.DkML@4.14.3)
  • version(P): the opam version S pins for P
  • depends(P): P's depends name-set, with the solved-closure optional dependencies folded in, compared as a set
  • version(D): for every package D in P's dependency closure, the opam version S pins for D
  • depends(D): for every package D in P's dependency closure, D's depends name-set, compared as a set

Under skiplocal a package recorded "local":"t" is built in-tree and is never imported. A package that fails any variable is built locally, and that outcome propagates to every package whose closure contains it. The compiler content is checked again at build time by the .dk-provenance gate.

Dk.OpamLock

Run one rule of the CommonsLang_OCaml.Dk.OpamLock scriptmodule so its author-time OpamLock uirule ships in this distribution. Running any rule of a scriptmodule brings in the whole scriptmodule; the marker output is otherwise unused. The value-id is harvested from the first CI run (the DkML pattern).

The @1.1.16 revision emits deterministic archives from the generators: GenerateSrc's localized-source form and GenerateDriver's legacy mergedprefix driver archive with the engine's in-process --zip special form (same inputs, same bytes on every platform), and the emitted Src form drops its S7z dependency. Building the emitted forms requires dk 2.4.2.342 or later.

The @1.1.15 revision declares the uirule capability manifest (M.uirule_capabilities): each OpamLock uirule names the capabilities it may request (Solve/Adopt/Refresh/OpamVenv: run+write; the three Generate* rules and GenerateForms: write). An engine >= 2.4.2.339 enforces the manifest as an upper bound and lists every declared capability in its trust prompts and suggested trust grant commands, so a consumer grants a rule's full need in one command; older engines ignore the field. No rule body changed.

The @1.1.14 revision completes the adoption generators. GenerateSrc emits the assembled tree's dune-workspace root marker (the project's own file, or a minimal (lang dune <X>) synthesized into the dk-owned dk-src/ directory and registered by Adopt): an assembly without the marker made every warm run-object of the final executable re-derive and re-save its traces instead of a silent cache read. Adopt forwards its derived root to the form generators, so the reuse_lock=t path works against a pre-@1.1.8 minimal-stamp lock whose generated.roots is not recorded.

The @1.1.13 revision makes the solve universe hermetic and re-adoption non-destructive. The opam-lock helper (Apparatus.OpamLockHelper@1.0.16) registers each pin-table repository under a URL-derived dk-owned name and selects only those names for its ephemeral switch, so a pre-existing repository in the machine's opam root can never supply the solve universe (a stale root's default silently overrode the pin table's snapshot, hiding the pinned dune/ocaml versions and surfacing as an unrelated-looking conflict on any constrained dependency); the ephemeral switch is recreated on every solve, the constraints repository name embeds the work directory so concurrent solves sharing one root cannot repoint each other, and every pin NAME VER is verified visible in the universe before solving, failing with a message that names the repository that should contain it. Adopt re-solves with --with-test (the canonical adoption lock is the with-test lock; wtest=f opts out), forwards wdoc=, and accepts reuse_lock=t to keep an existing committed lock untouched and regenerate only the build forms.

The @1.1.12 revision teaches the driver machinery the closure shape that pairs with Dk.OpamBuild's F_BuildLockedClosure (see "## Dk.OpamBuild"). GenerateDriver keys its emission off the rulefn family: an F_BuildLockedClosure rulefn -- the default when the import declares one -- emits ONE run-function precommand carrying the whole parameter set (the closure rule re-derives the per-package plan from the lock at build time), while an F_BuildLockedPackage rulefn emits the per-package lines byte-identically to @1.1.11 so existing drivers regenerate unchanged. Import resolution stays at author time (the emitted line carries resolved impdep_ ids, since a build rule cannot read the impsrclock project files), and the line keeps a literal ocaml= token that OpamVenv still reads off the raw driver text. Refresh resolves its target per driver: an explicit rulefn= wins; with the lock on disk a stamped driver upgrades to the newest F_BuildLockedClosure the import declares (a deliberate shape change that re-keys every Pkg object id, so it happens only when the lock -- the regeneration source -- is present); a stampless driver adopts the stamp in the per-package shape first (preserving the pkg=-token reproducibility guard, which a shape change would defeat); and a lockless (consume-from-archive) driver substitutes only within its stamped rulefn's family. mode=check compares within family and flags a per-package driver STALE when the import provides the closure rule and the lock is on disk. Its Export value-id is per-version and is harvested from CI as usual.

The @1.1.11 revision reduces what a maintainer types to adopt an opam+dune project. GenerateDriver derives its nine arguments from one pkg=MODULE@VERSION (formid, pkgpath, version, localsrc, and the out path; the roots from the lock's stamped generated.roots; the rulefn from the CommonsLang_OCaml import). GenerateSrc and GenerateFinal generate the localized-source and thin final forms a maintainer used to hand-author, and GenerateForms runs the fixed trio (Src, driver, Final) from one pkg=. Adopt carries a first-time adoption end to end (seed the pin table, solve, generate the forms, register the dk.u assets). Parallel scheduling is the default (sequential=t opts out); Refresh injects sequential=t when replaying a driver that stamped neither, keeping pre-@1.1.11 drivers byte-stable. Every stamped tool id and printed message derives from M.id, and in-module cross-calls dispatch through version-unique function bindings (H.Solve, H.GenerateDriver, ...) rather than the rebindable rules/uirules globals.

The generated driver values.jsonc stays a committed, on-disk artifact rather than being produced dynamically at build time. Dynamic generation is feasible (the engine's x-dynamic-driver-spike cram proves a stub form plus a generator function rule emitting the per-package forms via submit.values), but the committed driver is kept deliberately: the primary metric is characters TYPED, and the driver is machine-generated (GenerateDriver/Adopt write it), so it costs the maintainer zero typed characters -- collapsing it to a stub saves nothing on that metric. Meanwhile the committed driver earns its place: its generated stamp powers Refresh mode=check and the CI refresh-check gate (which compare the on-disk driver), it is on the include path at scan time so a fresh clone builds offline without first running a generator, and its formid is a published contract (the thin form and dist/*.u reference Closure@VER by name). Under the @1.1.12 closure shape the driver is one run-function line, so the auditable build plan a reviewer reads is the committed lock plus the closure rule rather than the enumerated per-package lines; that trade was made for warm-run speed (see "## Dk.OpamBuild"), and the stamp/formid/offline-scan reasons are unchanged. A dynamic driver would additionally retire the staleness-anchor and published-contract subsystem for no gain on the headline metric, so the layer is kept and only its authoring was removed.

The @1.1.10 revision adds the OpamVenv uirule (see "### OpamVenv: a native dune inner loop"). It materializes a real, dune-usable opam prefix from a GenerateDriver mergedprefix=t skiplocal=t closure into the project's opam-venv/ directory, so a developer runs native dune build -w against the working tree instead of dk's per-edit whole-package rebuild. Its Export value-id is per-version and is harvested from CI as usual.

The @1.1.9 revision adds the --wdoc solve: Solve passes --with-doc to opam when wdoc is set and stamps wdoc into the lock generated block, so a with-doc lock carries odoc (the odoc package that dune build @doc needs). The helper moves to Apparatus.OpamLockHelper@1.0.15; the --wdoc content edit rides an Apparatus bump per "## Assets". Its Export value-id is per-version and is harvested from CI as usual.

The @1.1.8 revision makes the two generated artifacts self-describing and adds the Refresh uirule (see "### Refresh: self-describing regeneration"). Solve stamps its roots/pins (and wtest/local_opam_dir when set) into the lock's generated block, and GenerateDriver stamps its full parameter set into a top-level generated member of the driver values.jsonc (right after schema_version). This needs no dk-value schema change: MlFront's value reader pulls members by name and ignores unknown top-level members. The helper moves to Apparatus.OpamLockHelper@1.0.14. Its Export value-id is per-version and is harvested from CI as usual.

The @1.1.7 revision flips the default host-tool ABI (see "### Host tools and the hosttoolabi= escape hatch"): GenerateDriver now emits targetabi=Release.target_abi for ocamlfind/ocamlbuild and takes an optional hosttoolabi=SLOT parameter that restores Release.execution_abi for a matrix with a host-unemulatable cross slot. Its Export value-id is per-version and is harvested from CI as usual.

The @1.1.6 revision is behaviorally identical to @1.1.5. It exists because the lock-helper assets were collapsed onto the stable assets/opam-lock/dk_opam_lock.ml path (Apparatus.OpamLockHelper@1.0.10, the same bytes as the retired dk_opam_lock_filtered.ml) and every earlier OpamLock revision was retired from HEAD; see "## Assets". Its Export value-id is per-version and is harvested from CI as usual.

How the lock is produced: the OpamLock.Solve uirule launches opam to SOLVE the dependency closure -- it runs opam list --resolve to compute the closure and opam show to read each package's version/source/deps/build commands, and never opam installs. opam has no switch-less solve (the solver needs a switch's repositories, pins, and os/arch variables), so Solve creates an EMPTY opam switch purely as a throwaway resolution context: it adds the pinned repositories, applies the version pins from dk-opam-pins.txt, path-pins the local packages, then resolves. By default that switch is an ephemeral LOCAL switch in the rule's sandbox -- unique per run (no cross-project or cross-run pin contamination, so the lock is reproducible) and removed once the solve finishes; nothing is ever installed into it.

Resolving ocaml 5.1.1 as the solve compiler

ocaml is left unpinned so the solve resolves it from the pinned repository commit to 5.1.1, one of the first releases with the corrected ocaml-env, host-arch and conf-mingw-w64 selectors (pinning ocaml in the shared pin table would break the CI build's DkML toolchain). The pinned commit makes that resolution deterministic, and the version is a solve artifact only: the DkML 4.14.3 toolchain ocaml replaces it at build time.

  • ocaml 5.1.1 carries the corrected ocaml-env, host-arch and conf-mingw-w64 selectors, so the solved closure resolves the right platform packages for every slot.
  • The resolved ocaml version drives per-slot mingw selection: 5.1.1 resolves the Windows_x86 slot to the 32-bit ocaml-env-mingw32 toolchain, where 4.14.2 resolves the wrong 64-bit one.
  • The DkML 4.14.3 toolchain ocaml replaces this solve compiler at build time, so the lock's ocaml and ocaml-base-compiler entries are solve artifacts, not build inputs.

Relocatable ocamlfind and ocamlbuild

The solver still resolves ocamlfind and ocamlbuild (so the rest of the closure resolves and both still satisfy their dependents at the resolved version), but when the helper emits these two entries it substitutes a fixed relocatable specification for the solved source and build commands. A stock findlib bakes an absolute stdlib path into topfind and findlib.conf, and a stock ocamlbuild bakes an absolute libdir. Those absolute paths are valid only in the build tree that produced them, so a prebuilt CommonsBase_Dk.Dk0.Pkg.Ocamlfind or Pkg.Ocamlbuild object is unusable once imported into a different build tree (the imported #use "topfind" loads a dead #directory). The relocatable builds write paths relative to the tool's own location instead, so the imported objects stay usable across build trees.

  • ocamlfind is pinned to dra27's relocatable fork (v1.9.8) and built with -sitelib ".", so findlib writes a relative topfind and findlib.conf.
  • ocamlbuild is pinned to dra27's relocatable-0.14.3 fork (0.14.3 plus the relocatable patch) and built through configure.make with OCAMLBUILD_LIBDIR=.., so ocamlbuild computes its libdir at runtime.
  • Both sources are addressed by git commit, so the pin does not move. The substitution is a property of the lock the helper writes; downstream projects do not list these packages in their dk-opam-pins.txt.
  • The DkML 4.14.3+relocatable toolchain supplies the runtime support the two forks rely on (standard_library_relative, -set-runtime-default), so no compiler change is needed.

Host tools and the hosttoolabi= escape hatch

ocamlfind and ocamlbuild are host tools: their built artifacts are native executables that run on the build host during every later package build (topkg's ocaml pkg/pkg.ml build invokes ocamlfind and ocamlbuild). They are dual-role: the build must RUN them, and their findlib metadata (stdlib path, ocamlmklib/ocamlc config, arch flags) flows into every later package build. Since @1.1.7 GenerateDriver emits targetabi=Release.target_abi for these two by default, so on a cross slot whose host can emulate the target (Windows_x86 under WOW64, Darwin_x86_64 under Rosetta, Linux_x86 under multilib) the metadata matches the target and the tool still runs. This is the dual-role convention in SPECIFICATION "Object Slot ABI"; it was validated as the ocamlearlybird 57fd802 hand edit before it moved into the generator.

The hosttoolabi=SLOT parameter restores Release.execution_abi for a matrix that contains a cross slot the host CANNOT emulate. Building a host tool at the target ABI there produces a binary the host cannot run: on Release.Linux_x86_64_musl the tool links against the target musl toolchain and becomes a musl-dynamic executable, and the glibc host that must run it during the build lacks the musl loader. Worse, the opam-build form is host-keyed and carries the Release.target_abi wildcard in its value-id, so a single such build is stored under one key and shared to every slot -- including the glibc Release.Linux_x86_64 one, where the tool then fails to exec. A consumer whose matrix includes such a slot passes hosttoolabi=Release.execution_abi to keep the host tools host-native; that is the musl hazard the @1.1.4 execution-abi pin originally guarded.

Refresh: self-describing regeneration

Since @1.1.8 the lock and the driver stamp their inputs, and the Refresh uirule reads those stamps back. Solve records roots/pins in the lock's generated block; GenerateDriver records its full parameter set in a top-level generated member of the driver values.jsonc. A consumer therefore regenerates without re-copying the roughly ten parameters that used to live only in prose, and CI detects a stale driver in seconds instead of hours into a release build.

Refresh has four modes. Default (driver) regenerates the driver from the existing lock using the stamped parameters, so a routine repin never silently changes solved package versions; when the lock is not checked in (a consume-from-archive consumer), it substitutes the target rulefn in place, which equals a full regeneration for a rule-version-only move. mode=solve fetches opam hermetically, re-solves the lock from its stamped roots/pins, then regenerates. mode=check is read-only: it compares each driver's stamped rulefn/tool against the newest the imported etc/dk/i/CommonsLang_OCaml.<ver>.values.json declares (and, when the lock is checked in, the stamped lock-sha256 against the lock on disk), prints the exact fix command and exits nonzero when stale. version=NEW rewrites the coupled version/formid/localsrc and regenerates.

A pre-@1.1.8 driver carries no stamp; the first driver-mode Refresh recovers its parameters from the generated text and emits the stamped form. mode=check on such a driver still recovers the rulefn: it fails when that rulefn is stale (the check that would have caught the 2026-08-20 stale-driver incident) and otherwise prints an "unstamped: run Refresh once to adopt" advisory and exits zero, so CI adoption is graceful. Rule versions are co-versioned: Refresh@1.1.12 bakes in its sibling Solve@1.1.12/GenerateDriver@1.1.12/OpamVenv@1.1.12 and, absent an explicit rulefn=, prefers the newest F_BuildLockedClosure the import declares (falling back to F_BuildLockedPackage); rulefn= remains an explicit override.

OpamVenv: a native dune inner loop

dk's incremental unit is the whole package object: editing one source file and rebuilding re-stages the localized-source object and rebuilds the entire leaf package in a fresh hermetic sandbox, which is minutes even with every dependency cached. The OpamVenv uirule hands the inner loop to dune instead. It reuses a GenerateDriver mergedprefix=t skiplocal=t driver -- the whole non-local dependency closure merged into one cached prefix.zip object -- and stages that prefix, the DkML compiler, and dune into the project's opam-venv/ directory, so source opam-venv/env.sh && dune build -w recompiles only the edited module and its dependents.

OpamVenv discovers the dev-prefix driver (the sole one whose stamp carries mergedprefix=t, or an explicit driver=), reads its stamp for the formid, lock, and lock-sha256, and refuses to run when the lock on disk no longer matches that stamp (pointing at the Refresh fix command). It get-objects the prefix for the requested slot= (default: the host execution ABI), rewrites the staged prefix to be relocatable (the @OPAM_IP@ dune-package sentinel and findlib.conf), and writes env.sh/env.ps1/env.cmd activators plus a dk-opam-venv.json stamp. A re-run is a no-op when that stamp still matches (force=t overrides); after a lock change, Refresh regenerates the dev-prefix driver and the next OpamVenv re-materializes.

A caller can also skip the driver: formid=ID@VER names the merged-prefix form to get-object directly, so a project whose merged prefix is a released object (a released with-test closure form, for one) needs no dev-prefix driver of its own, and lock=PATH names the lock that prefix was solved from so the stamp records its sha256 and a lock edit forces a rebuild. The stamp also records the formid, and the up-to-date check compares it, so a new closure version is never mistaken for the old one.

The activators also carry the project's declared environment modifications. A committed dk-opam-venv.envmods beside dk.u (or envmods=PATH) holds one modification per line in the specification's grammar (+NAME=VALUE, <NAME=VALUE, -NAME; # comments; ${PREFIX} and ${DKML} stand for the staged prefix and compiler), planned by the engine's envmod library so the ordering and dedupe are the engine's. Each of env.ps1, env.cmd and env.sh renders the same plan after its toolchain block: a prepend adds no separator when the variable is empty in all three, a removal is Remove-Item, unset or cmd's set "NAME=", and the stamp records the file and its sha256 so an edit re-materializes. A project with no such file gets the same activators as before.

The opam venv is additive and host-only: opam-venv/ and dune's _build/ are invisible to git and to dune. dk0 drops a self-ignoring .gitignore ("*") and a dune ("(dirs)") into its t/ store, and the OpamVenv dialog does the same for opam-venv/, so a host dune build never scans them and the reproducible run-object release build is unchanged. It resolves to the same dependency versions and the same DkML compiler the release build uses, driven from the same lock.

Dk.OpamBuild

Run one rule of the CommonsLang_OCaml.Dk.OpamBuild scriptmodule so its per-package build rule ships in this distribution. Running any rule of a scriptmodule brings in the whole scriptmodule; the marker output is otherwise unused. The value-id is harvested from the first CI run (the DkML pattern).

The @1.0.28 revision emits each external locked source as two mirrors of one asset: the opam content-addressed cache first (the file is named by its hash) and the direct opam URL second (named by its basename). The opam cache mirrors opam-repository sources only, so a cache miss -- the custom relocatable forks (ocamlfind/ocamlbuild) the cache never held -- falls back to the direct URL. The engine tries the mirrors in order and verifies each against the asset sha256, so source.incache, which OpamLock@1.1.19 dropped from the lock, is no longer load-bearing: the CDN serves the sources it holds without giving up correctness for the forks (the earlier @1.0.27 gave up the cache entirely to stop the forks 404ing on the CommonsBase_Dk binary build for MlFront 2.4.3.7). Per-mirror filenames need a dk0 that supports them. Its Export marker value-id is unchanged (Export@1.0.0 form is byte-identical).

The @1.0.26 revision archives the per-package install.zip and the mergedprefix prefix.zip with the engine's in-process --zip special form, which is deterministic: the same install prefix produces the same archive bytes on every platform. Building these forms requires dk 2.4.2.342 or later. S7z remains a dependency only where archives are extracted.

The @1.0.25 revision carries the closure rule with the @1.0.22 reference semantics restored: the toolchain resolves at the drivers' targetabi=Release.target_abi wildcard, which follows dk0's --target-abi through a cross-targeting distribute job whose forms materialize at the host key (the @1.0.23/@1.0.24 request-slot translation shipped 64-bit artifacts under the 32-bit labels and both consumer releases failed their architecture guards). The wildcard makes the resolved document differ per invocation target; the lazy-dependency evidence gap that once let a cross job's resolution reject a native cold High Performance fetch is repaired on the engine side (dk0 2.4.2.338 keeps every distinct imported dependency set and serves a restored pointer when any set matches). Each synthesized .Src bundle now names its origin after the source hash ("src-<first8>"): origin names resolve beyond the single bundle, so when the closure rule registered 57 bundles all named "src" in one submit, one package's opam-cache mirror directory (which embeds that hash's first two hex chars) served every asset and each cold fetch 404ed. And the mergedprefix aggregate merges each package (and each imported package) straight into the shared p/ prefix with merge-object <Pkg> -m ./install.zip -d p/, the value shell's many-merges-into-one-DIR primitive; 7zz remains only to create prefix.zip, since the value shell extracts but does not archive. The single-root path re-emits the root's install.zip. Each repair shipped as a version bump for the same seal reason as @1.0.20, and the re-key each bump causes is deliberate: a consumer release adopting a closure revision must distribute with store: none (or an engine whose distribute fails loudly on stale seals, dk0 2.4.2.336+) so the complete object set publishes -- the 1.3.202608262345 ocamlearlybird release shipped an incomplete set (restored store, unchanged thin-leaf value-id served stale, new Closure object and Pkg.*.Src bundles never published) and 404ed every cold High Performance fetch. The Export value-id is unchanged (Export@1.0.0 form is byte-identical).

The @1.0.20 revision adds F_BuildLockedClosure beside F_BuildLockedPackage (both share one per-package form synthesis, H.synth_package, so they cannot drift). It supersedes @1.0.19, which introduced the same rule but whose fix for the aggregate staging (a spurious -m ./install.zip that unpacked each package's install.zip instead of placing it, breaking the final copy) could not ship as a same-version body edit: the pre-2.4.2.336 distribute engine re-registered and sealed the previous release's stale @1.0.19 body. @1.0.20 is a fresh version so the fixed body ships cleanly. The closure rule builds the entire locked closure from ONE rule instantiation: it fetches and decodes the lock once, then a single submit registers every per-package build form (each still its own content-addressed Pkg object) plus an aggregate .Built output form whose unordered get-object precommands demand every package concurrently. Motivation: a rule instantiation can never be trace-cached (its scriptmodule dependency has no cloud-persistent hash, and a submit's registrations are side effects a cached value could not replay), so a warm run re-instantiated the per-package rule once per package -- roughly 9 s of a 14 s warm run on ocamlearlybird's 58-package closure, each force re-decoding the whole 83 KB lock in lua-ml. Paired with Dk.OpamLock@1.1.12's one-line closure driver (whose GenerateDriver and Refresh resolve the rule version from the import, so they pick up @1.0.20 without a co-version bump), the instantiation is paid once. The trade is deliberate and carries object-id churn: per-package Pkg value-ids derive from the canonical id of the values document that registers them, so registering the whole closure in ONE document changes every Pkg value-id (a one-time full closure rebuild plus a \dk.object re-harvest in every consumer, the same churn a lock change causes) and additionally couples them -- any later lock edit that alters one package's form re-keys the whole closure, where the per-package shape re-keyed only the edited package. Existing per-package drivers keep building: F_BuildLockedPackage is retained unchanged, and the lockless Refresh path refuses to cross rule families. No asset versions change (the closure rule reuses the same wrapper/tables/seq-META assets), and Export's submitted form is byte-identical (its declared id is pinned at Export@1.0.0), so the marker value-id stays shared and no new harvest is needed.

The @1.0.1 revision ships alongside @1.0.0 for the MlFront with-test closure (short-circuit filter eval, an arch fenv, and the dune-install --prefix repair); its per-slot value-id is likewise harvested from the first CI run.

The @1.0.8 revision ships alongside @1.0.7: it fetches the build wrapper from the fresh Apparatus.OpamBuildWrapper@1.0.4 (build-locked-package-v2.sh), whose @INSTALL@ installs Windows executables under their .exe name so cmd.exe can run a staged ocamlbuild. @1.0.4 is a new asset module because an in-place edit of @1.0.1 does not propagate through a distribution (value id hashes the invocation, not the content). All other assets stay at @1.0.1; the Export marker value-id is shared with @1.0.0/@1.0.6/@1.0.7, so no new harvest is needed.

The @1.0.9 revision supersedes @1.0.8's wrapper: @1.0.4's @INSTALL@ only added .exe when a literal <name>.exe existed, but DkML's ocamlopt emits <name> with no .exe when -o carries an extension (ocamlbuild.native), so nothing matched and the staged ocamlbuild stayed unrunnable. @1.0.9 fetches Apparatus.OpamBuildWrapper@1.0.5 (build-locked-package-v3.sh), which instead gives every bin/sbin destination the .exe suffix on Windows. @1.0.5 is again a new asset module for the same propagation reason; the Export marker value-id stays shared.

The @1.0.10 revision fetches Apparatus.OpamBuildWrapper@1.0.6 (build-locked-package-v4.sh), whose ocamlbuild-nh shim passes -install-lib-dir p/lib/ocamlbuild so ocamlbuild -where resolves to the package prefix. The relocatable ocamlbuild otherwise computes -where beside the compiler (dirname of ocaml_libdir), but the dk0 closure keeps the compiler separate and installs ocamlbuild.cmo into the package prefix, so compiling a myocamlbuild.ml plugin (e.g. ptime) fails to find ocamlbuild.cmo. @1.0.6 is a new asset module; the Export marker value-id stays shared.

The @1.0.11 revision fetches Apparatus.OpamBuildWrapper@1.0.7 (build-locked-package-v5.sh), which makes the imported relocatable findlib usable by a topkg #use "topfind". @1.0.10's wrapper set only OCAML_TOPLEVEL_PATH, which findlib_config reads to resolve its location, but the OCaml >= 4.13 toplevel does NOT search that variable for #use, so #use "topfind" failed with Cannot find file topfind whenever ocamlfind was imported (rather than built in-closure, where its build also seeded topfind into the then-writable shared stdlib). @1.0.7 also exports OCAMLTOP_INCLUDE_PATH (the toplevel's actual #use search path) and OCAMLFIND_LDCONF (pointing at the running compiler's ld.conf), because findlib_config bakes ocaml_stdlib/ocaml_ldconf as an absolute compile-time path that is dead once the object is imported into another build tree. All three variables are required together; the imported Dk0.Pkg.Ocamlfind object itself is correct and unchanged. @1.0.7 is a new asset module; the Export marker value-id stays shared.

The @1.0.15 revision fetches Apparatus.OpamBuildWrapper@1.0.9 (build-locked-package-v6.sh), which additionally rewrites the imported findlib.conf's stdlib= (and ldconf=) to the running compiler's lib/ocaml. @1.0.11's OCAMLFIND_LDCONF fixed ocamlfind list, but findlib_config's baked ocaml_stdlib still pointed at the dead compile-time path, so -package compiler-libs.toplevel (findlib expands it to <ocaml_stdlib>/compiler-libs) resolved into that dead directory and any consumer of the toplevel libraries failed with Unbound module Toploop -- first hit compiling astring's src/astring_top.ml. findlib exposes no environment override for stdlib (unlike ldconf), so the wrapper must rewrite findlib.conf itself; the DkML compiler does ship compiler-libs/toploop.cmi + ocamltoplevel.cma, so once stdlib points at it the toplevel packages resolve. @1.0.9 is a new asset module; the Export marker value-id stays shared.

The @1.0.16 revision is behaviorally identical to @1.0.15. It exists because the wrapper assets were collapsed onto the stable assets/opam/build-locked-package.sh path (Apparatus.OpamBuildWrapper@1.0.10, the same bytes as the retired build-locked-package-v6.sh) and every earlier OpamBuild revision was retired from HEAD; see "## Assets". The revision paragraphs above are history: the file names they mention exist only in earlier release tags. The Export marker value-id stays shared, so no new harvest is needed.

The @1.0.17 revision fetches Apparatus.OpamBuildWrapper@1.0.11, the same build-locked-package.sh with one Unix addition: it exports CAML_LD_LIBRARY_PATH pointing at the running compiler's stublibs. A package build that runs a bytecode helper linking unix -- first hit ocamlbuild's man/options_man.byte, run during the build to generate a man page -- loads dllunix-* at runtime via CAML_LD_LIBRARY_PATH and then the compiler's ld.conf. The DkML relocatable compiler's baked ld.conf lists a dead absolute stublibs dir (the same dead-baked-path root cause as the findlib stdlib above) and the rule strips CAML_LD_LIBRARY_PATH for hermeticity, so ocamlrun aborted (core dump) and the build failed. It is set on every slot -- as a native path (cygpath -m) on Windows, matching OCAMLFIND_LDCONF -- so the stub load path is correct regardless of how the host resolves DLLs. @1.0.11 is an OpamBuildWrapper patch bump (its bytes changed); the Export marker value-id stays shared.

The @1.0.18 revision fetches Apparatus.OpamBuildWrapper@1.0.12, the same build-locked-package.sh with a toolchain-fingerprint gate added on both sides. Producer half: after a successful build it records the sha256 of the DkML compiler-libs it linked against (compiler-libs/ocamlcommon.cmxa) into each library dir it produced, as a p/lib-mergeable ip/lib/<pkg>/.dk-provenance key=value sidecar. Consumer half: before building, it compares every staged dependency's recorded compiler-libs sha against the compiler-libs THIS build links against and, on a mismatch, fails fast with an actionable [abi-toolchain] message instead of letting the build die deep inside with the opaque .cmxa make inconsistent assumptions over implementation <Module> link error (the ppxlib astlib-vs-skewed-DkML failure). OCaml native compiler-libs are not bit-reproducible, so the SAME declaration-stable DkML object can hold different .cmx CRCs across CLO releases; this content fingerprint catches a producer and consumer that resolved different CLO releases even though their DkML module-id STRING matches. It is fail-open for dependencies with no recorded fingerprint (objects built by an earlier wrapper), so coverage grows as objects are rebuilt; fail-closed only when a fingerprint is present and differs. @1.0.12 is an OpamBuildWrapper patch bump (its bytes changed); the Export marker value-id stays shared.

Usage

DkML

  $ get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Darwin_arm64 -d ${RUNTIME}/Darwin_arm64-DkML-4.14.3
  \test(pass)
  \dk.object(abi: "Release.Darwin_arm64", value-id: "oo4ayzg7xkx5jehdewwtopexnnwmwidon22bpm5qpu7zwtui3uduq")\;

  $ run-object CommonsBase_FileMagic.File@7.8.50407 -s Release.execution_abi -m ./bin/file.exe -e bin/file.exe --
  >   -b $(get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.target_abi -d : -e file.exe)/bin/ocamlopt
  \test(pass)
  \dk.target(abi: "Darwin_arm64")[Mach-O 64-bit executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|WEAK_DEFINES|BINDS_TO_WEAK|PIE>
  ]\;

  $ run-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Darwin_arm64 -e 'bin/*' -c bin/ocamlopt -- -version
  \test(pass)
  \dk.target(abi: "Darwin_arm64")[4.14.3+relocatable
  ]\;

  $ get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Darwin_x86_64 -d ${RUNTIME}/Darwin_x86_64-DkML-4.14.3
  \test(pass)
  \dk.object(abi: "Release.Darwin_x86_64", value-id: "okzumfa6r4confdol3ixdbc7txprthvklwsrnmdiygkxwqr75fmea")\;

  $ run-object CommonsBase_FileMagic.File@7.8.50407 -s Release.execution_abi -m ./bin/file.exe -e bin/file.exe --
  >   -b $(get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.target_abi -d : -e file.exe)/bin/ocamlopt
  \test(pass)
  \dk.target(abi: "Darwin_x86_64")[Mach-O 64-bit executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|WEAK_DEFINES|BINDS_TO_WEAK|PIE>
  ]\;

  $ get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_arm64 -d ${RUNTIME}/Linux_arm64-DkML-4.14.3
  \test(pass)

  $ run-object CommonsBase_FileMagic.File@7.8.50407 -s Release.execution_abi -m ./bin/file.exe -e bin/file.exe --
  >   -b $(get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.target_abi -d : -e file.exe)/bin/ocamlopt
  \test(pass)
  \dk.target(abi: "Linux_arm64")[ELF 64-bit LSB executable, ARM aarch64
  ]\;

  $ run-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_arm64 -e 'bin/*' -c bin/ocamlopt -- -version
  \test(pass)

  $ get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_x86 -d ${RUNTIME}/Linux_x86-DkML-4.14.3
  \test(pass)
  \dk.object(abi: "Release.Linux_x86", value-id: "ovy2o34buas5pmhkxreefofjtqdxcr6c6rzshp3opang7uuznzbma")\;

  $ run-object CommonsBase_FileMagic.File@7.8.50407 -s Release.execution_abi -m ./bin/file.exe -e bin/file.exe --
  >   -b $(get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.target_abi -d : -e file.exe)/bin/ocamlopt
  \test(pass)
  \dk.target(abi: "Linux_x86")[ELF 32-bit LSB executable, Intel i386, version 1 (SYSV)
  ]\;

  $ get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_x86_64 -d ${RUNTIME}/Linux_x86_64-DkML-4.14.3
  \test(pass)
  \dk.object(abi: "Release.Linux_x86_64", value-id: "ot73vapttmhsm5oskmtiousmp7bmqheglknykhprnqp36bbzcm7ha")\;

  $ run-object CommonsBase_FileMagic.File@7.8.50407 -s Release.execution_abi -m ./bin/file.exe -e bin/file.exe --
  >   -b $(get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.target_abi -d : -e file.exe)/bin/ocamlopt
  \test(pass)
  \dk.target(abi: "Linux_x86_64")[ELF 64-bit LSB executable, x86-64, version 1 (SYSV)
  ]\;

  $ run-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_x86_64 -e 'bin/*' -c bin/ocamlopt -- -version
  \test(pass)
  \dk.target(abi: "Linux_x86_64")[4.14.3+relocatable
  ]\;

The native_pack_linker must be a relocatable, PATH-resolved partial linker (a
bare `ld -r -o`), never an absolute build-host path such as the ephemeral
`.../src-ocaml/support/with-host-c-compiler.sh.ld64.sh` a stock build bakes;
otherwise `ocamlopt -pack` fails off the build machine.

  $ run-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_x86_64 -e 'bin/*' -c bin/ocamlopt -- -config-var native_pack_linker
  \test(pass)
  \dk.target(abi: "Linux_x86_64")[ld -r -o ]\;

The baked C toolchain must be bare PATH-resolved single-word names, never the
absolute /opt/rh/gcc-toolset-14 paths of the manylinux build container
(issue #2): end-user hosts supply their own PATH toolchain, while the release
build still resolves the same gcc-toolset-14 first on PATH.

  $ run-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_x86_64 -e 'bin/*' -c bin/ocamlopt -- -config-var c_compiler
  \test(pass)
  \dk.target(abi: "Linux_x86_64")[gcc]\;

  $ run-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_x86_64 -e 'bin/*' -c bin/ocamlopt -- -config-var asm
  \test(pass)
  \dk.target(abi: "Linux_x86_64")[as]\;

The runtime archives must be PIE-safe (issue #3): a link forced to -pie fails
on a non-PIC libasmrun.a with `relocation R_X86_64_32S ... can not be used
when making a PIE object`, reproducing on the non-PIE-default gcc-toolset
builder exactly what PIE-default consumer hosts do by default.

  $ run-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_x86_64 -e 'bin/*' -c bin/ocamlopt --
  >   -ccopt -pie -o ${RUNTIME}/piecheck.exe
  >   $(get-asset CommonsLang_OCaml.Apparatus.DkMLPieCheck@1.0.1 -p assets/dkml/piecheck.ml -f piecheck.ml)
  \test(pass)
  \dk.target(abi: "Linux_x86_64")\;

  $ get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_x86_64_musl -d ${RUNTIME}/Linux_x86_64_musl-DkML-4.14.3
  \test(pass)
  \dk.object(abi: "Release.Linux_x86_64_musl", value-id: "obazby47qzcgflxlvkysgb7tcxcqfsm5ljhxktojhoui6dmuswzma")\;

The musl ocamlopt is a musl binary (ELF interpreter /lib/ld-musl-x86_64.so.1),
so it runs wherever the musl loader is present: natively on musl hosts, and on
the glibc manylinux build host because the build provisions the loader at that
path (see the per-ABI dynamic linker in DK0-REFERENCE.md). The file(1) string
below is harvested from the first CI run.

  $ run-object CommonsBase_FileMagic.File@7.8.50407 -s Release.execution_abi -m ./bin/file.exe -e bin/file.exe --
  >   -b $(get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.target_abi -d : -e file.exe)/bin/ocamlopt
  \test(pass)
  \dk.target(abi: "Linux_x86_64_musl")[ELF 64-bit LSB ${x?pie executable:shared object}, x86-64, version 1 (SYSV)
  ]\;

  $ run-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_x86_64_musl -e 'bin/*' -c bin/ocamlopt -- -version
  \test(pass)
  \dk.target(abi: "Linux_x86_64_musl")[4.14.3+relocatable
  ]\;

The native_pack_linker must be a relocatable, PATH-resolved partial linker (a
bare `x86_64-linux-musl-ld -r -o`, resolved through the slot's
bin/x86_64-linux-musl-* dispatch wrappers), never an absolute build-host path
such as the ephemeral `.../src-ocaml/support/with-host-c-compiler.sh.ld64.sh` a
stock build bakes; otherwise `ocamlopt -pack` fails off the build machine. The
musl partial linker is required because the host `ld` cannot read the musl
toolchain's compressed debug sections.

  $ run-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_x86_64_musl -e 'bin/*' -c bin/ocamlopt -- -config-var native_pack_linker
  \test(pass)
  \dk.target(abi: "Linux_x86_64_musl")[x86_64-linux-musl-ld -r -o ]\;

The baked C compiler must be the bare musl cross driver, resolved through the
bin/x86_64-linux-musl-* dispatch wrappers shipped in the same slot, so
consumer machines link static musl executables wherever the slot's bin/ is on
PATH.

  $ run-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Linux_x86_64_musl -e 'bin/*' -c bin/ocamlopt -- -config-var c_compiler
  \test(pass)
  \dk.target(abi: "Linux_x86_64_musl")[x86_64-linux-musl-gcc]\;

  $ get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Windows_x86 -d ${RUNTIME}/Windows_x86-DkML-4.14.3
  \test(pass)
  \dk.object(abi: "Release.Windows_x86", value-id: "otj6lfdhsvf6qonulwtjephn7wu7ow5ocwzkjknfplo2uanj65kya")\;

Release.Windows_x86_64 will be used as Release.execution_abi on normal (64-bit) build + CI machines.

  $ run-object CommonsBase_FileMagic.File@7.8.50407 -s Release.execution_abi -m ./bin/file.exe -e bin/file.exe --
  >   -b $(get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.target_abi -d : -e file.exe)/bin/ocamlopt.exe
  \test(pass)
  \dk.target(abi: "Windows_x86")[PE32 executable for MS Windows 6.00 (console),, 5 sections
  ]\;

  $ run-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Windows_x86 -c bin/ocamlopt.exe -- -version
  \test(pass)
  \dk.target(abi: "Windows_x86")[4.14.3+relocatable
  ]\;

  $ get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Windows_x86_64 -d ${RUNTIME}/Windows_x86_64-DkML-4.14.3
  \test(pass)
  \dk.object(abi: "Release.Windows_x86_64", value-id: "oxeed6f2bmqzx32bc4f5gy4fdkpmq7qzq7mizyrhlydogzmiaylua")\;

  $ run-object CommonsBase_FileMagic.File@7.8.50407 -s Release.execution_abi -m ./bin/file.exe -e bin/file.exe --
  >   -b $(get-object CommonsLang_OCaml.DkML@4.14.3 -s Release.target_abi -d : -e file.exe)/bin/ocamlopt.exe
  \test(pass)
  \dk.target(abi: "Windows_x86_64")[PE32+ executable for MS Windows 6.00 (console),, 6 sections
  ]\;

  $ run-object CommonsLang_OCaml.DkML@4.14.3 -s Release.Windows_x86_64 -c bin/ocamlopt.exe -- -version
  \test(pass)
  \dk.target(abi: "Windows_x86_64")[4.14.3+relocatable
  ]\;

Base

  $ run-object CommonsLang_OCaml.Base@5.5.0 -s Release.Darwin_arm64 -e 'bin/*' -c bin/ocamlopt -- -version
  \test(pass)
  \dk.target(abi: "Darwin_arm64")[5.5.0
  ]\;

  $ run-object CommonsLang_OCaml.Base@5.5.0 -s Release.Darwin_x86_64 -e 'bin/*' -c bin/ocamlopt -- -version
  \test(pass)
  \dk.target(abi: "Darwin_x86_64")[5.5.0
  ]\;

  $ run-object CommonsLang_OCaml.Base@5.5.0 -s Release.Linux_x86_64 -e 'bin/*' -c bin/ocamlopt -- -version
  \test(pass)
  \dk.target(abi: "Linux_x86_64")[5.5.0
  ]\;

The Base runtime archives must be PIE-safe like the DkML ones (issue #3): the
same forced -pie link exercises the -fPIC CFLAGS/ASPP added to the Base Linux
glibc configure blocks.

  $ run-object CommonsLang_OCaml.Base@5.5.0 -s Release.Linux_x86_64 -e 'bin/*' -c bin/ocamlopt --
  >   -ccopt -pie -o ${RUNTIME}/basepiecheck.exe
  >   $(get-asset CommonsLang_OCaml.Apparatus.DkMLPieCheck@1.0.1 -p assets/dkml/piecheck.ml -f piecheck.ml)
  \test(pass)
  \dk.target(abi: "Linux_x86_64")\;

  $ run-object CommonsLang_OCaml.Base@5.5.0 -s Release.Windows_x86_64 -e 'bin/*' -c bin/ocamlopt.exe -- -version
  \test(pass)
  \dk.target(abi: "Windows_x86_64")[5.5.0
  ]\;

Dune

  $ run-object CommonsLang_OCaml.Dune@3.23.1 -s Release.Darwin_arm64 -e 'bin/*' -c bin/dune.exe -- --version
  \test(pass)
  \dk.target(abi: "Darwin_arm64")[3.23.1
  ]\;

  $ run-object CommonsLang_OCaml.Dune@3.23.1 -s Release.Darwin_x86_64 -e 'bin/*' -c bin/dune.exe -- --version
  \test(pass)
  \dk.target(abi: "Darwin_x86_64")[3.23.1
  ]\;

  $ run-object CommonsLang_OCaml.Dune@3.23.1 -s Release.Linux_arm64 -e 'bin/*' -c bin/dune.exe -- --version
  \test(pass)
  \dk.target(abi: "Linux_arm64")[3.23.1
  ]\;

  $ run-object CommonsLang_OCaml.Dune@3.23.1 -s Release.Linux_x86 -e 'bin/*' -c bin/dune.exe -- --version
  \test(pass)
  \dk.target(abi: "Linux_x86")[3.23.1
  ]\;

  $ run-object CommonsLang_OCaml.Dune@3.23.1 -s Release.Linux_x86_64 -e 'bin/*' -c bin/dune.exe -- --version
  \test(pass)
  \dk.target(abi: "Linux_x86_64")[3.23.1
  ]\;

  $ run-object CommonsLang_OCaml.Dune@3.23.1 -s Release.Linux_x86_64_musl -e 'bin/*' -c bin/dune.exe -- --version
  \test(pass)
  \dk.target(abi: "Linux_x86_64_musl")[3.23.1
  ]\;

  $ run-object CommonsLang_OCaml.Dune@3.23.1 -s Release.Windows_x86 -e 'bin/*' -c bin/dune.exe -- --version
  \test(pass)
  \dk.target(abi: "Windows_x86")[3.23.1
  ]\;

  $ run-object CommonsLang_OCaml.Dune@3.23.1 -s Release.Windows_x86_64 -e 'bin/*' -c bin/dune.exe -- --version
  \test(pass)
  \dk.target(abi: "Windows_x86_64")[3.23.1
  ]\;

Opam

  $ run-object CommonsLang_OCaml.Opam@2.5.1 -s Release.Darwin_arm64 -e 'bin/*' -c bin/opam.exe -- --version
  \test(pass)
  \dk.target(abi: "Darwin_arm64")[2.5.1
  ]\;

  $ run-object CommonsLang_OCaml.Opam@2.5.1 -s Release.Darwin_x86_64 -e 'bin/*' -c bin/opam.exe -- --version
  \test(pass)
  \dk.target(abi: "Darwin_x86_64")[2.5.1
  ]\;

  $ run-object CommonsLang_OCaml.Opam@2.5.1 -s Release.Linux_arm64 -e 'bin/*' -c bin/opam.exe -- --version
  \test(pass)
  \dk.target(abi: "Linux_arm64")[2.5.1
  ]\;

  $ run-object CommonsLang_OCaml.Opam@2.5.1 -s Release.Linux_x86 -e 'bin/*' -c bin/opam.exe -- --version
  \test(pass)
  \dk.target(abi: "Linux_x86")[2.5.1
  ]\;

  $ run-object CommonsLang_OCaml.Opam@2.5.1 -s Release.Linux_x86_64 -e 'bin/*' -c bin/opam.exe -- --version
  \test(pass)
  \dk.target(abi: "Linux_x86_64")[2.5.1
  ]\;

  $ run-object CommonsLang_OCaml.Opam@2.5.1 -s Release.Windows_x86 -e 'bin/*' -c bin/opam.exe -- --version
  \test(pass)
  \dk.target(abi: "Windows_x86")[2.5.1
  ]\;

  $ run-object CommonsLang_OCaml.Opam@2.5.1 -s Release.Windows_x86_64 -e 'bin/*' -c bin/opam.exe -- --version
  \test(pass)
  \dk.target(abi: "Windows_x86_64")[2.5.1
  ]\;

Dk.OpamLock

Only the current OpamLock revision ships. The retired Export@1.0.0-@1.1.7
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamLock.Export@1.1.21 -f ${RUNTIME}/OpamLock.Export-1.1.21.zip
  \test(pass)
  \dk.object(abi: "Release.Darwin_arm64", value-id: "oe4g3eqnczobtqdjlxuj2k7lds2uc24c5cvmit5p45hpgbpaijzwq")\;


Only the current OpamLock revision ships. The retired Export@1.0.0-@1.1.7
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamLock.Export@1.1.21 -f ${RUNTIME}/OpamLock.Export-1.1.21.zip
  \test(pass)
  \dk.object(abi: "Release.Darwin_arm64", value-id: "ow3evojmb4rzns36nykczu2dmxv2ln3aznacr3yyq436df4zvj3zq")\;


Only the current OpamLock revision ships. The retired Export@1.0.0-@1.1.7
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy). As before on this arm64 slot
the marker output is unused (no object value-id is recorded).

  $ run-function CommonsLang_OCaml.Dk.OpamLock.Export@1.1.21 -f ${RUNTIME}/OpamLock.Export-1.1.21.zip
  \test(pass)

Only the current OpamLock revision ships. The retired Export@1.0.0-@1.1.7
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamLock.Export@1.1.21 -f ${RUNTIME}/OpamLock.Export-1.1.21.zip
  \test(pass)
  \dk.object(abi: "Release.Linux_x86_64", value-id: "oatz65a2xqpfhcgthasa5nclqtapzgk236u2m5zgcovlhky46ubha")\;


Only the current OpamLock revision ships. The retired Export@1.0.0-@1.1.7
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamLock.Export@1.1.21 -f ${RUNTIME}/OpamLock.Export-1.1.21.zip
  \test(pass)
  \dk.object(abi: "Release.Linux_x86_64", value-id: "obmkzfe7vutajk4ogxhwupzdzhcur3lv4p5easmv65hpqneu5f45q")\;


Only the current OpamLock revision ships. The retired Export@1.0.0-@1.1.7
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamLock.Export@1.1.21 -f ${RUNTIME}/OpamLock.Export-1.1.21.zip
  \test(pass)
  \dk.object(abi: "Release.Linux_x86_64", value-id: "oqypruww2im7iowtxdd2rycqxeszzo5bamahgvslmhr3l2sc3rtgq")\;

Only the current OpamLock revision ships. The retired Export@1.0.0-@1.1.7
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamLock.Export@1.1.21 -f ${RUNTIME}/OpamLock.Export-1.1.21.zip
  \test(pass)
  \dk.object(abi: "Release.Windows_x86_64", value-id: "ongbcj4lqh562b4vfpht6k4yor3jscw523sec4uusee76gqd7uxcq")\;


Only the current OpamLock revision ships. The retired Export@1.0.0-@1.1.7
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamLock.Export@1.1.21 -f ${RUNTIME}/OpamLock.Export-1.1.21.zip
  \test(pass)
  \dk.object(abi: "Release.Windows_x86_64", value-id: "opltpdbhogntvxld5qdnqjbjtkerusdn727pjiwxj76i2uwe4ijvq")\;


Dk.OpamBuild

Only the current OpamBuild revision ships. The retired Export@1.0.0-@1.0.15
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamBuild.Export@1.0.28 -f ${RUNTIME}/OpamBuild.Export-1.0.28.zip
  \test(pass)
  \dk.object(abi: "Release.Darwin_arm64", value-id: "ot36qu3466etoe2n4fwegx5oven5jtringcjn4njmy7n4ayspxb6q")\;
Only the current OpamBuild revision ships. The retired Export@1.0.0-@1.0.15
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamBuild.Export@1.0.28 -f ${RUNTIME}/OpamBuild.Export-1.0.28.zip
  \test(pass)
  \dk.object(abi: "Release.Darwin_arm64", value-id: "ofubkdsha44yxaupnig6ekbw7pgskunmgndhj5qno4xr44e3cmawa")\;
Only the current OpamBuild revision ships. The retired Export@1.0.0-@1.0.15
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamBuild.Export@1.0.28 -f ${RUNTIME}/OpamBuild.Export-1.0.28.zip
  \test(pass)
  \dk.object(abi: "Release.Linux_arm64", value-id: "o0000000000000000000000000000000000000000000000000000")\;
Only the current OpamBuild revision ships. The retired Export@1.0.0-@1.0.15
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamBuild.Export@1.0.28 -f ${RUNTIME}/OpamBuild.Export-1.0.28.zip
  \test(pass)
  \dk.object(abi: "Release.Linux_x86_64", value-id: "om5iozr3prdwgmre7iu7hkjfkeugphbfshqwrt3yy2dweh7inkk7a")\;
Only the current OpamBuild revision ships. The retired Export@1.0.0-@1.0.15
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamBuild.Export@1.0.28 -f ${RUNTIME}/OpamBuild.Export-1.0.28.zip
  \test(pass)
  \dk.object(abi: "Release.Linux_x86_64", value-id: "ox2yguwbuo7ev3o5ovs5vcjgsljpqjev73hi6ze6isy6mmksrfasq")\;
Only the current OpamBuild revision ships. The retired Export@1.0.0-@1.0.15
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamBuild.Export@1.0.28 -f ${RUNTIME}/OpamBuild.Export-1.0.28.zip
  \test(pass)
  \dk.object(abi: "Release.Linux_x86_64", value-id: "ogb2kkrd2txlaxwxcrdmg4t52ngii6mt6n3fiahs3j4idk63kgk6a")\;
Only the current OpamBuild revision ships. The retired Export@1.0.0-@1.0.15
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamBuild.Export@1.0.28 -f ${RUNTIME}/OpamBuild.Export-1.0.28.zip
  \test(pass)
  \dk.object(abi: "Release.Windows_x86_64", value-id: "om47rfyg26n7euugbb4uogoadpog66as4sxshpo6hppfhryq65ula")\;
Only the current OpamBuild revision ships. The retired Export@1.0.0-@1.0.15
ladder lives in pre-2026-08 release tags and git history (see dk.u
"## Assets" for the keep-latest-only policy).

  $ run-function CommonsLang_OCaml.Dk.OpamBuild.Export@1.0.28 -f ${RUNTIME}/OpamBuild.Export-1.0.28.zip
  \test(pass)
  \dk.object(abi: "Release.Windows_x86_64", value-id: "orlivsdhgqn6hmk3yq3gm35adggjgmx3bccn6nyluhahl4wl27cvq")\;

MSYS2

MSYS2 tree for `opam init --cygwin-local-install --cygwin-location=<obj>` in
the Dk.OpamLock hermetic bootstrap (opam detects MSYS2 via
usr/bin/cygpath.exe). Windows x86_64 only: x86/arm64 Windows hosts run the
x64 tree through WOW64/emulation.

  $ get-object CommonsLang_OCaml.MSYS2@2026.6.11 -s Release.Windows_x86_64 -f ${RUNTIME}/Windows_x86_64-MSYS2-2026.6.11.zip
  \test(pass)
  \dk.object(abi: "Release.Windows_x86_64", value-id: "ozjqpoyewgl2wsnrk5uekbleo3644auhcyri2gexstfr3k5slof5q")\;

Provides

ModuleVersionPlatformvalue-id
CommonsLang_OCaml.DkML 4.14.3 Darwin_arm64 oo4ayzg7xkx5…
CommonsLang_OCaml.DkML 4.14.3 Darwin_x86_64 okzumfa6r4co…
CommonsLang_OCaml.DkML 4.14.3 Linux_x86 ovy2o34buas5…
CommonsLang_OCaml.DkML 4.14.3 Linux_x86_64 ot73vapttmhs…
CommonsLang_OCaml.DkML 4.14.3 Linux_x86_64_musl obazby47qzcg…
CommonsLang_OCaml.DkML 4.14.3 Windows_x86 otj6lfdhsvf6…
CommonsLang_OCaml.DkML 4.14.3 Windows_x86_64 oxeed6f2bmqz…
CommonsLang_OCaml.Base 5.5.0 apparatus
CommonsLang_OCaml.Dune 3.23.1 apparatus
CommonsLang_OCaml.Opam 2.5.1 apparatus
CommonsLang_OCaml.Dk.OpamLock.Export 1.1.21 Darwin_arm64 oe4g3eqnczob…
CommonsLang_OCaml.Dk.OpamLock.Export 1.1.21 Darwin_arm64 ow3evojmb4rz…
CommonsLang_OCaml.Dk.OpamLock.Export 1.1.21 Linux_x86_64 oatz65a2xqpf…
CommonsLang_OCaml.Dk.OpamLock.Export 1.1.21 Linux_x86_64 obmkzfe7vuta…
CommonsLang_OCaml.Dk.OpamLock.Export 1.1.21 Linux_x86_64 oqypruww2im7…
CommonsLang_OCaml.Dk.OpamLock.Export 1.1.21 Windows_x86_64 ongbcj4lqh56…
CommonsLang_OCaml.Dk.OpamLock.Export 1.1.21 Windows_x86_64 opltpdbhognt…
CommonsLang_OCaml.Dk.OpamBuild.Export 1.0.28 Darwin_arm64 ot36qu3466et…
CommonsLang_OCaml.Dk.OpamBuild.Export 1.0.28 Darwin_arm64 ofubkdsha44y…
CommonsLang_OCaml.Dk.OpamBuild.Export 1.0.28 Linux_arm64 o00000000000…
CommonsLang_OCaml.Dk.OpamBuild.Export 1.0.28 Linux_x86_64 om5iozr3prdw…
CommonsLang_OCaml.Dk.OpamBuild.Export 1.0.28 Linux_x86_64 ox2yguwbuo7e…
CommonsLang_OCaml.Dk.OpamBuild.Export 1.0.28 Linux_x86_64 ogb2kkrd2txl…
CommonsLang_OCaml.Dk.OpamBuild.Export 1.0.28 Windows_x86_64 om47rfyg26n7…
CommonsLang_OCaml.Dk.OpamBuild.Export 1.0.28 Windows_x86_64 orlivsdhgqn6…
CommonsLang_OCaml.MSYS2 2026.6.11 Windows_x86_64 ozjqpoyewgl2…

Workspace assets

Files and directories in the package repo, bundled into the build.

AssetProject pathType
Patches assets/p directory
Scripts assets/s directory
Tables assets/table directory
WineHostShim assets/wine-hostshim directory
DkMLRoot assets/dkml/dkmlroot.2.4.2-29.txt file
DkMLPatchRelocatableVersion assets/dkml/patch-r-c-ocaml-1-setup-relocatable-version.sh file
DkMLRunBuildHost assets/dkml/run-build-host.sh file
DkMLDetectVsEnvBat assets/dkml/detect-vsenv.bat file
DkMLCleanupSlot assets/dkml/cleanup-dkml-slot.sh file
DkMLPatchStandardCompilerEnvWv18 assets/dkml/patch-standard-compiler-env-wv18.sh file
DkMLMuslWrap assets/dkml/musl-tool-wrapper.sh file
DkMLMuslBuildHost assets/dkml/run-musl-build-host.sh file
DkMLX86Wrap assets/dkml/x86-tool-wrapper.sh file
DkMLX86BuildHost assets/dkml/run-x86-build-host.sh file
DkMLGlibcEnv assets/dkml/glibc-compiler-env-to-ocaml-configure-env.sh file
DkMLPieCheck assets/dkml/piecheck.ml file
DuneBootstrapMsvc assets/dune/bootstrap-msvc.bat file
OpamBuildWin assets/opam/opam-build-win.sh file
OpamBuildWinVcvars assets/opam/opam-build-win-vcvars.bat file
OpamMsvsDetectStub assets/opam/msvs-detect-stub.sh file
OpamMccsGlpkStub assets/opam/mccs-glpk-wrmip-stub.c file
OpamBuildSeqMeta assets/opam/seq-META file
OpamFileFormat assets/opam-lock/opam_file_format.ml file
OpamBuildWrapper assets/opam/build-locked-package.sh file
DkMLMuslEnv assets/dkml/musl-compiler-env-to-ocaml-configure-env.sh file
DkMLX86Env assets/dkml/x86-compiler-env-to-ocaml-configure-env.sh file
OpamLockHelper assets/opam-lock/dk_opam_lock.ml file

Downloaded assets

Third-party sources fetched and checksum-verified during the build.

AssetSizesha256Source
4.14.3.tar.gz 5.3 MB e510689183b2d62b… https://github.com/ocaml/ocaml/archive/refs/tags/4.14.3.tar.gz
5.5.0.tar.gz 4.8 MB c018052c8264a379… https://github.com/ocaml/ocaml/archive/5.5.0.tar.gz
ocaml-5.4.1.tar.gz 6.2 MB d4528517aaa1a44b… https://github.com/ocaml/ocaml/releases/download/5.4.1/ocaml-5.4.1.tar.gz
2.5.1.tar.gz 1.2 MB 459a57cb84c3ea16… https://github.com/ocaml/opam/archive/refs/tags/2.5.1.tar.gz
menhir-20250903-no-symlinks.tar 4.2 MB 087792aff8fb1238… https://github.com/dkpkg/CommonsLang_OCaml/releases/download/opam-menhir-20250903-no-symlinks/menhir-20250903-no-symlinks.tar
2.4.2-50.zip 1.5 MB 3239282aaa91fff1… https://github.com/diskuv/dkml-compiler/archive/refs/tags/2.4.2-50.zip
src.zip 61 KB 6dde51c5f6605a83… https://github.com/diskuv/dkml-runtime-common/releases/download/2.4.2-26/src.zip
msys2-base-x86_64-20260611.tar.xz 51.1 MB a2d047e8ee213c3c… https://github.com/dkpkg/CommonsLang_OCaml/releases/download/msys2-20260611-assets/msys2-base-x86_64-20260611.tar.xzhttps://github.com/msys2/msys2-installer/releases/download/2026-06-11/msys2-base-x86_64-20260611.tar.xz
3.23.1.tar.gz 3.5 MB 63fbef75d09dd4a0… https://github.com/ocaml/dune/archive/refs/tags/3.23.1.tar.gz
x86_64-linux-musl-cross.tgz 107.2 MB c6226824d6b7214c… https://github.com/dkpkg/CommonsLang_OCaml/releases/download/muslcc-x86_64-11.2.1/x86_64-linux-musl-cross.tgzhttps://more.musl.cc/11.2.1/x86_64-linux-musl/x86_64-linux-musl-cross.tgz

Dependencies

PackageVersionsha256
CommonsBase_FileMagic 0.1.20260907154822 85d381d6da76af86…
CommonsBase_LLVM 0.1.20260907152615 98061bee11818ee2…
CommonsBase_Win32 0.1.20260909220127 5d63d04679c36616…
NotMitEdu_Kerberos 0.1.20260909215049 c2fa90cea60254ec…
NotMatveevKondratyev_Libinotify 0.1.20260909201008 5fcdb9dd69fe350d…
CommonsBase_GNU 0.1.20260909175841 ba738de232fae84a…
CommonsBase_Std 2.6.20260907152615 79d7b1456fa32c02…
CommonsBase_Build 0.1.20260907152615 444603e54879afae…

Producer signing key

Releases of this package are signed with this OpenBSD signify key. After you import the package, dk1 trust list prints the same public key and fingerprint; compare them here to confirm you are trusting the intended publisher over a channel independent of the download.

Fingerprint 2b19619c380dd657
Public key RWQrGWGcOA3WV93QbuXdm8aAWjDkYvCM5jgFAanfDRiW9n3PzSvLESmR