From f4c6bf95c28fe395b893648778e2ecfab51ed94e Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Sun, 9 Mar 2025 16:28:37 +0000 Subject: [PATCH 1/2] Adjust configuration for Relocatable OCaml Makefile.config contains copies of PREFIX, BINDIR, LIBDIR and MANDIR from OCaml's Makefile.config. These values were not actually being used, and they become much less reliable with Relocatable OCaml. They've therefore been removed. OCAML_LIBDIR was previously a copy of LIBDIR from OCaml's Makefile.config. However, this file is found by running `ocamlc -where`, which itself _gives_ the value for OCAML_LIBDIR. For Relocatable OCaml, `ocamlc -where` is guaranteed to be correct, where the LIBDIR value may not be, so tweak the generation of Makefile.config to use this value instead. --- configure.make | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/configure.make b/configure.make index 39349891..9dc154ad 100644 --- a/configure.make +++ b/configure.make @@ -6,11 +6,11 @@ # from the main Makefile, but this made it not robust to addition of # new variables to this ocaml/Makefile.config that we do not control. -include $(shell ocamlc -where)/Makefile.config +OCAML_LIBDIR = $(shell ocamlc -where) +include $(OCAML_LIBDIR)/Makefile.config OCAML_PREFIX = $(PREFIX) OCAML_BINDIR = $(BINDIR) -OCAML_LIBDIR = $(LIBDIR) OCAML_MANDIR = $(MANDIR) # If you want to affect ocamlbuild's configuration by passing variable @@ -67,11 +67,6 @@ distclean: Makefile.config: (echo "# This file was generated from configure.make"; \ echo ;\ - echo "OCAML_PREFIX=$(OCAML_PREFIX)"; \ - echo "OCAML_BINDIR=$(OCAML_BINDIR)"; \ - echo "OCAML_LIBDIR=$(OCAML_LIBDIR)"; \ - echo "OCAML_MANDIR=$(OCAML_MANDIR)"; \ - echo ;\ echo "EXT_OBJ=$(EXT_OBJ)"; \ echo "EXT_ASM=$(EXT_ASM)"; \ echo "EXT_LIB=$(EXT_LIB)"; \ From 1b4b2ea49762cda69b288616429e83535f7048cf Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Sun, 9 Mar 2025 18:00:42 +0000 Subject: [PATCH 2/2] Relocatable ocamlbuild In configure.make, specifying a path beginning ./ or ../ or OCAMLBUILD_LIBDIR enabled Relocatable ocamlbuild, as long as the ocamlbuild binary is being installed in the same directory as the compiler and the compiler itself is Relocatable OCaml. The relative path given for OCAMLBUILD_LIBDIR describes how to get from OCaml's Standard Library to the directory containing the "ocamlbuild" package directory (in opam, this is just ".."). In this mode, `ocamlbuild -where` is determined relative to the Standard Library. --- Makefile | 4 +-- configure.make | 67 +++++++++++++++++++++++++++++++++---- ocamlbuild.opam | 2 +- src/ocamlbuild_config.ml.in | 35 +++++++++++++++++++ 4 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 src/ocamlbuild_config.ml.in diff --git a/Makefile b/Makefile index 934361a4..29043323 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ endif CP ?= cp OCB_COMPFLAGS ?= -w @14@29 -w +L -w +R -w +Z -I src -I plugin-lib -I bin -I +unix -safe-string -bin-annot -strict-sequence -OCB_LINKFLAGS ?= -I +unix -I src +OCB_LINKFLAGS ?= -I +unix -I src $(OCB_EXTRA_LINKFLAGS) PACK_CMO= $(addprefix src/,\ const.cmo \ @@ -179,7 +179,7 @@ configure: $(MAKE) -f configure.make all # proxy rule for rebuilding configuration files directly from the main Makefile -Makefile.config src/ocamlbuild_config.ml: +Makefile.config src/ocamlbuild_config.ml: src/ocamlbuild_config.ml.in $(MAKE) -f configure.make $@ clean:: diff --git a/configure.make b/configure.make index 9dc154ad..eda2acab 100644 --- a/configure.make +++ b/configure.make @@ -29,6 +29,35 @@ OCAMLBUILD_MANDIR ?= \ $(or $(shell opam config var man 2>/dev/null),\ $(OCAML_MANDIR)) +# OCAMLBUILD_RELOCATABLE is true if: +# 1. The compiler is Relocatable OCaml +# 2. The ocamlbuild will be installed in the same directory as the compiler +# 3. OCAMLBUILD_LIBDIR is an explicit relative path (i.e. begins ./ or ../) +# OCAMLBUILD_RELOCATABLE is empty if any of these things are not true. +OCAMLBUILD_LIBDIR_RELATIVE = $(filter . .. ./% ../%, $(OCAMLBUILD_LIBDIR)) +OCAML_RELOCATABLE = \ + $(shell ocamlc -config-var standard_library_relative 2>/dev/null) +OCAMLC_BIN_DIR = $(abspath $(dir $(shell command -v ocamlc))) +# On Windows, OCAMLC_BIN_DIR will be a Cygwin-style path but OCAMLBUILD_BINDIR +# is a native path. The requirement is that the OCAMLBUILD_BINDIR needs to be +# the same as the compiler - that means it _must_ already exist, so it gets +# canonicalised using "poor man's realpath" by doing cd+pwd. +OCAMLBUILD_BINDIR_RESOLVED = $(shell cd '$(OCAMLBUILD_BINDIR)' 2>/dev/null ; pwd) +OCAMLBUILD_RELOCATABLE := \ + $(if $(OCAMLBUILD_LIBDIR_RELATIVE),$\ + $(if $(OCAML_RELOCATABLE),$\ + $(if $(filter $(abspath $(OCAMLBUILD_BINDIR_RESOLVED)),$(OCAMLC_BIN_DIR)),true))) + +# If OCAMLBUILD_LIBDIR is an explicit relative path, but Relocatable ocamlbuild +# cannot be built (see above), then OCAMLBUILD_LIBDIR_ACTUAL is the absolute +# path calculated by concatenating OCAML_LIBDIR and OCAMLBUILD_LIBDIR. Otherwise +# it is just OCAMLBUILD_LIBDIR. +OCAMLBUILD_LIBDIR_ACTUAL := \ + $(if $(OCAMLBUILD_RELOCATABLE),$(OCAMLBUILD_LIBDIR),$\ + $(if $(OCAMLBUILD_LIBDIR_RELATIVE),$\ + $(if $(filter .., $(OCAMLBUILD_LIBDIR)),$(dir $(OCAML_LIBDIR)),$\ + $(abspath $(OCAML_LIBDIR)/$(OCAMLBUILD_LIBDIR)),$(OCAMLBUILD_LIBDIR)))) + # It is important to distinguish OCAML_LIBDIR, which points to the # directory of the ocaml compiler distribution, and OCAMLBUILD_LIBDIR, # which should be the general library directory of OCaml projects on @@ -77,20 +106,45 @@ Makefile.config: echo "OCAML_NATIVE_TOOLS=$(OCAML_NATIVE_TOOLS)"; \ echo "NATDYNLINK=$(NATDYNLINK)"; \ echo "SUPPORT_SHARED_LIBRARIES=$(SUPPORTS_SHARED_LIBRARIES)"; \ + echo "OCB_EXTRA_LINKFLAGS=$(OCB_EXTRA_LINKFLAGS)"; \ echo ;\ echo "PREFIX=$(OCAMLBUILD_PREFIX)"; \ echo "BINDIR=$(OCAMLBUILD_BINDIR)"; \ - echo "LIBDIR=$(OCAMLBUILD_LIBDIR)"; \ + echo "LIBDIR=$(OCAMLBUILD_LIBDIR_ACTUAL)"; \ echo "MANDIR=$(OCAMLBUILD_MANDIR)"; \ ) > $@ -src/ocamlbuild_config.ml: +ifeq ($(OCAMLBUILD_RELOCATABLE), true) + +# For Relocatable ocamlbuild, just record the relative path specified for +# OCAMLBUILD_LIBDIR and the current directory name (".") for BINDIR and the +# extra code apppended from src/ocamlbuild_config.ml.in will process the correct +# values at runtime. +src/ocamlbuild_config.ml: BINDIR = . +src/ocamlbuild_config.ml: OCAML_LIBDIR = +src/ocamlbuild_config.ml: LIBDIR_ABS = + +OCB_EXTRA_LINKFLAGS = \ + -set-runtime-default standard_library_default=$(OCAML_RELOCATABLE) + +else + +# For normal ocamlbuild, record the configured values. +src/ocamlbuild_config.ml: BINDIR := $(OCAMLBUILD_BINDIR) +src/ocamlbuild_config.ml: OCAML_LIBDIR := $(abspath $(OCAML_LIBDIR)) +src/ocamlbuild_config.ml: LIBDIR_ABS := $(abspath $(OCAMLBUILD_LIBDIR_ACTUAL)) + +OCB_EXTRA_LINKFLAGS = + +endif + +src/ocamlbuild_config.ml: src/ocamlbuild_config.ml.in (echo "(* This file was generated from ../configure.make *)"; \ echo ;\ - echo 'let bindir = {|$(OCAMLBUILD_BINDIR)|}'; \ - echo 'let libdir = {|$(OCAMLBUILD_LIBDIR)|}'; \ - echo 'let ocaml_libdir = {|$(abspath $(OCAML_LIBDIR))|}'; \ - echo 'let libdir_abs = {|$(abspath $(OCAMLBUILD_LIBDIR))|}'; \ + echo 'let bindir = {|$(BINDIR)|}'; \ + echo 'let libdir = {|$(OCAMLBUILD_LIBDIR_ACTUAL)|}'; \ + echo 'let ocaml_libdir = {|$(OCAML_LIBDIR)|}'; \ + echo 'let libdir_abs = {|$(LIBDIR_ABS)|}'; \ echo 'let ocaml_native = $(OCAML_NATIVE)'; \ echo 'let ocaml_native_tools = $(OCAML_NATIVE_TOOLS)'; \ echo 'let supports_shared_libraries = $(SUPPORTS_SHARED_LIBRARIES)';\ @@ -100,4 +154,5 @@ src/ocamlbuild_config.ml: echo 'let ext_dll = "$(EXT_DLL)"'; \ echo 'let exe = "$(EXE)"'; \ echo 'let version = "$(shell ocaml scripts/cat.ml VERSION)"'; \ + $(if $(OCAMLBUILD_RELOCATABLE),cat src/ocamlbuild_config.ml.in;) \ ) > $@ diff --git a/ocamlbuild.opam b/ocamlbuild.opam index 894fcdac..dad4473f 100644 --- a/ocamlbuild.opam +++ b/ocamlbuild.opam @@ -17,7 +17,7 @@ build: [ "all" "OCAMLBUILD_PREFIX=%{prefix}%" "OCAMLBUILD_BINDIR=%{bin}%" - "OCAMLBUILD_LIBDIR=%{lib}%" + "OCAMLBUILD_LIBDIR=.." "OCAMLBUILD_MANDIR=%{man}%" "OCAML_NATIVE=%{ocaml:native}%" "OCAML_NATIVE_TOOLS=%{ocaml:native}%" diff --git a/src/ocamlbuild_config.ml.in b/src/ocamlbuild_config.ml.in new file mode 100644 index 00000000..afcccc61 --- /dev/null +++ b/src/ocamlbuild_config.ml.in @@ -0,0 +1,35 @@ +#2 "ocamlbuild_config.ml.in" +(***********************************************************************) +(* *) +(* ocamlbuild *) +(* *) +(* David Allsopp, Tarides *) +(* *) +(* Copyright 2025 David Allsopp Ltd. All rights reserved. This *) +(* file is distributed under the terms of the GNU Library General *) +(* Public License, with the special exception on linking described *) +(* in file ../LICENSE. *) +(* *) +(***********************************************************************) + +(* Compute the effective default for the Standard Library *) +let ocaml_libdir, bindir = + let module Defs = struct + external default : unit -> string = "%standard_library_default" + external get : string -> string * string option = "caml_sys_get_stdlib_dirs" + end in + match Defs.get (Defs.default ()) with + | ocaml_libdir, Some bindir -> + ocaml_libdir, bindir + | ocaml_libdir, None -> + (* This code should in theory only be being executed on a relocatable + runtime *) + ocaml_libdir, Filename.dirname Sys.executable_name + +let libdir = + if libdir = ".." then + (* Cheeky special case, as it happens to match opam *) + Filename.dirname ocaml_libdir + else + (* General case *) + Filename.concat ocaml_libdir libdir