@@ -94,6 +94,9 @@ let modules_rules
9494 ~preprocessor_deps
9595 ~lint
9696 ~empty_module_interface_if_absent
97+ ~ctypes
98+ ~modules_loc
99+ ~buildable_loc
97100 sctx
98101 expander
99102 ~dir
@@ -135,6 +138,39 @@ let modules_rules
135138 fun name -> default || List. mem executable_names name ~equal: Module_name. equal)
136139 else fun _ -> default
137140 in
141+ let * () =
142+ match ctypes with
143+ | Some ctypes ->
144+ let (ctypes : Ctypes_field.t ) = ctypes in
145+ let modules = Modules.With_vlib. modules modules in
146+ (* Here we collect all the modules that ctypes expects to be present in
147+ that stanza in order to validate their existence. We do this using
148+ [Memo.parallel_iter] in order to collect all the errors rather than
149+ just the first occurances. *)
150+ (ctypes.type_description.functor_loc, ctypes.type_description.functor_)
151+ :: List. map
152+ ~f: (fun (x : Ctypes_field.Function_description.t ) -> x.functor_loc, x.functor_)
153+ ctypes.function_description
154+ |> Memo. parallel_iter ~f: (fun ((functor_loc , m ) : Loc. t * Module_name. t ) ->
155+ match Modules.With_vlib. find modules m with
156+ | Some _ -> Memo. return ()
157+ | None ->
158+ let loc =
159+ Option. first_some modules_loc buildable_loc
160+ |> Option. value
161+ ~default:
162+ (Path. build dir |> Path. drop_optional_build_context |> Loc. in_dir)
163+ in
164+ User_error. raise
165+ ~loc
166+ [ Pp. textf
167+ " Module %s is required by ctypes at %s but is missing in the modules \
168+ field of the stanza."
169+ (Module_name. to_string m)
170+ (Loc. to_file_colon_line functor_loc)
171+ ])
172+ | None -> Memo. return ()
173+ in
138174 let + modules =
139175 Modules. map_user_written modules ~f: (fun m ->
140176 let * m = Pp_spec. pp_module pp m in
@@ -159,15 +195,31 @@ let modules_rules sctx kind expander ~dir scope modules =
159195 [ Pp. text " The compiler you are using is not compatible with library parameter"
160196 ]
161197 in
162- let preprocess, preprocessor_deps, lint, empty_module_interface_if_absent =
198+ let ( preprocess
199+ , preprocessor_deps
200+ , lint
201+ , empty_module_interface_if_absent
202+ , ctypes
203+ , modules_loc
204+ , buildable_loc )
205+ =
163206 match kind with
164207 | Executables (buildable , _ ) | Library (buildable , _ ) | Parameter (buildable , _ ) ->
165208 ( buildable.preprocess
166209 , buildable.preprocessor_deps
167210 , buildable.lint
168- , buildable.empty_module_interface_if_absent )
211+ , buildable.empty_module_interface_if_absent
212+ , buildable.ctypes
213+ , Ordered_set_lang.Unexpanded. loc buildable.modules.modules
214+ , Some buildable.loc )
169215 | Melange { preprocess; preprocessor_deps; lint; empty_module_interface_if_absent } ->
170- preprocess, preprocessor_deps, lint, empty_module_interface_if_absent
216+ ( preprocess
217+ , preprocessor_deps
218+ , lint
219+ , empty_module_interface_if_absent
220+ , None
221+ , None
222+ , None )
171223 in
172224 let lib_name =
173225 match kind with
@@ -184,6 +236,9 @@ let modules_rules sctx kind expander ~dir scope modules =
184236 ~preprocessor_deps
185237 ~lint
186238 ~empty_module_interface_if_absent
239+ ~ctypes
240+ ~modules_loc
241+ ~buildable_loc
187242 sctx
188243 expander
189244 ~dir
0 commit comments