2018-02-27 19:06:12 +00:00
|
|
|
open Import
|
|
|
|
open Jbuild
|
|
|
|
open Build.O
|
|
|
|
open! No_io
|
|
|
|
|
|
|
|
module SC = Super_context
|
|
|
|
|
|
|
|
module Backend = struct
|
|
|
|
module M = struct
|
|
|
|
module Info = struct
|
|
|
|
let name = Sub_system_name.make "inline_tests.backend"
|
|
|
|
|
|
|
|
type t =
|
|
|
|
{ loc : Loc.t
|
|
|
|
; runner_libraries : (Loc.t * string) list
|
|
|
|
; flags : Ordered_set_lang.Unexpanded.t
|
2018-05-02 12:46:22 +00:00
|
|
|
; generate_runner : (Loc.t * Action.Unexpanded.t) option
|
2018-03-20 00:47:51 +00:00
|
|
|
; extends : (Loc.t * string) list
|
2018-02-27 19:06:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Jbuild.Sub_system_info.t += T of t
|
|
|
|
|
|
|
|
let loc t = t.loc
|
|
|
|
|
|
|
|
open Sexp.Of_sexp
|
|
|
|
|
|
|
|
let short = None
|
|
|
|
let parse =
|
|
|
|
record
|
|
|
|
(record_loc >>= fun loc ->
|
|
|
|
field "runner_libraries" (list (located string)) ~default:[]
|
|
|
|
>>= fun runner_libraries ->
|
|
|
|
Ordered_set_lang.Unexpanded.field "flags" >>= fun flags ->
|
2018-05-02 12:46:22 +00:00
|
|
|
field_o "generate_runner" (located Action.Unexpanded.t)
|
2018-02-27 19:06:12 +00:00
|
|
|
>>= fun generate_runner ->
|
2018-03-20 00:47:51 +00:00
|
|
|
field "extends" (list (located string)) ~default:[]
|
|
|
|
>>= fun extends ->
|
2018-02-27 19:06:12 +00:00
|
|
|
return
|
|
|
|
{ loc
|
|
|
|
; runner_libraries
|
|
|
|
; flags
|
|
|
|
; generate_runner
|
|
|
|
; extends
|
|
|
|
})
|
|
|
|
|
|
|
|
let parsers =
|
|
|
|
Syntax.Versioned_parser.make
|
|
|
|
[ (1, 0),
|
|
|
|
{ Jbuild.Sub_system_info.
|
|
|
|
short
|
|
|
|
; parse
|
|
|
|
}
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
type t =
|
|
|
|
{ info : Info.t
|
2018-02-28 19:04:02 +00:00
|
|
|
; lib : Lib.t
|
2018-03-30 20:55:44 +00:00
|
|
|
; runner_libraries : Lib.t list Or_exn.t
|
|
|
|
; extends : t list Or_exn.t
|
2018-02-27 19:06:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let desc ~plural = "inline tests backend" ^ if plural then "s" else ""
|
|
|
|
let desc_article = "an"
|
|
|
|
|
2018-02-28 19:04:02 +00:00
|
|
|
let lib t = t.lib
|
2018-03-20 00:47:51 +00:00
|
|
|
let extends t = t.extends
|
2018-02-27 19:06:12 +00:00
|
|
|
|
2018-02-28 19:04:02 +00:00
|
|
|
let instantiate ~resolve ~get lib (info : Info.t) =
|
2018-02-27 19:06:12 +00:00
|
|
|
{ info
|
2018-02-28 19:04:02 +00:00
|
|
|
; lib
|
2018-03-20 00:47:51 +00:00
|
|
|
; runner_libraries =
|
|
|
|
Result.all (List.map info.runner_libraries ~f:resolve)
|
2018-02-27 19:06:12 +00:00
|
|
|
; extends =
|
|
|
|
let open Result.O in
|
2018-03-20 00:47:51 +00:00
|
|
|
Result.all
|
|
|
|
(List.map info.extends
|
|
|
|
~f:(fun ((loc, name) as x) ->
|
|
|
|
resolve x >>= fun lib ->
|
|
|
|
match get lib with
|
|
|
|
| None ->
|
|
|
|
Error (Loc.exnf loc "%S is not an %s" name
|
|
|
|
(desc ~plural:false))
|
|
|
|
| Some t -> Ok t))
|
2018-02-27 19:06:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let to_sexp t =
|
|
|
|
let open Sexp.To_sexp in
|
|
|
|
let lib x = string (Lib.name x) in
|
2018-02-28 19:04:02 +00:00
|
|
|
let f x = string (Lib.name x.lib) in
|
2018-02-27 19:06:12 +00:00
|
|
|
((1, 0),
|
2018-03-18 13:43:24 +00:00
|
|
|
record_fields
|
|
|
|
[ field "runner_libraries" (list lib)
|
|
|
|
(Result.ok_exn t.runner_libraries)
|
|
|
|
; field "flags" Ordered_set_lang.Unexpanded.sexp_of_t t.info.flags
|
|
|
|
; field_o "generate_runner" Action.Unexpanded.sexp_of_t
|
2018-05-02 12:46:22 +00:00
|
|
|
(Option.map t.info.generate_runner ~f:snd)
|
2018-03-20 00:47:51 +00:00
|
|
|
; field "extends" (list f) (Result.ok_exn t.extends) ~default:[]
|
2018-02-27 19:06:12 +00:00
|
|
|
])
|
|
|
|
end
|
|
|
|
include M
|
|
|
|
include Sub_system.Register_backend(M)
|
|
|
|
end
|
|
|
|
|
|
|
|
include Sub_system.Register_end_point(
|
|
|
|
struct
|
|
|
|
module Backend = Backend
|
|
|
|
|
|
|
|
module Info = struct
|
|
|
|
let name = Sub_system_name.make "inline_tests"
|
|
|
|
|
|
|
|
type t =
|
2018-03-09 19:51:02 +00:00
|
|
|
{ loc : Loc.t
|
|
|
|
; deps : Dep_conf.t list
|
|
|
|
; flags : Ordered_set_lang.Unexpanded.t
|
|
|
|
; backend : (Loc.t * string) option
|
|
|
|
; libraries : (Loc.t * string) list
|
2018-02-27 19:06:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Jbuild.Sub_system_info.t += T of t
|
|
|
|
|
|
|
|
let empty loc =
|
|
|
|
{ loc
|
2018-03-09 19:51:02 +00:00
|
|
|
; deps = []
|
|
|
|
; flags = Ordered_set_lang.Unexpanded.standard
|
|
|
|
; backend = None
|
|
|
|
; libraries = []
|
2018-02-27 19:06:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let loc t = t.loc
|
|
|
|
let backends t = Option.map t.backend ~f:(fun x -> [x])
|
|
|
|
|
|
|
|
open Sexp.Of_sexp
|
|
|
|
|
|
|
|
let short = Some empty
|
|
|
|
let parse =
|
|
|
|
record
|
|
|
|
(record_loc >>= fun loc ->
|
|
|
|
field "deps" (list Dep_conf.t) ~default:[] >>= fun deps ->
|
|
|
|
Ordered_set_lang.Unexpanded.field "flags" >>= fun flags ->
|
|
|
|
field_o "backend" (located string) >>= fun backend ->
|
2018-03-09 19:51:02 +00:00
|
|
|
field "libraries" (list (located string)) ~default:[]
|
|
|
|
>>= fun libraries ->
|
2018-02-27 19:06:12 +00:00
|
|
|
return
|
|
|
|
{ loc
|
|
|
|
; deps
|
|
|
|
; flags
|
|
|
|
; backend
|
2018-03-09 19:51:02 +00:00
|
|
|
; libraries
|
2018-02-27 19:06:12 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
let parsers =
|
|
|
|
Syntax.Versioned_parser.make
|
|
|
|
[ (1, 0),
|
|
|
|
{ Jbuild.Sub_system_info.
|
|
|
|
short
|
|
|
|
; parse
|
|
|
|
}
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
let gen_rules c ~(info:Info.t) ~backends =
|
|
|
|
let { Sub_system.Library_compilation_context.
|
|
|
|
super_context = sctx
|
|
|
|
; dir
|
|
|
|
; stanza = lib
|
|
|
|
; scope
|
|
|
|
; source_modules
|
|
|
|
; _
|
|
|
|
} = c
|
|
|
|
in
|
|
|
|
|
|
|
|
let inline_test_dir =
|
|
|
|
Path.relative dir (sprintf ".%s.inline-tests" lib.name)
|
|
|
|
in
|
|
|
|
|
|
|
|
let name = "run" in
|
|
|
|
let main_module_filename = name ^ ".ml" in
|
2018-03-03 18:03:37 +00:00
|
|
|
let main_module_name = Module.Name.of_string name in
|
2018-02-27 19:06:12 +00:00
|
|
|
let modules =
|
2018-03-03 18:03:37 +00:00
|
|
|
Module.Name.Map.singleton main_module_name
|
2018-06-05 17:38:27 +00:00
|
|
|
(Module.make main_module_name
|
|
|
|
~impl:{ name = main_module_filename
|
|
|
|
; syntax = OCaml
|
|
|
|
}
|
|
|
|
~obj_name:name)
|
2018-02-27 19:06:12 +00:00
|
|
|
in
|
|
|
|
|
|
|
|
let extra_vars =
|
2018-04-23 05:43:20 +00:00
|
|
|
String.Map.singleton "library-name"
|
2018-02-27 19:06:12 +00:00
|
|
|
(Action.Var_expansion.Strings ([lib.name], Concat))
|
|
|
|
in
|
|
|
|
|
2018-03-30 19:54:33 +00:00
|
|
|
let runner_libs =
|
2018-02-27 19:06:12 +00:00
|
|
|
let open Result.O in
|
2018-03-30 21:59:43 +00:00
|
|
|
Result.concat_map backends
|
|
|
|
~f:(fun (backend : Backend.t) -> backend.runner_libraries)
|
|
|
|
>>= fun libs ->
|
|
|
|
Lib.DB.find_many (Scope.libs scope) [lib.name]
|
|
|
|
>>= fun lib ->
|
|
|
|
Result.all
|
|
|
|
(List.map info.libraries
|
|
|
|
~f:(Lib.DB.resolve (Scope.libs scope)))
|
|
|
|
>>= fun more_libs ->
|
|
|
|
Lib.closure (lib @ libs @ more_libs)
|
2018-02-27 19:06:12 +00:00
|
|
|
in
|
|
|
|
|
|
|
|
(* Generate the runner file *)
|
|
|
|
SC.add_rule sctx (
|
|
|
|
let target = Path.relative inline_test_dir main_module_filename in
|
2018-03-03 18:03:37 +00:00
|
|
|
let source_modules = Module.Name.Map.values source_modules in
|
2018-02-27 19:06:12 +00:00
|
|
|
let files ml_kind =
|
|
|
|
Action.Var_expansion.Paths (
|
|
|
|
List.filter_map source_modules ~f:(fun m ->
|
|
|
|
Module.file m ~dir ml_kind),
|
|
|
|
Split)
|
|
|
|
in
|
|
|
|
let extra_vars =
|
|
|
|
List.fold_left
|
|
|
|
[ "impl-files", files Impl
|
|
|
|
; "intf-files", files Intf
|
|
|
|
]
|
|
|
|
~init:extra_vars
|
2018-04-23 05:43:20 +00:00
|
|
|
~f:(fun acc (k, v) -> String.Map.add acc k v)
|
2018-02-27 19:06:12 +00:00
|
|
|
in
|
|
|
|
Build.return []
|
|
|
|
>>>
|
|
|
|
Build.all
|
|
|
|
(List.filter_map backends ~f:(fun (backend : Backend.t) ->
|
2018-05-02 12:46:22 +00:00
|
|
|
Option.map backend.info.generate_runner ~f:(fun (loc, action) ->
|
|
|
|
SC.Action.run sctx action ~loc
|
2018-02-27 19:06:12 +00:00
|
|
|
~extra_vars ~dir ~dep_kind:Required ~targets:Alias ~scope)))
|
|
|
|
>>^ (fun actions ->
|
|
|
|
Action.with_stdout_to target
|
|
|
|
(Action.progn actions))
|
|
|
|
>>>
|
|
|
|
Build.action_dyn ~targets:[target] ());
|
|
|
|
|
2018-05-25 16:53:10 +00:00
|
|
|
let cctx =
|
|
|
|
Compilation_context.create ()
|
|
|
|
~super_context:sctx
|
|
|
|
~scope
|
|
|
|
~dir:inline_test_dir
|
|
|
|
~modules
|
|
|
|
~requires:runner_libs
|
|
|
|
~flags:(Ocaml_flags.of_list ["-w"; "-24"]);
|
|
|
|
in
|
|
|
|
Exe.build_and_link cctx
|
2018-02-27 19:06:12 +00:00
|
|
|
~program:{ name; main_module_name }
|
|
|
|
~linkages:[Exe.Linkage.native_or_custom (SC.context sctx)]
|
2018-05-25 16:53:10 +00:00
|
|
|
~link_flags:(Build.return ["-linkall"]);
|
2018-02-27 19:06:12 +00:00
|
|
|
|
|
|
|
let flags =
|
|
|
|
let flags =
|
|
|
|
List.map backends ~f:(fun backend ->
|
|
|
|
backend.Backend.info.flags) @ [info.flags]
|
|
|
|
in
|
|
|
|
Build.all (
|
|
|
|
List.map flags ~f:(fun flags ->
|
|
|
|
Super_context.expand_and_eval_set sctx flags
|
|
|
|
~scope
|
|
|
|
~dir
|
|
|
|
~extra_vars
|
2018-05-04 15:49:25 +00:00
|
|
|
~standard:(Build.return [])))
|
2018-02-27 19:06:12 +00:00
|
|
|
>>^ List.concat
|
|
|
|
in
|
|
|
|
|
|
|
|
SC.add_alias_action sctx
|
|
|
|
(Build_system.Alias.runtest ~dir)
|
|
|
|
~stamp:(List [ Sexp.unsafe_atom_of_string "ppx-runner"
|
|
|
|
; Quoted_string name
|
|
|
|
])
|
|
|
|
(let module A = Action in
|
|
|
|
let exe = Path.relative inline_test_dir (name ^ ".exe") in
|
|
|
|
Build.path exe >>>
|
|
|
|
Build.fanout
|
|
|
|
(Super_context.Deps.interpret sctx info.deps ~dir ~scope)
|
|
|
|
flags
|
|
|
|
>>^ fun (_deps, flags) ->
|
|
|
|
A.chdir dir
|
|
|
|
(A.progn
|
|
|
|
(A.run (Ok exe) flags ::
|
2018-03-03 18:03:37 +00:00
|
|
|
(Module.Name.Map.values source_modules
|
2018-02-27 19:06:12 +00:00
|
|
|
|> List.concat_map ~f:(fun m ->
|
|
|
|
[ Module.file m ~dir Impl
|
|
|
|
; Module.file m ~dir Intf
|
|
|
|
])
|
|
|
|
|> List.filter_map ~f:(fun x -> x)
|
|
|
|
|> List.map ~f:(fun fn ->
|
|
|
|
A.diff ~optional:true
|
|
|
|
fn (Path.extend_basename fn ~suffix:".corrected"))))))
|
|
|
|
end)
|
|
|
|
|
|
|
|
let linkme = ()
|