diff --git a/src/action.ml b/src/action.ml index 757a3e44..2539155a 100644 --- a/src/action.ml +++ b/src/action.ml @@ -36,8 +36,7 @@ let expand_prog ctx ~dir ~f template = else match Context.which ctx s with | Some p -> p - | None -> - die "@{Error@}: Program %s not found in PATH (context: %s)" s ctx.name + | None -> Utils.program_not_found ~context:ctx.name s in match String_with_vars.just_a_var template with | None -> resolve (expand_str ~dir ~f template) diff --git a/src/context.ml b/src/context.ml index ac21eaa2..f65f366f 100644 --- a/src/context.ml +++ b/src/context.ml @@ -44,9 +44,10 @@ type t = ; version : string ; stdlib_dir : Path.t ; ccomp_type : string - ; bytecomp_c_compiler : string + ; c_compiler : string + ; ocamlc_cflags : string + ; ocamlopt_cflags : string ; bytecomp_c_libraries : string - ; native_c_compiler : string ; native_c_libraries : string ; native_pack_linker : string ; ranlib : string @@ -107,7 +108,7 @@ let compare a b = compare a.name b.name let get_arch_sixtyfour stdlib_dir = let config_h = Path.relative stdlib_dir "caml/config.h" in List.exists (lines_of_file (Path.to_string config_h)) ~f:(fun line -> - match String.split_words line with + match String.extract_blank_separated_words line with | ["#define"; "ARCH_SIXTYFOUR"] -> true | _ -> false) @@ -168,7 +169,7 @@ let create ~(kind : Kind.t) ~path ~base_env ~env_extra ~name ~merlin ~use_findli Hashtbl.add opam_var_cache ~key:"root" ~data:root | Default -> ()); let prog_not_found_in_path prog = - die "Program %s not found in PATH (context: %s)" prog name + Utils.program_not_found prog ~context:name in let which_cache = Hashtbl.create 128 in let which x = which ~cache:which_cache ~path x in @@ -232,8 +233,9 @@ let create ~(kind : Kind.t) ~path ~base_env ~env_extra ~name ~merlin ~use_findli | Error (key, _, _) -> die "variable %S present twice in the output of `%s`" key ocamlc_config_cmd in + let get_opt var = String_map.find var ocamlc_config in let get ?default var = - match String_map.find var ocamlc_config with + match get_opt var with | Some s -> s | None -> match default with @@ -268,6 +270,29 @@ let create ~(kind : Kind.t) ~path ~base_env ~env_extra ~name ~merlin ~use_findli else env,env_extra in + let c_compiler, ocamlc_cflags, ocamlopt_cflags = + match get_opt "c_compiler" with + | Some c_compiler -> (* >= 4.06 *) + (c_compiler, get "ocamlc_cflags", get "ocamlopt_cflags") + | None -> + let split_prog s = + let len = String.length s in + let rec loop i = + if i = len then + (s, "") + else + match s.[i] with + | ' ' | '\t' -> + (String.sub s ~pos:0 ~len:i, + String.sub s ~pos:i ~len:(len - i)) + | _ -> loop (i + 1) + in + loop 0 + in + let c_compiler, ocamlc_cflags = split_prog (get "bytecomp_c_compiler") in + let _, ocamlopt_cflags = split_prog (get "native_c_compiler") in + (c_compiler, ocamlc_cflags, ocamlopt_cflags) + in return { name ; kind @@ -299,9 +324,10 @@ let create ~(kind : Kind.t) ~path ~base_env ~env_extra ~name ~merlin ~use_findli ; ocamlc_config = String_map.bindings ocamlc_config ; version ; ccomp_type = get "ccomp_type" - ; bytecomp_c_compiler = get "bytecomp_c_compiler" + ; c_compiler + ; ocamlc_cflags + ; ocamlopt_cflags ; bytecomp_c_libraries = get "bytecomp_c_libraries" - ; native_c_compiler = get "native_c_compiler" ; native_c_libraries = get "native_c_libraries" ; native_pack_linker = get "native_pack_linker" ; ranlib = get "ranlib" @@ -354,7 +380,7 @@ let default ?(merlin=true) ?(use_findlib=true) () = let create_for_opam ?root ~switch ~name ?(merlin=false) () = match Bin.opam with - | None -> die "Program opam not found in PATH" + | None -> Utils.program_not_found "opam" | Some fn -> (match root with | Some root -> return root diff --git a/src/context.mli b/src/context.mli index c16bba51..da6a5809 100644 --- a/src/context.mli +++ b/src/context.mli @@ -81,9 +81,10 @@ type t = ; version : string ; stdlib_dir : Path.t ; ccomp_type : string - ; bytecomp_c_compiler : string + ; c_compiler : string + ; ocamlc_cflags : string + ; ocamlopt_cflags : string ; bytecomp_c_libraries : string - ; native_c_compiler : string ; native_c_libraries : string ; native_pack_linker : string ; ranlib : string diff --git a/src/findlib.ml b/src/findlib.ml index 3f5325e7..c301d6c1 100644 --- a/src/findlib.ml +++ b/src/findlib.ml @@ -115,7 +115,7 @@ module Vars = struct | None -> "" | Some rules -> Rules.interpret rules ~preds - let get_words t var preds = String.split_words (get t var preds) + let get_words t var preds = String.extract_comma_space_separated_words (get t var preds) end type package = diff --git a/src/gen_rules.ml b/src/gen_rules.ml index d526f7af..70521108 100644 --- a/src/gen_rules.ml +++ b/src/gen_rules.ml @@ -334,22 +334,14 @@ module Gen(P : Params) = struct | User variables | +-----------------------------------------------------------------+ *) - let cxx_compiler, cxx_flags = - match String.split_words ctx.bytecomp_c_compiler with - | [] -> assert false - | prog :: flags -> - let comp = - if Filename.is_relative prog then - match Bin.which prog with - | None -> Path.of_string "g++" - | Some p -> p - else - Path.of_string prog - in - let flags = - List.filter flags ~f:(fun s -> not (String.is_prefix s ~prefix:"-std=")) - in - (comp, flags) + let cxx_flags = + String.extract_blank_separated_words ctx.ocamlc_cflags + |> List.filter ~f:(fun s -> not (String.is_prefix s ~prefix:"-std=")) + + let cxx_compiler = + lazy (match Context.which ctx ctx.c_compiler with + | Some path -> Build.Prog_spec.Dep path + | None -> Dyn (fun _ -> Utils.program_not_found ctx.c_compiler)) (* Expand some $-vars within action strings of rules defined in jbuild files *) let dollar_var_map = @@ -364,10 +356,11 @@ module Gen(P : Params) = struct | Some p -> Path.to_string p in [ "-verbose" , "" (*"-verbose";*) - ; "CPP" , ctx.bytecomp_c_compiler ^ " -E" - ; "PA_CPP" , ctx.bytecomp_c_compiler ^ " -undef -traditional -x c -E" - ; "CC" , ctx.bytecomp_c_compiler - ; "CXX" , String.concat ~sep:" " (Path.to_string cxx_compiler :: cxx_flags) + ; "CPP" , sprintf "%s %s -E" ctx.c_compiler ctx.ocamlc_cflags + ; "PA_CPP" , sprintf "%s %s -undef -traditional -x c -E" ctx.c_compiler + ctx.ocamlc_cflags + ; "CC" , sprintf "%s %s" ctx.c_compiler ctx.ocamlc_cflags + ; "CXX" , String.concat ~sep:" " (ctx.c_compiler :: cxx_flags) ; "ocaml_bin" , Path.to_string ctx.ocaml_bin ; "OCAML" , Path.to_string ctx.ocaml ; "OCAMLC" , Path.to_string ctx.ocamlc @@ -454,8 +447,8 @@ module Gen(P : Params) = struct String.capitalize_ascii module_basename in let deps = - String.split_words (String.sub line ~pos:(i + 1) - ~len:(String.length line - (i + 1))) + String.extract_blank_separated_words (String.sub line ~pos:(i + 1) + ~len:(String.length line - (i + 1))) |> List.filter ~f:(fun m -> m <> unit && String_map.mem m modules) in let deps = @@ -1327,7 +1320,7 @@ module Gen(P : Params) = struct (* We have to execute the rule in the library directory as the .o is produced in the current directory *) ~dir - (Dep cxx_compiler) + (Lazy.force cxx_compiler) [ S [A "-I"; Path ctx.stdlib_dir] ; expand_includes ~dir lib.includes ; As cxx_flags @@ -1858,7 +1851,8 @@ module Gen(P : Params) = struct List.iter template ~f:(fun s -> if String.is_prefix s ~prefix:"#" then match - String.split_words (String.sub s ~pos:1 ~len:(String.length s - 1)) + String.extract_blank_separated_words + (String.sub s ~pos:1 ~len:(String.length s - 1)) with | ["JBUILDER_GEN"] -> Format.fprintf ppf "%a@," Meta.pp meta.entries | _ -> Format.fprintf ppf "%s@," s diff --git a/src/import.ml b/src/import.ml index 1d74cd5b..22377d94 100644 --- a/src/import.ml +++ b/src/import.ml @@ -205,24 +205,34 @@ module String = struct let uncapitalize_ascii = String.uncapitalize end - let split_words s = + let extract_words s ~is_word_char = let rec skip_blanks i = if i = length s then [] + else if is_word_char s.[i] then + parse_word i (i + 1) else - match s.[i] with - | ',' | ' ' | '\t' | '\n' -> skip_blanks (i + 1) - | _ -> parse_word i (i + 1) + skip_blanks (i + 1) and parse_word i j = if j = length s then [sub s ~pos:i ~len:(j - i)] + else if is_word_char s.[j] then + parse_word i (j + 1) else - match s.[j] with - | ',' | ' ' | '\t' | '\n' -> sub s ~pos:i ~len:(j - i) :: skip_blanks (j + 1) - | _ -> parse_word i (j + 1) + sub s ~pos:i ~len:(j - i) :: skip_blanks (j + 1) in skip_blanks 0 + let extract_comma_space_separated_words s = + extract_words s ~is_word_char:(function + | ',' | ' ' | '\t' | '\n' -> false + | _ -> true) + + let extract_blank_separated_words s = + extract_words s ~is_word_char:(function + | ' ' | '\t' -> false + | _ -> true) + let lsplit2 s ~on = match index s on with | exception Not_found -> None diff --git a/src/utils.ml b/src/utils.ml index 7641f26d..9739c3de 100644 --- a/src/utils.ml +++ b/src/utils.ml @@ -79,3 +79,9 @@ let describe_target fn = sprintf "alias %s" (Path.to_string dir) | _ -> Path.to_string fn + +let program_not_found ?context prog = + die "@{Error@}: Program %s not found in PATH%s" prog + (match context with + | None -> "" + | Some name -> sprintf " (context: %s)" name) diff --git a/src/utils.mli b/src/utils.mli index d37dbb35..515b2a30 100644 --- a/src/utils.mli +++ b/src/utils.mli @@ -17,3 +17,6 @@ val jbuild_name_in : dir:Path.t -> string (** Nice description of a target *) val describe_target : Path.t -> string + +(** Raise an error about a program not found in the PATH *) +val program_not_found : ?context:string -> string -> _