The Dune team is pleased to announce the release of dune 3.25.0.
Highlights of this release include:
Breaking changes
-
Actions no longer see the shared install staging area (
_build/install/<context>/{bin,lib,lib/stublibs}) onPATH,OCAMLPATHandCAML_LD_LIBRARY_PATH. An action's environment only contains the packages it declares with(deps (package <pkg>))(and their library closure, see below). Actions that rely on packages being visible (such as tests that#requirethe package under test from an mdx block, steps that runocamlfind, a nesteddunebuild, or load a bytecode stub library) must now declare the package dependency explicitly. ocaml/dune#14373, ocaml/dune#16617. -
The
:character is now rejected in context names, to ensure they remain portable path components. ocaml/dune#16085. -
Generated files are now read-only even with Dune language versions before 2.4, regardless of whether the shared cache is enabled. Executable permissions are preserved. ocaml/dune#16388
-
In dune-project, (warnings (duplicate_deps ..)) requires a dune lang version of 3.22, instead of 3.18.1. ocaml/dune#5696.
-
(env (env-vars ...))in a(context ...)stanza ofdune-workspacenow takes precedence over the rootenvstanza, as documented. This affects commands such asdune exec; rules already used the documented order. ocaml/dune#16290.
Features
-
Added command, subcommand, and flag completion in the command line. Supported shells are
bash,zsh,pwsh, andfish. Seedune completion [shell] --help. ocaml/dune#14779, ocaml/dune#15334. -
Tab completion for
dune promotenow lists pending promotion files. ocaml/dune#5338. -
Add build time information to watch mode. ocaml/dune#15384.
-
Display build duration and average process parallelism in the status line for batch builds. ocaml/dune#15564.
-
Add
(flags ...)to theocamllexandocamlyaccstanzas to pass custom options to parser generators. ocaml/dune#15907. -
Starting with Dune language 3.25, restrict sandboxed actions on Linux systems with Landlock ABI 3 or newer from writing outside their sandbox, temporary directory, action-trace directory, and
/dev. SetDUNE_CONFIG__LANDLOCK=disabledto opt out. ocaml/dune#15858.
Fixes
-
$ dune rpc buildinvocations no longer queue. All build requests are built in parallel. Watch servers started by$ dune exec --watchcan now also handle forwarded build and runtest requests. ocaml/dune#14954.dune rpc buildalso now exits with the proper code on completion. ocaml/dune#15341. -
Portable lock directories now select one package version across all requested platforms, and fail when no common version exists. ocaml/dune#15982.
See the full changelog for all new features and fixes, and for attribution to the contributors who made it all possible. Thank you, contributors!
If you encounter a problem with this release, please report it in our issue tracker.
See full changelog
Fixed
- Fix crashes when expanding module artifact pforms (
%{cmi:...}etc.) with(include_subdirs qualified). Qualified modules can now be referenced by dotted logical paths such as%{cmi:Sub_a.Foo}. (#14498, #16214, fixes #14496, @Alizter, @anmonteiro) dune show targetsnow accepts build-only directories such as_build/default/.simple.objs. (#14664, fixes #13782, @Alizter)- Reword the error raised when
%{target}is used in a rule that omits the(target ...)(or(targets ...)) field, so it points at the missing field instead of mentioning "inferred rules". (#14668, fixes #12439, @Alizter) - Fix watch mode on Windows by creating the file-watcher sync directory before
using it, avoiding
open(_build/.sync\0): No such file or directorywhen an RPC client requests a build. (#14678, fixes #14632, @rgrinberg) - Add file watcher trace events for the Mac and Windows backends (#14722, @rgrinberg)
- Fix decoding coalesced MacOS file notification events. (#14725, @rgrinberg)
- Handle directory invalidations correctly in watch mode on MacOS (#14756, @rgrinberg)
- Update ctime when restoring from the shared cache in copy mode. This prevents the trimmer from deleting the file. (#14777, @rgrinberg)
- Allow the use of all the available variables in the
(enabled_if)field in(executable ...)and(install ...)stanzas, similar to other stanzas like(library ...). (#14860, fixes #14789, @punchagan) - Linux: dune will now wait for the process group to be dead after the group leader is dead. This tightens dune's policy for what constitutes a successful action. Actions for which dune cannot be clean up the process group will now fail. (@rgrinberg, #14868)
- Fix caching of package sources with symlinks by resolving symlinks after fetching the sources, similar to the directory symlinks resolution introduced in #13792 (#14871, fixes #14509, @punchagan)
- Fixed wrong suggestion for duplicate entries in
conflictsfield (#14956, fixes #14903, @Leonidas-from-XIV) - Fix building Dune on Solaris/illumos by handling its
wait4semantics and retrying interrupted reads when spawning processes. (#14980, fixes #14182, @jperkin) - Fix
dune-rpc-lwtclients so disconnecting shuts down socket output without invalidating pending input reads, avoidingEBADFerrors. (#14983, fixes #7624, @rgrinberg) - Dune now restores dependency cutoffs concurrently when they were originally
computed in parallel, instead of recomputing them one at a time. The
cutoffs_that_reduce_concurrency_in_watch_modesetting, which existed to avoid this serialisation, is no longer needed and has been removed. (#15012, @snowleopard) - Validate project module names before creating the project directory in
dune init project, so aborted initializations no longer leave empty directories behind. (#15014, fixes #9963, @rgrinberg) - Fix cram test output sanitization when the project path contains a space.
Absolute paths are now rewritten to
$TESTCASE_ROOTeven when the path contains spaces, and lines with multiple paths have every path sanitized. (#15017, fixes #14943, @yussypu) - Improve the error message for private libraries that cannot be dependencies of
public libraries by mentioning the
(package ...)field as an alternative to giving the private library a public name (#15070, fixes #10230, @rgrinberg). - Clarify the module conflict error shown when a module is used in multiple stanzas. The message now explains implicit module ownership and lists all relevant stanza kinds (#15072, fixes #6598, @rgrinberg).
- Emit relative artifact references in installed
dune-packagefiles when using an absolute externalDUNE_BUILD_DIR, avoiding build-directory-dependent archive and module paths (#15077, fixes #11774, @rgrinberg). - Simplify away
(when false _)expressions (encodedNils) that previously survived insideconcatandwhenforms, producing cleaner generated lock directories. (#15092, fixes #15090, @chizy7) - Drop
(when false _)arguments fromrunactions in generated lock directories instead of keeping them as no-op entries that were re-encoded as(when false ""). (#15128, fixes #15099, @chizy7) - Make dune-configurator pass
--personalitytopkgconfonly for version 1.7.0 and later. (#15142, fixes #11536, @dra27) dune utopnow accepts an absolute path to a workspace directory instead of crashing with an internal error. (#15272, fixes #15108, @chizy7)- Fix watch-mode status lines after source changes interrupt a build. Dune now shows the restart status while cancelling the current build and resumes the normal progress counter when the next build starts. (#15289, fixes #11134, @rgrinberg)
- Short-circuit AND and OR expressions in blang. This makes their evaluation lazy by default. (#15291, @Sudha247)
- Fix the
%{ppx:ppx1+..+ppxn}form. Previously, it was just broken and pointed at the wrong binary (#15361, @rgrinberg) - Remove ppx runtime dependencies from the list of dependencies provided via
the
root_modulefield. If such a runtime dependency is needed, it should be written in thelibrariesfield. (#15419, @rgrinberg) - Avoid rebuilding
js_of_ocamllibrary archives on every invocation for interface-only and empty libraries. (#15427, @anmonteiro) - Do not crash when
~/.config/duneis a file instead of a directory. Just pretend it doesn't exist (#15475, fixes #15406, @rgrinberg) - Dune will now terminate all launched sub-processes even if it received
SIGKILLitself (#15483, @rgrinberg) - Account for
ctimein stat based digest cache (#15495, @rgrinberg) $ dune install --dry-runnow checks for non empty directories as part of its validation (#15501, @rgrinberg)- Fix a target-less rule attached to multiple aliases (
(rule (aliases a b) ...)) leaking unrelated contributions between those aliases. Building one alias no longer pulls in actions or dependencies that were added only to another of the rule's aliases. (#15581, @NatKarmios) - Make
dune pkg enabledquery a running Dune RPC server, so it observes transient server-side--pkg enabledand--pkg disabledsettings without trying to acquire the build lock (#15589, fixes #15587, @Alizter) - Make generated MDX executables inherit
link_flagsfromenvstanzas. (#15614, fixes #15613, @Alizter) - Return Unix errors from
Fs_io.read_filerather than raising them. (#15641, @rgrinberg) - Correct filesystem trace metrics for file writes and directory scans. (#15686, @rgrinberg)
- Preserve runtime-event ring IDs in Dune traces so consumers can distinguish interleaved event streams. (#15687, @rgrinberg)
- BREAKING CHANGE: in dune-project, (warnings (duplicate_deps ..)) requires a dune lang version of 3.22, instead of 3.18 (#15696, @v-gb).
- Preserve spaces in unquoted filenames when applying Git patches instead of truncating paths at the first space (#15781, @rgrinberg)
- Respect
enabled_ifoninstallstanzas when adding their files and directories to the@allalias. (#15895, fixes #15825, @aryemans) - Fix Melange emission with installed libraries whose
.cmjand.cmifiles are stored in themelangeobject directory (#15949, fixes #14820, @anmonteiro) - Reject package dependencies in named dependency bindings while decoding dependency fields, including for disabled stanzas. (#15966, @rgrinberg)
- Fix Merlin definition lookup for libraries with private modules (#15977, fixes #4892, @anmonteiro)
- Fix a crash when generating install rules for a Melange-only implementation of an installed virtual library (#16033, @anmonteiro)
- Prevent build cancellation from crashing Dune when macOS reports
EPERMwhile signaling a process group (#16059, fixes #16053, @rgrinberg) - Fix
dune pkg outdatedso it fails early with a clear user message if it is run when package management is not enabled. (#16065, @shonfeder) - Fix watch mode builds remaining stale after the file watcher event queue overflows (#16068, fixes #16052, @rgrinberg)
- Reject Windows path separators in validated filename components (#16076, @rgrinberg)
- Preserve output following malformed ANSI escape sequences and erase-line controls (#16116, @rgrinberg).
- Resolve relative paths passed to
dune ocaml top-modulefrom the directory where Dune was started, allowing use from workspace subdirectories. (#16135, @rgrinberg) - Allow
dune ocaml topto accept absolute directory paths inside the workspace. (#16142, @rgrinberg) - Allow Dune promotion commands to accept absolute source paths inside the workspace. (#16143, @rgrinberg)
- Allow
dune describe workspaceto accept absolute directory filters inside the workspace. (#16144, @rgrinberg) - Reject empty
module_systemsfields inmelange.emitstanzas instead of silently producing no JavaScript files (#16162, @anmonteiro) - Sandbox PPX lint actions starting with Dune language 3.25 so linters cannot observe undeclared build targets. (#16176, @rgrinberg)
- Prevent diagnostic source locations at compact-position field boundaries from being truncated (#16180, @rgrinberg)
- Sandbox
ocaml-mdx depswhen using MDX extension 0.6 so dependency discovery cannot observe undeclared workspace inputs. (#16183, @rgrinberg) - Fix missing Odoc generation of OxCaml parameter implementations (#16200, @art-w)
- Make
Dune_rpc_lwt.V1.Action_plugin.read_directory_with_globreturn an empty listing for absent directories (#16207, fixes #4445, @rgrinberg) - Fix compiling Melange implementations of installed virtual libraries, both with and without binary annotations, including transitive private module dependencies (#16211, #16212, #16272, @anmonteiro)
- Run Ctypes stub generation in a sandbox and honor its declared dependencies. (#16223, @rgrinberg)
- Fix
@opamfailing to promote a generated opam file after it is deleted (#16234, fixes #16233, @Alizter) - Rebuild generated Ctypes helpers when headers from Ctypes' implicit include directories change (#16243, @rgrinberg)
- Collect action-provided trace events when an action fails instead of dropping them during result validation. (#16250, @rgrinberg)
- Report the usual program-not-found error when a
dynamic-runexecutable is missing instead of failing with an assertion. (#16251, @rgrinberg) - Prevent rules with duplicate lock declarations from deadlocking by acquiring each lock only once. (#16252, @rgrinberg)
- Prevent concurrent action children from closing shared redirections before their siblings use them (#16257, @rgrinberg)
- Resolve relative paths in forwarded build, runtest, and exec commands from the client's directory instead of the RPC server's directory (#16267, @rgrinberg)
(env (env-vars ...))in a(context ...)stanza ofdune-workspacenow takes precedence over the rootenvstanza, as documented. This affects commands such asdune exec; rules already used the documented order. (#16290, @punchagan)- Fix a crash when an opam filter is not a boolean (#16313, @art-w)
- Correct module paths for generated interfaces of nested qualified module groups. (#16322, @anmonteiro)
- Resolve
%{cmi:...},%{cmt:...}, and%{cmti:...}against Melange module sets when no OCaml module is selected, while preferring OCaml for modules selected in both modes. (#16339, @anmonteiro) - Reject
.and..asmelange.emittargets instead of raising an internal error (#16371, @anmonteiro) - Validate custom toplevel names as filenames, reporting an error for empty names and avoiding crashes for names containing paths (#16373, @anmonteiro)
- Fix Menhir type inference with package-managed relocatable compilers on macOS by making the compiler standard library available in the sandbox (#16374, fixes #15642, @Alizter, @shonfeder)
- Reject invalid Menhir
merge_intonames during parsing to prevent internal errors (#16387, @anmonteiro) - Reject conflicting module sources in unqualified directory groups, including generated sources, instead of silently discarding one (#16414, @anmonteiro)
- fix copying of directory targets on windows (#16434, @kentookura)
- Track local module dependencies used by Menhir's type inference so generated parsers and dependent modules build and rebuild correctly (#16447, fixes #14450, @anmonteiro)
- Fix Menhir type inference for qualified module group interfaces while keeping dependency lookup in terms of logical module names (#16464, #16489, #16497, fixes #8989, @anmonteiro)
- Fix intermittent crashes on Windows caused by unstable file descriptor hashing (#16476, fixes #16459, @Alizter)
- Explain that forwarded build requests require a watch-mode Dune server instead of reporting an internal RPC error. (#16486, fixes #16219, @Alizter)
(deps (package ...))now tracks installed files of lock-built packages and their package dependencies, rebuilding actions when they change. (#16507, @Alizter)- Share Rocq plugin layout dependencies between discovery and compilation rules, reducing repeated dependency processing in unchanged builds. (#16622, @Alizter)
- Support directory dependencies in hardlink sandboxes by linking their files rather than the directories themselves (#16675, @Alizter).
- Fix recursive copy actions rejecting symbolic links, including file links created by symlink sandboxes (#16686, @rgrinberg).
- Fix copy sandbox failures caused by overlapping directory and file dependencies (#16806, fixes #16547, @Alizter)
- Fix Menhir inference producing invalid module paths for types imported from other modules (#16952, @anmonteiro)
Added
- Add
(dirs ...)to(include_subdirs (mode qualified) ...), allowing qualified source directories to be renamed in the module path, including when bootstrapping. Mappings can use variables, including reads from generated files outside the qualified group (#13691, #16418, #16420, fixes #7605, @anmonteiro). - Add opt-in action runners via
--action-runner, and add--sandbox-actionsto run eligible process-spawning actions in a bubblewrap-wrapped worker. (#14240, @rgrinberg) - Add platform support for DragonFly BSD (#14774, fixes same issue with lev as seen on NetBSD in #14484, @mneumann).
- Added command, subcommand, and flag completion in the command line.
Supported shells are
bash,zsh, andpwsh. Seedune completion [shell] --help. (#14779, @ElectreAAS) - Add
%{git-sha}variable that expands to the short git SHA of the current HEAD commit, or the empty string when git is unavailable or the workspace is not inside a git repository (#14810, @toots). - Add a
?staticoptional argumentinConfigurator.V1.Pkg_config.getto instruct pkg-config to get static linking options. (#14947, @raphael-proust) - Only generate Melange rule for multi-mode libraries if
melcis installed (#15021, @anmonteiro) - Add
Configurator.V1.Pkg_config.query_variableto query package variables throughpkg-config --variable(#15078, fixes #3332, @rgrinberg). - Add
env_varsas an alias for theenv-varsfield inenvstanzas (#15187, fixes #11424, @rgrinberg). - Add
@rocqprojectalias to generate all `_RocqProject files (#15221, @rlepigre-skylabs-ai). - Tab completion for
dune promotenow lists pending promotion files. (#15338, fixes #7254, @Alizter). - Add build time information to watch mode (#15384, @rgrinberg)
- Added the missing
dune tools exec utopanddune tools exec odocoptions. (#15388, @Leonidas-from-XIV) - Display build parallelism in watch mode. (#15390, @rgrinberg)
- Add process counts, system cpu, user cpu, and wall clock cpu times to trace events (#15401, @rgrinberg)
- Support
--sandbox-actionson macOS using sandbox-exec. (#15500, @rgrinberg) - Add
fishto the shells supported bydune completion, enabling command, subcommand, and flag completion in the fish shell (#15515, fixes #15334, @chizy7) - Display build duration and average process parallelism in the status line for batch builds. (#15564, @rgrinberg)
- Add a
--split-public-namesflag todune describe workspaceanddune describe external-lib-deps. When enabled, thename/namesfields report only private names and a newpublic_name/public_namesfield reports the public names. (#15582, @natkarmios) - Add a
--include-emptyflag todune describe external-lib-depsto also print libraries that have no internal or external dependencies (#15585, @NatKarmios) - Support qualified module references in fields such as
per_modulewhen using(include_subdirs qualified)(#15633, fixes #15578, @anmonteiro) - Display the current build run at the end of watch-mode status lines. (#15673, @rgrinberg)
- Record per-build Memo compute, restore, and cycle-detection metrics in Dune traces. (#15698, @rgrinberg)
- Record discovered, validated, and failed rule counts in Dune traces. (#15701, @rgrinberg)
- Add
%{melange.emit:...}to reference a Melange output directory and depend on its emitted files (#15751, @anmonteiro) - Add
(flags ...)to theocamllexandocamlyaccstanzas to pass custom options to parser generators. (#15907, @rgrinberg) - Added an opt-in
sattrace category emitting asat/solveevent with the SAT solver's stats (variables, clauses, decisions, conflicts) and duration. Enable withDUNE_TRACE=+sat. (#15923, @Alizter) - Add
dune ocaml inferred-mlito infer an interface with a module's build configuration and register it for promotion. (#16111, fixes #12727, @rgrinberg) - Add
--no-actionsand--only-actionstodune trace catto filter events collected from actions. (#16245, @rgrinberg)
Changed
- BREAKING CHANGE: Actions no longer see the shared install staging area
(
_build/install/<context>/{bin,lib,lib/stublibs}) onPATH,OCAMLPATHandCAML_LD_LIBRARY_PATH. An action's environment only contains the packages it declares with(deps (package <pkg>))(and their library closure, see below). Actions that rely on packages being visible (such as tests that#requirethe package under test from an mdx block, steps that runocamlfind, a nesteddunebuild, or load a bytecode stub library) must now declare the package dependency explicitly. (#14373, #16617, @Alizter) (package <pkg>)now also includes the packages owning the library closures of libraries in workspace and installed packages. Installed packages reached through those closures also work with Dune language versions older than 2.9. (#14373, #16362, #16529, @Alizter, @anmonteiro)- Extract the structural-hash accumulator into a new
Stdune.Hashmodule and routeStdune.Tuple.T2.hash,Stdune.Tuple.T3.hash,Stdune.List.hash,Stdune.Result.hash, andResolve.error_hashthrough it. Hashing these structural shapes no longer allocates per call. (#14542, @robinbb) - Remove
(using melange 0.1)in Dune 3.25 in favor of version 1.0 of the extension. (#14574, @anmonteiro) $ dune rpc buildinvocations no longer queue. All build requests are built in parallel. Watch servers started by$ dune exec --watchcan now also handle forwarded build and runtest requests (#14954, @rgrinberg)- Report rule build progress as the number of rules built against the total number of live rules, rather than rules executed against rules discovered during the current run. This affects both the status line and the progress reported over RPC. (#14985, @snowleopard, @pwhite)
- With
--error-reporting=twice, print an==== Error Summary ====separator before the deterministic list of errors reported at the end of the build. The separator is omitted when there are no errors to report. (#15016, fixes #14757, @yussypu) - Enable fuzzy patch application by default for Dune. This is similar to OPAM's behaviour, and this makes it easier for packages like OxCaml to build. (#15146, fixes #15145, @Sudha247)
- Odoc rules are now sandboxed (#15190, @rgrinberg)
- In watch mode,
$ dune rpc buildrequests now complete as soon as their requested build finishes, instead of waiting for unrelated concurrent RPC build requests in the same build iteration. (#15191, fixes #13788, @rgrinberg) - Cleanup all build processes spawned by dune before starting a fresh build on Linux. (#15239, #15274, @rgrinberg)
- Show partial output timed out cram tests (#15269, @rgrinberg)
- In watch mode,
$ dune rpc buildnow exits with status 1 when the requested build fails. (#15341, @rgrinberg) - Debounce file change events in watch mode (#15344, @rgrinberg)
- Align dune's C compiler vendor detection with the OCaml compiler's own
identifiers (
msvc,icc,mingw,clang,gcc,xlc,sunc), so more C compilers are recognized without emitting a spurious warning. (#15423, fixes #14870, @chizy7) - Never use
$ lsoffor counting file descriptors, as it is not allowed to reap processes outside of the scheduler. We have better mechanisms on MacOS and Linux for counting file descriptors. So this is only an issue on other Unices. (#15477, @rgrinberg) dune describe workspacenow reports anoriginfield for every module, indicating whether its source was written by hand (source), generated by arulestanza (dune, with the generating dune file), produced byocamllex,ocamlyacc, ormenhir, or synthesised by dune itself for wrapping (wrapper). Generated modules point at the responsible file. The--with-origin-depsand--with-origin-deps-expandedflags additionally report the dependencies of arule-generated module, as declared and expanded to concrete files respectively. (#15478, @nat-karmios)- Numbers with unit now allow dropping the unit if the number is zero ("0").
For example,
dune cache trim --trimmed-size 0anddune cache trim --trimmed-size 0TiBare now both accepted and equivalent. (#15498, @reynir) - Run artifact substitution in background workers. (#15559, @anmonteiro)
dune describenow reports the public name of an executable (frompublic_name/public_names) instead of its private name when one is available, falling back to the private name otherwise. (#15582, @natkarmios)- Calculate status-line build parallelism from process CPU time rather than wall-clock action time; Windows continues to use wall-clock time. (#15685, @rgrinberg)
- Use sha256 instead of md5 for source archives that lack a checksum (#15824, @shunueda)
- Starting with Dune language 3.25, restrict sandboxed actions on Linux
systems with Landlock ABI 3 or newer from writing outside their sandbox,
temporary directory, action-trace directory, and
/dev. SetDUNE_CONFIG__LANDLOCK=disabledto opt out. (#15858, @rgrinberg) dune pkg locknow fails without writing a lock directory when any platform requested bysolve_for_platformscannot be solved, instead of producing a partial lock directory containing only the successful platforms. (#15981, @Alizter)- Portable lock directories now select one package version across all requested platforms, and fail when no common version exists. (#15982, fixes #13645, fixes #13647, @Alizter)
- BREAKING CHANGE: Reject
:in context names so they remain portable path components (#16085, @rgrinberg) - Keep
.tsuffixes in cram test names, including aliases andapplies_to, starting with Dune language 3.25 (#16146, @rgrinberg) - Sandbox
ocaml-mdx dune-genwhen using MDX extension 0.6, available from Dune 3.25. (#16177, @rgrinberg) - Sandbox
pkg-configqueries starting with Dune language 3.25 so they cannot observe undeclared workspace inputs. (#16178, @rgrinberg) - Remove the experimental OCamlFDO integration, including the
(fdo ...)workspace field (#16198, @rgrinberg) - BREAKING CHANGE: Generated files are now read-only even with Dune language versions before 2.4, regardless of whether the shared cache is enabled. Executable permissions are preserved. (#16388, @rgrinberg)
- Make newly written shared-cache metadata files read-only to guard against accidental modification. (#16393, @rgrinberg)