The unpac monorepo manager self-hosting as a monorepo using unpac
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Generate a relocatable cloning script

+335 -3
+1
.gitattributes
··· 109 109 # Some Unicode characters here and there 110 110 utils/misc.ml typo.non-ascii 111 111 runtime/sak.c typo.non-ascii 112 + tools/opam/process.sh typo.non-ascii 112 113 113 114 testsuite/tests/** typo.missing-header typo.long-line=may 114 115 testsuite/tests/lib-bigarray-2/bigarrf.f typo.tab linguist-language=Fortran
+34 -3
Makefile.common
··· 299 299 else 300 300 # Symlinks aren't available, so copy the file again using the target name 301 301 RECORD_SYMLINK_TO_INSTALL = \ 302 - $(call RECORD_opam_ITEM_TO_INSTALL,$(1),$(2),$(3),$(5)) 302 + $(call RECORD_$(INSTALL_MODE)_ITEM_TO_INSTALL,$(1),$(2),$(3),$(5)) 303 303 endif 304 304 305 - # Process the arguments to pass to RECORD_opam_ITEM_TO_INSTALL: 305 + # Process the arguments to pass to RECORD_$(INSTALL_MODE)_ITEM_TO_INSTALL: 306 306 # - Items installed to the stublibs section need to be remapped to the stublibs 307 307 # subdirectory of libexec (since we install to lib/ocaml/stublibs rather than 308 308 # opam's default lib/stublibs) ··· 316 316 $(if $(filter stublibs,$(2)),\ 317 317 $(call RECORD_ITEM_TO_INSTALL,$\ 318 318 $(1),libexec,stublibs$(addprefix /,$(3)),$(4),$(5)),\ 319 - $(call RECORD_opam_ITEM_TO_INSTALL,$\ 319 + $(call RECORD_$(INSTALL_MODE)_ITEM_TO_INSTALL,$\ 320 320 $(addsuffix /,$(SUBDIR_NAME))$(1),$\ 321 321 $(2),$\ 322 322 $(if $(filter doc lib%,$(2)),ocaml$(addprefix /,$(3)),$(3)),$\ ··· 383 383 # then munge clone-* and create-symlinks into the fixup script. 384 384 INSTALL_DESPATCH_opam_END = \ 385 385 tools/opam/generate-install.sh $(OPAM_PACKAGE_NAME) $(UNIX_OR_WIN32) '$(LN)' 386 + 387 + # Generate $(OPAM_PACKAGE_NAME)-clone.sh (INSTALL_MODE=clone) 388 + 389 + # ld.conf is explicitly copied, rather than cloned, to allow (in principle, if 390 + # not in practice) the cloning installation to edit it. 391 + RECORD_clone_ITEM_TO_INSTALL = \ 392 + $(if $(filter runtime/ld.conf Makefile.config, $(1)), true, \ 393 + $(if $(filter libexec,$(2)), \ 394 + $(call RECORD_clone_ITEM_TO_INSTALL,$(1),lib,$(3),$(4),$(5)), \ 395 + $(call ADD_LINE, \ 396 + $(ROOTDIR)/clone-$(2)$(addprefix @,$(subst /,@,$(3))), \ 397 + $(2)$(addprefix /,$(3))/$(if $(4),$(4),$(notdir $(1)))) \ 398 + $(foreach link, $(5), && \ 399 + $(call RECORD_SYMLINK_TO_INSTALL,$(1),$(2),$(3),$(4),$(link))))) 400 + 401 + INSTALL_DESPATCH_clone_ITEM = $(RECORD_ITEM_TO_INSTALL) 402 + 403 + INSTALL_DESPATCH_clone_ITEMS = $(INSTALL_EVALUATE_GLOBS) 404 + 405 + INSTALL_clone_PREFIX = @ 406 + 407 + INSTALL_DESPATCH_clone_RM = @ 408 + 409 + # INSTALL_MKDIR is ignored - INSTALL_DESPATCH_clone_END automatically creates 410 + # directories for each cp file. 411 + INSTALL_DESPATCH_clone_MKDIR = 412 + 413 + INSTALL_DESPATCH_clone_BEGIN = rm -f clone-* create-symlinks 414 + 415 + INSTALL_DESPATCH_clone_END = \ 416 + tools/opam/generate-clone.sh $(OPAM_PACKAGE_NAME) $(UNIX_OR_WIN32) '$(LN)' 386 417 387 418 FLEXDLL_SUBMODULE_PRESENT := $(wildcard $(ROOTDIR)/flexdll/Makefile) 388 419
+110
tools/opam/generate-clone.sh
··· 1 + #!/bin/sh -e 2 + #************************************************************************** 3 + #* * 4 + #* OCaml * 5 + #* * 6 + #* David Allsopp, University of Cambridge & Tarides * 7 + #* * 8 + #* Copyright 2025 David Allsopp Ltd. * 9 + #* * 10 + #* All rights reserved. This file is distributed under the terms of * 11 + #* the GNU Lesser General Public License version 2.1, with the * 12 + #* special exception on linking described in the file LICENSE. * 13 + #* * 14 + #************************************************************************** 15 + 16 + # This script is called from the root of the repository at the end of 17 + # `make INSTALL_MODE=clone install` and is responsible for converting the 18 + # various files generated by the clone installation backend into a -clone.sh 19 + # script. 20 + # Parameters are the following Makefile variables: 21 + # $1 = $(OPAM_PACKAGE_NAME) 22 + # $2 = $(UNIX_OR_WIN32) 23 + # $3 = $(LN) 24 + 25 + echo 'share/ocaml/clone' > clone-share@ocaml 26 + if [ -e config.cache ]; then 27 + echo 'share/ocaml/config.cache' >> clone-share@ocaml 28 + fi 29 + 30 + if [ "$2" = 'win32' ]; then 31 + preserve='' 32 + else 33 + preserve='p' 34 + fi 35 + 36 + { 37 + cat <<'EOF' 38 + #!/bin/sh 39 + set -eu 40 + mkdir -p "$1" 41 + rm -f "$1/__cp_test" "$1/__ln_test" 42 + if cp --reflink=always doc/ocaml/LICENSE "$1/__cp_test" 2>/dev/null; then 43 + rm -f "$1/__cp_test" 44 + EOF 45 + echo " CP='cp --reflink=always -${preserve}f'" 46 + cat <<'EOF' 47 + if ! test -e "$1/clone-files"; then 48 + echo "$CP"' "$@" "$dest/"' > "$1/clone-files" 49 + fi 50 + else 51 + EOF 52 + echo " CP='cp -${preserve}f'" 53 + cat <<'EOF' 54 + if ! test -e "$1/clone-files"; then 55 + if ln -f doc/ocaml/LICENSE "$1/__ln_test" 2>/dev/null; then 56 + rm -f "$1/__ln_test" 57 + echo 'ln -f "$@" "$dest/"' > "$1/clone-files" 58 + else 59 + echo "$CP"' "$@" "$dest/"' > "$1/clone-files" 60 + fi 61 + fi 62 + fi 63 + EOF 64 + for fileset in clone-*; do 65 + dir="$(echo "${fileset#clone-}" | sed -e 's|@|/|g')" 66 + echo 'mkdir -p "$1"'"'/$dir'" 67 + echo 'dest="$1"'"'/$dir'"' xargs sh "$1/clone-files" <<'"'EOF'" 68 + cat "$fileset" 69 + echo 'EOF' 70 + done 71 + rm -f clone-* 72 + # ld.conf is a configuration file, so is always copied. Makefile.config and 73 + # config.status will both contain the original prefix, which must be updated. 74 + cat <<'EOF' 75 + cp lib/ocaml/ld.conf "$1/lib/ocaml/ld.conf" 76 + cat > "$1/prefix.awk" <<'ENDAWK' 77 + { 78 + rest = $0 79 + while ((p = index(rest, ENVIRON["O"]))) { 80 + printf "%s%s", substr(rest, 1, p-1), ENVIRON["N"] 81 + rest = substr(rest, p + length(ENVIRON["O"])) 82 + } 83 + print rest 84 + } 85 + ENDAWK 86 + prefix="$(sed -ne 's/^prefix *= *//p' lib/ocaml/Makefile.config)" 87 + for file in lib/ocaml/Makefile.config share/ocaml/config.status; do 88 + O="$prefix" N="$1" awk -f "$1/prefix.awk" "$file" > "$1/$file" 89 + done 90 + rm -f "$1/clone-files" "$1/prefix.awk" 91 + EOF 92 + if [ -f create-symlinks ]; then 93 + echo 'cd "$1"' 94 + if [ "$2" = 'win32' ]; then 95 + echo 'cmd /c "mklink __ln_test mklink-test"' 96 + echo 'if test -L "$1/__ln_test"; then' 97 + sed -e 's|\(.*\) \(.*\) \(.*\)|mklink \1/\3 \2|' \ 98 + -e 's|/|\\\\|g' \ 99 + -e 's|.*| cmd /c "&"|' create-symlinks 100 + echo 'else' 101 + sed -e 's|\(.*\) \(.*\) \(.*\)| $CP '"'\\1/\\2' '\\1/\\3'|" \ 102 + create-symlinks 103 + echo 'fi' 104 + echo 'rm -f __ln_test' 105 + else 106 + sed -e 's|\(.*\) \(.*\) \(.*\)|'"$3 '\\2' '\\1/\\3'|" create-symlinks 107 + fi 108 + rm create-symlinks 109 + fi 110 + } > "$1-clone.sh"
+190
tools/opam/process.sh
··· 1 + #!/bin/sh 2 + #************************************************************************** 3 + #* * 4 + #* OCaml * 5 + #* * 6 + #* David Allsopp, University of Cambridge & Tarides * 7 + #* * 8 + #* Copyright 2025 David Allsopp Ltd. * 9 + #* * 10 + #* All rights reserved. This file is distributed under the terms of * 11 + #* the GNU Lesser General Public License version 2.1, with the * 12 + #* special exception on linking described in the file LICENSE. * 13 + #* * 14 + #************************************************************************** 15 + 16 + set -eu 17 + 18 + # POSIX.1-2024 (Issue 8) lifts this from being a bashism. The sub-shell dance is 19 + # necessary because set is a builtin and is permitted to abort the script 20 + # unconditionally on error. 21 + if (set -o pipefail 2> /dev/null); then 22 + set -o pipefail 23 + fi 24 + 25 + # This script is responsible for building and cloning OCaml installations. It is 26 + # invoked by both the build and install sections of an opam package. 27 + # $1 = make command (the `make` variable in opam). This should be the path to 28 + # a binary only and is invoked without word-splitting (i.e. any 29 + # additional arguments should be passed in $2 and the command is invoked 30 + # "$1"). 31 + # $2 = additional arguments passed to "$1". This variable will be used 32 + # unquoted - arguments with spaces cannot be passed. From the build 33 + # section, this allows the -j argument to be specified. For the install 34 + # section, this argument must be "install". 35 + # $3 = opam build-id variable of this package. 36 + # $4 = name of the opam package to be used when generating .install and 37 + # .config files. 38 + # The remaining arguments depend on the value of $2. When it is "install": 39 + # $5 = installation prefix, which may be a native Windows path, rather than a 40 + # Cygwin path. 41 + # When $2 is not "install" (the build opam section): 42 + # $5 = "enabled" if cloning the compiler from an existing switch is permitted 43 + # and "disabled" to force the compiler to be built from sources. 44 + # $6, and any further arguments are additional options to pass to `configure` 45 + # if the compiler is built from sources. 46 + 47 + make="$1" 48 + make_args="$2" 49 + build_id="$3" 50 + package_name="$4" 51 + 52 + if [ x"$make_args" = 'xinstall' ]; then 53 + prefix="$5" 54 + 55 + echo "📦 Installing the compiler to $prefix" 56 + if [ -e 'config.status' ]; then 57 + echo "📜 Using make install" 58 + "$make" install 59 + else 60 + origin="$(tail -n 1 build-id)" 61 + origin_prefix="$(opam var --safe --switch="$origin" prefix | tr -d '\r')" 62 + echo "🪄 Duplicating $origin_prefix" 63 + ( cd "$origin_prefix" && sh ./share/ocaml/clone "$prefix" ) 64 + fi 65 + 66 + exit 0 67 + fi 68 + 69 + # Build the package 70 + 71 + cloning="$5" 72 + shift 5 73 + # "$@" now expands to the correctly-quoted arguments to pass to configure 74 + 75 + origin='' 76 + clone_mechanism='' 77 + if [ x"$cloning" = 'xenabled' ]; then 78 + echo "🕵️ Searching for a switch containing build-id $build_id" 79 + 80 + if [ -e "$OPAM_SWITCH_PREFIX/share/ocaml/build-id" ]; then 81 + switch="$(tail -n 1 "$OPAM_SWITCH_PREFIX/share/ocaml/build-id")" 82 + if [ -n "$switch" ]; then 83 + switch_share_dir="$(opam var --safe --switch="$switch" share \ 84 + | tr -d '\r')" 85 + switch_build_id="$switch_share_dir/ocaml/build-id" 86 + if [ -e "$switch_build_id" ]; then 87 + if [ x"$build_id" = x"$(head -n 1 "$switch_build_id")" ]; then 88 + echo "🔁 Prefer to re-clone from $switch" 89 + echo "$switch" > opam-switches 90 + origin="$switch" 91 + if ln "$switch_build_id" __cp_test 2>/dev/null; then 92 + rm __cp_test 93 + clone_mechanism='hard-linking' 94 + fi 95 + fi 96 + fi 97 + fi 98 + fi 99 + 100 + echo "🐫 Requesting list of switches from opam" 101 + opam switch list --safe --short | tr -d '\r' | grep -Fxv "$OPAMSWITCH" \ 102 + >> opam-switches 2> /dev/null || true 103 + 104 + while IFS= read -r switch; do 105 + switch_share_dir="$(opam var --safe --switch="$switch" share | tr -d '\r')" 106 + switch_build_id="$switch_share_dir/ocaml/build-id" 107 + if [ -e "$switch_build_id" ]; then 108 + if [ x"$build_id" = x"$(head -n 1 "$switch_build_id")" ]; then 109 + # There are three ways of cloning a switch: 110 + # - Copy-on-Write (cp --reflink=always) 111 + # - Hard linking 112 + # - Copy 113 + # Copy-on-Write is the ideal - virtually no space overhead, but with 114 + # defence against accidental subsequent alterations. Hard linking is 115 + # preferred over copying for the space-saving, and because the 116 + # compiler should not being subsequently altered. 117 + if cp --reflink=always "$switch_build_id" __cp_test 2>/dev/null; then 118 + rm __cp_test 119 + echo "📝 - can reflink from: $switch" 120 + origin="$switch" 121 + clone_mechanism='copy-on-write' 122 + break 123 + elif ln "$switch_build_id" __cp_test 2>/dev/null; then 124 + rm __cp_test 125 + if [ -z "$clone_mechanism" ]; then 126 + echo "🔗 - can hard link from: $switch" 127 + origin="$switch" 128 + clone_mechanism='hard-linking' 129 + fi 130 + elif [ -z "$origin" ]; then 131 + echo "📄 - can copy from: $switch" 132 + origin="$switch" 133 + fi 134 + elif [ -z "$origin" ]; then 135 + echo "⛔ - different compiler: $switch" 136 + fi 137 + fi 138 + done < opam-switches 139 + fi 140 + 141 + { echo "$build_id"; echo "$origin" ; } > build-id 142 + 143 + if [ -n "$origin" ]; then 144 + 145 + echo "🧬 Will clone the compiler from $origin" 146 + test -n "$clone_mechanism" || clone_mechanism='copying' 147 + 148 + cloned='true' 149 + clone_source="$(sed -e '1d;s/\\/\\\\/g;s/%/%%/g;s/"/\\"/g' build-id)" 150 + case "$origin" in 151 + */*|*\\*) clone_source="local switch $clone_source";; 152 + *) clone_source="global switch $clone_source";; 153 + esac 154 + 155 + cat > "$package_name.install" <<'EOF' 156 + share_root: [ 157 + "build-id" {"ocaml/build-id"} 158 + ] 159 + EOF 160 + 161 + else 162 + 163 + echo "🏗️ Will build the compiler from sources" 164 + 165 + cloned='false' 166 + clone_source='' 167 + 168 + ./configure --cache-file=config.cache "$@" 169 + "$make" $make_args 170 + "$make" OPAM_PACKAGE_NAME=ocaml-compiler INSTALL_MODE=clone install 171 + 172 + cat > "$package_name.install" <<'EOF' 173 + share_root: [ 174 + "build-id" {"ocaml/build-id"} 175 + "ocaml-compiler-clone.sh" {"ocaml/clone"} 176 + "config.cache" {"ocaml/config.cache"} 177 + "config.status" {"ocaml/config.status"} 178 + ] 179 + EOF 180 + fi 181 + 182 + # Create the .config file 183 + cat > "$package_name.config" <<EOF 184 + opam-version: "2.0" 185 + variables { 186 + cloned: $cloned 187 + clone-source: "$clone_source" 188 + clone-mechanism: "$clone_mechanism" 189 + } 190 + EOF