Skip to content

Commit

Permalink
Add runtime suffixes to bytecode stub libraries
Browse files Browse the repository at this point in the history
ocamlc -dllib-suffixed appends the runtime's host triplet and bytecode
runtime ID to the supplied name when searching for the DLL, and records
the base name only in .cma / executable files.

ocamlmklib -suffixed instructs ocamlmklib to use -dllib-suffixed when
generating .cma files instead of -dllib.

The effect is that stub libraries built this way have names which will
be unique for a given configuration of OCaml and so will be ignored by
other runtimes.
  • Loading branch information
dra27 committed Sep 25, 2024
1 parent 807e420 commit 3d32d5c
Show file tree
Hide file tree
Showing 23 changed files with 149 additions and 51 deletions.
7 changes: 5 additions & 2 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,11 @@ ___________

- #13???: Introduce a RuntimeID for use in filename mangling to allow different
configurations and different versions of ocamlrun and the shared runtime
libraries to coexist harmoniously on a single system. A portable version is
used in launcher header for bytecode executables.
libraries to coexist harmoniously on a single system. The RuntimeID is used,
along with the host triplet to mangle the names of stub libraries so that
stub libraries compiled for a given configuration of the runtime will only be
sought by that runtime. A portable version of the RuntimeID containing only
the release number is used in the launcher header for bytecode executables.
(David Allsopp, review by ???)

### Code generation and optimizations:
Expand Down
Binary file modified boot/ocamlc
Binary file not shown.
Binary file modified boot/ocamllex
Binary file not shown.
36 changes: 30 additions & 6 deletions bytecomp/bytelink.ml
Original file line number Diff line number Diff line change
Expand Up @@ -487,13 +487,28 @@ let link_bytecode ?final_name tolink exec_name standalone =
let start_code = pos_out outchan in
Symtable.init();
clear_crc_interfaces ();
let sharedobjs = List.map Dll.extract_dll_name !Clflags.dllibs in
let (tocheck, sharedobjs) =
let process_dllib ((suffixed, name) as dllib) (tocheck, sharedobjs) =
let resolved_name = Dll.extract_dll_name dllib in
let partial_name =
if suffixed then
if String.starts_with ~prefix:"-l" name then
(suffixed, "dll" ^ String.sub name 2 (String.length name - 2))
else
dllib
else
(false, resolved_name)
in
(resolved_name::tocheck, partial_name::sharedobjs)
in
List.fold_right process_dllib !Clflags.dllibs ([], [])
in
let check_dlls = standalone && Config.target = Config.host in
if check_dlls then begin
(* Initialize the DLL machinery *)
Dll.init_compile !Clflags.no_std_include;
Dll.add_path (Load_path.get_path_list ());
try Dll.open_dlls Dll.For_checking sharedobjs
try Dll.open_dlls Dll.For_checking tocheck
with Failure reason -> raise(Error(Cannot_open_dll reason))
end;
let output_fun buf =
Expand All @@ -508,11 +523,20 @@ let link_bytecode ?final_name tolink exec_name standalone =
(* DLL stuff *)
if standalone then begin
(* The extra search path for DLLs *)
output_string outchan (concat_null_terminated !Clflags.dllpaths);
Bytesections.record toc_writer DLPT;
if !Clflags.dllpaths <> [] then begin
output_string outchan (concat_null_terminated !Clflags.dllpaths);
Bytesections.record toc_writer DLPT
end;
(* The names of the DLLs *)
output_string outchan (concat_null_terminated sharedobjs);
Bytesections.record toc_writer DLLS
if sharedobjs <> [] then begin
let output_sharedobj (suffixed, name) =
output_char outchan (if suffixed then '-' else ':');
output_string outchan name;
output_byte outchan 0
in
List.iter output_sharedobj sharedobjs;
Bytesections.record toc_writer DLLS
end
end;
(* The names of all primitives *)
Symtable.output_primitive_names outchan;
Expand Down
17 changes: 12 additions & 5 deletions bytecomp/dll.ml
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,20 @@ let remove_path dirs =

(* Extract the name of a DLLs from its external name (xxx.so or -lxxx) *)

let extract_dll_name file =
if Filename.check_suffix file Config.ext_dll then
let extract_dll_name (suffixed, file) =
if not suffixed && Filename.check_suffix file Config.ext_dll then
Filename.chop_suffix file Config.ext_dll
else if String.length file >= 2 && String.sub file 0 2 = "-l" then
"dll" ^ String.sub file 2 (String.length file - 2)
else
file (* will cause error later *)
let file =
if String.starts_with ~prefix:"-l" file then
"dll" ^ String.sub file 2 (String.length file - 2)
else
file
in
if suffixed then
Printf.sprintf "%s-%s-%s" file Config.target Config.bytecode_runtime_id
else
file

(* Open a list of DLLs, adding them to opened_dlls.
Raise [Failure msg] in case of error. *)
Expand Down
2 changes: 1 addition & 1 deletion bytecomp/dll.mli
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
(* Handling of dynamically-linked libraries *)

(* Extract the name of a DLLs from its external name (xxx.so or -lxxx) *)
val extract_dll_name: string -> string
val extract_dll_name: bool * string -> string

type dll_mode =
| For_checking (* will just check existence of symbols;
Expand Down
8 changes: 4 additions & 4 deletions driver/compenv.ml
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ type deferred_action =
| ProcessCFile of string
| ProcessOtherFile of string
| ProcessObjects of string list
| ProcessDLLs of string list
| ProcessDLLs of bool * string list

let c_object_of_filename name =
Filename.chop_suffix (Filename.basename name) ".c" ^ Config.ext_obj
Expand Down Expand Up @@ -627,8 +627,8 @@ let process_action
ccobjs := obj_name :: !ccobjs
| ProcessObjects names ->
ccobjs := names @ !ccobjs
| ProcessDLLs names ->
dllibs := names @ !dllibs
| ProcessDLLs (suffixed, names) ->
dllibs := (List.map (fun n -> (suffixed, n)) names) @ !dllibs
| ProcessOtherFile name ->
if Filename.check_suffix name ocaml_mod_ext
|| Filename.check_suffix name ocaml_lib_ext then
Expand All @@ -641,7 +641,7 @@ let process_action
ccobjs := name :: !ccobjs
end
else if not !native_code && Filename.check_suffix name Config.ext_dll then
dllibs := name :: !dllibs
dllibs := (false, name) :: !dllibs
else
match Compiler_pass.of_input_filename name with
| Some start_from ->
Expand Down
2 changes: 1 addition & 1 deletion driver/compenv.mli
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type deferred_action =
| ProcessCFile of string
| ProcessOtherFile of string
| ProcessObjects of string list
| ProcessDLLs of string list
| ProcessDLLs of bool * string list

val c_object_of_filename : string -> string

Expand Down
11 changes: 10 additions & 1 deletion driver/main_args.ml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ let mk_custom f =
let mk_dllib f =
"-dllib", Arg.String f, "<lib> Use the dynamically-loaded library <lib>"

let mk_dllib_suffixed f =
"-dllib-suffixed", Arg.String f,
"<lib> Use the dynamically-loaded library <lib>, with runtime suffix \
appended to the name"

let mk_dllpath f =
"-dllpath", Arg.String f,
"<dir> Add <dir> to the run-time search path for shared libraries"
Expand Down Expand Up @@ -902,6 +907,7 @@ module type Bytecomp_options = sig
val _custom : unit -> unit
val _no_check_prims : unit -> unit
val _dllib : string -> unit
val _dllib_suffixed : string -> unit
val _dllpath : string -> unit
val _make_runtime : unit -> unit
val _vmthread : unit -> unit
Expand Down Expand Up @@ -1036,6 +1042,7 @@ struct
mk_config_var F._config_var;
mk_custom F._custom;
mk_dllib F._dllib;
mk_dllib_suffixed F._dllib_suffixed;
mk_dllpath F._dllpath;
mk_dtypes F._annot;
mk_for_pack_byt F._for_pack;
Expand Down Expand Up @@ -1906,7 +1913,9 @@ third-party libraries such as Lwt, but with a different API."
let _custom = set custom_runtime
let _dcamlprimc = set keep_camlprimc_file
let _dinstr = set dump_instr
let _dllib s = Compenv.defer (ProcessDLLs (Misc.rev_split_words s))
let _dllib s = Compenv.defer (ProcessDLLs (false, Misc.rev_split_words s))
let _dllib_suffixed s =
Compenv.defer (ProcessDLLs (true, Misc.rev_split_words s))
let _dllpath s = dllpaths := ((!dllpaths) @ [s])
let _make_runtime () =
custom_runtime := true; make_runtime := true; link_everything := true
Expand Down
1 change: 1 addition & 0 deletions driver/main_args.mli
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ module type Bytecomp_options = sig
val _custom : unit -> unit
val _no_check_prims : unit -> unit
val _dllib : string -> unit
val _dllib_suffixed : string -> unit
val _dllpath : string -> unit
val _make_runtime : unit -> unit
val _vmthread : unit -> unit
Expand Down
2 changes: 1 addition & 1 deletion file_formats/cmo_format.mli
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ type library =
how they end up being used on the command line. *)
lib_ccobjs: string list; (* C object files needed for -custom *)
lib_ccopts: string list; (* Extra opts to C compiler *)
lib_dllibs: string list } (* DLLs needed *)
lib_dllibs: (bool * string) list } (* DLLs needed *)

(* Format of a .cma file:
magic number (Config.cma_magic_number)
Expand Down
1 change: 1 addition & 0 deletions ocamltest/ocaml_actions.ml
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@ let mklib log env =
[
Ocaml_commands.ocamlrun_ocamlmklib;
"-ocamlc '" ^ ocamlc_command ^ "'";
"-suffixed";
"-o " ^ program
] @ modules env in
let expected_exit_status = 0 in
Expand Down
14 changes: 8 additions & 6 deletions otherlibs/Makefile.otherlibs.common
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ CLIBNAME ?= $(LIBNAME)

ifeq "$(C_SOURCES)" ""
STUBSLIB=
STUBSDLL=
else
COBJS_BYTECODE = $(C_SOURCES:.c=.b.$(O))
COBJS_NATIVE = $(C_SOURCES:.c=.n.$(O))
Expand All @@ -61,6 +62,7 @@ COBJS = $(COBJS_BYTECODE) $(COBJS_NATIVE)
CLIBNAME_BYTECODE=$(CLIBNAME)byt
CLIBNAME_NATIVE=$(CLIBNAME)nat
STUBSLIB_BYTECODE=lib$(CLIBNAME_BYTECODE).$(A)
STUBSDLL=dll$(CLIBNAME_BYTECODE)-$(TARGET)-$(BYTECODE_RUNTIME_ID)$(EXT_DLL)
STUBSLIB_NATIVE=lib$(CLIBNAME_NATIVE).$(A)
endif

Expand All @@ -75,34 +77,34 @@ ifeq "$(COBJS)" ""
$(V_LINKC)$(CAMLC) -o $@ -a -linkall $(CAMLOBJS) $(LINKOPTS)
else
$(V_OCAMLMKLIB)$(MKLIB) -o $(LIBNAME) -oc $(CLIBNAME_BYTECODE) -ocamlc '$(CAMLC)' \
-linkall $(CAMLOBJS) $(LINKOPTS)
-linkall $(CAMLOBJS) $(LINKOPTS) -suffixed
endif

$(LIBNAME).cmxa: $(CAMLOBJS_NAT)
ifeq "$(COBJS)" ""
$(V_OCAMLOPT)$(CAMLOPT) -o $@ -a -linkall $(CAMLOBJS_NAT) $(LINKOPTS)
else
$(V_OCAMLMKLIB)$(MKLIB) -o $(LIBNAME) -oc $(CLIBNAME_NATIVE) -ocamlopt '$(CAMLOPT)' \
-linkall $(CAMLOBJS_NAT) $(LINKOPTS)
-linkall $(CAMLOBJS_NAT) $(LINKOPTS) -suffixed
endif

$(LIBNAME).cmxs: $(LIBNAME).cmxa $(STUBSLIB_NATIVE)
$(V_OCAMLOPT)$(CAMLOPT) -shared -o $(LIBNAME).cmxs -I . $(LIBNAME).cmxa

lib$(CLIBNAME_BYTECODE).$(A): $(COBJS)
$(V_OCAMLMKLIB)$(MKLIB) -oc $(CLIBNAME_BYTECODE) $(COBJS_BYTECODE) $(LDOPTS)
$(V_OCAMLMKLIB)$(MKLIB) -oc $(CLIBNAME_BYTECODE) $(COBJS_BYTECODE) $(LDOPTS) -suffixed

lib$(CLIBNAME_NATIVE).$(A): $(COBJS)
$(V_OCAMLMKLIB)$(MKLIB) -oc $(CLIBNAME_NATIVE) $(COBJS_NATIVE) $(LDOPTS)

INSTALL_LIBDIR_LIBNAME = $(INSTALL_LIBDIR)/$(LIBNAME)

install::
if test -f dll$(CLIBNAME_BYTECODE)$(EXT_DLL); then \
ifneq "$(STUBSLIB_BYTECODE)" ""
if test -f $(STUBSDLL); then \
$(INSTALL_PROG) \
dll$(CLIBNAME_BYTECODE)$(EXT_DLL) "$(INSTALL_STUBLIBDIR)"; \
$(STUBSDLL) "$(INSTALL_STUBLIBDIR)"; \
fi
ifneq "$(STUBSLIB_BYTECODE)" ""
$(INSTALL_DATA) $(STUBSLIB_BYTECODE) "$(INSTALL_LIBDIR)/"
endif
# If installing over a previous OCaml version, ensure the library is removed
Expand Down
28 changes: 18 additions & 10 deletions otherlibs/dynlink/byte/dynlink_symtable.ml
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,25 @@ let primitives : (string, int) Hashtbl.t = Hashtbl.create 100
#52 "bytecomp/dll.ml"
(* Extract the name of a DLLs from its external name (xxx.so or -lxxx) *)

let extract_dll_name file =
if Filename.check_suffix file Config.ext_dll then
let extract_dll_name (suffixed, file) =
if not suffixed && Filename.check_suffix file Config.ext_dll then
Filename.chop_suffix file Config.ext_dll
else if String.length file >= 2 && String.sub file 0 2 = "-l" then
"dll" ^ String.sub file 2 (String.length file - 2)
else
file (* will cause error later *)
#100 "otherlibs/dynlink/byte/dynlink_symtable.ml"
let file =
if String.starts_with ~prefix:"-l" file then
"dll" ^ String.sub file 2 (String.length file - 2)
else
file
in
if suffixed then
Printf.sprintf "%s-%s-%s" file Config.target Config.bytecode_runtime_id
else
file
#107 "otherlibs/dynlink/byte/dynlink_symtable.ml"
(* Specialized version of [Dll.{open_dll,open_dlls,find_primitive}] for the
execution mode. *)
let open_dll name =
(* XXX Adding ext_dll equivalent here to elsewhere? *)
let name = (extract_dll_name name) ^ Config.ext_dll in
let fullname =
if Filename.is_implicit name then
Expand Down Expand Up @@ -233,12 +241,12 @@ let patch_object buff patchlist =
(* Functions for toplevel use *)

(* Update the in-core table of globals *)
#237 "otherlibs/dynlink/byte/dynlink_symtable.ml"
#245 "otherlibs/dynlink/byte/dynlink_symtable.ml"
module Meta = struct
#16 "bytecomp/meta.ml"
external global_data : unit -> Obj.t array = "caml_get_global_data"
external realloc_global_data : int -> unit = "caml_realloc_global"
#242 "otherlibs/dynlink/byte/dynlink_symtable.ml"
#250 "otherlibs/dynlink/byte/dynlink_symtable.ml"
end
#332 "bytecomp/symtable.ml"
let update_global_table () =
Expand All @@ -264,7 +272,7 @@ external get_bytecode_sections : unit -> bytecode_sections =
let init_toplevel () =
let sect = get_bytecode_sections () in
global_table := sect.symb;
#268 "otherlibs/dynlink/byte/dynlink_symtable.ml"
#276 "otherlibs/dynlink/byte/dynlink_symtable.ml"
Dll.init ~dllpaths:sect.dlpt ~prims:sect.prim;
#358 "bytecomp/symtable.ml"
sect.crcs
Expand Down Expand Up @@ -317,7 +325,7 @@ let current_state () = !global_table
#412 "bytecomp/symtable.ml"
let hide_additions (st : global_map) =
if st.cnt > !global_table.cnt then
#321 "otherlibs/dynlink/byte/dynlink_symtable.ml"
#329 "otherlibs/dynlink/byte/dynlink_symtable.ml"
failwith "Symtable.hide_additions";
#415 "bytecomp/symtable.ml"
global_table :=
Expand Down
2 changes: 1 addition & 1 deletion otherlibs/dynlink/byte/dynlink_symtable.mli
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ module Global : sig
val description: Format.formatter -> t -> unit
end

val open_dlls : string list -> unit
val open_dlls : (bool * string) list -> unit

val patch_object:
(char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t ->
Expand Down
4 changes: 4 additions & 0 deletions otherlibs/dynlink/dynlink_config.ml.in
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ let ext_dll = "." ^ {@QS@|@SO@|@QS@}
and cmo_magic_number = {@QS@|@CMO_MAGIC_NUMBER@|@QS@}
and cma_magic_number = {@QS@|@CMA_MAGIC_NUMBER@|@QS@}
and cmxs_magic_number = {@QS@|@CMXS_MAGIC_NUMBER@|@QS@}

let bytecode_runtime_id = {@QS@|@bytecode_runtime_id@|@QS@}

let target = {@QS@|@target@|@QS@}
4 changes: 4 additions & 0 deletions otherlibs/dynlink/dynlink_config.mli
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ val ext_dll: string
val cmo_magic_number: string
val cma_magic_number: string
val cmxs_magic_number: string

val bytecode_runtime_id: string

val target : string
12 changes: 7 additions & 5 deletions otherlibs/systhreads/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ allopt: lib$(LIBNAME)nat.$(A) $(LIBNAME).cmxa $(CMIFILES)
lib$(LIBNAME).$(A): OC_CFLAGS = $(OC_BYTECODE_CFLAGS)

lib$(LIBNAME).$(A): $(BYTECODE_C_OBJS)
$(V_OCAMLMKLIB)$(MKLIB) -o $(LIBNAME) $(BYTECODE_C_OBJS)
$(V_OCAMLMKLIB)$(MKLIB) -o $(LIBNAME) $(BYTECODE_C_OBJS) -suffixed

lib$(LIBNAME)nat.$(A): OC_CFLAGS = $(OC_NATIVE_CFLAGS)

lib$(LIBNAME)nat.$(A): $(NATIVECODE_C_OBJS)
$(V_OCAMLMKLIB)$(MKLIB) -o $(LIBNAME)nat $^
$(V_OCAMLMKLIB)$(MKLIB) -o $(LIBNAME)nat $^ -suffixed

$(LIBNAME).cma: $(THREADS_BCOBJS)
$(V_OCAMLMKLIB)$(MKLIB) -o $(LIBNAME) -ocamlc '$(CAMLC)' -linkall $^
$(V_OCAMLMKLIB)$(MKLIB) -o $(LIBNAME) -ocamlc '$(CAMLC)' -linkall $^ -suffixed

# See remark above: force static linking of libthreadsnat.a
$(LIBNAME).cmxa: $(THREADS_NCOBJS)
Expand Down Expand Up @@ -101,9 +101,11 @@ distclean: clean

INSTALL_THREADSLIBDIR=$(INSTALL_LIBDIR)/$(LIBNAME)

DLLTHREADS = dllthreads-$(TARGET)-$(BYTECODE_RUNTIME_ID)$(EXT_DLL)

install:
if test -f dllthreads$(EXT_DLL); then \
$(INSTALL_PROG) dllthreads$(EXT_DLL) "$(INSTALL_STUBLIBDIR)"; \
if test -f $(DLLTHREADS); then \
$(INSTALL_PROG) $(DLLTHREADS) "$(INSTALL_STUBLIBDIR)"; \
fi
$(INSTALL_DATA) libthreads.$(A) "$(INSTALL_LIBDIR)"
$(MKDIR) "$(INSTALL_THREADSLIBDIR)"
Expand Down
Loading

0 comments on commit 3d32d5c

Please sign in to comment.