diff --git a/haskell/compile.bzl b/haskell/compile.bzl index da8cf1783..c9cd9da99 100644 --- a/haskell/compile.bzl +++ b/haskell/compile.bzl @@ -170,7 +170,7 @@ def _modules_by_name(ctx: AnalysisContext, *, sources: list[Artifact], link_styl return modules -def _dynamic_target_metadata_impl(actions, artifacts, dynamic_values, outputs, arg): +def _dynamic_target_metadata_impl(actions, output, arg, pkg_deps) -> list[Provider]: # Add -package-db and -package/-expose-package flags for each Haskell # library dependency. @@ -185,7 +185,7 @@ def _dynamic_target_metadata_impl(actions, artifacts, dynamic_values, outputs, a enable_profiling = False, use_empty_lib = True, for_deps = True, - resolved = dynamic_values, + pkg_deps = pkg_deps, ) package_flag = _package_flag(arg.haskell_toolchain) ghc_args = cmd_args() @@ -210,13 +210,20 @@ def _dynamic_target_metadata_impl(actions, artifacts, dynamic_values, outputs, a md_args.add( arg.lib_package_name_and_prefix, ) - md_args.add("--output", outputs[arg.md_file].as_output()) + md_args.add("--output", output) actions.run(md_args, category = "haskell_metadata", identifier = arg.suffix if arg.suffix else None) return [] -_dynamic_target_metadata = dynamic_actions(impl = _dynamic_target_metadata_impl) +_dynamic_target_metadata = dynamic_actions( + impl = _dynamic_target_metadata_impl, + attrs = { + "output": dynattrs.output(), + "arg": dynattrs.value(typing.Any), + "pkg_deps": dynattrs.option(dynattrs.dynamic_value()), + }, +) def target_metadata( ctx: AnalysisContext, @@ -245,9 +252,8 @@ def target_metadata( # (module X.Y.Z must be defined in a file at X/Y/Z.hs) ctx.actions.dynamic_output_new(_dynamic_target_metadata( - dynamic = [], - dynamic_values = [haskell_toolchain.packages.dynamic] if haskell_toolchain.packages else [], - outputs = [md_file.as_output()], + pkg_deps = haskell_toolchain.packages.dynamic if haskell_toolchain.packages else None, + output = md_file.as_output(), arg = struct( compiler_flags = ctx.attrs.compiler_flags, deps = ctx.attrs.deps, @@ -255,7 +261,6 @@ def target_metadata( haskell_direct_deps_lib_infos = haskell_direct_deps_lib_infos, haskell_toolchain = haskell_toolchain, lib_package_name_and_prefix =_attr_deps_haskell_lib_package_name_and_prefix(ctx), - md_file = md_file, md_gen = md_gen, sources = sources, strip_prefix = _strip_prefix(str(ctx.label.cell_root), str(ctx.label.path)), @@ -313,7 +318,7 @@ def get_packages_info( specify_pkg_version = specify_pkg_version, enable_profiling = enable_profiling, use_empty_lib = use_empty_lib, - resolved = {}, + pkg_deps = None, ) def get_packages_info2( @@ -326,7 +331,7 @@ def get_packages_info2( specify_pkg_version: bool, enable_profiling: bool, use_empty_lib: bool, - resolved: dict[DynamicValue, ResolvedDynamicValue], + pkg_deps: ResolvedDynamicValue | None, for_deps: bool = False) -> PackagesInfo: # Collect library dependencies. Note that these don't need to be in a @@ -363,8 +368,7 @@ def get_packages_info2( ]) exposed_package_args.add(hidden_args) - if resolved: - pkg_deps = resolved[haskell_toolchain.packages.dynamic] + if pkg_deps: package_db = pkg_deps.providers[DynamicHaskellPackageDbInfo].packages else: package_db = {} @@ -418,7 +422,7 @@ def _common_compile_module_args( compiler_flags: list[ArgLike], ghc_wrapper: RunInfo, haskell_toolchain: HaskellToolchainInfo, - resolved: dict[DynamicValue, ResolvedDynamicValue], + pkg_deps: ResolvedDynamicValue | None, enable_haddock: bool, enable_profiling: bool, link_style: LinkStyle, @@ -493,7 +497,6 @@ def _common_compile_module_args( toolchain_libs = direct_toolchain_libs + libs.reduce("packages") if haskell_toolchain.packages: - pkg_deps = resolved[haskell_toolchain.packages.dynamic] package_db = pkg_deps.providers[DynamicHaskellPackageDbInfo].packages else: package_db = [] @@ -563,7 +566,7 @@ def _compile_module( md_file: Artifact, graph: dict[str, list[str]], package_deps: dict[str, list[str]], - outputs: dict[Artifact, Artifact], + outputs: dict[Artifact, OutputArtifact], artifact_suffix: str, direct_deps_by_name: dict[str, typing.Any], toolchain_deps_by_name: dict[str, None], @@ -590,8 +593,8 @@ def _compile_module( objects = [outputs[obj] for obj in module.objects] his = [outputs[hi] for hi in module.interfaces] - compile_args_for_file.add("-o", objects[0].as_output()) - compile_args_for_file.add("-ohi", his[0].as_output()) + compile_args_for_file.add("-o", objects[0]) + compile_args_for_file.add("-ohi", his[0]) # Set the output directories. We do not use the -outputdir flag, but set the directories individually. # Note, the -outputdir option is shorthand for the combination of -odir, -hidir, -hiedir, -stubdir and -dumpdir. @@ -603,12 +606,12 @@ def _compile_module( ) if module.stub_dir != None: stubs = outputs[module.stub_dir] - compile_args_for_file.add("-stubdir", stubs.as_output()) + compile_args_for_file.add("-stubdir", stubs) if link_style in [LinkStyle("static_pic"), LinkStyle("static")]: compile_args_for_file.add("-dynamic-too") - compile_args_for_file.add("-dyno", objects[1].as_output()) - compile_args_for_file.add("-dynohi", his[1].as_output()) + compile_args_for_file.add("-dyno", objects[1]) + compile_args_for_file.add("-dynohi", his[1]) compile_args_for_file.add(module.source) @@ -623,9 +626,9 @@ def _compile_module( toolchain_deps.append(dep_pkgname) elif dep_pkgname in direct_deps_by_name: library_deps.append(dep_pkgname) - exposed_package_dbs.append(direct_deps_by_name[dep_pkgname].package_db) + exposed_package_dbs.append(direct_deps_by_name[dep_pkgname][0]) for dep_modname in dep_modules: - exposed_package_modules.append(direct_deps_by_name[dep_pkgname].modules[dep_modname]) + exposed_package_modules.append(direct_deps_by_name[dep_pkgname][1].providers[DynamicCompileResultInfo].modules[dep_modname]) else: fail("Unknown library dependency '{}'. Add the library to the `deps` attribute".format(dep_pkgname)) @@ -698,7 +701,7 @@ def _compile_module( tagged_dep_file = abi_tag.tag_artifacts(dep_file) compile_cmd.add("--buck2-dep", tagged_dep_file) - compile_cmd.add("--abi-out", outputs[module.hash].as_output()) + compile_cmd.add("--abi-out", outputs[module.hash]) actions.run( compile_cmd, category = "haskell_compile_" + artifact_suffix.replace("-", "_"), identifier = module_name, @@ -720,14 +723,7 @@ def _compile_module( return module_tset -def _dynamic_do_compile_impl(actions, artifacts, dynamic_values, outputs, arg): - direct_deps_by_name = { - info.value.name: struct( - package_db = info.value.empty_db, - modules = dynamic_values[info.value.dynamic[arg.enable_profiling]].providers[DynamicCompileResultInfo].modules, - ) - for info in arg.direct_deps_info - } +def _dynamic_do_compile_impl(actions, md_file, pkg_deps, arg, direct_deps_by_name, outputs): common_args = _common_compile_module_args( actions, compiler_flags = arg.compiler_flags, @@ -737,7 +733,7 @@ def _dynamic_do_compile_impl(actions, artifacts, dynamic_values, outputs, arg): haskell_toolchain = arg.haskell_toolchain, label = arg.label, main = arg.main, - resolved = dynamic_values, + pkg_deps = pkg_deps, sources = arg.sources, enable_haddock = arg.enable_haddock, enable_profiling = arg.enable_profiling, @@ -746,7 +742,7 @@ def _dynamic_do_compile_impl(actions, artifacts, dynamic_values, outputs, arg): pkgname = arg.pkgname, ) - md = artifacts[arg.md_file].read_json() + md = md_file.read_json() th_modules = md["th_modules"] module_map = md["module_mapping"] graph = md["module_graph"] @@ -785,7 +781,16 @@ def _dynamic_do_compile_impl(actions, artifacts, dynamic_values, outputs, arg): -_dynamic_do_compile = dynamic_actions(impl = _dynamic_do_compile_impl) +_dynamic_do_compile = dynamic_actions( + impl = _dynamic_do_compile_impl, + attrs = { + "md_file" : dynattrs.artifact_value(), + "arg" : dynattrs.value(typing.Any), + "pkg_deps": dynattrs.option(dynattrs.dynamic_value()), + "outputs": dynattrs.dict(Artifact, dynattrs.output()), + "direct_deps_by_name": dynattrs.dict(str, dynattrs.tuple(dynattrs.value(Artifact), dynattrs.dynamic_value())), + }, +) # Compile all the context's sources. def compile( @@ -822,17 +827,13 @@ def compile( ] dyn_module_tsets = ctx.actions.dynamic_output_new(_dynamic_do_compile( - dynamic = [md_file], - dynamic_values = [ - info.value.dynamic[enable_profiling] - for lib in attr_deps_haskell_link_infos(ctx) - for info in [ - lib.prof_info[link_style] - if enable_profiling else - lib.info[link_style] - ] - ] + ([ haskell_toolchain.packages.dynamic ] if haskell_toolchain.packages else [ ]), - outputs = [o.as_output() for o in interfaces + objects + stub_dirs + abi_hashes], + md_file = md_file, + pkg_deps = haskell_toolchain.packages.dynamic if haskell_toolchain.packages else None, + outputs = {o: o.as_output() for o in interfaces + objects + stub_dirs + abi_hashes}, + direct_deps_by_name = { + info.value.name: (info.value.empty_db, info.value.dynamic[enable_profiling]) + for info in direct_deps_info + }, arg = struct( artifact_suffix = artifact_suffix, compiler_flags = ctx.attrs.compiler_flags, diff --git a/haskell/haskell.bzl b/haskell/haskell.bzl index 6e7a2f5ce..a209e5ad0 100644 --- a/haskell/haskell.bzl +++ b/haskell/haskell.bzl @@ -243,6 +243,10 @@ def haskell_prebuilt_library_impl(ctx: AnalysisContext) -> list[Provider]: hlibinfo = HaskellLibraryInfo( name = ctx.attrs.name, db = ctx.attrs.db, + empty_db = None, + deps_db = None, + objects = {}, + dependencies = [], import_dirs = {}, stub_dirs = [], id = ctx.attrs.id, @@ -255,6 +259,10 @@ def haskell_prebuilt_library_impl(ctx: AnalysisContext) -> list[Provider]: prof_hlibinfo = HaskellLibraryInfo( name = ctx.attrs.name, db = ctx.attrs.db, + empty_db = None, + deps_db = None, + objects = {}, + dependencies = [], import_dirs = {}, stub_dirs = [], id = ctx.attrs.id, @@ -549,8 +557,7 @@ def _get_haskell_shared_library_name_linker_flags( else: fail("Unknown linker type '{}'.".format(linker_type)) -def _dynamic_link_shared_impl(actions, artifacts, dynamic_values, outputs, arg): - pkg_deps = dynamic_values[arg.haskell_toolchain.packages.dynamic] +def _dynamic_link_shared_impl(actions, pkg_deps, lib, arg): package_db = pkg_deps.providers[DynamicHaskellPackageDbInfo].packages package_db_tset = actions.tset( @@ -591,7 +598,7 @@ def _dynamic_link_shared_impl(actions, artifacts, dynamic_values, outputs, arg): link_cmd_args.append(link_args) link_cmd = cmd_args(link_cmd_args, hidden = link_cmd_hidden) - link_cmd.add("-o", outputs[arg.lib].as_output()) + link_cmd.add("-o", lib) actions.run( link_cmd, @@ -600,7 +607,14 @@ def _dynamic_link_shared_impl(actions, artifacts, dynamic_values, outputs, arg): return [] -_dynamic_link_shared = dynamic_actions(impl = _dynamic_link_shared_impl) +_dynamic_link_shared = dynamic_actions( + impl = _dynamic_link_shared_impl, + attrs = { + "arg": dynattrs.value(typing.Any), + "lib": dynattrs.output(), + "pkg_deps": dynattrs.dynamic_value(), + }, +) def _build_haskell_lib( ctx, @@ -664,9 +678,8 @@ def _build_haskell_lib( ) ctx.actions.dynamic_output_new(_dynamic_link_shared( - dynamic = [], - dynamic_values = [haskell_toolchain.packages.dynamic], - outputs = [lib.as_output()], + pkg_deps = haskell_toolchain.packages.dynamic, + lib = lib.as_output(), arg = struct( artifact_suffix = artifact_suffix, haskell_toolchain = haskell_toolchain, @@ -979,6 +992,7 @@ def haskell_library_impl(ctx: AnalysisContext) -> list[Provider]: cmd_args( haskell_toolchain.haddock, "--gen-index", + "--optghc=-package-env=-", "-o", cmd_args(styles[0].as_output(), parent=1), hidden=[file.as_output() for file in styles] ), @@ -1124,7 +1138,7 @@ def _make_link_package( return db -def _dynamic_link_binary_impl(actions, artifacts, dynamic_values, outputs, arg): +def _dynamic_link_binary_impl(actions, pkg_deps, output, arg): link_cmd = arg.link.copy() # link is already frozen, make a copy # Add -package-db and -package/-expose-package flags for each Haskell @@ -1136,7 +1150,7 @@ def _dynamic_link_binary_impl(actions, artifacts, dynamic_values, outputs, arg): haskell_toolchain = arg.haskell_toolchain, haskell_direct_deps_lib_infos = arg.haskell_direct_deps_lib_infos, link_style = arg.link_style, - resolved = dynamic_values, + pkg_deps = pkg_deps, specify_pkg_version = False, enable_profiling = arg.enable_profiling, use_empty_lib = False, @@ -1149,13 +1163,20 @@ def _dynamic_link_binary_impl(actions, artifacts, dynamic_values, outputs, arg): link_cmd.add(arg.haskell_toolchain.linker_flags) link_cmd.add(arg.linker_flags) - link_cmd.add("-o", outputs[arg.output].as_output()) + link_cmd.add("-o", output) actions.run(link_cmd, category = "haskell_link") return [] -_dynamic_link_binary = dynamic_actions(impl = _dynamic_link_binary_impl) +_dynamic_link_binary = dynamic_actions( + impl = _dynamic_link_binary_impl, + attrs = { + "arg": dynattrs.value(typing.Any), + "pkg_deps": dynattrs.option(dynattrs.dynamic_value()), + "output": dynattrs.output(), + }, +) def haskell_binary_impl(ctx: AnalysisContext) -> list[Provider]: enable_profiling = ctx.attrs.enable_profiling @@ -1377,9 +1398,8 @@ def haskell_binary_impl(ctx: AnalysisContext) -> list[Provider]: ) ctx.actions.dynamic_output_new(_dynamic_link_binary( - dynamic = [], - dynamic_values = [haskell_toolchain.packages.dynamic] if haskell_toolchain.packages else [ ], - outputs = [output.as_output()], + pkg_deps = haskell_toolchain.packages.dynamic if haskell_toolchain.packages else None, + output = output.as_output(), arg = struct( deps = ctx.attrs.deps, direct_deps_link_info = attr_deps_haskell_link_infos(ctx), @@ -1389,7 +1409,6 @@ def haskell_binary_impl(ctx: AnalysisContext) -> list[Provider]: link = link, link_style = link_style, linker_flags = ctx.attrs.linker_flags, - output = output, toolchain_libs = toolchain_libs, ), )) diff --git a/haskell/haskell_haddock.bzl b/haskell/haskell_haddock.bzl index ec31f17f5..66687e6ec 100644 --- a/haskell/haskell_haddock.bzl +++ b/haskell/haskell_haddock.bzl @@ -54,7 +54,7 @@ def _haddock_dump_interface( haddock_info: _HaddockInfo, module_deps: list[CompiledModuleTSet], graph: dict[str, list[str]], - outputs: dict[Artifact, Artifact]) -> _HaddockInfoTSet: + outputs: dict[Artifact, OutputArtifact]) -> _HaddockInfoTSet: # Transitive module dependencies from other packages. cross_package_modules = actions.tset( @@ -69,7 +69,7 @@ def _haddock_dump_interface( for dep_name in graph[module_name] ] - expected_html = outputs[haddock_info.html] + expected_html = haddock_info.html module_html = _haddock_module_to_html(module_name) if paths.basename(expected_html.short_path) != module_html: @@ -82,7 +82,7 @@ def _haddock_dump_interface( actions.run( cmd.copy().add( "--odir", cmd_args(html_output.as_output(), parent = 1), - "--dump-interface", outputs[haddock_info.haddock].as_output(), + "--dump-interface", outputs[haddock_info.haddock], "--html", "--hoogle", cmd_args( @@ -102,36 +102,26 @@ def _haddock_dump_interface( if make_copy: # XXX might as well use `symlink_file`` but that does not work with buck2 RE # (see https://github.com/facebook/buck2/issues/222) - actions.copy_file(expected_html.as_output(), html_output) + actions.copy_file(outputs[expected_html], html_output) return actions.tset( _HaddockInfoTSet, - value = _HaddockInfo(interface = haddock_info.interface, haddock = outputs[haddock_info.haddock], html = outputs[haddock_info.html]), + value = _HaddockInfo(interface = haddock_info.interface, haddock = haddock_info.haddock, html = haddock_info.html), children = this_package_modules, ) -def _dynamic_haddock_dump_interfaces_impl(actions, artifacts, dynamic_values, outputs, arg): - md = artifacts[arg.md_file].read_json() +def _dynamic_haddock_dump_interfaces_impl(actions, md_file, dynamic_info_lib, outputs, arg): + md = md_file.read_json() module_map = md["module_mapping"] graph = md["module_graph"] package_deps = md["package_deps"] - dynamic_info_lib = {} - - for lib in arg.direct_deps_link_info: - info = lib.info[arg.link_style] - direct = info.value - dynamic = direct.dynamic[False] - dynamic_info = dynamic_values[dynamic].providers[DynamicCompileResultInfo] - - dynamic_info_lib[direct.name] = dynamic_info - haddock_infos = { module_map.get(k, k): v for k, v in arg.haddock_infos.items() } module_tsets = {} for module_name in post_order_traversal(graph): module_deps = [ - info.modules[mod] + info.providers[DynamicCompileResultInfo].modules[mod] for lib, info in dynamic_info_lib.items() for mod in package_deps.get(module_name, {}).get(lib, []) ] @@ -149,7 +139,15 @@ def _dynamic_haddock_dump_interfaces_impl(actions, artifacts, dynamic_values, ou return [] -_dynamic_haddock_dump_interfaces = dynamic_actions(impl = _dynamic_haddock_dump_interfaces_impl) +_dynamic_haddock_dump_interfaces = dynamic_actions( + impl = _dynamic_haddock_dump_interfaces_impl, + attrs = { + "md_file": dynattrs.artifact_value(), + "arg": dynattrs.value(typing.Any), + "dynamic_info_lib": dynattrs.dict(str, dynattrs.dynamic_value()), + "outputs": dynattrs.dict(Artifact, dynattrs.output()), + }, +) def haskell_haddock_lib(ctx: AnalysisContext, pkgname: str, compiled: CompileResultInfo, md_file: Artifact) -> HaskellHaddockInfo: haskell_toolchain = ctx.attrs._haskell_toolchain[HaskellToolchainInfo] @@ -165,6 +163,7 @@ def haskell_haddock_lib(ctx: AnalysisContext, pkgname: str, compiled: CompileRes "index.html", "--no-tmp-comp-dir", "--no-warnings", + "--optghc=-package-env=-", "--package-name", pkgname, ) @@ -188,19 +187,18 @@ def haskell_haddock_lib(ctx: AnalysisContext, pkgname: str, compiled: CompileRes direct_deps_link_info = attr_deps_haskell_link_infos(ctx) ctx.actions.dynamic_output_new(_dynamic_haddock_dump_interfaces( - dynamic = [md_file], - dynamic_values = [ - info.value.dynamic[False] + md_file = md_file, + dynamic_info_lib = { + info.value.name: info.value.dynamic[False] for lib in direct_deps_link_info for info in [ #lib.prof_info[link_style] #if enable_profiling else lib.info[link_style], ] - ], - outputs = [output.as_output() for info in haddock_infos.values() for output in [info.haddock, info.html]], + }, + outputs = {output: output.as_output() for info in haddock_infos.values() for output in [info.haddock, info.html]}, arg = struct( - direct_deps_link_info = direct_deps_link_info, dyn_cmd = cmd.copy(), haddock_infos = haddock_infos, link_style = link_style, @@ -221,6 +219,7 @@ def haskell_haddock_impl(ctx: AnalysisContext) -> list[Provider]: cmd = cmd_args(haskell_toolchain.haddock) cmd.add( + "--optghc=-package-env=-", "--gen-index", "--gen-contents", "-o", diff --git a/haskell/library_info.bzl b/haskell/library_info.bzl index 5eb033a84..dbd80cbea 100644 --- a/haskell/library_info.bzl +++ b/haskell/library_info.bzl @@ -26,9 +26,9 @@ HaskellLibraryInfo = record( # package config database: e.g. platform009/build/ghc/lib/package.conf.d db = Artifact, # package config database, referring to the empty lib which is only used for compilation - empty_db = Artifact, - # pacakge config database, used for ghc -M - deps_db = Artifact, + empty_db = Artifact | None, + # package config database, used for ghc -M + deps_db = Artifact | None, # e.g. "base-4.13.0.0" id = str, # dynamic dependency information