Skip to content

Commit

Permalink
Allow libdir to be found relative to bindir
Browse files Browse the repository at this point in the history
When configured with --enable-relative, the runtime uses the directory
of the executable to determine the location of the Standard Library.
Thus, ocamlrun and the compilers look for ../lib/ocaml by default.

This is implemented by changing caml_standard_library_default to be a
relative path, and then computing the actual value at startup (for
bytecode) and when queried (for native, since it is only ever used if
Dynlink is being used).

Executables (and objects) produced by the compiler always have an
absolute value of caml_standard_library_default. ocamlc.opt and
ocamlopt.opt are built using -set-global-string to force
caml_standard_library_default to stay a relative value.
  • Loading branch information
dra27 committed Sep 25, 2024
1 parent b316fc9 commit 5a71a3e
Show file tree
Hide file tree
Showing 27 changed files with 352 additions and 25 deletions.
4 changes: 4 additions & 0 deletions .depend
Original file line number Diff line number Diff line change
Expand Up @@ -2336,6 +2336,7 @@ bytecomp/bytelink.cmo : \
utils/consistbl.cmi \
utils/config.cmi \
utils/compression.cmi \
driver/compenv.cmi \
file_formats/cmo_format.cmi \
utils/clflags.cmi \
utils/ccomp.cmi \
Expand All @@ -2355,6 +2356,7 @@ bytecomp/bytelink.cmx : \
utils/consistbl.cmx \
utils/config.cmx \
utils/compression.cmx \
driver/compenv.cmx \
file_formats/cmo_format.cmi \
utils/clflags.cmx \
utils/ccomp.cmx \
Expand Down Expand Up @@ -2750,6 +2752,7 @@ asmcomp/asmlink.cmo : \
utils/consistbl.cmi \
utils/config.cmi \
middle_end/compilenv.cmi \
driver/compenv.cmi \
file_formats/cmx_format.cmi \
asmcomp/cmm_helpers.cmi \
asmcomp/cmm.cmi \
Expand All @@ -2771,6 +2774,7 @@ asmcomp/asmlink.cmx : \
utils/consistbl.cmx \
utils/config.cmx \
middle_end/compilenv.cmx \
driver/compenv.cmx \
file_formats/cmx_format.cmi \
asmcomp/cmm_helpers.cmx \
asmcomp/cmm.cmx \
Expand Down
6 changes: 6 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ ___________
runtime assertions.
(Antonin Décimo, review by Miod Vallat, Gabriel Scherer, and David Allsopp)

- #13???: Added --enable-relative which allows the runtime and the compilers to
locate the Standard Library relative to where the binaries themselves,
removing the absolute path previously embedded in
caml_standard_library_default.
(David Allsopp, review by ???)

### Code generation and optimizations:

- #13014: Enable compile-time option -function-sections on all previously
Expand Down
21 changes: 15 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1429,15 +1429,22 @@ C_LITERAL = $(shell $(SAK) encode-C-literal '$(1)')

runtime/build_config.h: $(ROOTDIR)/Makefile.config $(SAK)
$(V_GEN)echo '/* This file is generated from $(ROOTDIR)/Makefile.config */' > $@ && \
echo '#define OCAML_STDLIB_DIR $(call C_LITERAL,$(LIBDIR))' >> $@ && \
echo '#define HOST "$(HOST)"' >> $@
echo '#define OCAML_STDLIB_DIR $(call C_LITERAL,$(LIBDIR))' >> $@
ifneq "$(LIBDIR_REL)" ""
@echo '#define OCAML_STDLIB_DIR_REL $(call C_LITERAL,$(LIBDIR_REL))' >> $@
endif
@echo '#define HOST "$(HOST)"' >> $@

runtime/stdlib.$(O): runtime/build_config.h

## Runtime libraries and programs

runtime/ocamlrun$(EXE): runtime/prims.$(O) runtime/libcamlrun.$(A)
runtime/ocamlrun$(EXE): runtime/prims.$(O) runtime/stdlib.$(O) \
runtime/libcamlrun.$(A)
$(V_MKEXE)$(MKEXE) -o $@ $^ $(BYTECCLIBS)

runtime/ocamlruns$(EXE): runtime/prims.$(O) runtime/libcamlrun_non_shared.$(A)
runtime/ocamlruns$(EXE): runtime/prims.$(O) runtime/stdlib.$(O) \
runtime/libcamlrun_non_shared.$(A)
$(V_MKEXE)$(call MKEXE_VIA_CC,$@,$^ $(BYTECCLIBS))

runtime/libcamlrun.$(A): $(libcamlrun_OBJECTS)
Expand All @@ -1446,13 +1453,15 @@ runtime/libcamlrun.$(A): $(libcamlrun_OBJECTS)
runtime/libcamlrun_non_shared.$(A): $(libcamlrun_non_shared_OBJECTS)
$(V_MKLIB)$(call MKLIB,$@, $^)

runtime/ocamlrund$(EXE): runtime/prims.$(O) runtime/libcamlrund.$(A)
runtime/ocamlrund$(EXE): runtime/prims.$(O) runtime/stdlib.$(O) \
runtime/libcamlrund.$(A)
$(V_MKEXE)$(MKEXE) $(MKEXEDEBUGFLAG) -o $@ $^ $(BYTECCLIBS)

runtime/libcamlrund.$(A): $(libcamlrund_OBJECTS)
$(V_MKLIB)$(call MKLIB,$@, $^)

runtime/ocamlruni$(EXE): runtime/prims.$(O) runtime/libcamlruni.$(A)
runtime/ocamlruni$(EXE): runtime/prims.$(O) runtime/stdlib.$(O) \
runtime/libcamlruni.$(A)
$(V_MKEXE)$(MKEXE) -o $@ $^ $(INSTRUMENTED_RUNTIME_LIBS) $(BYTECCLIBS)

runtime/libcamlruni.$(A): $(libcamlruni_OBJECTS)
Expand Down
2 changes: 2 additions & 0 deletions Makefile.build_config.in
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,5 @@ TSAN=@tsan@
# Contains TSan-specific runtime files, or nothing if TSan support is
# disabled
TSAN_NATIVE_RUNTIME_C_SOURCES = @tsan_native_runtime_c_sources@

RELOCATABLE = @relocatable@
10 changes: 10 additions & 0 deletions Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,15 @@ ifeq "$(FUNCTION_SECTIONS)" "true"
OPTCOMPFLAGS += -function-sections
endif

ifeq "$(LIBDIR_REL)" ""
SET_RELATIVE_STDLIB =
else
SET_RELATIVE_STDLIB = \
-set-global-string 'caml_standard_library_default=$(LIBDIR_REL)'
endif

DOTOPT_LINKFLAGS = $(SET_RELATIVE_STDLIB)

# The rule to compile C files

# This rule is similar to GNU make's implicit rule, except that it is more
Expand Down Expand Up @@ -360,6 +369,7 @@ $(basename $(notdir $(1)))_NATIVE_LINKFLAGS =
$(basename $(notdir $(1)))_NATIVE_LINKCMD = \
$(strip \
$$(CAMLOPT) $$(OC_COMMON_LINKFLAGS) $$(OC_NATIVE_LINKFLAGS) \
$(DOTOPT_LINKFLAGS) \
$$($(basename $(notdir $(1)))_COMMON_LINKFLAGS) \
$$($(basename $(notdir $(1)))_NATIVE_LINKFLAGS))

Expand Down
1 change: 1 addition & 0 deletions asmcomp/asmlink.ml
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ let link ~ppf_dump objfiles output_name =
let obj_infos = List.map read_file objfiles in
let ldeps = Linkdeps.create ~complete:true in
let units_tolink = List.fold_right (scan_file ldeps) obj_infos [] in
Compenv.set_caml_standard_library_default ();
(match Linkdeps.check ldeps with
| None -> ()
| Some e -> raise (Error (Link_error e)));
Expand Down
2 changes: 2 additions & 0 deletions bytecomp/bytelink.ml
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,8 @@ let link objfiles output_name =
Clflags.all_ccopts := !lib_ccopts @ !Clflags.all_ccopts;
(* put user's opts first *)
Clflags.dllibs := !lib_dllibs @ !Clflags.dllibs; (* put user's DLLs first *)
if !Clflags.custom_runtime then
Compenv.set_caml_standard_library_default ();
if not !Clflags.custom_runtime then begin
assert (!Clflags.global_string_constants = []);
link_bytecode tolink output_name true
Expand Down
3 changes: 2 additions & 1 deletion bytecomp/dll.ml
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ let synchronize_primitive num symb =
let ld_conf_contents () =
let path = ref [] in
begin try
let ic = open_in (Filename.concat Config.standard_library "ld.conf") in
let ic =
open_in (Filename.concat Config.standard_library_effective "ld.conf") in
begin try
while true do
path := input_line ic :: !path
Expand Down
15 changes: 15 additions & 0 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ ocamltest_unix_impl="dummy"
unix_library=""
unix_directory=""
bindir_to_libdir=''
relocatable=no

# Information about the package

Expand Down Expand Up @@ -257,6 +258,7 @@ AC_SUBST([ocaml_libdir])
AC_SUBST([QS])
AC_SUBST([ar_supports_response_files])
AC_SUBST([bindir_to_libdir])
AC_SUBST([relocatable])

## Generated files

Expand Down Expand Up @@ -1169,6 +1171,7 @@ AS_CASE([$host],
[AC_CHECK_HEADERS([unistd.h],[AC_DEFINE([HAS_UNISTD], [1])])])

AC_CHECK_HEADER([math.h])
AC_CHECK_HEADERS([unistd.h],[AC_DEFINE([HAS_UNISTD])])
AC_CHECK_HEADER([pthread_np.h],[AC_DEFINE([HAS_PTHREAD_NP_H], [1])])
AC_CHECK_HEADER([dirent.h], [AC_DEFINE([HAS_DIRENT], [1])], [],
[#include <sys/types.h>])
Expand Down Expand Up @@ -2645,6 +2648,7 @@ AS_IF([test x"$mandir" = x'${datarootdir}/man'],
[mandir='${prefix}/man'])

AS_IF([test x"$enable_relative" = "xyes"],[
relocatable=yes
OCAML_COMPUTE_BINDIR_TO_LIBDIR([bindir],[libdir],[bindir_to_libdir])
dnl Tests for the OCAML_COMPUTE_BINDIR_TO_LIBDIR macro
dnl OCAML_COMPUTE_BINDIR_TO_LIBDIR_TESTS
Expand Down
7 changes: 7 additions & 0 deletions driver/compenv.ml
Original file line number Diff line number Diff line change
Expand Up @@ -732,3 +732,10 @@ let parse_arguments ?(current=ref 0) argv f program =
Printf.sprintf "Usage: %s <options> <files>\nOptions are:" program in
Printf.printf "%s\n%s" help_msg err_msg;
raise (Exit_with_status 0)

let set_caml_standard_library_default () =
let symbol = "caml_standard_library_default" in
if not (List.exists (fun (name, _) -> name = symbol)
!global_string_constants) then
global_string_constants :=
(symbol, Config.standard_library_effective) :: !global_string_constants
4 changes: 4 additions & 0 deletions driver/compenv.mli
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,7 @@ val process_deferred_actions :
*)
val parse_arguments : ?current:(int ref)
-> string array ref -> Arg.anon_fun -> string -> unit

(** Adds caml_standard_library_default to {!Clflags.global_string_constants}
if it isn't already present. *)
val set_caml_standard_library_default: unit -> unit
3 changes: 0 additions & 3 deletions runtime/caml/dynlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ extern void caml_build_primitive_table_builtin(void);
/* Unload all the previously loaded shared libraries */
extern void caml_free_shared_libs(void);

/* Return the effective location of the standard library */
extern char_os * caml_get_stdlib_location(void);

/* Parse ld.conf and add the lines read to caml_shared_libs_path */
extern char_os * caml_parse_ld_conf(void);

Expand Down
20 changes: 20 additions & 0 deletions runtime/caml/osdeps.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ CAMLextern clock_t caml_win32_clock(void);

CAMLextern value caml_win32_xdg_defaults(void);

#define CAML_DIR_SEP T("\\")
#define Is_dir_separator(c) (c == '\\' || c == '/')

#else

#define CAML_DIR_SEP "/"
#define Is_dir_separator(c) (c == '/')

#endif /* _WIN32 */

/* Returns the current value of a counter that increments once per nanosecond.
Expand All @@ -155,6 +163,18 @@ extern uint64_t caml_time_counter(void);

extern void caml_init_os_params(void);

/* True if:
- dir equals "."
- dir equals ".."
- dir begins "./"
- dir begins "../"
The tests for null avoid the need to call strlen_os. */
#define Is_relative_dir(dir) \
(dir[0] == '.' \
&& (dir[1] == 0 \
|| Is_dir_separator(dir[1]) \
|| (dir[1] == '.' && (dir[2] == 0 || Is_dir_separator(dir[2])))))

#endif /* CAML_INTERNALS */

#ifdef _WIN32
Expand Down
4 changes: 4 additions & 0 deletions runtime/caml/s.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@

/* Define HAS_UNISTD if you have /usr/include/unistd.h. */

#undef HAS_LIBGEN_H

/* Define HAS_LIBGEN_H if you have /usr/include/libgen.h. */

#undef HAS_DIRENT

/* Define HAS_DIRENT if you have /usr/include/dirent.h and the result of
Expand Down
6 changes: 6 additions & 0 deletions runtime/caml/sys.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,15 @@ CAMLnoret CAMLextern void caml_sys_io_error (value);

CAMLextern double caml_sys_time_unboxed(value);
CAMLextern void caml_sys_init (char_os * exe_name, char_os ** argv);
CAMLextern void caml_locate_standard_library (const char_os *);

CAMLnoret CAMLextern void caml_do_exit (int);

extern char_os * caml_standard_library_default;
extern char_os * caml_standard_library_relative;
extern char_os * caml_standard_library;
extern char_os *_Atomic caml_relative_root_dir;

#ifdef __cplusplus
}
#endif
Expand Down
3 changes: 2 additions & 1 deletion runtime/dynlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "caml/signals.h"
#include "caml/intext.h"
#include "caml/startup.h"
#include "caml/sys.h"

#include "build_config.h"

Expand Down Expand Up @@ -88,7 +89,7 @@ CAMLexport char_os * caml_get_stdlib_location(void)
char_os * stdlib;
stdlib = caml_secure_getenv(T("OCAMLLIB"));
if (stdlib == NULL) stdlib = caml_secure_getenv(T("CAMLLIB"));
if (stdlib == NULL) stdlib = OCAML_STDLIB_DIR;
if (stdlib == NULL) stdlib = caml_standard_library;
return stdlib;
}

Expand Down
11 changes: 7 additions & 4 deletions runtime/startup_byt.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,9 +383,7 @@ static void do_print_config(void)
/* Print the runtime configuration */
printf("version: %s\n", OCAML_VERSION_STRING);
printf("standard_library_default: %s\n",
caml_stat_strdup_of_os(OCAML_STDLIB_DIR));
printf("standard_library: %s\n",
caml_stat_strdup_of_os(caml_get_stdlib_location()));
caml_stat_strdup_of_os(caml_standard_library_default));
printf("int_size: %d\n", 8 * (int)sizeof(value));
printf("word_size: %d\n", 8 * (int)sizeof(value) - 1);
printf("os_type: %s\n", OCAML_OS_TYPE);
Expand Down Expand Up @@ -486,11 +484,14 @@ CAMLexport void caml_main(char_os **argv)
With -custom, we have an executable that is ocamlrun itself
concatenated with the bytecode. So, if the attempt with argv[0]
failed, it is worth trying again with executable_name. */
if (fd < 0 && (proc_self_exe = caml_executable_name()) != NULL) {
proc_self_exe = caml_executable_name();
if (fd < 0 && proc_self_exe != NULL) {
exe_name = proc_self_exe;
fd = caml_attempt_open(&exe_name, &trail, 0);
}

caml_locate_standard_library(proc_self_exe ? proc_self_exe : exe_name);

if (fd < 0) {
pos = parse_command_line(argv);
if (caml_params->print_config) {
Expand Down Expand Up @@ -622,6 +623,8 @@ CAMLexport value caml_startup_code_exn(
exe_name = caml_executable_name();
if (exe_name == NULL) exe_name = caml_search_exe_in_path(argv[0]);

caml_locate_standard_library(exe_name);

Caml_state->external_raise = NULL;
/* Setup signal handling */
caml_init_signals();
Expand Down
22 changes: 22 additions & 0 deletions runtime/stdlib.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**************************************************************************/
/* */
/* OCaml */
/* */
/* David Allsopp, OCaml Labs, Cambridge. */
/* */
/* Copyright 2021 David Allsopp Ltd. */
/* */
/* All rights reserved. This file is distributed under the terms of */
/* the GNU Lesser General Public License version 2.1, with the */
/* special exception on linking described in the file LICENSE. */
/* */
/**************************************************************************/

#include "caml/misc.h"
#include "build_config.h"

#if defined(OCAML_STDLIB_DIR_REL)
char_os * caml_standard_library_default = OCAML_STDLIB_DIR_REL;
#else
char_os * caml_standard_library_default = OCAML_STDLIB_DIR;
#endif
Loading

0 comments on commit 5a71a3e

Please sign in to comment.