Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions .github/workflows/binaries.yml
Original file line number Diff line number Diff line change
@@ -1,37 +1,62 @@
name: Binaries

on:
push:
branches:
- main
pull_request:
merge_group:
workflow_dispatch:
inputs:
upload:
description: Upload built binaries as artifacts
type: boolean
default: false

jobs:
binary:
name: Create
name: ${{ matrix.name }}
strategy:
fail-fast: false
matrix:
# `name` follows the LLVM/Rust target-triple convention
# (`<arch>-<vendor>-<sys>-<abi>`). For Windows, `-gnu` denotes the
# MinGW (GNU) ABI, as opposed to `-msvc`.
include:
- os: macos-15-intel
name: x86_64-apple-darwin
installable: .#
installable: .#dune
- os: macos-14
name: aarch64-apple-darwin
installable: .#
installable: .#dune
- os: ubuntu-22.04
name: x86_64-unknown-linux-musl
installable: .#dune-static
- os: ubuntu-22.04
name: x86_64-pc-windows-gnu
installable: .#windows-static
binary: dune.exe
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # for git describe
- uses: cachix/install-nix-action@v31
- uses: nix-community/cache-nix-action@v7
with:
primary-key: |
nix-${{ runner.os }}-${{ github.job }}-${{ matrix.name }}--${{ hashFiles('**/*.nix', '**/flake.lock') }}
restore-prefixes-first-match: nix-${{ runner.os }}-${{ github.job }}-${{ matrix.name }}--
gc-max-store-size-linux: 2G
- run: echo "(version $(git describe --always --dirty --abbrev=7))" >> dune-project
- run: nix build ${{ matrix.installable }}
- uses: actions/upload-artifact@v7
- if: ${{ inputs.upload }}
uses: actions/upload-artifact@v7
with:
path: result/bin/dune
path: result/bin/${{ matrix.binary || 'dune' }}
name: dune-${{ matrix.name }}
combine:
if: ${{ inputs.upload }}
runs-on: ubuntu-latest
needs: binary
steps:
Expand Down
29 changes: 26 additions & 3 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,26 @@
inherit (nixpkgsOcaml.odoc) version src;
doCheck = false;
});
# Templates the cross-compiled dune binary used by
# `windows-static`. Lives at the top-level scope so
# `nix-overlays`' cross-overlay sees it during scope
# construction and `fixOCamlPackage` can pair the cross
# derivation with this native template via
# `findNativePackage`.
dune_target = oself.callPackage ./nix/dune-target.nix { };
}
);
# Keep `ocaml-ng.ocamlPackages_5_4` in sync with the override
# above. nix-overlays' `cross/ocaml.nix:46` looks up the native
# OCaml via `buildPackages.ocaml-ng."ocamlPackages_5_4"`, so
# without this the cross-target side uses our overridden ocaml
# while the native side (used to build findlib's `nativeBuild-
# Inputs` etc.) uses the unoverridden ocaml+flambda — the
# mismatch shows up as cross `ocamlopt` rejecting native
# `topdirs.cmx` ("not a compilation unit description").
ocaml-ng = super.ocaml-ng // {
ocamlPackages_5_4 = self.ocamlPackages;
};
})
melange.overlays.default
];
Expand Down Expand Up @@ -106,9 +124,14 @@
src = ./.;
};
in
{
inherit (dune-package) default dune-static;
dune = self.packages.${pkgs.stdenv.hostPlatform.system}.default;
rec {
inherit (dune-package)
default
musl-static
windows-static
;
dune = default;
dune-static = musl-static;
}
);

Expand Down
71 changes: 69 additions & 2 deletions nix/dune-package.nix
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# The dune package, built from the source tree at `src`.
#
# Returns `default` (native build) and `dune-static` (musl64 cross build).
# Returns:
# - `default`: native build
# - `musl-static`: x86_64 musl static cross build (nixpkgs' dune with the
# source tree's bootstrap invoked under `--static`)
# - `windows-static`: mingw static cross build (via `dune build -x windows`,
# driven from the `dune-target.nix` derivation)
# - `dune-static`: alias for `musl-static`
{
nixpkgs,
ocaml-overlays,
Expand Down Expand Up @@ -38,6 +44,11 @@ let
]
);

# Static musl build: nixpkgs' own dune, pointed at this source tree and
# bootstrapped with `--static`. Matches the setup on `main`. The
# `dune-target.nix` cross machinery is windows-only for now — once
# `nix-overlays` applies its cross-overlay to `pkgsCross.musl64` (it
# currently only applies the static-overlay) we can move this over too.
dune-static-overlay = self: super: {
ocamlPackages = super.ocaml-ng.ocamlPackages_5_4.overrideScope (
oself: osuper: {
Expand All @@ -53,6 +64,56 @@ let
ocaml-overlays.overlays.default
dune-static-overlay
];

# Used by `windows-static`. The `dune_target` overlay is applied only to
# the cross pkgs we're building against, so it never leaks into the dev
# shells. We also widen `meta.platforms` on `ocaml` and on every
# `buildDunePackage` derivation in that scope: nixpkgs' ocaml-side metadata
# excludes mingw even though those packages build fine there, and widening
# avoids the `NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1` escape hatch at the call
# site.
duneFor =
crossPkgs:
let
withDuneTarget = crossPkgs.appendOverlays [
(self: super: {
ocamlPackages = super.ocamlPackages.overrideScope (
oself: osuper: {
# ocaml itself excludes mingw via `meta.platforms`. Widen it
# so cross builds against this scope evaluate.
ocaml = osuper.ocaml.overrideAttrs (o: {
meta = (o.meta or { }) // { platforms = lib.platforms.all; };
});
buildDunePackage =
arg:
let
widen = a: a // {
meta = (a.meta or { }) // { platforms = lib.platforms.all; };
};
in
# nix-overlays' `buildDunePackage` accepts either an attrset
# or a `final: attrset` function (see `cross/ocaml.nix`).
osuper.buildDunePackage (
if builtins.isFunction arg then final: widen (arg final) else widen arg
);
}
);
})
];
in
withDuneTarget.ocamlPackages.dune_target.overrideAttrs { src = dune-source; };

overrideOcaml =
ocamlOverride: crossPkgs:
crossPkgs.appendOverlays [
(self: super: {
ocamlPackages = super.ocamlPackages.overrideScope (
oself: osuper: {
ocaml = osuper.ocaml.override ocamlOverride;
}
);
})
];
in
{
default =
Expand All @@ -78,5 +139,11 @@ in
"LIBDIR=$(OCAMLFIND_DESTDIR)"
];
};
dune-static = pkgs-static.pkgsCross.musl64.ocamlPackages.dune;

musl-static = pkgs-static.pkgsCross.musl64.ocamlPackages.dune;

# `framePointerSupport` is forced off because mingw can't build OCaml
windows-static = duneFor (
overrideOcaml { framePointerSupport = false; } pkgs.pkgsCross.mingwW64Static
);
}
61 changes: 61 additions & 0 deletions nix/dune-target.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Cross-compile-friendly dune derivation. Native: a buildDunePackage template
# (not buildable natively by design — exists so findlib config has dune's deps
# in scope). Cross: overrides build/install phases to use `dune build -x
# <target>`.
{
lib,
stdenv,
buildPackages,
buildDunePackage,
ocaml,
dune_3,
csexp,
pp,
ppx_expect,
re,
spawn,
uutf,
}:
let
isCross = stdenv.hostPlatform.config != stdenv.buildPlatform.config;
# Must match the toolchain name nix-overlays sets in the findlib config
# (`cross/ocaml.nix`). Otherwise dune's `-x` lookup misses and falls back
# to a native build.
crossName =
if stdenv.hostPlatform.isMinGW then "windows" else lib.head (lib.splitString "-" stdenv.system);
installedName = if stdenv.hostPlatform.isMinGW then "dune.exe" else "dune";

template = buildDunePackage {
pname = "dune_target";
inherit (dune_3) version src;
buildInputs = [
csexp
pp
ppx_expect
re
spawn
uutf
];
};
in
if !isCross then
template
else
assert stdenv.hostPlatform.isMinGW -> lib.versionAtLeast ocaml.version "5.4";
template.overrideAttrs (o: {
dontAddPrefix = true;
dontFixup = true;
depsBuildBuild = [ buildPackages.stdenv.cc ];
nativeBuildInputs = lib.remove buildPackages.stdenv.cc (o.nativeBuildInputs or [ ]);
buildPhase = ''
runHook preBuild
dune build -x ${crossName} ''${enableParallelBuilding:+-j $NIX_BUILD_CORES} bin/main.exe
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out/bin
cp _build/default.${crossName}/bin/main.exe $out/bin/${installedName}
runHook postInstall
'';
})
Loading