···109109# Some Unicode characters here and there
110110utils/misc.ml typo.non-ascii
111111runtime/sak.c typo.non-ascii
112112+tools/opam/process.sh typo.non-ascii
112113113114testsuite/tests/** typo.missing-header typo.long-line=may
114115testsuite/tests/lib-bigarray-2/bigarrf.f typo.tab linguist-language=Fortran
+34-3
Makefile.common
···299299else
300300# Symlinks aren't available, so copy the file again using the target name
301301RECORD_SYMLINK_TO_INSTALL = \
302302- $(call RECORD_opam_ITEM_TO_INSTALL,$(1),$(2),$(3),$(5))
302302+ $(call RECORD_$(INSTALL_MODE)_ITEM_TO_INSTALL,$(1),$(2),$(3),$(5))
303303endif
304304305305-# Process the arguments to pass to RECORD_opam_ITEM_TO_INSTALL:
305305+# Process the arguments to pass to RECORD_$(INSTALL_MODE)_ITEM_TO_INSTALL:
306306# - Items installed to the stublibs section need to be remapped to the stublibs
307307# subdirectory of libexec (since we install to lib/ocaml/stublibs rather than
308308# opam's default lib/stublibs)
···316316 $(if $(filter stublibs,$(2)),\
317317 $(call RECORD_ITEM_TO_INSTALL,$\
318318 $(1),libexec,stublibs$(addprefix /,$(3)),$(4),$(5)),\
319319- $(call RECORD_opam_ITEM_TO_INSTALL,$\
319319+ $(call RECORD_$(INSTALL_MODE)_ITEM_TO_INSTALL,$\
320320 $(addsuffix /,$(SUBDIR_NAME))$(1),$\
321321 $(2),$\
322322 $(if $(filter doc lib%,$(2)),ocaml$(addprefix /,$(3)),$(3)),$\
···383383# then munge clone-* and create-symlinks into the fixup script.
384384INSTALL_DESPATCH_opam_END = \
385385 tools/opam/generate-install.sh $(OPAM_PACKAGE_NAME) $(UNIX_OR_WIN32) '$(LN)'
386386+387387+# Generate $(OPAM_PACKAGE_NAME)-clone.sh (INSTALL_MODE=clone)
388388+389389+# ld.conf is explicitly copied, rather than cloned, to allow (in principle, if
390390+# not in practice) the cloning installation to edit it.
391391+RECORD_clone_ITEM_TO_INSTALL = \
392392+ $(if $(filter runtime/ld.conf Makefile.config, $(1)), true, \
393393+ $(if $(filter libexec,$(2)), \
394394+ $(call RECORD_clone_ITEM_TO_INSTALL,$(1),lib,$(3),$(4),$(5)), \
395395+ $(call ADD_LINE, \
396396+ $(ROOTDIR)/clone-$(2)$(addprefix @,$(subst /,@,$(3))), \
397397+ $(2)$(addprefix /,$(3))/$(if $(4),$(4),$(notdir $(1)))) \
398398+ $(foreach link, $(5), && \
399399+ $(call RECORD_SYMLINK_TO_INSTALL,$(1),$(2),$(3),$(4),$(link)))))
400400+401401+INSTALL_DESPATCH_clone_ITEM = $(RECORD_ITEM_TO_INSTALL)
402402+403403+INSTALL_DESPATCH_clone_ITEMS = $(INSTALL_EVALUATE_GLOBS)
404404+405405+INSTALL_clone_PREFIX = @
406406+407407+INSTALL_DESPATCH_clone_RM = @
408408+409409+# INSTALL_MKDIR is ignored - INSTALL_DESPATCH_clone_END automatically creates
410410+# directories for each cp file.
411411+INSTALL_DESPATCH_clone_MKDIR =
412412+413413+INSTALL_DESPATCH_clone_BEGIN = rm -f clone-* create-symlinks
414414+415415+INSTALL_DESPATCH_clone_END = \
416416+ tools/opam/generate-clone.sh $(OPAM_PACKAGE_NAME) $(UNIX_OR_WIN32) '$(LN)'
386417387418FLEXDLL_SUBMODULE_PRESENT := $(wildcard $(ROOTDIR)/flexdll/Makefile)
388419
+110
tools/opam/generate-clone.sh
···11+#!/bin/sh -e
22+#**************************************************************************
33+#* *
44+#* OCaml *
55+#* *
66+#* David Allsopp, University of Cambridge & Tarides *
77+#* *
88+#* Copyright 2025 David Allsopp Ltd. *
99+#* *
1010+#* All rights reserved. This file is distributed under the terms of *
1111+#* the GNU Lesser General Public License version 2.1, with the *
1212+#* special exception on linking described in the file LICENSE. *
1313+#* *
1414+#**************************************************************************
1515+1616+# This script is called from the root of the repository at the end of
1717+# `make INSTALL_MODE=clone install` and is responsible for converting the
1818+# various files generated by the clone installation backend into a -clone.sh
1919+# script.
2020+# Parameters are the following Makefile variables:
2121+# $1 = $(OPAM_PACKAGE_NAME)
2222+# $2 = $(UNIX_OR_WIN32)
2323+# $3 = $(LN)
2424+2525+echo 'share/ocaml/clone' > clone-share@ocaml
2626+if [ -e config.cache ]; then
2727+ echo 'share/ocaml/config.cache' >> clone-share@ocaml
2828+fi
2929+3030+if [ "$2" = 'win32' ]; then
3131+ preserve=''
3232+else
3333+ preserve='p'
3434+fi
3535+3636+{
3737+ cat <<'EOF'
3838+#!/bin/sh
3939+set -eu
4040+mkdir -p "$1"
4141+rm -f "$1/__cp_test" "$1/__ln_test"
4242+if cp --reflink=always doc/ocaml/LICENSE "$1/__cp_test" 2>/dev/null; then
4343+ rm -f "$1/__cp_test"
4444+EOF
4545+ echo " CP='cp --reflink=always -${preserve}f'"
4646+ cat <<'EOF'
4747+ if ! test -e "$1/clone-files"; then
4848+ echo "$CP"' "$@" "$dest/"' > "$1/clone-files"
4949+ fi
5050+else
5151+EOF
5252+ echo " CP='cp -${preserve}f'"
5353+ cat <<'EOF'
5454+ if ! test -e "$1/clone-files"; then
5555+ if ln -f doc/ocaml/LICENSE "$1/__ln_test" 2>/dev/null; then
5656+ rm -f "$1/__ln_test"
5757+ echo 'ln -f "$@" "$dest/"' > "$1/clone-files"
5858+ else
5959+ echo "$CP"' "$@" "$dest/"' > "$1/clone-files"
6060+ fi
6161+ fi
6262+fi
6363+EOF
6464+ for fileset in clone-*; do
6565+ dir="$(echo "${fileset#clone-}" | sed -e 's|@|/|g')"
6666+ echo 'mkdir -p "$1"'"'/$dir'"
6767+ echo 'dest="$1"'"'/$dir'"' xargs sh "$1/clone-files" <<'"'EOF'"
6868+ cat "$fileset"
6969+ echo 'EOF'
7070+ done
7171+ rm -f clone-*
7272+ # ld.conf is a configuration file, so is always copied. Makefile.config and
7373+ # config.status will both contain the original prefix, which must be updated.
7474+ cat <<'EOF'
7575+cp lib/ocaml/ld.conf "$1/lib/ocaml/ld.conf"
7676+cat > "$1/prefix.awk" <<'ENDAWK'
7777+{
7878+ rest = $0
7979+ while ((p = index(rest, ENVIRON["O"]))) {
8080+ printf "%s%s", substr(rest, 1, p-1), ENVIRON["N"]
8181+ rest = substr(rest, p + length(ENVIRON["O"]))
8282+ }
8383+ print rest
8484+}
8585+ENDAWK
8686+prefix="$(sed -ne 's/^prefix *= *//p' lib/ocaml/Makefile.config)"
8787+for file in lib/ocaml/Makefile.config share/ocaml/config.status; do
8888+ O="$prefix" N="$1" awk -f "$1/prefix.awk" "$file" > "$1/$file"
8989+done
9090+rm -f "$1/clone-files" "$1/prefix.awk"
9191+EOF
9292+ if [ -f create-symlinks ]; then
9393+ echo 'cd "$1"'
9494+ if [ "$2" = 'win32' ]; then
9595+ echo 'cmd /c "mklink __ln_test mklink-test"'
9696+ echo 'if test -L "$1/__ln_test"; then'
9797+ sed -e 's|\(.*\) \(.*\) \(.*\)|mklink \1/\3 \2|' \
9898+ -e 's|/|\\\\|g' \
9999+ -e 's|.*| cmd /c "&"|' create-symlinks
100100+ echo 'else'
101101+ sed -e 's|\(.*\) \(.*\) \(.*\)| $CP '"'\\1/\\2' '\\1/\\3'|" \
102102+ create-symlinks
103103+ echo 'fi'
104104+ echo 'rm -f __ln_test'
105105+ else
106106+ sed -e 's|\(.*\) \(.*\) \(.*\)|'"$3 '\\2' '\\1/\\3'|" create-symlinks
107107+ fi
108108+ rm create-symlinks
109109+ fi
110110+} > "$1-clone.sh"
+190
tools/opam/process.sh
···11+#!/bin/sh
22+#**************************************************************************
33+#* *
44+#* OCaml *
55+#* *
66+#* David Allsopp, University of Cambridge & Tarides *
77+#* *
88+#* Copyright 2025 David Allsopp Ltd. *
99+#* *
1010+#* All rights reserved. This file is distributed under the terms of *
1111+#* the GNU Lesser General Public License version 2.1, with the *
1212+#* special exception on linking described in the file LICENSE. *
1313+#* *
1414+#**************************************************************************
1515+1616+set -eu
1717+1818+# POSIX.1-2024 (Issue 8) lifts this from being a bashism. The sub-shell dance is
1919+# necessary because set is a builtin and is permitted to abort the script
2020+# unconditionally on error.
2121+if (set -o pipefail 2> /dev/null); then
2222+ set -o pipefail
2323+fi
2424+2525+# This script is responsible for building and cloning OCaml installations. It is
2626+# invoked by both the build and install sections of an opam package.
2727+# $1 = make command (the `make` variable in opam). This should be the path to
2828+# a binary only and is invoked without word-splitting (i.e. any
2929+# additional arguments should be passed in $2 and the command is invoked
3030+# "$1").
3131+# $2 = additional arguments passed to "$1". This variable will be used
3232+# unquoted - arguments with spaces cannot be passed. From the build
3333+# section, this allows the -j argument to be specified. For the install
3434+# section, this argument must be "install".
3535+# $3 = opam build-id variable of this package.
3636+# $4 = name of the opam package to be used when generating .install and
3737+# .config files.
3838+# The remaining arguments depend on the value of $2. When it is "install":
3939+# $5 = installation prefix, which may be a native Windows path, rather than a
4040+# Cygwin path.
4141+# When $2 is not "install" (the build opam section):
4242+# $5 = "enabled" if cloning the compiler from an existing switch is permitted
4343+# and "disabled" to force the compiler to be built from sources.
4444+# $6, and any further arguments are additional options to pass to `configure`
4545+# if the compiler is built from sources.
4646+4747+make="$1"
4848+make_args="$2"
4949+build_id="$3"
5050+package_name="$4"
5151+5252+if [ x"$make_args" = 'xinstall' ]; then
5353+ prefix="$5"
5454+5555+ echo "📦 Installing the compiler to $prefix"
5656+ if [ -e 'config.status' ]; then
5757+ echo "📜 Using make install"
5858+ "$make" install
5959+ else
6060+ origin="$(tail -n 1 build-id)"
6161+ origin_prefix="$(opam var --safe --switch="$origin" prefix | tr -d '\r')"
6262+ echo "🪄 Duplicating $origin_prefix"
6363+ ( cd "$origin_prefix" && sh ./share/ocaml/clone "$prefix" )
6464+ fi
6565+6666+ exit 0
6767+fi
6868+6969+# Build the package
7070+7171+cloning="$5"
7272+shift 5
7373+# "$@" now expands to the correctly-quoted arguments to pass to configure
7474+7575+origin=''
7676+clone_mechanism=''
7777+if [ x"$cloning" = 'xenabled' ]; then
7878+ echo "🕵️ Searching for a switch containing build-id $build_id"
7979+8080+ if [ -e "$OPAM_SWITCH_PREFIX/share/ocaml/build-id" ]; then
8181+ switch="$(tail -n 1 "$OPAM_SWITCH_PREFIX/share/ocaml/build-id")"
8282+ if [ -n "$switch" ]; then
8383+ switch_share_dir="$(opam var --safe --switch="$switch" share \
8484+ | tr -d '\r')"
8585+ switch_build_id="$switch_share_dir/ocaml/build-id"
8686+ if [ -e "$switch_build_id" ]; then
8787+ if [ x"$build_id" = x"$(head -n 1 "$switch_build_id")" ]; then
8888+ echo "🔁 Prefer to re-clone from $switch"
8989+ echo "$switch" > opam-switches
9090+ origin="$switch"
9191+ if ln "$switch_build_id" __cp_test 2>/dev/null; then
9292+ rm __cp_test
9393+ clone_mechanism='hard-linking'
9494+ fi
9595+ fi
9696+ fi
9797+ fi
9898+ fi
9999+100100+ echo "🐫 Requesting list of switches from opam"
101101+ opam switch list --safe --short | tr -d '\r' | grep -Fxv "$OPAMSWITCH" \
102102+ >> opam-switches 2> /dev/null || true
103103+104104+ while IFS= read -r switch; do
105105+ switch_share_dir="$(opam var --safe --switch="$switch" share | tr -d '\r')"
106106+ switch_build_id="$switch_share_dir/ocaml/build-id"
107107+ if [ -e "$switch_build_id" ]; then
108108+ if [ x"$build_id" = x"$(head -n 1 "$switch_build_id")" ]; then
109109+ # There are three ways of cloning a switch:
110110+ # - Copy-on-Write (cp --reflink=always)
111111+ # - Hard linking
112112+ # - Copy
113113+ # Copy-on-Write is the ideal - virtually no space overhead, but with
114114+ # defence against accidental subsequent alterations. Hard linking is
115115+ # preferred over copying for the space-saving, and because the
116116+ # compiler should not being subsequently altered.
117117+ if cp --reflink=always "$switch_build_id" __cp_test 2>/dev/null; then
118118+ rm __cp_test
119119+ echo "📝 - can reflink from: $switch"
120120+ origin="$switch"
121121+ clone_mechanism='copy-on-write'
122122+ break
123123+ elif ln "$switch_build_id" __cp_test 2>/dev/null; then
124124+ rm __cp_test
125125+ if [ -z "$clone_mechanism" ]; then
126126+ echo "🔗 - can hard link from: $switch"
127127+ origin="$switch"
128128+ clone_mechanism='hard-linking'
129129+ fi
130130+ elif [ -z "$origin" ]; then
131131+ echo "📄 - can copy from: $switch"
132132+ origin="$switch"
133133+ fi
134134+ elif [ -z "$origin" ]; then
135135+ echo "⛔ - different compiler: $switch"
136136+ fi
137137+ fi
138138+ done < opam-switches
139139+fi
140140+141141+{ echo "$build_id"; echo "$origin" ; } > build-id
142142+143143+if [ -n "$origin" ]; then
144144+145145+ echo "🧬 Will clone the compiler from $origin"
146146+ test -n "$clone_mechanism" || clone_mechanism='copying'
147147+148148+ cloned='true'
149149+ clone_source="$(sed -e '1d;s/\\/\\\\/g;s/%/%%/g;s/"/\\"/g' build-id)"
150150+ case "$origin" in
151151+ */*|*\\*) clone_source="local switch $clone_source";;
152152+ *) clone_source="global switch $clone_source";;
153153+ esac
154154+155155+ cat > "$package_name.install" <<'EOF'
156156+share_root: [
157157+ "build-id" {"ocaml/build-id"}
158158+]
159159+EOF
160160+161161+else
162162+163163+ echo "🏗️ Will build the compiler from sources"
164164+165165+ cloned='false'
166166+ clone_source=''
167167+168168+ ./configure --cache-file=config.cache "$@"
169169+ "$make" $make_args
170170+ "$make" OPAM_PACKAGE_NAME=ocaml-compiler INSTALL_MODE=clone install
171171+172172+ cat > "$package_name.install" <<'EOF'
173173+share_root: [
174174+ "build-id" {"ocaml/build-id"}
175175+ "ocaml-compiler-clone.sh" {"ocaml/clone"}
176176+ "config.cache" {"ocaml/config.cache"}
177177+ "config.status" {"ocaml/config.status"}
178178+]
179179+EOF
180180+fi
181181+182182+# Create the .config file
183183+cat > "$package_name.config" <<EOF
184184+opam-version: "2.0"
185185+variables {
186186+ cloned: $cloned
187187+ clone-source: "$clone_source"
188188+ clone-mechanism: "$clone_mechanism"
189189+}
190190+EOF