summaryrefslogtreecommitdiffstats
path: root/ocamlbuild/ocaml_compiler.ml
diff options
context:
space:
mode:
Diffstat (limited to 'ocamlbuild/ocaml_compiler.ml')
-rw-r--r--ocamlbuild/ocaml_compiler.ml315
1 files changed, 315 insertions, 0 deletions
diff --git a/ocamlbuild/ocaml_compiler.ml b/ocamlbuild/ocaml_compiler.ml
new file mode 100644
index 000000000..f536af8d1
--- /dev/null
+++ b/ocamlbuild/ocaml_compiler.ml
@@ -0,0 +1,315 @@
+(***********************************************************************)
+(* ocamlbuild *)
+(* *)
+(* Nicolas Pouillard, Berke Durak, projet Gallium, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2007 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+(* Original author: Nicolas Pouillard *)
+open My_std
+open Format
+open Log
+open Pathname.Operators
+open Tools
+open Command
+open Rule
+open Tags.Operators
+open Ocaml_utils
+open Rule.Common_commands
+open Outcome
+
+let forpack_flags arg tags =
+ if Tags.mem "pack" tags then
+ Ocaml_arch.forpack_flags_of_pathname arg
+ else N
+
+let ocamlc_c tags arg out =
+ let tags = tags++"ocaml"++"byte" in
+ Cmd (S [!Options.ocamlc; A"-c"; T(tags++"compile");
+ ocaml_ppflags tags; flags_of_pathname arg;
+ ocaml_include_flags arg; A"-o"; Px out; P arg])
+
+let ocamlc_link flag tags deps out =
+ Cmd (S [!Options.ocamlc; flag; T tags;
+ atomize_paths deps; flags_of_pathname out; A"-o"; Px out])
+
+let ocamlc_link_lib = ocamlc_link (A"-a")
+let ocamlc_link_prog = ocamlc_link N
+
+let ocamlmklib tags deps out =
+ Cmd (S [!Options.ocamlmklib; T tags;
+ atomize_paths deps; flags_of_pathname out; A"-o"; Px (Pathname.remove_extensions out)])
+
+let byte_lib_linker tags =
+ if Tags.mem "ocamlmklib" tags then
+ ocamlmklib tags
+ else
+ ocamlc_link_lib tags
+
+let byte_lib_linker_tags tags = tags++"ocaml"++"link"++"byte"++"library"
+
+let ocamlc_p tags deps out =
+ Cmd (S [!Options.ocamlc; A"-pack"; T tags;
+ atomize_paths deps; flags_of_pathname out; A"-o"; Px out])
+
+let ocamlopt_c tags arg out =
+ let tags = tags++"ocaml"++"native" in
+ Cmd (S [!Options.ocamlopt; A"-c"; Ocaml_arch.forpack_flags_of_pathname arg;
+ T(tags++"compile"); ocaml_ppflags tags; flags_of_pathname arg;
+ flags_of_pathname out; ocaml_include_flags arg;
+ A"-o"; Px out (* FIXME ocamlopt bug -o cannot be after the input file *); P arg])
+
+let ocamlopt_link flag tags deps out =
+ Cmd (S [!Options.ocamlopt; flag; forpack_flags out tags; T tags;
+ atomize_paths deps; flags_of_pathname out; A"-o"; Px out])
+
+let ocamlopt_link_lib = ocamlopt_link (A"-a")
+let ocamlopt_link_prog = ocamlopt_link N
+
+let ocamlopt_p tags deps out =
+ let include_flags = List.fold_right begin fun dep ->
+ ocaml_add_include_flag (Pathname.dirname dep)
+ end deps [] in
+ let cmi = cmi_of out and cmitmp = Pathname.update_extensions "cmitmp" out in
+ Seq[mv cmi cmitmp;
+ Cmd (S [!Options.ocamlopt; A"-pack"; forpack_flags out tags; T tags; S include_flags;
+ atomize_paths deps; flags_of_pathname out; (* FIXME: P (cmi_of out);*) A"-o"; Px out]);
+ cmp cmitmp cmi]
+
+let native_lib_linker tags =
+ if Tags.mem "ocamlmklib" tags then
+ ocamlmklib tags
+ else
+ ocamlopt_link_lib tags
+
+let native_lib_linker_tags tags = tags++"ocaml"++"link"++"native"++"library"
+
+let prepare_compile build ml =
+ let dir = Pathname.dirname ml in
+ let include_dirs = Pathname.include_dirs_of dir in
+ let modules = Ocamldep.module_dependencies_of ml in
+ let results =
+ build (List.map (fun x -> expand_module include_dirs x ["cmi"]) modules) in
+ List.iter2 begin fun name res ->
+ match res with
+ | Good _ -> ()
+ | Bad exn ->
+ if !Options.ignore_auto then
+ dprintf 3 "Warning: Failed to build the module \
+ %s requested by ocamldep" name
+ else raise exn
+ end modules results
+
+let byte_compile_ocaml_interf mli cmi env build =
+ let mli = env mli and cmi = env cmi in
+ prepare_compile build mli;
+ ocamlc_c (tags_of_pathname mli++"interf") mli cmi
+
+let byte_compile_ocaml_implem ?tag ml cmo env build =
+ let ml = env ml and cmo = env cmo in
+ prepare_compile build ml;
+ ocamlc_c (tags_of_pathname ml++"implem"+++tag) ml cmo
+
+let cache_prepare_link = Hashtbl.create 107
+let rec prepare_link tag cmx extensions build =
+ let key = (tag, cmx, extensions) in
+ let dir = Pathname.dirname cmx in
+ let include_dirs = Pathname.include_dirs_of dir in
+ if Hashtbl.mem cache_prepare_link key then () else
+ let () = Hashtbl.add cache_prepare_link key true in
+ let modules = List.map (fun x -> expand_module include_dirs x extensions)
+ (Ocamldep.module_dependencies_of (Pathname.update_extensions "ml" cmx)) in
+ List.iter begin function
+ | Good p -> prepare_link tag p extensions build
+ | Bad exn -> if not !Options.ignore_auto then raise exn
+ end (build modules)
+
+let native_compile_ocaml_implem ?tag ?(cmx_ext="cmx") ml env build =
+ let ml = env ml in
+ let cmi = Pathname.update_extensions "cmi" ml in
+ let cmx = Pathname.update_extensions cmx_ext ml in
+ prepare_link cmx cmi [cmx_ext; "cmi"] build;
+ ocamlopt_c (tags_of_pathname ml++"implem"+++tag) ml cmx
+
+let libs_of_use_lib tags =
+ Tags.fold begin fun tag acc ->
+ if String.is_prefix "use_" tag then
+ let lib = String.after tag 4 in
+ try let libpath, extern = Hashtbl.find info_libraries lib in
+ if extern then acc else libpath :: acc
+ with Not_found -> acc
+ else acc
+ end tags []
+
+let prepare_libs cma_ext a_ext out build =
+ let out_no_ext = Pathname.remove_extension out in
+ let libs1 = List.union (libraries_of out_no_ext) (libs_of_use_lib (tags_of_pathname out)) in
+ let () = dprintf 10 "prepare_libs: %S -> %a" out pp_l libs1 in
+ let libs = List.map (fun x -> x-.-cma_ext) libs1 in
+ let libs2 = List.map (fun lib -> [lib-.-a_ext]) libs1 in
+ List.iter ignore_good (build libs2); libs
+
+let library_index = Hashtbl.create 32
+let package_index = Hashtbl.create 32
+let hidden_packages = ref []
+
+let hide_package_contents package = hidden_packages := package :: !hidden_packages
+
+module Ocaml_dependencies_input = struct
+ let fold_dependencies = Resource.Cache.fold_dependencies
+ let fold_libraries f = Hashtbl.fold f library_index
+ let fold_packages f = Hashtbl.fold f package_index
+end
+module Ocaml_dependencies = Ocaml_dependencies.Make(Ocaml_dependencies_input)
+
+let caml_transitive_closure = Ocaml_dependencies.caml_transitive_closure
+
+let link_gen cmX_ext cma_ext a_ext extensions linker tagger cmX out env build =
+ let cmX = env cmX and out = env out in
+ let tags = tagger (tags_of_pathname out) in
+ let dyndeps = Rule.build_deps_of_tags build tags in
+ let cmi = Pathname.update_extensions "cmi" cmX in
+ prepare_link cmX cmi extensions build;
+ let libs = prepare_libs cma_ext a_ext out build in
+ let hidden_packages = List.map (fun x -> x-.-cmX_ext) !hidden_packages in
+ let deps =
+ caml_transitive_closure
+ ~caml_obj_ext:cmX_ext ~caml_lib_ext:cma_ext
+ ~used_libraries:libs ~hidden_packages (cmX :: dyndeps) in
+ let deps = (List.filter (fun l -> not (List.mem l deps)) libs) @ deps in
+ if deps = [] then failwith "Link list cannot be empty";
+ let () = dprintf 6 "link: %a -o %a" print_string_list deps Pathname.print out in
+ linker tags deps out
+
+let byte_link_gen = link_gen "cmo" "cma" "cma" ["cmo"; "cmi"]
+
+let byte_link = byte_link_gen ocamlc_link_prog
+ (fun tags -> tags++"ocaml"++"link"++"byte"++"program")
+
+let byte_library_link = byte_link_gen byte_lib_linker byte_lib_linker_tags
+
+let byte_debug_link_gen =
+ link_gen "d.cmo" "d.cma" "d.cma" ["d.cmo"; "cmi"]
+
+let byte_debug_link = byte_debug_link_gen ocamlc_link_prog
+ (fun tags -> tags++"ocaml"++"link"++"byte"++"debug"++"program")
+
+let byte_debug_library_link = byte_debug_link_gen byte_lib_linker
+ (fun tags -> byte_lib_linker_tags tags++"debug")
+
+let native_link_gen linker =
+ link_gen "cmx" "cmxa" !Options.ext_lib [!Options.ext_obj; "cmi"] linker
+
+let native_link x = native_link_gen ocamlopt_link_prog
+ (fun tags -> tags++"ocaml"++"link"++"native"++"program") x
+
+let native_library_link x =
+ native_link_gen native_lib_linker native_lib_linker_tags x
+
+let native_profile_link_gen linker =
+ link_gen "p.cmx" "p.cmxa" ("p" -.- !Options.ext_lib) ["p" -.- !Options.ext_obj; "cmi"] linker
+
+let native_profile_link x = native_profile_link_gen ocamlopt_link_prog
+ (fun tags -> tags++"ocaml"++"link"++"native"++"profile"++"program") x
+
+let native_profile_library_link x = native_profile_link_gen native_lib_linker
+ (fun tags -> native_lib_linker_tags tags++"profile") x
+
+let link_units table extensions cmX_ext cma_ext a_ext linker tagger contents_list cmX env build =
+ let cmX = env cmX in
+ let tags = tagger (tags_of_pathname cmX) in
+ let _ = Rule.build_deps_of_tags build tags in
+ let dir =
+ let dir1 = Pathname.remove_extensions cmX in
+ if Pathname.exists_in_source_dir dir1 then dir1
+ else Pathname.dirname cmX in
+ let include_dirs = Pathname.include_dirs_of dir in
+ let extension_keys = List.map fst extensions in
+ let libs = prepare_libs cma_ext a_ext cmX build in
+ let results =
+ build begin
+ List.map begin fun module_name ->
+ expand_module include_dirs module_name extension_keys
+ end contents_list
+ end in
+ let module_paths =
+ List.map begin function
+ | Good p ->
+ let extension_values = List.assoc (Pathname.get_extensions p) extensions in
+ List.iter begin fun ext ->
+ List.iter ignore_good (build [[Pathname.update_extensions ext p]])
+ end extension_values; p
+ | Bad exn -> raise exn
+ end results in
+ Hashtbl.replace table cmX module_paths;
+ let hidden_packages = List.map (fun x -> x-.-cmX_ext) !hidden_packages in
+ let deps =
+ caml_transitive_closure
+ ~caml_obj_ext:cmX_ext ~caml_lib_ext:cma_ext
+ ~hidden_packages ~pack_mode:true module_paths in
+ let full_contents = libs @ module_paths in
+ let deps = List.filter (fun x -> List.mem x full_contents) deps in
+ let deps = (List.filter (fun l -> not (List.mem l deps)) libs) @ deps in
+ linker tags deps cmX
+
+let link_modules = link_units library_index
+let pack_modules = link_units package_index
+
+let link_from_file link modules_file cmX env build =
+ let modules_file = env modules_file in
+ let contents_list = string_list_of_file modules_file in
+ link contents_list cmX env build
+
+let byte_library_link_modules =
+ link_modules [("cmo",[]); ("cmi",[])] "cmo" "cma" "cma" byte_lib_linker byte_lib_linker_tags
+
+let byte_library_link_mllib = link_from_file byte_library_link_modules
+
+let byte_debug_library_link_modules =
+ link_modules [("d.cmo",[]); ("cmi",[])] "d.cmo" "d.cma" "d.cma" byte_lib_linker
+ (fun tags -> byte_lib_linker_tags tags++"debug")
+
+let byte_debug_library_link_mllib = link_from_file byte_debug_library_link_modules
+
+let byte_pack_modules =
+ pack_modules [("cmo",["cmi"]); ("cmi",[])] "cmo" "cma" "cma" ocamlc_p
+ (fun tags -> tags++"ocaml"++"pack"++"byte")
+
+let byte_pack_mlpack = link_from_file byte_pack_modules
+
+let byte_debug_pack_modules =
+ pack_modules [("d.cmo",["cmi"]); ("cmi",[])] "d.cmo" "d.cma" "d.cma" ocamlc_p
+ (fun tags -> tags++"ocaml"++"pack"++"byte"++"debug")
+
+let byte_debug_pack_mlpack = link_from_file byte_debug_pack_modules
+
+let native_pack_modules x =
+ pack_modules [("cmx",["cmi"; !Options.ext_obj]); ("cmi",[])] "cmx" "cmxa" !Options.ext_lib ocamlopt_p
+ (fun tags -> tags++"ocaml"++"pack"++"native") x
+
+let native_pack_mlpack = link_from_file native_pack_modules
+
+let native_profile_pack_modules x =
+ pack_modules [("p.cmx",["cmi"; "p" -.- !Options.ext_obj]); ("cmi",[])] "p.cmx" "p.cmxa"
+ ("p" -.- !Options.ext_lib) ocamlopt_p
+ (fun tags -> tags++"ocaml"++"pack"++"native"++"profile") x
+
+let native_profile_pack_mlpack = link_from_file native_profile_pack_modules
+
+let native_library_link_modules x =
+ link_modules [("cmx",[!Options.ext_obj]); ("cmi",[])] "cmx" "cmxa"
+ !Options.ext_lib native_lib_linker native_lib_linker_tags x
+
+let native_library_link_mllib = link_from_file native_library_link_modules
+
+let native_profile_library_link_modules x =
+ link_modules [("p.cmx",["p" -.- !Options.ext_obj]); ("cmi",[])] "p.cmx" "p.cmxa"
+ ("p" -.- !Options.ext_lib) native_lib_linker
+ (fun tags -> native_lib_linker_tags tags++"profile") x
+
+let native_profile_library_link_mllib = link_from_file native_profile_library_link_modules