diff --git a/prelude/decls/haskell_common.bzl b/prelude/decls/haskell_common.bzl index 87df9cb..5fe337d 100644 --- a/prelude/decls/haskell_common.bzl +++ b/prelude/decls/haskell_common.bzl @@ -50,6 +50,24 @@ def _compiler_flags_arg(): ), } +def _build_tool_depends_arg(): + return { + "build_tool_depends": attrs.list( + attrs.dep(), + default = [], + doc = """ + Executables (haskell_binary(), export_exe(), or anything else with a + single default output) that this rule's own GHC invocation needs + reachable via PATH by bare name. The executables can then be used + with -pgmL or -pgmF flags for example, either as a command-line + arg or in a {-# OPTIONS_GHC ... #-} pragma. + + The build_tool_depends attribute is used to implement Cabal's + build-tool-depends: field. +""", + ), + } + def _exported_linker_flags_arg(): return { "exported_linker_flags": attrs.list( @@ -66,4 +84,5 @@ haskell_common = struct( deps_arg = _deps_arg, compiler_flags_arg = _compiler_flags_arg, exported_linker_flags_arg = _exported_linker_flags_arg, + build_tool_depends_arg = _build_tool_depends_arg, ) diff --git a/prelude/decls/haskell_rules.bzl b/prelude/decls/haskell_rules.bzl index 902f0c9..471d116 100644 --- a/prelude/decls/haskell_rules.bzl +++ b/prelude/decls/haskell_rules.bzl @@ -51,6 +51,7 @@ haskell_binary = prelude_rule( | haskell_common.srcs_arg() | haskell_common.compiler_flags_arg() | haskell_common.deps_arg() + | haskell_common.build_tool_depends_arg() | { "deps_query": attrs.option(attrs.query(), default = None), "enable_profiling": attrs.bool(default = False), @@ -175,6 +176,7 @@ haskell_library = prelude_rule( | haskell_common.compiler_flags_arg() | haskell_common.deps_arg() | haskell_common.exported_linker_flags_arg() + | haskell_common.build_tool_depends_arg() | native_common.link_whole(link_whole_type = attrs.bool(default = False)) | native_common.preferred_linkage(preferred_linkage_type = attrs.enum(Linkage.values())) | { diff --git a/prelude/haskell/compile.bzl b/prelude/haskell/compile.bzl index 45c66d3..ac37c10 100644 --- a/prelude/haskell/compile.bzl +++ b/prelude/haskell/compile.bzl @@ -308,11 +308,26 @@ def compile(ctx: AnalysisContext, link_style: LinkStyle, enable_profiling: bool, # build-action time rather than baking absolute host paths into .bzl # or BUCK files (see toolchains/BUCK's `compiler`/`packager`). run_cmd = compile_cmd - if haskell_toolchain.compile_env: - env_exports = "".join([ - 'export {}="{}"; '.format(name, value) - for name, value in haskell_toolchain.compile_env.items() - ]) + env_exports = "".join([ + 'export {}="{}"; '.format(name, value) + for name, value in haskell_toolchain.compile_env.items() + ]) if haskell_toolchain.compile_env else "" + + build_tool_dirs = { + dep[DefaultInfo].default_outputs[0].basename: dep[DefaultInfo].default_outputs[0] + for dep in ctx.attrs.build_tool_depends + } + if build_tool_dirs: + build_tool_bin_dir = ctx.actions.symlinked_dir( + artifact_suffix + "-build-tool-depends", + build_tool_dirs, + has_content_based_path = False, + ) + run_cmd = cmd_args( + ["sh", "-c", env_exports + 'export PATH="$PATH:$1"; shift; exec "$@"', "sh", build_tool_bin_dir], + compile_cmd, + ) + elif haskell_toolchain.compile_env: run_cmd = cmd_args(["sh", "-c", env_exports + 'exec "$@"', "sh"], compile_cmd) ctx.actions.run(