diff --git a/decls/haskell_common.bzl b/decls/haskell_common.bzl index 8bcf122be..6a8f15998 100644 --- a/decls/haskell_common.bzl +++ b/decls/haskell_common.bzl @@ -24,6 +24,9 @@ def _deps_arg(): from which this rules sources import modules or native linkable rules exporting symbols this rules sources call into. """), + "srcs_deps": attrs.dict(attrs.source(), attrs.list(attrs.source()), default = {}, doc = """ + Allows to declare dependencies for sources manually, additionally to the dependencies automatically detected. + """), } def _compiler_flags_arg(): diff --git a/haskell/compile.bzl b/haskell/compile.bzl index 8fc952a53..58c29cc82 100644 --- a/haskell/compile.bzl +++ b/haskell/compile.bzl @@ -125,6 +125,7 @@ PackagesInfo = record( exposed_package_dbs = field(list[Artifact]), packagedb_args = cmd_args, transitive_deps = field(HaskellLibraryInfoTSet), + bin_paths = cmd_args, ) _Module = record( @@ -246,9 +247,6 @@ def target_metadata( def get_metadata(ctx, _artifacts, resolved, outputs, catalog=catalog): - pkg_deps = resolved[haskell_toolchain.packages.dynamic] - package_db = pkg_deps[DynamicHaskellPackageDbInfo].packages - # Add -package-db and -package/-expose-package flags for each Haskell # library dependency. @@ -265,18 +263,13 @@ def target_metadata( ghc_args.add("-hide-all-packages") ghc_args.add(package_flag, "base") - package_dbs = ctx.actions.tset( - HaskellPackageDbTSet, - children = [package_db[name] for name in toolchain_libs if name in package_db] - ) - ghc_args.add(cmd_args(toolchain_libs, prepend=package_flag)) ghc_args.add(cmd_args(packages_info.exposed_package_args)) ghc_args.add(cmd_args(packages_info.packagedb_args, prepend = "-package-db")) - ghc_args.add(cmd_args(package_dbs.project_as_args("package_db"), prepend="-package-db")) ghc_args.add(ctx.attrs.compiler_flags) md_args = cmd_args(md_gen) + md_args.add(packages_info.bin_paths) md_args.add("--toolchain-libs", catalog) md_args.add("--ghc", haskell_toolchain.compiler) md_args.add(cmd_args(ghc_args, format="--ghc-arg={}")) @@ -403,8 +396,10 @@ def get_packages_info( ) packagedb_args.add(package_db_tset.project_as_args("package_db")) + bin_paths = cmd_args(package_db_tset.project_as_args("path"), format="--bin-path={}/bin") else: packagedb_args.add(haskell_toolchain.packages.package_db) + bin_paths = cmd_args() # Expose only the packages we depend on directly for lib in haskell_direct_deps_lib_infos: @@ -423,6 +418,7 @@ def get_packages_info( exposed_package_dbs = exposed_package_dbs, packagedb_args = packagedb_args, transitive_deps = libs, + bin_paths = bin_paths, ) def _compile_module( @@ -547,6 +543,7 @@ def _compile_module( 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("-stubdir", stubs.as_output()) + compile_args_for_file.add(packages_info.bin_paths) if link_style in [LinkStyle("static_pic"), LinkStyle("static")]: compile_args_for_file.add("-dynamic-too") @@ -554,13 +551,17 @@ def _compile_module( compile_args_for_file.add("-dynohi", his[1].as_output()) compile_args_for_file.add(module.source) - for (path, src) in srcs_to_pairs(ctx.attrs.srcs): - # hs-boot files aren't expected to be an argument to compiler but does need - # to be included in the directory of the associated src file - # TODO(ah) We should not indiscriminately include all non-hs sources, - # but only those that this module actually depends on. - if not is_haskell_src(path): - compile_args_for_file.hidden(src) + + aux_deps = ctx.attrs.srcs_deps.get(module.source) + if aux_deps: + compile_args_for_file.hidden(aux_deps) + + non_haskell_sources = [src for (path, src) in srcs_to_pairs(ctx.attrs.srcs) if not is_haskell_src(path)] + + if non_haskell_sources: + warning("{} specifies non-haskell file in `srcs`, consider using `srcs_deps` instead".format(ctx.label)) + + compile_args_for_file.hidden(non_haskell_sources) if haskell_toolchain.use_argsfile: argsfile = ctx.actions.declare_output( diff --git a/haskell/haskell.bzl b/haskell/haskell.bzl index 08d7167a6..bb3498b86 100644 --- a/haskell/haskell.bzl +++ b/haskell/haskell.bzl @@ -523,8 +523,6 @@ def _build_haskell_lib( non_profiling_hlib: [HaskellLibBuildOutput, None] = None) -> HaskellLibBuildOutput: linker_info = ctx.attrs._cxx_toolchain[CxxToolchainInfo].linker_info - toolchain_libs = [dep[HaskellToolchainLibrary].name for dep in ctx.attrs.deps if HaskellToolchainLibrary in dep] - # Link the objects into a library haskell_toolchain = ctx.attrs._haskell_toolchain[HaskellToolchainInfo] diff --git a/haskell/toolchain.bzl b/haskell/toolchain.bzl index 8961e9838..b7f4d636f 100644 --- a/haskell/toolchain.bzl +++ b/haskell/toolchain.bzl @@ -52,12 +52,21 @@ HaskellPackagesInfo = record( dynamic = DynamicValue, ) -def _haskell_package_info_as_package_db(p: Artifact): - return cmd_args(p) +HaskellPackage = record( + db = Artifact, + path = Artifact, +) + +def _haskell_package_info_as_package_db(p: HaskellPackage): + return cmd_args(p.db) + +def _haskell_package_info_as_package_path(p: HaskellPackage): + return cmd_args(p.path) HaskellPackageDbTSet = transitive_set( args_projections = { "package_db": _haskell_package_info_as_package_db, + "path": _haskell_package_info_as_package_path, } ) diff --git a/haskell/tools/generate_target_metadata.py b/haskell/tools/generate_target_metadata.py index 7de325fe9..2c533c582 100755 --- a/haskell/tools/generate_target_metadata.py +++ b/haskell/tools/generate_target_metadata.py @@ -66,6 +66,13 @@ def main(): action="append", default=[], help="Package dependencies formated as `NAME:PREFIX_PATH`.") + parser.add_argument( + "--bin-path", + type=Path, + action="append", + default=[], + help="Add given path to PATH.", + ) args = parser.parse_args() result = obtain_target_metadata(args) @@ -82,7 +89,8 @@ def json_default_handler(o): def obtain_target_metadata(args): toolchain_packages = load_toolchain_packages(args.toolchain_libs) ghc_args = fix_ghc_args(args.ghc_arg, toolchain_packages) - ghc_depends, ghc_options = run_ghc_depends(args.ghc, ghc_args, args.source) + paths = [str(binpath) for binpath in args.bin_path if binpath.is_dir()] + ghc_depends, ghc_options = run_ghc_depends(args.ghc, ghc_args, args.source, paths) th_modules = determine_th_modules(ghc_options, args.source_prefix) package_prefixes = calc_package_prefixes(args.package) module_mapping, module_graph, package_deps, toolchain_deps = interpret_ghc_depends( @@ -151,7 +159,7 @@ def fix_ghc_args(ghc_args, toolchain_packages): return result -def run_ghc_depends(ghc, ghc_args, sources): +def run_ghc_depends(ghc, ghc_args, sources, aux_paths): with tempfile.TemporaryDirectory() as dname: json_fname = os.path.join(dname, "depends.json") opt_json_fname = os.path.join(dname, "options.json") @@ -165,7 +173,12 @@ def run_ghc_depends(ghc, ghc_args, sources): "-opt-json", opt_json_fname, "-dep-makefile", make_fname, ] + ghc_args + sources - subprocess.run(args, check=True) + + env = os.environ.copy() + path = env.get("PATH", "") + env["PATH"] = os.pathsep.join([path] + aux_paths) + + subprocess.run(args, env=env, check=True) with open(json_fname) as f, open(opt_json_fname) as o: return json.load(f), json.load(o) diff --git a/haskell/tools/ghc_wrapper.py b/haskell/tools/ghc_wrapper.py index d7f84b744..567f99f43 100755 --- a/haskell/tools/ghc_wrapper.py +++ b/haskell/tools/ghc_wrapper.py @@ -46,12 +46,24 @@ def main(): type=Path, help="Output path of the abi file to create.", ) + parser.add_argument( + "--bin-path", + type=Path, + action="append", + default=[], + help="Add given path to PATH.", + ) args, ghc_args = parser.parse_known_args() cmd = [args.ghc] + ghc_args - subprocess.check_call(cmd) + aux_paths = [str(binpath) for binpath in args.bin_path if binpath.is_dir()] + env = os.environ.copy() + path = env.get("PATH", "") + env["PATH"] = os.pathsep.join([path] + aux_paths) + + subprocess.check_call(cmd, env=env) recompute_abi_hash(args.ghc, args.abi_out)