···93939494- #14245: Introduce Runtime IDs for use in filename mangling to allow different
9595 configurations and different versions of the runtime system to coexist
9696- harmoniously on a single system.
9696+ harmoniously on a single system. The IDs are used, along with the host
9797+ triplet, to provide mangled names for the ocamlrun executable and its
9898+ variants, with symlinks created for the original names. The behaviour is
9999+ disabled by configuring with --disable-suffixing.
97100 (David Allsopp, review by Damien Doligez and Samuel Hym)
9810199102- #12269, #12410, #13063: Fix unsafety, deadlocks, and/or leaks should
···110110MKEXE_VIA_CC=$(CC) @mkexe_via_cc_ldflags@ @mkexe_via_cc_extra_cmd@
111111112112LAUNCH_METHOD = @launch_method@
113113+SUFFIXING = @suffixing@
113114114115# How to build sak
115116SAK_BUILD=@SAK_BUILD@
+17
Makefile.common
···367367BYTECODE_LAUNCHER_FLAGS :=
368368endif
369369370370+ifeq "$(SUFFIXING)-$(UNIX_OR_WIN32)" "true-win32"
371371+# Historically, the native Windows ports are assumed to be finding ocamlrun
372372+# using a PATH search. -use-runtime ocamlrun-$(ZINC_RUNTIME_ID) won't work here
373373+# as ocamlc will convert it to an absolute path. Instead, we (ab)use
374374+# -runtime-variant to append the -$(ZINC_RUNTIME_ID) to the default ocamlrun.
375375+BYTECODE_LAUNCHER_FLAGS += -runtime-variant -$(ZINC_RUNTIME_ID)
376376+# boot/ocamlc is built with suffixing disabled, so this works both before and
377377+# after bootstrapping, however this would cause $(ROOTDIR)/ocamlc to add the
378378+# suffix twice. Thwart this by further (ab)using -runtime-variant.
379379+ROOT_LINK_FLAGS += -runtime-variant ''
380380+else ifeq "$(SUFFIXING)" "true"
381381+# boot/ocamlc is built with suffixing disabled or not yet bootstrapped, so
382382+# either way pass the suffixed runtime name explicitly with -use-runtime.
383383+BYTECODE_LAUNCHER_FLAGS += \
384384+ -use-runtime $(call QUOTE_SINGLE,$(BINDIR)/ocamlrun-$(ZINC_RUNTIME_ID))
385385+endif
386386+370387MAYBE_ADD_BYTECODE_LAUNCHER_FLAGS = \
371388 $(if $(filter -custom, $(1)),,\
372389 -use-prims $(ROOTDIR)/runtime/primitives $(BYTECODE_LAUNCHER_FLAGS))
+37-23
bytecomp/bytelink.ml
···412412 called) *)
413413414414let write_header outchan =
415415+ let zinc_runtime_id, write_exe_launcher =
416416+ let header =
417417+ let header = "runtime-launch-info" in
418418+ try Load_path.find header
419419+ with Not_found -> raise (Error (File_not_found header))
420420+ in
421421+ let data =
422422+ try In_channel.with_open_bin header In_channel.input_all
423423+ with Sys_error msg -> raise (Error (Camlheader (msg, header)))
424424+ in
425425+ let zinc_runtime_id, offset =
426426+ if String.length data < 2 then
427427+ raise (Error (Camlheader ("corrupt header", header)))
428428+ (* Compatibility with previous header format - remove post-bootstrap *)
429429+ else if List.mem data.[0] ['/'; 'e'; 's'] then
430430+ None, String.index data '\000' + 2
431431+ else if data.[0] = '\000' then
432432+ None, 1
433433+ else
434434+ let zinc = Misc.RuntimeID.of_zinc_hi (String.sub data 0 2) in
435435+ if Option.fold ~none:false ~some:Misc.RuntimeID.is_zinc zinc then
436436+ zinc, 2
437437+ else
438438+ raise (Error (Camlheader ("corrupt header", header)))
439439+ in
440440+ let write_exe_header outchan =
441441+ let len = String.length data in
442442+ Out_channel.output_substring outchan data offset (len - offset)
443443+ in
444444+ zinc_runtime_id, write_exe_header
445445+ in
415446 let runtime, search =
416447 if String.length !Clflags.use_runtime > 0 then
417448 (* Do not use BUILD_PATH_PREFIX_MAP mapping for this. *)
···421452 else
422453 runtime, Config.Disable
423454 else
424424- let runtime = "ocamlrun" ^ !Clflags.runtime_variant in
455455+ let runtime =
456456+ let runtime = "ocamlrun" ^ !Clflags.runtime_variant in
457457+ let some = Misc.RuntimeID.ocamlrun !Clflags.runtime_variant in
458458+ Option.fold ~none:runtime ~some zinc_runtime_id
459459+ in
425460 let runtime =
426461 if !Clflags.search_method = Config.Disable then
427462 Filename.concat !Clflags.target_bindir runtime
···452487 else
453488 Shebang_runtime
454489 in
455455- let write_exe_launcher data =
456456- (* Compatibility with previous header format - remove post-bootstrap *)
457457- let data =
458458- if data = "" || not (List.mem data.[0] ['/'; 'e'; 's']) then
459459- data
460460- else
461461- let exe_start = String.index data '\000' + 2 in
462462- let len = String.length data in
463463- String.sub data exe_start (len - exe_start)
464464- in
465465- Out_channel.output_string outchan data
466466- in
467490 (* Write the header *)
468491 match launcher with
469492 | Shebang_runtime ->
···477500 Bytesections.init_record outchan
478501 | Executable ->
479502 (* Use the executable stub launcher *)
480480- let header =
481481- let header = "runtime-launch-info" in
482482- try Load_path.find header
483483- with Not_found -> raise (Error (File_not_found header))
484484- in
485485- let data =
486486- try In_channel.with_open_bin header In_channel.input_all
487487- with Sys_error msg -> raise (Error (Camlheader (msg, header)))
488488- in
489489- write_exe_launcher data;
503503+ write_exe_launcher outchan;
490504 (* The runtime name needs recording in RNTM *)
491505 let toc_writer = Bytesections.init_record outchan in
492506 (* stdlib/header.c determines which mode is needed based on whether the
+2-1
bytecomp/byterntm.mli
···2626 (** Always search for the interpreter *)
27272828val read_runtime :
2929- Bytesections.section_table -> in_channel -> (string * search_method) option
2929+ Bytesections.section_table -> in_channel
3030+ -> (string * Misc.RuntimeID.t option * search_method) option
3031(** Returns the runtime used by this tendered/standalone image. If the runtime
3132 used cannot be parsed, or the image was linked using -without-runtime, then
3233 [None] is returned. *)
+26-8
bytecomp/byterntm.mll
···2121(* First word of the current line being analysed - [exec ...], [r=...], or
2222 [c=...] *)
2323type state = Exec | R | C of string
2424+2525+let cut_runtime_id search name =
2626+ let len = String.length name in
2727+ let id =
2828+ if len < 6 || name.[len - 5] <> '-' then
2929+ None
3030+ else
3131+ Misc.RuntimeID.of_string (String.sub name (len - 4) 4)
3232+ in
3333+ let name =
3434+ if id = None then
3535+ name
3636+ else
3737+ String.sub name 0 (len - 5)
3838+ in
3939+ Some (name, id, search)
2440}
25412642rule analyze = parse
···3147 ([^ '\\' '/' '\000']+ as runtime) eof (* Runtime portion *)
3248 { if sep = '\000' then
3349 if dir = "" then
3434- Some (runtime, Enable)
5050+ cut_runtime_id Enable runtime
3551 else
3636- Some (runtime, Fallback (Filename.concat dir ""))
5252+ let dir = Filename.concat dir "" in
5353+ cut_runtime_id (Fallback dir) runtime
3754 else
3838- Some (runtime, Disable (dir ^ String.make 1 sep)) }
5555+ let dir = dir ^ String.make 1 sep in
5656+ cut_runtime_id (Disable dir) runtime }
39574058(* Legacy RNTM (remove after bootstrap) *)
4159 | (([^ '\000']* ['/' '\\']) as dir)
4260 ([^ '\\' '/' '\000']+ as runtime) '\000' eof
4361 { if dir = "" then
4444- Some (runtime, Enable)
6262+ Some (runtime, None, Enable)
4563 else
4646- Some (runtime, Disable dir) }
6464+ Some (runtime, None, Disable dir) }
47654866(* Shell script launcher (if it matches, this always matches more than the above
4967 regexp) *)
···7088 let dir =
7189 String.sub name 0 (String.length name - String.length runtime)
7290 in
7373- Some (runtime, Disable dir)
9191+ cut_runtime_id (Disable dir) runtime
7492 else
7593 None }
7694···7997 { if state = R then
8098 let runtime = Buffer.contents b in
8199 if c = None then
8282- Some (runtime, Enable)
100100+ cut_runtime_id Enable runtime
83101 else
84102 analyze_sh_launcher (C runtime) (Buffer.clear b; b) lexbuf
85103 else
···89107 | "'\"$r\"\n"
90108 { match state with
91109 | C runtime ->
9292- Some (runtime, Fallback (Buffer.contents b))
110110+ cut_runtime_id (Fallback (Buffer.contents b)) runtime
93111 | _ ->
94112 None }
95113
+19
configure
···800800build_vendor
801801build_cpu
802802build
803803+suffixing
803804native_runtime_id
804805bytecode_runtime_id
805806zinc_runtime_id_hi
···10581059enable_function_sections
10591060enable_mmap_map_stack
10601061with_relative_libdir
10621062+enable_suffixing
10611063with_afl
10621064with_flexdll
10631065with_winpthreads_msvc
···17691771 --disable-function-sections
17701772 do not emit each function in a separate section
17711773 --enable-mmap-map-stack use mmap to allocate stacks instead of malloc
17741774+ --disable-suffixing disable suffixing of runtime executables and shared
17751775+ libraries
17721776 --enable-shared[=PKGS] build shared libraries [default=yes]
17731777 --enable-static[=PKGS] build static libraries [default=yes]
17741778 --enable-pic[=PKGS] try to use only PIC/non-PIC objects [default=use
···36123616361336173614361836193619+36153620## Generated files
3616362136173622ac_config_files="$ac_config_files Makefile.build_config"
···44054410esac
44064411else $as_nop
44074412 bindir_to_libdir=''
44134413+fi
44144414+44154415+44164416+# Check whether --enable-suffixing was given.
44174417+if test ${enable_suffixing+y}
44184418+then :
44194419+ enableval=$enable_suffixing; if test "x$enableval" = 'xno'
44204420+then :
44214421+ suffixing=false
44224422+else $as_nop
44234423+ suffixing=true
44244424+fi
44254425+else $as_nop
44264426+ suffixing=true
44084427fi
4409442844104429
···166166# update build-aux/ocaml_version.m4 with the new future branch,
167167# 4.07.0+dev1-2018-06-26 => 4.08.0+dev0-2018-06-30
168168# Also increment OCAML__RELEASE_NUMBER in build-aux/ocaml_version.m4
169169+# If the major version number is changing, the logic in p_runtime_id in
170170+# tools/objinfo.ml mapping release number to major/minor version will need
171171+# altering.
169172# Update ocaml-variants.opam with new version.
170173tools/autogen
171174# Add a "Working version" section" to Changes
···2626 | Tendered of {header: launch_mode;
2727 dlls: bool;
2828 runtime: string;
2929+ id: Misc.RuntimeID.t option;
2930 search: Byterntm.search_method}
3031 (** Tendered bytecode image. Executable uses the given mechanism to locate
3132 a suitable runtime to execute the image. [dlls] is [true] if the
···7475 bytecode_shebangs_by_default: bool;
7576 (** True if ocamlc uses a shebang-style header rather than an executable
7677 header for tendered bytecode executables. *)
7777- libraries: string list list
7878+ filename_mangling: bool;
7979+ (** True if the Runtime ID is being used for filename mangling. *)
8080+ libraries: string list list;
7881 (** Sorted list of basenames of libraries to test.
7982 Derived from {v [$(OTHERLIBRARIES)] v} - {v Makefile.config v} *)
8383+ zinc_bootstrapped: bool;
8484+ (** True if boot/ocamlc has been bootstrapped (temporary, to allow the
8585+ tests to pass on the bootstrap commit before they're updated following
8686+ the bootstrap) *)
8087 }
8188end
8289
+23-4
testsuite/tools/testBytecodeBinaries.ml
···8383 program
8484 else
8585 failed, "compiled with -custom"
8686- | Tendered {runtime; header; search; _} ->
8686+ | Tendered {runtime; id; header; search; _} ->
8787 let reported_runtime =
8888+ let id =
8989+ Option.map
9090+ (fun t -> "-" ^ Misc.RuntimeID.to_string t) id
9191+ |> Option.value ~default:""
9292+ in
8893 match search with
8994 | Disable dir ->
9090- dir ^ runtime
9595+ dir ^ runtime ^ id
9196 | Fallback dir ->
9292- Printf.sprintf "[%s/]%s" dir runtime
9797+ Printf.sprintf "[%s]%s%s" dir runtime id
9398 | Enable ->
9494- runtime
9999+ runtime ^ id
100100+ in
101101+ let expected_id =
102102+ if config.filename_mangling then
103103+ Some (Misc.RuntimeID.make_zinc ())
104104+ else
105105+ None
95106 in
96107 let expected_search =
97108 if Sys.win32 then
···105116 Header_shebang
106117 else
107118 Header_exe
119119+ in
120120+ let pp_runtime_id f = function
121121+ | None ->
122122+ Format.pp_print_string f "<NONE>"
123123+ | Some id ->
124124+ Format.pp_print_string f (Misc.RuntimeID.to_string id)
108125 in
109126 let pp_search f = function
110127 | Byterntm.Disable _ ->
···130147 failed
131148 |> check expected_search search
132149 "search mechanism" pp_search
150150+ |> check expected_id id
151151+ "runtime ID" pp_runtime_id
133152 |> check "ocamlrun" runtime
134153 "runtime" Format.pp_print_string
135154 |> check expected_launch_mode header
+1-1
testsuite/tools/testRelocation.ml
···111111 else
112112 (* Bytecode runtimes and ocamlyacc of which only ocamlrund is linked
113113 with -g *)
114114- `Other, (basename = "ocamlrund")
114114+ `Other, (List.mem "ocamlrund" (String.split_on_char '-' basename))
115115 in
116116 (* Combine this with the properties of the platform to determine whether the
117117 executable will contain the build path. *)
+24-6
testsuite/tools/test_in_prefix.ml
···4949 \ @{<hint>libdir@} = [$prefix/]%s\n\
5050 \ - C compiler is %s [%s] for %s\n\
5151 \ - OCaml is %a%a; target binaries by default are %a\n\
5252- \ - Executable header size is %.2fKiB (%d bytes)\n\
5252+ \ - Executable header size is %.2fKiB (%Ld bytes)\n\
5353 \ - Testing %s\n@?"
5454 prefix bindir_suffix libdir_suffix
5555 Config.c_compiler Config.c_compiler_vendor Config.target
5656 pp_relocatable relocatable pp_reproducible reproducible
5757 pp_relocatable target_relocatable
5858- (float_of_int header_size /. 1024.0) header_size summary
5858+ (Int64.to_float header_size /. 1024.0) header_size summary
59596060let run_tests ~sh config env =
6161 TestDynlink.run config env Bytecode;
···119119 in
120120 List.map add_dependencies libraries
121121 in
122122- let header_size =
123123- (Unix.stat (Filename.concat libdir "runtime-launch-info")).Unix.st_size in
122122+ let header_size, filename_mangling =
123123+ let file = Filename.concat libdir "runtime-launch-info" in
124124+ In_channel.with_open_bin file @@ fun ic ->
125125+ In_channel.length ic, (input_char ic <> '\000')
126126+ in
124127 let bytecode_shebangs_by_default =
125128 Config.launch_method <> Config.Executable in
126129 let launcher_searches_for_ocamlrun = Sys.win32 in
···129132 {config with libraries;
130133 launcher_searches_for_ocamlrun;
131134 target_launcher_searches_for_ocamlrun;
132132- bytecode_shebangs_by_default}
135135+ bytecode_shebangs_by_default;
136136+ filename_mangling}
133137 in
134138 (* A compiler distribution is _Relocatable_ if its build, for a given system,
135139 satisfies the following three properties:
···199203 | _ ->
200204 Harness.fail_because "Unexpected response from command -v sh"
201205 in
206206+ let config =
207207+ let boot_ocamlc = Environment.in_test_root env "../../boot/ocamlc" in
208208+ let ocamlrun = Environment.ocamlrun env in
209209+ let zinc_bootstrapped =
210210+ snd (Environment.run_process env ocamlrun [boot_ocamlc; "-config"])
211211+ |> List.exists (String.starts_with ~prefix:"zinc_runtime_id: ")
212212+ in
213213+ {config with zinc_bootstrapped}
214214+ in
202215 let run_tests = run_tests ~sh config in
203216 (* 1. Relocation test *)
204217 TestRelocation.run ~reproducible config env;
···225238 Printf.printf "Re-running test programs\n%!";
226239 (* Verify that the searching runtimes are searching the directory containing
227240 the program itself first. *)
228228- let runtime = "ocamlrun" in
241241+ let runtime =
242242+ if config.filename_mangling then
243243+ Misc.RuntimeID.(ocamlrun "" (make_zinc ()))
244244+ else
245245+ "ocamlrun"
246246+ in
229247 rename_exe_in_test_root env ("test-" ^ runtime) runtime;
230248 Fun.protect
231249 ~finally:(fun () -> rename_exe_in_test_root env runtime ("test-" ^ runtime))
+41-2
tools/objinfo.ml
···292292 p_title title;
293293 List.iter print l
294294295295-let p_runtime (runtime, search) =
295295+let p_runtime_id ({Misc.RuntimeID.dev; release; no_flat_float_array; fp; tsan;
296296+ int31; static; no_compression; ansi; reserved} as t) =
297297+ let version =
298298+ if release > Config.release_number then
299299+ ""
300300+ else
301301+ if release = 0 then
302302+ " (Objective Caml 3.12)"
303303+ else if release < 16 then
304304+ Printf.sprintf " (OCaml 4.%02d)" (release - 1)
305305+ else
306306+ Printf.sprintf " (OCaml 5.%d)" (release - 16)
307307+ in
308308+ printf "\t%s = Release %d%s%s\n"
309309+ (Misc.RuntimeID.to_string t)
310310+ release version (if dev then " - development/altered version" else "");
311311+ if reserved > 0 then
312312+ printf "\t - %d reserved header bit%s\n"
313313+ reserved (if reserved = 1 then "" else "s");
314314+ if no_flat_float_array then
315315+ printf "\t - Flat float array representation disabled\n";
316316+ if fp then
317317+ printf "\t - Frame pointers enabled\n";
318318+ if tsan then
319319+ printf "\t - TSAN enabled\n";
320320+ if int31 then
321321+ printf "\t - Compiled without 64-bit support\n";
322322+ if static then
323323+ printf "\t - Compiled without support dynamic loading\n";
324324+ if no_compression then
325325+ printf "\t - Compiled without support for compressed marshalling\n";
326326+ if ansi then
327327+ printf "\t - Windows Unicode support disabled\n"
328328+329329+let p_runtime (runtime, id, search) =
330330+ let runtime =
331331+ let some id = runtime ^ "-" ^ Misc.RuntimeID.to_string id in
332332+ Option.fold ~none:runtime ~some id
333333+ in
296334 let runtime =
297335 match search with
298336 | Byterntm.Enable -> runtime
299337 | Byterntm.Disable dir -> dir ^ runtime
300338 | Byterntm.Fallback dir -> Printf.sprintf "[%s]%s" dir runtime
301339 in
302302- printf "Runtime:\n\t%s\n" runtime
340340+ printf "Runtime:\n\t%s\n" runtime;
341341+ Option.iter p_runtime_id id
303342304343let dump_byte ic =
305344 let toc = Bytesections.read_toc ic in
+10
utils/misc.ml
···15361536 ansi = set 3 q3; (* bit 4 of q3 is unused *)}
15371537 else
15381538 None
15391539+15401540+ let of_zinc_hi ?(dev = not Config.is_official_release)
15411541+ ?(release = Config.release_number) s =
15421542+ Option.map (fun id -> {id with dev; release}) (of_string ("00" ^ s))
15431543+15441544+ let ocamlrun variant runtime_id =
15451545+ if is_zinc runtime_id then
15461546+ Printf.sprintf "ocamlrun%s-%s" variant (to_string runtime_id)
15471547+ else
15481548+ invalid_arg "Misc.RuntimeID.ocamlrun"
15391549end
+8
utils/misc.mli
···945945946946 val of_string: string -> t option
947947 (** Converts the 4-character representation back to a {!t} *)
948948+949949+ val of_zinc_hi: ?dev:bool -> ?release:int -> string -> t option
950950+ (** Converts hi 2 characters of the representation back to a {!t} (using the
951951+ default version information from {!Config}. *)
952952+953953+ val ocamlrun: string -> t -> string
954954+ (** [ocamlrun variant runtime_id] returns the name for the runtime for the
955955+ given Zinc Runtime ID. *)
948956end
949957950958(** {1 Miscellaneous type aliases} *)