1212 "//haskell:private/mode.bzl" ,
1313 "is_profiling_enabled" ,
1414)
15+ load ("//haskell:private/pkg_id.bzl" , "pkg_id" )
1516load (
1617 "//haskell:private/packages.bzl" ,
1718 "expose_packages" ,
3233)
3334load ("//haskell:providers.bzl" , "HaskellInfo" , "HaskellLibraryInfo" )
3435
36+ # Note [Narrowed Dependencies]
37+ #
38+ # Usually, when a module M depends on a library L, it doesn't depend on
39+ # all the modules of the library. The user expresses which modules are
40+ # needed with the cross_library_deps attribute and rules_haskell looks
41+ # for the modules in the libraries of the narrowed_deps attribute in the
42+ # enclosing haskell_library.
43+ #
44+ # build_haskell_modules from module.bzl produces dictionaries that say
45+ # for every module label which interface and object files it produces
46+ # and which interface and object files it depends upon transitively.
47+ # These dictionaries end up in the HaskellInfo provider.
48+ #
49+ # It is not strictly necessary to depend on all interface and object
50+ # files transitively, but we have no easy way to discern which files
51+ # from the transitive dependencies are actually needed, so we
52+ # over-approximate by depending on all of them.
53+ #
54+ # When compilation doesn't involve Template Haskell, a module only needs
55+ # the interface files of its module dependencies. When the user
56+ # specifies that a module uses Template Haskell via the enable_th
57+ # attribute, we also pass the potentially needed object files in the
58+ # inputs of the build action of haskell_module.
59+ #
60+ # Telling ghc which interface files are available is easy by specifying
61+ # package databases and package-ids on the command line. Passing object
62+ # files is harder because ghc only expects the object files of libraries
63+ # to be linked together in installed packages. It is possible to tell to
64+ # ghc about individual object files by listing their filepaths on the
65+ # command line, but see Note [Empty Libraries] in haskell_impl.bzl for an
66+ # extra nuance.
67+ #
68+ # Unfortunately, passing object files in the command line doesn't cause
69+ # ghc to load them in the external interpreter, so narrowing doesn't
70+ # work in any configuration needing the external interpreter. Therefore,
71+ # profiling builds use the libraries of narrowed_deps instead of the
72+ # their object files.
73+
3574def _build_haskell_module (
3675 ctx ,
3776 hs ,
@@ -46,6 +85,7 @@ def _build_haskell_module(
4685 module_outputs ,
4786 interface_inputs ,
4887 object_inputs ,
88+ narrowed_objects ,
4989 module ):
5090 """Build a module
5191
@@ -63,6 +103,7 @@ def _build_haskell_module(
63103 module_outputs: A struct containing the interfaces and object files produced for a haskell_module.
64104 interface_inputs: A depset containing the interface files needed as input
65105 object_inputs: A depset containing the object files needed as input
106+ narrowed_objects: A depset containing the narrowed object files needed as arguments to ghc.
66107 module: The Target of the haskell_module rule
67108 """
68109
@@ -151,7 +192,12 @@ def _build_haskell_module(
151192 hs ,
152193 pkg_info = expose_packages (
153194 package_ids = hs .package_ids ,
154- package_databases = depset (transitive = [dep_info .package_databases , narrowed_deps_info .package_databases ]),
195+ package_databases = depset (
196+ transitive = [
197+ dep_info .package_databases ,
198+ narrowed_deps_info .empty_lib_package_databases ,
199+ ],
200+ ),
155201 # TODO[AH] Support version macros
156202 version = None ,
157203 ),
@@ -192,6 +238,7 @@ def _build_haskell_module(
192238 moduleAttr .tools ,
193239 ]
194240 args .add_all (expand_make_variables ("ghcopts" , ctx , moduleAttr .ghcopts , module_extra_attrs ))
241+ args .add_all (narrowed_objects )
195242
196243 outputs = [module_outputs .hi ]
197244 if module_outputs .o :
@@ -210,16 +257,21 @@ def _build_haskell_module(
210257 transitive = [
211258 dep_info .package_databases ,
212259 dep_info .interface_dirs ,
213- dep_info . hs_libraries ,
214- narrowed_deps_info .package_databases ,
260+ narrowed_deps_info . empty_hs_libraries ,
261+ narrowed_deps_info .empty_lib_package_databases ,
215262 pkg_info_inputs ,
216263 plugin_dep_info .package_databases ,
217264 plugin_dep_info .interface_dirs ,
218265 plugin_dep_info .hs_libraries ,
219266 plugin_tool_inputs ,
220267 preprocessors_inputs ,
221268 interface_inputs ,
222- object_inputs ,
269+ narrowed_objects ,
270+ ] + [
271+ files
272+ for files in [dep_info .hs_libraries , object_inputs ]
273+ # libraries and object inputs are only needed if the module uses TH
274+ if module [HaskellModuleInfo ].attr .enable_th
223275 ],
224276 ),
225277 input_manifests = preprocessors_input_manifests + plugin_tool_input_manifests ,
@@ -377,10 +429,15 @@ def _merge_narrowed_deps_dicts(rule_label, narrowed_deps):
377429 narrowed_deps: The contents of the narrowed_deps attribute
378430
379431 Returns:
380- dict of module labels to their interfaces and the interfaces of their transitive
381- module dependencies
432+ pair of per_module_transitive_interfaces, per_module_transitive_objects:
433+ per_module_transitive_interfaces: dict of module labels to their
434+ interfaces and the interfaces of their transitive module dependencies
435+ per_module_transitive_objects: dict of module labels to their
436+ object files and the object file of their transitive module
437+ dependencies
382438 """
383439 per_module_transitive_interfaces = {}
440+ per_module_transitive_objects = {}
384441 for dep in narrowed_deps :
385442 if not HaskellInfo in dep or not HaskellLibraryInfo in dep :
386443 fail ("{}: depedency {} is not a haskell_library as required when used in narrowed_deps" .format (
@@ -394,7 +451,8 @@ def _merge_narrowed_deps_dicts(rule_label, narrowed_deps):
394451 str (dep .label ),
395452 ))
396453 _merge_depset_dicts (per_module_transitive_interfaces , lib_info .per_module_transitive_interfaces )
397- return per_module_transitive_interfaces
454+ _merge_depset_dicts (per_module_transitive_objects , lib_info .per_module_transitive_objects )
455+ return per_module_transitive_interfaces , per_module_transitive_objects
398456
399457def interfaces_as_list (with_shared , o ):
400458 if with_shared :
@@ -411,50 +469,79 @@ def build_haskell_modules(ctx, hs, cc, posix, package_name, with_shared, hidir,
411469 hs: Haskell context
412470 cc: CcInteropInfo, information about C dependencies
413471 posix: posix toolchain
472+ package_name: package name if building a library or empty if building a binary
414473 with_shared: Whether to build dynamic object files
415474 hidir: The directory in which to output interface files
416475 odir: The directory in which to output object files
417476
418477 Returns:
419- struct(his, dyn_his, os, dyn_os, per_module_transitive_interfaces):
478+ struct(his, dyn_his, os, dyn_os, per_module_transitive_interfaces, per_module_transitive_objects ):
420479 his: interface files of all modules in ctx.attr.modules
421480 dyn_his: dynamic interface files of all modules in ctx.attr.modules
422481 os: object files of all modules in ctx.attr.modules
423482 dyn_os: dynamic object files of all modules in ctx.attr.modules
424483 per_module_transitive_interfaces: dict of module labels to their
425484 interfaces and the interfaces of their transitive module
426- dependencies
485+ dependencies. See Note [Narrowed Dependencies].
486+ per_module_transitive_objects: dict of module labels to their
487+ object files and the object files of their transitive module
488+ dependencies. See Note [Narrowed Dependencies].
427489 """
490+ per_module_transitive_interfaces , per_module_transitive_objects = _merge_narrowed_deps_dicts (ctx .label , ctx .attr .narrowed_deps )
428491
429- per_module_transitive_interfaces = _merge_narrowed_deps_dicts (ctx .label , ctx .attr .narrowed_deps )
430-
492+ # We produce separate infos for narrowed_deps and deps because the module
493+ # files in dep_info are given as inputs to the build action, but the
494+ # modules files from narrowed_deps_info are only given when haskell_module
495+ # declares to depend on them.
431496 dep_info = gather_dep_info (ctx .attr .name , ctx .attr .deps )
432497 narrowed_deps_info = gather_dep_info (ctx .attr .name , ctx .attr .narrowed_deps )
498+ all_deps_info = gather_dep_info (ctx .attr .name , ctx .attr .deps + ctx .attr .narrowed_deps )
499+ empty_deps_info = gather_dep_info (ctx .attr .name , [])
433500 transitive_module_deps = _reorder_module_deps_to_postorder (ctx .label , ctx .attr .modules )
434501 module_outputs = {dep .label : _declare_module_outputs (hs , with_shared , hidir , odir , dep ) for dep in transitive_module_deps }
435502
436503 module_interfaces = {}
437504 module_objects = {}
438505 for dep in transitive_module_deps :
506+ # called in all cases to validate cross_library_deps, although the output
507+ # might be ignored when disabling narrowing
508+ narrowed_interfaces = _collect_narrowed_deps_module_files (ctx .label , per_module_transitive_interfaces , dep )
509+ enable_th = dep [HaskellModuleInfo ].attr .enable_th
510+
511+ # Narrowing doesn't work when using the external interpreter so we disable it here
512+ if enable_th and is_profiling_enabled (hs ):
513+ per_module_transitive_interfaces_i = []
514+ per_module_transitive_objects_i = []
515+ dep_info_i = all_deps_info
516+ narrowed_deps_info_i = empty_deps_info
517+ narrowed_interfaces = depset ()
518+ narrowed_objects = depset ()
519+ else :
520+ dep_info_i = dep_info
521+ narrowed_deps_info_i = narrowed_deps_info
522+
523+ # objects are only needed if the module uses TH
524+ narrowed_objects = _collect_narrowed_deps_module_files (ctx .label , per_module_transitive_objects , dep ) if enable_th else depset ()
525+
439526 his , os = _collect_module_outputs_of_direct_deps (with_shared , module_outputs , dep )
440527 interface_inputs = _collect_module_inputs (module_interfaces , his , dep )
441528 object_inputs = _collect_module_inputs (module_objects , os , dep )
442- narrowed_interfaces = _collect_narrowed_deps_module_files (ctx .label , per_module_transitive_interfaces , dep )
443529
444530 _build_haskell_module (
445531 ctx ,
446532 hs ,
447533 cc ,
448534 posix ,
449- dep_info ,
450- narrowed_deps_info ,
535+ dep_info_i ,
536+ narrowed_deps_info_i ,
451537 package_name ,
452538 with_shared ,
453539 hidir ,
454540 odir ,
455541 module_outputs [dep .label ],
456542 depset (transitive = [interface_inputs , narrowed_interfaces ]),
457543 object_inputs ,
544+ narrowed_objects ,
458545 dep ,
459546 )
460547
@@ -477,13 +564,22 @@ def build_haskell_modules(ctx, hs, cc, posix, package_name, with_shared, hidir,
477564 for dep in transitive_module_deps
478565 }
479566 _merge_depset_dicts (per_module_transitive_interfaces0 , per_module_transitive_interfaces )
567+ per_module_transitive_objects0 = {
568+ dep .label : depset (
569+ [module_outputs [dep .label ].o ],
570+ transitive = [module_objects [dep .label ]],
571+ )
572+ for dep in transitive_module_deps
573+ }
574+ _merge_depset_dicts (per_module_transitive_objects0 , per_module_transitive_objects )
480575
481576 return struct (
482577 his = hi_set ,
483578 dyn_his = dyn_hi_set ,
484579 os = o_set ,
485580 dyn_os = dyn_o_set ,
486581 per_module_transitive_interfaces = per_module_transitive_interfaces0 ,
582+ per_module_transitive_objects = per_module_transitive_objects0 ,
487583 )
488584
489585def haskell_module_impl (ctx ):
0 commit comments