Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] custom runtimes & reproducible builds #1845

Merged
11 commits merged into from Jun 27, 2018
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -354,6 +354,7 @@ utils/config.ml: utils/config.mlp config/Makefile Makefile
$(call SUBST,WITH_SPACETIME) \
$(call SUBST,ENABLE_CALL_COUNTS) \
$(call SUBST,FLAT_FLOAT_ARRAY) \
$(call SUBST,CC_HAS_DEBUG_PREFIX_MAP) \
$< > $@

ifeq "$(UNIX_OR_WIN32)" "unix"
Expand Down
24 changes: 17 additions & 7 deletions bytecomp/bytelink.ml
Expand Up @@ -536,8 +536,13 @@ let link_bytecode_as_c ppf tolink outfile =

let build_custom_runtime prim_name exec_name =
let runtime_lib = "-lcamlrun" ^ !Clflags.runtime_variant in
let debug_prefix_map =
if Config.c_has_debug_prefix_map then
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably not pass this option if -dcamlprimc is passed as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure; it makes the build reproducible even if you change
the output name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized that my definition of "reproducible" was slightly
broken: I understood it as "produces the same contents"
while it is "produces the contents in the same file".

[Printf.sprintf "-fdebug-prefix-map=%s=camlprim.c" prim_name]
else
[] in
Ccomp.call_linker Ccomp.Exe exec_name
([prim_name] @ List.rev !Clflags.ccobjs @ [runtime_lib])
(debug_prefix_map @ [prim_name] @ List.rev !Clflags.ccobjs @ [runtime_lib])
(Clflags.std_include_flag "-I" ^ " " ^ Config.bytecomp_c_libraries)

let append_bytecode_and_cleanup bytecode_name exec_name prim_name =
Expand All @@ -547,7 +552,7 @@ let append_bytecode_and_cleanup bytecode_name exec_name prim_name =
close_in ic;
close_out oc;
remove_file bytecode_name;
remove_file prim_name
if not !Clflags.keep_camlprimc_file then remove_file prim_name

(* Fix the name of the output file, if the C compiler changes it behind
our back. *)
Expand Down Expand Up @@ -582,7 +587,11 @@ let link ppf objfiles output_name =
link_bytecode ppf tolink output_name true
else if not !Clflags.output_c_object then begin
let bytecode_name = Filename.temp_file "camlcode" "" in
let prim_name = Filename.temp_file "camlprim" ".c" in
let prim_name =
if !Clflags.keep_camlprimc_file then
output_name ^ ".camlprim.c"
else
Filename.temp_file "camlprim" ".c" in
try
link_bytecode ppf tolink bytecode_name false;
let poc = open_out prim_name in
Expand All @@ -608,12 +617,13 @@ let link ppf objfiles output_name =
let exec_name = fix_exec_name output_name in
if not (build_custom_runtime prim_name exec_name)
then raise(Error Custom_runtime);
if !Clflags.make_runtime
then (remove_file bytecode_name; remove_file prim_name)
else append_bytecode_and_cleanup bytecode_name exec_name prim_name
if !Clflags.make_runtime then begin
remove_file bytecode_name;
if not !Clflags.keep_camlprimc_file then remove_file prim_name
end else append_bytecode_and_cleanup bytecode_name exec_name prim_name
with x ->
remove_file bytecode_name;
remove_file prim_name;
if not !Clflags.keep_camlprimc_file then remove_file prim_name;
raise x
end else begin
let basename = Filename.chop_extension output_name in
Expand Down
25 changes: 25 additions & 0 deletions config/auto-aux/cc_has_debug_prefix_map.c
@@ -0,0 +1,25 @@
/* Determine whether the C compiler supports -fdebug-prefix-map */

/* This file is to be preprocessed and its output examined. */
/* It is not C source code to be executed. */
/* This helps with cross-compilation. */

#if defined(__INTEL_COMPILER)
false
#elif defined(__clang_major__) && defined(__clang_minor__)
#if __clang_major__ >= 7
true
#else
false
#endif
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
true
#else
false
#endif
#elif defined(__xlc__) && (__xlC__)
false
#else
false
#endif
2 changes: 2 additions & 0 deletions configure
Expand Up @@ -409,6 +409,7 @@ export cc verbose
# Determine the C compiler family (GCC, Clang, etc)

ccfamily=`$cc -E cckind.c | grep '^[a-z]' | tr -s ' ' '-'`
cc_has_debug_prefix_map=`$cc -E cc_has_debug_prefix_map.c | grep '^[a-z]'`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about just passing -fdebug-prefix-map and seeing if the compiler fails or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I reused the logic from config/auto-aux/cckind.c.
Actually, a third possibly would be to do all the work
in the aforementioned file.
I don't have a strong opinion.

case $? in
0) inf "Compiler family and version: $ccfamily.";;
*) err "Unable to preprocess the test program.\n" \
Expand Down Expand Up @@ -2167,6 +2168,7 @@ config AFL_INSTRUMENT "$afl_instrument"
config MAX_TESTSUITE_DIR_RETRIES "$max_testsuite_dir_retries"
config FLAT_FLOAT_ARRAY "$flat_float_array"
config AWK "awk"
config CC_HAS_DEBUG_PREFIX_MAP "$cc_has_debug_prefix_map"


rm -f tst hasgot.c
Expand Down
1 change: 1 addition & 0 deletions driver/main.ml
Expand Up @@ -116,6 +116,7 @@ module Options = Main_args.Make_bytecomp_options (struct
let _drawlambda = set dump_rawlambda
let _dlambda = set dump_lambda
let _dinstr = set dump_instr
let _dcamlprimc = set keep_camlprimc_file
let _dtimings () = profile_columns := [ `Time ]
let _dprofile () = profile_columns := Profile.all_columns

Expand Down
6 changes: 6 additions & 0 deletions driver/main_args.ml
Expand Up @@ -682,6 +682,10 @@ let mk_dinstr f =
"-dinstr", Arg.Unit f, " (undocumented)"
;;

let mk_dcamlprimc f =
"-dcamlprimc", Arg.Unit f, " (undocumented)"
;;

let mk_dcmm f =
"-dcmm", Arg.Unit f, " (undocumented)"
;;
Expand Down Expand Up @@ -923,6 +927,7 @@ module type Bytecomp_options = sig
val _use_runtime : string -> unit

val _dinstr : unit -> unit
val _dcamlprimc : unit -> unit

val _use_prims : string -> unit
end;;
Expand Down Expand Up @@ -1123,6 +1128,7 @@ struct
mk_drawlambda F._drawlambda;
mk_dlambda F._dlambda;
mk_dinstr F._dinstr;
mk_dcamlprimc F._dcamlprimc;
mk_dtimings F._dtimings;
mk_dprofile F._dprofile;

Expand Down
1 change: 1 addition & 0 deletions driver/main_args.mli
Expand Up @@ -138,6 +138,7 @@ module type Bytecomp_options = sig
val _use_runtime : string -> unit

val _dinstr : unit -> unit
val _dcamlprimc : unit -> unit

val _use_prims : string -> unit
end;;
Expand Down
1 change: 1 addition & 0 deletions ocamldoc/odoc_args.ml
Expand Up @@ -250,6 +250,7 @@ module Options = Main_args.Make_ocamldoc_options(struct
let _dlambda = set Clflags.dump_lambda
let _dflambda = set Clflags.dump_flambda
let _dinstr = set Clflags.dump_instr
let _dcamlprimc = set Clflags.keep_camlprimc_file
let anonymous = anonymous
end)

Expand Down
1 change: 1 addition & 0 deletions testsuite/tools/expect_test.ml
Expand Up @@ -410,6 +410,7 @@ module Options = Main_args.Make_bytetop_options (struct
let _dtimings () = profile_columns := [ `Time ]
let _dprofile () = profile_columns := Profile.all_columns
let _dinstr = set dump_instr
let _dcamlprimc = set keep_camlprimc_file

let _args = Arg.read_arg
let _args0 = Arg.read_arg0
Expand Down
1 change: 1 addition & 0 deletions tools/ocamlcp.ml
Expand Up @@ -132,6 +132,7 @@ module Options = Main_args.Make_bytecomp_options (struct
let _dlambda = option "-dlambda"
let _dflambda = option "-dflambda"
let _dinstr = option "-dinstr"
let _dcamlprimc = option "-dcamlprimc"
let _dtimings = option "-dtimings"
let _dprofile = option "-dprofile"
let _args = Arg.read_arg
Expand Down
1 change: 1 addition & 0 deletions utils/clflags.ml
Expand Up @@ -106,6 +106,7 @@ and dump_flambda = ref false (* -dflambda *)
and dump_flambda_let = ref (None : int option) (* -dflambda-let=... *)
and dump_flambda_verbose = ref false (* -dflambda-verbose *)
and dump_instr = ref false (* -dinstr *)
and keep_camlprimc_file = ref false (* -dcamlprimc *)

let keep_asm_file = ref false (* -S *)
let optimize_for_speed = ref true (* -compact *)
Expand Down
1 change: 1 addition & 0 deletions utils/clflags.mli
Expand Up @@ -132,6 +132,7 @@ val dump_rawflambda : bool ref
val dump_flambda : bool ref
val dump_flambda_let : int option ref
val dump_instr : bool ref
val keep_camlprimc_file : bool ref
val keep_asm_file : bool ref
val optimize_for_speed : bool ref
val dump_cmm : bool ref
Expand Down
2 changes: 2 additions & 0 deletions utils/config.mli
Expand Up @@ -31,6 +31,8 @@ val c_compiler: string
val c_output_obj: string
(* Name of the option of the C compiler for specifying the output
file *)
val c_has_debug_prefix_map : bool
(* Whether the C compiler supports -fdebug-prefix-map *)
val ocamlc_cflags : string
(* The flags ocamlc should pass to the C compiler *)
val ocamlc_cppflags : string
Expand Down
1 change: 1 addition & 0 deletions utils/config.mlp
Expand Up @@ -32,6 +32,7 @@ let standard_runtime = "%%BYTERUN%%"
let ccomp_type = "%%CCOMPTYPE%%"
let c_compiler = "%%CC%%"
let c_output_obj = "%%OUTPUTOBJ%%"
let c_has_debug_prefix_map = %%CC_HAS_DEBUG_PREFIX_MAP%%
let ocamlc_cflags = "%%OCAMLC_CFLAGS%%"
let ocamlc_cppflags = "%%OCAMLC_CPPFLAGS%%"
let ocamlopt_cflags = "%%OCAMLOPT_CFLAGS%%"
Expand Down