dune/src/main.ml

189 lines
5.8 KiB
OCaml
Raw Normal View History

2016-11-13 12:25:45 +00:00
open Import
open Fiber.O
2016-12-02 13:54:32 +00:00
let () = Inline_tests.linkme
type setup =
{ build_system : Build_system.t
Refactor library management (#516) Lib module ---------- We have a new module Lib that replaces Lib, parts of Lib_db and parts of Findlib. It is used to manage all libraries (internal and extrernal). Lib.t represent a completely resolved library, i.e. where all the dependencies have been resolved. Lib.Compile is used to provide what is necessary to build the library itself. Lib.Meta provides what is necessary to generate the META file for the library. We also have library databases represented as Lib.DB.t. A library database is simply a mapping from names to Lib.t values and and created from a resolve function that looks up a name and return a Lib.Info.t. A Lib.Info.t is the same as a Lib.t except that dependencies are not resolved. A library database can have a parent database that is used to lookup names that are not found in the current database. In practice we have the following hierarchy: 1. For every scope, we have a library database that holds all the libraries of this scope. In this DB, a library can be referred by either it's name or public name 2. the parent of each of these databases is a database that holds all the public libraries of the workspace. In this DB libraries must be referred by their public name 3. the parent of this DB is for installed libraries (1) databases are accessible via Scope.libs (Super_context.find_scope_by_{name,dir} sctx xxx) (2) is accessible via Super_context.public_libs sctx (3) is accessible via Super_context.installed_libs sctx The dependencies of a library are always resolved inside the DB it is part of. When we compute a transitive closure, we check that we don't have two libraries from two different DB with the same name. So for instance linting Base should now supported. Jbuild.Scope_info ----------------- Jbuild.Scope was renamed Jbuild.Scope_info Scope module ------------ This replaces Lib_db. A Scope.t is now just a pair of a Jbuild.Scope_info.t and a Lib.DB.t. Scope.DB.t is an object used to lookup scopes by either name or directory. We no longer have an external scope or special anonymous scope. Instead one should use Super_context.installed_libs or Super_context.public_libs depending on the context.
2018-02-20 11:46:10 +00:00
; stanzas : (Path.t * Jbuild.Scope_info.t * Jbuild.Stanzas.t) list String_map.t
2017-02-25 02:38:41 +00:00
; contexts : Context.t list
2017-02-24 18:21:22 +00:00
; packages : Package.t String_map.t
; file_tree : File_tree.t
}
let package_install_file { packages; _ } pkg =
match String_map.find packages pkg with
| None -> Error ()
| Some p ->
Ok (Path.relative p.path
(Utils.install_file ~package:p.name ~findlib_toolchain:None))
let setup ?(log=Log.no_log)
?filter_out_optional_stanzas_with_missing_deps
2017-03-01 13:25:18 +00:00
?workspace ?(workspace_file="jbuild-workspace")
?(use_findlib=true)
?only_packages
?extra_ignored_subtrees
?x
2018-01-25 19:07:46 +00:00
?ignore_promoted_rules
() =
2018-01-25 19:07:46 +00:00
let conf = Jbuild_load.load ?extra_ignored_subtrees ?ignore_promoted_rules () in
Option.iter only_packages ~f:(fun set ->
String_set.iter set ~f:(fun pkg ->
if not (String_map.mem conf.packages pkg) then
die "@{<error>Error@}: I don't know about package %s \
(passed through --only-packages/--release)%s"
pkg (hint pkg (String_map.keys conf.packages))));
2017-02-25 02:38:41 +00:00
let workspace =
match workspace with
| Some w -> w
| None ->
2017-02-27 15:04:49 +00:00
if Sys.file_exists workspace_file then
Workspace.load ?x workspace_file
2017-02-25 02:38:41 +00:00
else
{ merlin_context = Some "default"
; contexts = [Default [
match x with
| None -> Native
| Some x -> Named x
]]
}
2017-02-25 02:38:41 +00:00
in
Fiber.parallel_map workspace.contexts ~f:(fun ctx_def ->
let name = Workspace.Context.name ctx_def in
Context.create ctx_def ~merlin:(workspace.merlin_context = Some name) ~use_findlib)
2017-02-25 00:28:10 +00:00
>>= fun contexts ->
let contexts = List.concat contexts in
List.iter contexts ~f:(fun (ctx : Context.t) ->
Log.infof log "@[<1>Jbuilder context:@,%a@]@." Sexp.pp (Context.sexp_of_t ctx));
let rule_done = ref 0 in
let rule_total = ref 0 in
let gen_status_line () =
Some (sprintf "Done: %u/%u" !rule_done !rule_total)
in
let hook (hook : Build_system.hook) =
match hook with
| Rule_started -> incr rule_total
| Rule_completed -> incr rule_done
in
let build_system =
Build_system.create ~contexts ~file_tree:conf.file_tree ~hook
in
Gen_rules.gen conf
~build_system
~contexts
?only_packages
2017-02-26 19:49:54 +00:00
?filter_out_optional_stanzas_with_missing_deps
>>= fun stanzas ->
Scheduler.set_status_line_generator gen_status_line
>>>
Fiber.return
{ build_system
; stanzas
; contexts
; packages = conf.packages
; file_tree = conf.file_tree
}
2016-12-02 13:54:32 +00:00
2017-02-24 13:08:37 +00:00
let external_lib_deps ?log ~packages () =
Scheduler.go ?log
2016-12-15 13:00:30 +00:00
(setup () ~filter_out_optional_stanzas_with_missing_deps:false
2017-03-01 19:19:43 +00:00
>>| fun setup ->
let install_files =
List.map packages ~f:(fun pkg ->
match package_install_file setup pkg with
| Ok path -> path
| Error () -> die "Unknown package %S" pkg)
in
match String_map.find setup.stanzas "default" with
2017-03-01 19:19:43 +00:00
| None -> die "You need to set a default context to use external-lib-deps"
| Some stanzas ->
2017-06-02 13:32:05 +00:00
let internals = Jbuild.Stanzas.lib_names stanzas in
2017-03-01 19:19:43 +00:00
Path.Map.map
(Build_system.all_lib_deps setup.build_system
~request:(Build.paths install_files))
~f:(String_map.filteri ~f:(fun name _ ->
not (String_set.mem internals name))))
2016-12-02 13:54:32 +00:00
let ignored_during_bootstrap =
Path.Set.of_list
(List.map ~f:Path.of_string
[ "test"
; "example"
])
2017-02-21 15:09:58 +00:00
(* Called by the script generated by ../build.ml *)
let bootstrap () =
Colors.setup_err_formatter_colors ();
2017-02-21 15:09:58 +00:00
let main () =
let anon s = raise (Arg.Bad (Printf.sprintf "don't know what to do with %s\n" s)) in
let subst () =
Scheduler.go (Watermarks.subst () ~name:"jbuilder");
2017-05-07 19:53:40 +00:00
exit 0
in
let display = ref None in
let display_mode =
Arg.Symbol
(List.map Config.Display.all ~f:fst,
fun s ->
display := Some (List.assoc s Config.Display.all))
in
let concurrency = ref None in
let set r x = r := Some x in
Arg.parse
[ "-j" , Int (set concurrency), "JOBS concurrency"
; "--dev" , Set Clflags.dev_mode , " set development mode"
; "--display" , display_mode , " set the display mode"
; "--subst" , Unit subst ,
" substitute watermarks in source files"
; "--debug-backtraces",
Set Clflags.debug_backtraces,
" always print exception backtraces"
]
anon "Usage: boot.exe [-j JOBS] [--dev]\nOptions are:";
Clflags.debug_dep_path := true;
let config =
(* Only load the configuration with --dev *)
if !Clflags.dev_mode then
Config.load_user_config_file ()
else
Config.default
in
let config =
Config.merge config
{ display = !display
; concurrency = !concurrency
}
in
let config =
Config.adapt_display config
~output_is_a_tty:(Lazy.force Colors.stderr_supports_colors)
in
let log = Log.create ~display:config.display () in
Scheduler.go ~log ~config
(setup ~log ~workspace:{ merlin_context = Some "default"
; contexts = [Default [Native]] }
~use_findlib:false
~extra_ignored_subtrees:ignored_during_bootstrap
()
>>= fun { build_system = bs; _ } ->
Build_system.do_build bs
~request:(Build.path (Path.of_string "_build/default/jbuilder.install")))
2017-02-21 15:09:58 +00:00
in
2016-12-02 13:54:32 +00:00
try
main ()
with
| Fiber.Never -> exit 1
| exn ->
Report_error.report exn;
2016-12-02 13:54:32 +00:00
exit 1
let setup = setup ~use_findlib:true ~extra_ignored_subtrees:Path.Set.empty
let find_context_exn t ~name =
match List.find t.contexts ~f:(fun c -> c.name = name) with
| Some ctx -> ctx
| None ->
die "@{<Error>Error@}: Context %S not found!@." name