160 lines
5.4 KiB
OCaml
160 lines
5.4 KiB
OCaml
|
|
open Import
|
||
|
|
|
||
|
|
let doc = "Execute a Coq toplevel with the local configuration."
|
||
|
|
|
||
|
|
let man =
|
||
|
|
[ `S "DESCRIPTION"
|
||
|
|
; `P
|
||
|
|
{|$(b,dune coq top FILE -- ARGS) runs the Coq toplevel to process the
|
||
|
|
given $(b,FILE). The given arguments are completed according to the
|
||
|
|
local configuration. This is equivalent to running $(b,coqtop ARGS)
|
||
|
|
with a $(b,_CoqProject) file containing the local configurations
|
||
|
|
from the $(b,dune) files, but does not require maintaining a
|
||
|
|
$(b,_CoqProject) file.|}
|
||
|
|
; `Blocks Common.help_secs
|
||
|
|
]
|
||
|
|
;;
|
||
|
|
|
||
|
|
let info = Cmd.info "top" ~doc ~man
|
||
|
|
|
||
|
|
let term =
|
||
|
|
let+ default_builder = Common.Builder.term
|
||
|
|
and+ context =
|
||
|
|
let doc = "Run the Coq toplevel in this build context." in
|
||
|
|
Common.context_arg ~doc
|
||
|
|
and+ coqtop =
|
||
|
|
let doc = "Run the given toplevel command instead of the default." in
|
||
|
|
Arg.(value & opt string "coqtop" & info [ "toplevel" ] ~docv:"CMD" ~doc)
|
||
|
|
and+ coq_file_arg =
|
||
|
|
Arg.(required & pos 0 (some string) None (Arg.info [] ~docv:"COQFILE"))
|
||
|
|
and+ extra_args = Arg.(value & pos_right 0 string [] (Arg.info [] ~docv:"ARGS"))
|
||
|
|
and+ no_rebuild =
|
||
|
|
Arg.(
|
||
|
|
value
|
||
|
|
& flag
|
||
|
|
& info [ "no-build" ] ~doc:"Don't rebuild dependencies before executing.")
|
||
|
|
in
|
||
|
|
let common, config =
|
||
|
|
let builder =
|
||
|
|
if no_rebuild then Common.Builder.forbid_builds default_builder else default_builder
|
||
|
|
in
|
||
|
|
Common.init builder
|
||
|
|
in
|
||
|
|
let coq_file_arg = Common.prefix_target common coq_file_arg |> Path.Local.of_string in
|
||
|
|
let coqtop, args, env =
|
||
|
|
Scheduler.go_with_rpc_server ~common ~config
|
||
|
|
@@ fun () ->
|
||
|
|
let open Fiber.O in
|
||
|
|
let* setup = Import.Main.setup () in
|
||
|
|
let* setup = Memo.run setup in
|
||
|
|
let sctx = Import.Main.find_scontext_exn setup ~name:context in
|
||
|
|
let context = Dune_rules.Super_context.context sctx in
|
||
|
|
let coq_file_build =
|
||
|
|
Path.Build.append_local (Context.build_dir context) coq_file_arg
|
||
|
|
in
|
||
|
|
let dir =
|
||
|
|
(match Path.Local.parent coq_file_arg with
|
||
|
|
| None -> Path.Local.root
|
||
|
|
| Some dir -> dir)
|
||
|
|
|> Path.Build.append_local (Context.build_dir context)
|
||
|
|
in
|
||
|
|
let* coqtop, args, env =
|
||
|
|
build_exn
|
||
|
|
@@ fun () ->
|
||
|
|
let open Memo.O in
|
||
|
|
let* (tr : Dune_rules.Dir_contents.triage) =
|
||
|
|
Dune_rules.Dir_contents.triage sctx ~dir
|
||
|
|
in
|
||
|
|
let dir =
|
||
|
|
match tr with
|
||
|
|
| Group_part dir -> dir
|
||
|
|
| Standalone_or_root _ -> dir
|
||
|
|
in
|
||
|
|
let* dc = Dune_rules.Dir_contents.get sctx ~dir in
|
||
|
|
let* coq_src = Dune_rules.Dir_contents.coq dc in
|
||
|
|
let coq_module =
|
||
|
|
let source = coq_file_build in
|
||
|
|
match Dune_rules.Coq.Coq_sources.find_module ~source coq_src with
|
||
|
|
| Some m -> snd m
|
||
|
|
| None ->
|
||
|
|
let hints =
|
||
|
|
[ Pp.textf "Is the file part of a stanza?"
|
||
|
|
; Pp.textf "Has the file been written to disk?"
|
||
|
|
]
|
||
|
|
in
|
||
|
|
User_error.raise
|
||
|
|
~hints
|
||
|
|
[ Pp.textf "Cannot find file: %s" (coq_file_arg |> Path.Local.to_string) ]
|
||
|
|
in
|
||
|
|
let stanza = Dune_rules.Coq.Coq_sources.lookup_module coq_src coq_module in
|
||
|
|
let args, use_stdlib, coq_lang_version, wrapper_name, mode =
|
||
|
|
match stanza with
|
||
|
|
| None ->
|
||
|
|
User_error.raise
|
||
|
|
[ Pp.textf
|
||
|
|
"File not part of any stanza: %s"
|
||
|
|
(coq_file_arg |> Path.Local.to_string)
|
||
|
|
]
|
||
|
|
| Some (`Theory theory) ->
|
||
|
|
( Dune_rules.Coq.Coq_rules.coqtop_args_theory
|
||
|
|
~sctx
|
||
|
|
~dir
|
||
|
|
~dir_contents:dc
|
||
|
|
theory
|
||
|
|
coq_module
|
||
|
|
, theory.buildable.use_stdlib
|
||
|
|
, theory.buildable.coq_lang_version
|
||
|
|
, Dune_rules.Coq.Coq_lib_name.wrapper (snd theory.name)
|
||
|
|
, theory.buildable.mode )
|
||
|
|
| Some (`Extraction extr) ->
|
||
|
|
( Dune_rules.Coq.Coq_rules.coqtop_args_extraction ~sctx ~dir extr coq_module
|
||
|
|
, extr.buildable.use_stdlib
|
||
|
|
, extr.buildable.coq_lang_version
|
||
|
|
, "DuneExtraction"
|
||
|
|
, extr.buildable.mode )
|
||
|
|
in
|
||
|
|
(* Run coqdep *)
|
||
|
|
let* (_ : unit * Dep.Fact.t Dep.Map.t) =
|
||
|
|
let deps_of =
|
||
|
|
if no_rebuild
|
||
|
|
then Action_builder.return ()
|
||
|
|
else (
|
||
|
|
let mode =
|
||
|
|
match mode with
|
||
|
|
| None -> Dune_rules.Coq.Coq_mode.VoOnly
|
||
|
|
| Some mode -> mode
|
||
|
|
in
|
||
|
|
Dune_rules.Coq.Coq_rules.deps_of
|
||
|
|
~dir
|
||
|
|
~use_stdlib
|
||
|
|
~wrapper_name
|
||
|
|
~mode
|
||
|
|
~coq_lang_version
|
||
|
|
coq_module)
|
||
|
|
in
|
||
|
|
Action_builder.evaluate_and_collect_facts deps_of
|
||
|
|
in
|
||
|
|
(* Get args *)
|
||
|
|
let* (args, _) : string list * Dep.Fact.t Dep.Map.t =
|
||
|
|
let* args = args in
|
||
|
|
let dir = Path.external_ Path.External.initial_cwd in
|
||
|
|
let args = Dune_rules.Command.expand ~dir (S args) in
|
||
|
|
Action_builder.evaluate_and_collect_facts args.build
|
||
|
|
in
|
||
|
|
let* prog = Super_context.resolve_program_memo sctx ~dir ~loc:None coqtop in
|
||
|
|
let prog = Action.Prog.ok_exn prog in
|
||
|
|
let* () = Build_system.build_file prog in
|
||
|
|
let+ env = Super_context.context_env sctx in
|
||
|
|
Path.to_string prog, args, env
|
||
|
|
in
|
||
|
|
let args =
|
||
|
|
let topfile = Path.to_absolute_filename (Path.build coq_file_build) in
|
||
|
|
("-topfile" :: topfile :: args) @ extra_args
|
||
|
|
in
|
||
|
|
Fiber.return (coqtop, args, env)
|
||
|
|
in
|
||
|
|
restore_cwd_and_execve (Common.root common) coqtop args env
|
||
|
|
;;
|
||
|
|
|
||
|
|
let command = Cmd.v info term
|