From 8fa344a99f02601a54ec46fd082f5f9bfe2e2af6 Mon Sep 17 00:00:00 2001 From: Kyle Butt Date: Fri, 3 Apr 2026 14:01:16 -0600 Subject: [PATCH 1/9] Remove calls to resolve_tools Replace them mostly with `FilesToRunProvider`s. For cc_wrapper, where repl's also need the runfiles, use a struct that has the executable, the `FilesToRunProvider` and the runfiles. The executable could be retrieved from the `FilesToRunProvider`, but it is more convenient to just have it in the struct. Remove outdated comment about re-enabling resolve_tools for bazel 8 --- README.md | 4 -- haskell/c2hs.bzl | 22 +++---- haskell/cabal.bzl | 51 ++++++----------- haskell/cc.bzl | 7 +-- haskell/doctest.bzl | 4 +- haskell/experimental/private/module.bzl | 36 ++++-------- haskell/private/actions/compile.bzl | 57 ++++++++----------- haskell/private/actions/info.bzl | 3 +- haskell/private/actions/link.bzl | 2 +- haskell/private/actions/process_hsc_file.bzl | 9 ++- haskell/private/actions/runghc.bzl | 1 - haskell/private/cc_wrapper.py.tpl | 5 ++ haskell/private/haskell_impl.bzl | 43 +++++++------- haskell/private/plugins.bzl | 12 ---- haskell/private/runghc.bzl | 17 +++++- haskell/protobuf.bzl | 19 ++----- haskell/toolchain.bzl | 36 ++++-------- .../tests/stackage_zlib_runpath/BUILD.bazel | 8 +-- 18 files changed, 129 insertions(+), 207 deletions(-) delete mode 100644 haskell/private/plugins.bzl diff --git a/README.md b/README.md index 40f9d3fc8..344111f90 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,6 @@ You'll need [Bazel >= 6.0][bazel-getting-started] installed. If you are on NixOS, skip to the [Nixpkgs](#Nixpkgs) section. -> [!NOTE] -> Bazel 8 users will need to add -> `common --noincompatible_disallow_ctx_resolve_tools` to `.bazelrc` - ### System dependencies Refer to the "Before you begin" section in [the documentation](docs/haskell.rst). diff --git a/haskell/c2hs.bzl b/haskell/c2hs.bzl index 73b98cefc..eeee9b724 100644 --- a/haskell/c2hs.bzl +++ b/haskell/c2hs.bzl @@ -31,7 +31,6 @@ def _c2hs_library_impl(ctx): ) args = hs.actions.args() c2hs = ctx.toolchains["@rules_haskell//haskell/c2hs:toolchain"].c2hs - c2hs_exe = ctx.toolchains["@rules_haskell//haskell/c2hs:toolchain"].c2hs_exe if len(ctx.files.srcs) != 1: fail("srcs field should contain exactly one file.") @@ -44,7 +43,7 @@ def _c2hs_library_impl(ctx): args.add_all([chs_file.path, "-o", hs_file.path]) args.add("-C-E") - args.add_all(["--cpp", cc.tools.cc]) + args.add_all(["--cpp", cc.tools.cc.executable.path]) args.add("-C-includeghcplatform.h") args.add("-C-includeghcversion.h") args.add_all(["-C" + x for x in cc.cpp_flags]) @@ -70,21 +69,16 @@ def _c2hs_library_impl(ctx): (version_macro_headers, version_macro_flags) = version_macro_includes(dep_info) args.add_all(["-C" + x for x in version_macro_flags]) - (inputs, input_manifests) = ctx.resolve_tools(tools = [c2hs]) - hs.actions.run_shell( inputs = depset(transitive = [ depset(cc.hdrs), depset([chs_file]), depset(dep_chi_files), - depset(cc.files), depset(hs.toolchain.bindir), depset(hs.toolchain.libdir), set.to_depset(version_macro_headers), - inputs, ]), - input_manifests = input_manifests, - tools = [hs.tools.ghc_pkg, c2hs_exe], + tools = [hs.tools.ghc_pkg, c2hs, cc.tools.cc.as_tool], outputs = [hs_file, chi_file], command = # cpp (called via c2hs) gets very unhappy if the mingw bin dir is @@ -103,7 +97,7 @@ def _c2hs_library_impl(ctx): {c2hs} "${{include_dirs_args[@]}}" "$@" """.format( ghc_pkg = hs.tools.ghc_pkg.path, - c2hs = c2hs_exe.path, + c2hs = c2hs.executable.path, ), mnemonic = "HaskellC2Hs", arguments = [args], @@ -159,12 +153,10 @@ def _c2hs_toolchain_impl(ctx): return [ platform_common.ToolchainInfo( name = ctx.label.name, - # We have both c2hs which points to the target and c2hs_exe - # which points to the file. The former is used to collect - # runfiles while the latter is used to get the path to - # c2hs. - c2hs = ctx.attr.c2hs, - c2hs_exe = ctx.executable.c2hs, + # Get a FilesToRunProvider which can be used to insert all the + # necessary files for the tool into the environment of an action + # run. + c2hs = ctx.attr.c2hs[DefaultInfo].files_to_run, ), ] diff --git a/haskell/cabal.bzl b/haskell/cabal.bzl index a20204719..bc19f6566 100644 --- a/haskell/cabal.bzl +++ b/haskell/cabal.bzl @@ -125,17 +125,6 @@ main = defaultMain ) return setup -_CABAL_TOOLS = ["alex", "c2hs", "cpphs", "doctest", "happy"] - -def _cabal_tool_flag(tool): - """Return a --with-PROG=PATH flag if input is a recognized Cabal tool. None otherwise.""" - if tool.basename in _CABAL_TOOLS: - return "--with-{}={}".format(tool.basename, tool.path) - return None - -def _binary_paths(binaries): - return [binary.dirname for binary in binaries.to_list()] - def _concat(sequences): return [item for sequence in sequences for item in sequence] @@ -161,7 +150,7 @@ def _cabal_toolchain_info(hs, cc, workspace_name, runghc): hsc2hs = hs.tools.hsc2hs.path, runghc = runghc.path, ar = ar, - cc = cc.tools.cc, + cc = cc.tools.cc.executable.path, ld = cc.tools.ld, strip = cc.tools.strip, is_windows = hs.toolchain.is_windows, @@ -179,8 +168,6 @@ def _prepare_cabal_inputs( direct_cc_info, component, package_id, - tool_inputs, - tool_input_manifests, cabal, setup, setup_deps, @@ -252,7 +239,7 @@ def _prepare_cabal_inputs( env = dicts.add(hs.env, cc.env) env["PATH"] = join_path_list( hs.toolchain.is_windows, - _binary_paths(tool_inputs) + posix.paths + hs.tools_config.path_for_cabal, + posix.paths + hs.tools_config.path_for_cabal, ) if hs.toolchain.is_darwin: env["SDKROOT"] = "macosx" # See haskell/private/actions/link.bzl @@ -348,7 +335,6 @@ def _prepare_cabal_inputs( extra_ldflags_file = darwin_flags_for_linking_indirect_cc_deps(hs, cc, posix, hs.name, dynamic = True) # Redundant with _binary_paths() above, but better be explicit when we can. - path_args.extend([_cabal_tool_flag(tool_flag) for tool_flag in tool_inputs.to_list() if _cabal_tool_flag(tool_flag)]) repo_name = "_main" if generate_paths_module and label and label.repo_name: @@ -389,7 +375,6 @@ def _prepare_cabal_inputs( input_files, transitive = [ depset(srcs), - depset(cc.files), depset(ghc_files), package_databases, setup_dep_info.package_databases, @@ -402,18 +387,14 @@ def _prepare_cabal_inputs( setup_dep_info.hs_libraries, dep_info.interface_dirs, dep_info.hs_libraries, - tool_inputs, ], ) - input_manifests = tool_input_manifests + hs.toolchain.cc_wrapper.manifests - runfiles_direct = runfiles_libs if static_binary else dynamic_libs return struct( cabal_wrapper = cabal_wrapper, args = args, inputs = inputs, - input_manifests = input_manifests, env = env, runfiles = depset(direct = runfiles_direct), ) @@ -575,7 +556,7 @@ def _haskell_cabal_library_impl(ctx): ), sibling = cabal, ) - (tool_inputs, tool_input_manifests) = ctx.resolve_tools(tools = ctx.attr.tools) + attr_tools = [tool[DefaultInfo].files_to_run for tool in ctx.attr.tools] c = _prepare_cabal_inputs( hs, cc, @@ -586,8 +567,6 @@ def _haskell_cabal_library_impl(ctx): direct_cc_info, component = "lib:{}".format(ctx.attr.sublibrary_name or ctx.attr.package_name or hs.label.name), package_id = package_id, - tool_inputs = tool_inputs, - tool_input_manifests = tool_input_manifests, cabal = cabal, setup = setup, setup_deps = setup_deps, @@ -620,15 +599,23 @@ def _haskell_cabal_library_impl(ctx): if with_profiling: outputs.append(profiling_library) - (_, runghc_manifest) = ctx.resolve_tools(tools = [ctx.attr._runghc]) json_args = ctx.actions.declare_file("{}_cabal_wrapper_args.json".format(ctx.label.name)) ctx.actions.write(json_args, json.encode(c.args)) + + # Ensure that dependent tools can be found. + paths = [] + if "PATH" in c.env: + paths.append(c.env["PATH"]) + paths.extend([t.executable.dirname for t in attr_tools]) + c.env["PATH"] = ":".join(paths) + ctx.actions.run( executable = c.cabal_wrapper, arguments = [json_args.path], inputs = depset([json_args], transitive = [c.inputs]), - input_manifests = c.input_manifests + runghc_manifest, - tools = [c.cabal_wrapper, ctx.executable._runghc] + hs.tools_config.tools_for_ghc, + tools = attr_tools + + [c.cabal_wrapper, ctx.executable._runghc, hs.toolchain.cc_wrapper.as_tool] + + hs.tools_config.tools_for_ghc, outputs = outputs, env = c.env, mnemonic = "HaskellCabalLibrary", @@ -911,7 +898,7 @@ def _haskell_cabal_binary_impl(ctx): "_install/{}_data".format(hs.label.name), sibling = cabal, ) - (tool_inputs, tool_input_manifests) = ctx.resolve_tools(tools = ctx.attr.tools) + attr_tools = [tool[DefaultInfo].files_to_run for tool in ctx.attr.tools] c = _prepare_cabal_inputs( hs, cc, @@ -922,8 +909,6 @@ def _haskell_cabal_binary_impl(ctx): direct_cc_info, component = "exe:{}".format(exe_name), package_id = hs.label.name, - tool_inputs = tool_inputs, - tool_input_manifests = tool_input_manifests, cabal = cabal, setup = setup, setup_deps = setup_deps, @@ -942,20 +927,20 @@ def _haskell_cabal_binary_impl(ctx): static_binary = static_binary, label = ctx.label, ) - (_, runghc_manifest) = ctx.resolve_tools(tools = [ctx.attr._runghc]) json_args = ctx.actions.declare_file("{}_cabal_wrapper_args.json".format(ctx.label.name)) ctx.actions.write(json_args, json.encode(c.args)) ctx.actions.run( executable = c.cabal_wrapper, arguments = [json_args.path], inputs = depset([json_args], transitive = [c.inputs]), - input_manifests = c.input_manifests + runghc_manifest, outputs = [ package_database, binary, data_dir, ], - tools = [c.cabal_wrapper, ctx.executable._runghc] + hs.tools_config.tools_for_ghc, + tools = attr_tools + + [c.cabal_wrapper, ctx.executable._runghc, hs.toolchain.cc_wrapper.as_tool] + + hs.tools_config.tools_for_ghc, env = c.env, mnemonic = "HaskellCabalBinary", progress_message = "HaskellCabalBinary {}".format(hs.label), diff --git a/haskell/cc.bzl b/haskell/cc.bzl index 8d0c0f30a..7cfe47c4b 100644 --- a/haskell/cc.bzl +++ b/haskell/cc.bzl @@ -118,13 +118,10 @@ def cc_interop_info(ctx, override_cc_toolchain = None): # Generate cc wrapper script on Darwin that adjusts load commands. hs_toolchain = ctx.toolchains["@rules_haskell//haskell:toolchain"] cc_wrapper = hs_toolchain.cc_wrapper - cc = cc_wrapper.executable.path - cc_files = depset(transitive = [cc_toolchain.all_files, cc_wrapper.inputs]) - cc_manifests = cc_wrapper.manifests tools = { "ar": cc_toolchain.ar_executable, - "cc": cc, + "cc": cc_wrapper, "ld": cc_toolchain.ld_executable, "cpp": cc_toolchain.preprocessor_executable, "nm": cc_toolchain.nm_executable, @@ -163,8 +160,6 @@ def cc_interop_info(ctx, override_cc_toolchain = None): return CcInteropInfo( tools = struct(**tools), env = env, - files = cc_files.to_list(), - manifests = cc_manifests, hdrs = hdrs.to_list(), cpp_flags = cpp_flags, include_args = include_args, diff --git a/haskell/doctest.bzl b/haskell/doctest.bzl index 664cd61c9..2fb453c4b 100644 --- a/haskell/doctest.bzl +++ b/haskell/doctest.bzl @@ -98,7 +98,7 @@ def _haskell_doctest_single(target, ctx): ctx, override_cc_toolchain = hs.tools_config.maybe_exec_cc_toolchain, ) - args.add_all(ghc_cc_program_args(hs, cc.tools.cc, cc.tools.ld)) + args.add_all(ghc_cc_program_args(hs, cc.tools.cc.executable.path, cc.tools.ld)) doctest_log = ctx.actions.declare_file( "doctest-log-" + ctx.label.name + "-" + target.label.name, @@ -137,7 +137,6 @@ def _haskell_doctest_single(target, ctx): depset(get_ghci_library_files(hs, cc_libraries_info, cc.transitive_libraries)), depset( toolchain.doctest + - cc.files + [hs.tools.ghc], ), ]), @@ -173,6 +172,7 @@ def _haskell_doctest_single(target, ctx): # sandboxing altogether for doctest tests. "no-sandbox": "1", }, + tools = [cc.tools.cc.as_tool], ) return doctest_log diff --git a/haskell/experimental/private/module.bzl b/haskell/experimental/private/module.bzl index 754a64c72..3e77c9c3e 100644 --- a/haskell/experimental/private/module.bzl +++ b/haskell/experimental/private/module.bzl @@ -21,10 +21,6 @@ load( ) load("//haskell:private/path_utils.bzl", "infer_main_module") load("//haskell:private/pkg_id.bzl", "pkg_id") -load( - "//haskell:private/plugins.bzl", - "resolve_plugin_tools", -) load( "//haskell:providers.bzl", "GhcPluginInfo", @@ -173,8 +169,9 @@ def _build_haskell_module( module_attr.name, [dep for plugin in plugin_decl for dep in plugin[GhcPluginInfo].deps], ) - plugins = [resolve_plugin_tools(ctx, plugin[GhcPluginInfo]) for plugin in plugin_decl] - (preprocessors_inputs, preprocessors_input_manifests) = ctx.resolve_tools(tools = ctx.attr.tools + module_attr.tools) + plugin_infos = [plugin[GhcPluginInfo] for plugin in plugin_decl] + plugin_tools = [tool[DefaultInfo].files_to_run for i in plugin_infos for tool in i.tools] + attr_tools = [tool[DefaultInfo].files_to_run for tool in (ctx.attr.tools + module_attr.tools)] # TODO[AH] Support additional outputs such as `.hie`. @@ -254,7 +251,7 @@ def _build_haskell_module( args.add_all(cc.include_args) - if plugins or enable_th: + if plugin_infos or enable_th: # cc toolchain linker flags would be necessary when the interpreter wants to # load any libraries args.add_all(cc.linker_flags, format_each = "-optl%s") @@ -278,8 +275,8 @@ def _build_haskell_module( plugin_pkg_info = expose_packages( package_ids = [ pkg_id - for plugin in plugins - for pkg_id in all_dependencies_package_ids(plugin.deps) + for plugin_info in plugin_infos + for pkg_id in all_dependencies_package_ids(plugin_info.deps) ], package_databases = plugin_dep_info.package_databases, version = version, @@ -288,17 +285,10 @@ def _build_haskell_module( ) args.add_all(pkg_info_args) - for plugin in plugins: - args.add("-fplugin={}".format(plugin.module)) - for opt in plugin.args: - args.add_all(["-fplugin-opt", "{}:{}".format(plugin.module, opt)]) - - plugin_tool_inputs = depset(transitive = [plugin.tool_inputs for plugin in plugins]) - plugin_tool_input_manifests = [ - manifest - for plugin in plugins - for manifest in plugin.tool_input_manifests - ] + for plugin_info in plugin_infos: + args.add("-fplugin={}".format(plugin_info.module)) + for opt in plugin_info.args: + args.add_all(["-fplugin-opt", "{}:{}".format(plugin_info.module, opt)]) args.add_all(hs.toolchain.ghcopts) args.add_all(user_ghcopts) @@ -310,7 +300,7 @@ def _build_haskell_module( args.add(paths.join(ar_bindir, "otool"), format = "-pgmotool=%s") args.add(paths.join(ar_bindir, "install_name_tool"), format = "-pgminstall_name_tool=%s") - if plugins and not enable_th: + if plugin_infos and not enable_th: # For #1681. These suppresses bogus warnings about missing libraries which # aren't really needed. args.add("-Wno-missed-extra-shared-lib") @@ -345,8 +335,6 @@ def _build_haskell_module( plugin_dep_info.package_databases, plugin_dep_info.interface_dirs, plugin_dep_info.hs_libraries, - plugin_tool_inputs, - preprocessors_inputs, interface_inputs, abi_inputs, ] + [ @@ -361,7 +349,6 @@ def _build_haskell_module( if enable_th ], ), - input_manifests = preprocessors_input_manifests + plugin_tool_input_manifests, outputs = outputs, mnemonic = "HaskellBuildObject" + ("Prof" if with_profiling else ""), progress_message = "HaskellBuildObject {} {}".format(hs.label, module.label), @@ -371,6 +358,7 @@ def _build_haskell_module( extra_name = module.label.package.replace("/", "_") + "_" + module.label.name, hi_file = module_outputs.hi, abi_file = module_outputs.abi, + extra_tools = attr_tools + plugin_tools, ) is_boot = _is_boot(src.path) diff --git a/haskell/private/actions/compile.bzl b/haskell/private/actions/compile.bzl index a2203f1af..5971ef6df 100644 --- a/haskell/private/actions/compile.bzl +++ b/haskell/private/actions/compile.bzl @@ -42,9 +42,8 @@ def _compilation_defaults( my_pkg_id, version, extra_ldflags_file, - plugins, - non_default_plugins, - preprocessors): + plugin_infos, + non_default_plugin_infos): """Compute variables common to all compilation targets (binary and library). Returns: @@ -134,9 +133,9 @@ def _compilation_defaults( ] package_ids = [] - all_plugins = plugins + non_default_plugins - for plugin in all_plugins: - package_ids.extend(all_dependencies_package_ids(plugin.deps)) + all_plugin_infos = plugin_infos + non_default_plugin_infos + for plugin_info in all_plugin_infos: + package_ids.extend(all_dependencies_package_ids(plugin_info.deps)) (pkg_info_inputs, pkg_info_args) = pkg_info_to_compile_flags( hs, @@ -258,18 +257,11 @@ def _compilation_defaults( args.add_all(compile_flags) # Plugins - for plugin in plugins: - args.add("-fplugin={}".format(plugin.module)) - for plugin in all_plugins: - for opt in plugin.args: - args.add_all(["-fplugin-opt", "{}:{}".format(plugin.module, opt)]) - - plugin_tool_inputs = depset(transitive = [plugin.tool_inputs for plugin in all_plugins]) - plugin_tool_input_manifests = [ - manifest - for plugin in all_plugins - for manifest in plugin.tool_input_manifests - ] + for plugin_info in plugin_infos: + args.add("-fplugin={}".format(plugin_info.module)) + for plugin_info in all_plugin_infos: + for opt in plugin_info.args: + args.add_all(["-fplugin-opt", "{}:{}".format(plugin_info.module, opt)]) # Pass source files args.add_all(source_files) @@ -313,10 +305,7 @@ def _compilation_defaults( plugin_dep_info.hs_libraries, depset(get_ghci_library_files(hs, cc.cc_libraries_info, cc.transitive_libraries + cc.plugin_libraries)), java.inputs, - preprocessors.inputs, - plugin_tool_inputs, ]), - input_manifests = preprocessors.input_manifests + plugin_tool_input_manifests, object_files = object_files, dyn_object_files = dyn_object_files, interface_files = interface_files, @@ -363,8 +352,10 @@ def compile_binary( version, extra_ldflags_file, inspect_coverage = False, - plugins = [], - non_default_plugins = [], + plugin_infos = [], + plugin_tools = [], + non_default_plugin_infos = [], + non_default_plugin_tools = [], preprocessors = []): """Compile a Haskell target into object files suitable for linking. @@ -394,9 +385,8 @@ def compile_binary( my_pkg_id = None, version = version, extra_ldflags_file = extra_ldflags_file, - plugins = plugins, - non_default_plugins = non_default_plugins, - preprocessors = preprocessors, + plugin_infos = plugin_infos, + non_default_plugin_infos = non_default_plugin_infos, ) c.args.add_all(["-main-is", main_function]) if dynamic: @@ -418,12 +408,12 @@ def compile_binary( hs, cc, inputs = c.inputs, - input_manifests = c.input_manifests, outputs = c.outputs + [datum.mix_file for datum in coverage_data], mnemonic = "HaskellBuildBinary" + ("Prof" if with_profiling else ""), progress_message = "HaskellBuildBinary {}".format(hs.label), env = c.env, arguments = c.args, + extra_tools = preprocessors + plugin_tools + non_default_plugin_tools, ) return struct( @@ -455,8 +445,10 @@ def compile_library( objects_dir, my_pkg_id, extra_ldflags_file, - plugins = [], - non_default_plugins = [], + plugin_infos = [], + plugin_tools = [], + non_default_plugin_infos = [], + non_default_plugin_tools = [], preprocessors = []): """Build arguments for Haskell package build. @@ -490,9 +482,8 @@ def compile_library( my_pkg_id = my_pkg_id, version = my_pkg_id.version, extra_ldflags_file = extra_ldflags_file, - plugins = plugins, - non_default_plugins = non_default_plugins, - preprocessors = preprocessors, + plugin_infos = plugin_infos, + non_default_plugin_infos = non_default_plugin_infos, ) if with_shared: c.args.add("-dynamic-too") @@ -515,12 +506,12 @@ def compile_library( hs, cc, inputs = c.inputs, - input_manifests = c.input_manifests, outputs = c.outputs + [datum.mix_file for datum in coverage_data], mnemonic = "HaskellBuildLibrary" + ("Prof" if with_profiling else ""), progress_message = "HaskellBuildLibrary {}".format(hs.label), env = c.env, arguments = c.args, + extra_tools = preprocessors + plugin_tools + non_default_plugin_tools, ) return struct( diff --git a/haskell/private/actions/info.bzl b/haskell/private/actions/info.bzl index fc970285b..efbd9c6e4 100644 --- a/haskell/private/actions/info.bzl +++ b/haskell/private/actions/info.bzl @@ -32,8 +32,7 @@ def write_proto_file(hs, output_name, proto_type, content): hs.actions.run_shell( outputs = [proto_pb], - inputs = depset([proto_txt] + rule_info_protos, transitive = [protoc.inputs]), - input_manifests = protoc.input_manifests, + inputs = depset([proto_txt] + rule_info_protos), tools = [protoc.executable], command = "{protoc} {rule_info_proto} --encode {proto_type} < {proto_txt} > {proto_pb}" diff --git a/haskell/private/actions/link.bzl b/haskell/private/actions/link.bzl index c01777ac8..0fa4fd99a 100644 --- a/haskell/private/actions/link.bzl +++ b/haskell/private/actions/link.bzl @@ -323,7 +323,7 @@ def link_library_static(hs, cc, _posix, _dep_info, object_files, my_pkg_id, with "lib{0}.a".format(pkg_id.library_name(hs, my_pkg_id, prof_suffix = with_profiling)), ), ) - inputs = depset(cc.files, transitive = [object_files]) + inputs = depset(transitive = [object_files]) args = hs.actions.args() # On Windows, any of the object files might actually be static archives already diff --git a/haskell/private/actions/process_hsc_file.bzl b/haskell/private/actions/process_hsc_file.bzl index b22fcfd58..52c474517 100644 --- a/haskell/private/actions/process_hsc_file.bzl +++ b/haskell/private/actions/process_hsc_file.bzl @@ -26,8 +26,8 @@ def process_hsc_file(hs, cc, hsc_flags, hsc_inputs, hsc_file): hs_out = declare_compiled(hs, hsc_file, ".hs", directory = hsc_dir_raw) args.add_all([hsc_file.path, "-o", hs_out.path]) - args.add_all(["-c", cc.tools.cc]) - args.add_all(["-l", cc.tools.cc]) + args.add_all(["-c", cc.tools.cc.executable.path]) + args.add_all(["-l", cc.tools.cc.executable.path]) args.add("-ighcplatform.h") args.add("-ighcversion.h") args.add_all(cc.cpp_flags, format_each = "--cflag=%s") @@ -64,11 +64,9 @@ def process_hsc_file(hs, cc, hsc_flags, hsc_inputs, hsc_file): inputs = depset(transitive = [ depset(cc.hdrs), depset([hsc_file]), - depset(cc.files), depset(hsc_inputs), depset(hs.toolchain.bindir), ]), - input_manifests = cc.manifests, outputs = [hs_out], mnemonic = "HaskellHsc2hs", command = @@ -84,12 +82,13 @@ def process_hsc_file(hs, cc, hsc_flags, hsc_inputs, hsc_file): include_dirs_args=( "${{include_dirs[@]/#/-C-I}}" ) {hsc2hs} "${{include_dirs_args[@]}}" "$@" """.format( - mingw_bin = paths.dirname(cc.tools.cc) if hs.toolchain.is_windows else "", + mingw_bin = paths.dirname(cc.tools.cc.executable.path) if hs.toolchain.is_windows else "", ghc_pkg = hs.tools.ghc_pkg.path, hsc2hs = hs.tools.hsc2hs.path, ), arguments = [args], env = hs.env, + tools = [cc.tools.cc.as_tool], ) idir = paths.join( diff --git a/haskell/private/actions/runghc.bzl b/haskell/private/actions/runghc.bzl index 2a5c4b53c..9f601bb5e 100644 --- a/haskell/private/actions/runghc.bzl +++ b/haskell/private/actions/runghc.bzl @@ -104,6 +104,5 @@ def build_haskell_runghc( pkg_info_inputs, depset(get_ghci_library_files(hs, cc.cc_libraries_info, cc.transitive_libraries + cc.plugin_libraries)), hs_info.source_files, - hs.toolchain.cc_wrapper.runfiles.files, ]) ln(hs, posix, runghc_file, output, extra_inputs) diff --git a/haskell/private/cc_wrapper.py.tpl b/haskell/private/cc_wrapper.py.tpl index 1e0062743..0b8e69ca0 100644 --- a/haskell/private/cc_wrapper.py.tpl +++ b/haskell/private/cc_wrapper.py.tpl @@ -571,6 +571,11 @@ def link(output, libraries, rpaths, args): rpaths = shorten_rpaths(rpaths, libraries, output) args.extend(rpath_args(rpaths)) + # See note in cabal_wrapper.py + if "RUNFILES_DIR" in os.environ: + del os.environ["RUNFILES_DIR"] + if "RUNFILES_MANIFEST_FILE" in os.environ: + del os.environ["RUNFILES_MANIFEST_FILE"] # Note: `RULES_HASKELL_SILENCE_LINKER` is only set if called from doctest, # which is used to silence the linker output to not interfere with the output # from GHCi diff --git a/haskell/private/haskell_impl.bzl b/haskell/private/haskell_impl.bzl index e120d99c7..6fd893e79 100644 --- a/haskell/private/haskell_impl.bzl +++ b/haskell/private/haskell_impl.bzl @@ -41,7 +41,6 @@ load( "parse_pattern", ) load(":private/pkg_id.bzl", "pkg_id") -load(":private/plugins.bzl", "resolve_plugin_tools") load(":private/set.bzl", "set") load(":private/version_macros.bzl", "generate_version_macros") load( @@ -141,18 +140,8 @@ def _condition_coverage_src(hs, src): return conditioned_src -def _resolve_preprocessors(ctx, preprocessors): - if not hasattr(ctx, "resolve_tools"): - # No resolve_tools when ctx is faked (see protobuf.bzl). - return struct( - inputs = depset(), - input_manifests = [], - ) - (inputs, input_manifests) = ctx.resolve_tools(tools = preprocessors) - return struct( - inputs = inputs, - input_manifests = input_manifests, - ) +def _resolve_preprocessors(preprocessors): + return [tool[DefaultInfo].files_to_run for tool in preprocessors] def haskell_module_from_target(m): """ Produces the module name from a HaskellModuleInfo """ @@ -234,9 +223,11 @@ def _haskell_binary_common_impl(ctx, is_test): objects_dir, ) - plugins = [resolve_plugin_tools(ctx, plugin[GhcPluginInfo]) for plugin in plugin_decl] - non_default_plugins = [resolve_plugin_tools(ctx, plugin[GhcPluginInfo]) for plugin in non_default_plugin_decl] - preprocessors = _resolve_preprocessors(ctx, ctx.attr.tools) + plugin_infos = [plugin[GhcPluginInfo] for plugin in plugin_decl] + plugin_tools = [tool[DefaultInfo].files_to_run for i in plugin_infos for tool in i.tools] + non_default_plugin_infos = [plugin[GhcPluginInfo] for plugin in non_default_plugin_decl] + non_default_plugin_tools = [tool[DefaultInfo].files_to_run for i in non_default_plugin_infos for tool in i.tools] + preprocessors = _resolve_preprocessors(ctx.attr.tools) user_compile_flags = haskell_library_expand_make_variables("ghcopts", ctx, ctx.attr.ghcopts) c = hs.toolchain.actions.compile_binary( hs, @@ -258,8 +249,10 @@ def _haskell_binary_common_impl(ctx, is_test): version = ctx.attr.version, inspect_coverage = inspect_coverage, extra_ldflags_file = extra_ldflags_file, - plugins = plugins, - non_default_plugins = non_default_plugins, + plugin_infos = plugin_infos, + plugin_tools = plugin_tools, + non_default_plugin_infos = non_default_plugin_infos, + non_default_plugin_tools = non_default_plugin_tools, preprocessors = preprocessors, ) @@ -466,9 +459,11 @@ def haskell_library_impl(ctx): objects_dir, ) - plugins = [resolve_plugin_tools(ctx, plugin[GhcPluginInfo]) for plugin in ctx.attr.plugins] - non_default_plugins = [resolve_plugin_tools(ctx, plugin[GhcPluginInfo]) for plugin in ctx.attr.non_default_plugins] - preprocessors = _resolve_preprocessors(ctx, ctx.attr.tools) + plugin_infos = [plugin[GhcPluginInfo] for plugin in ctx.attr.plugins] + plugin_tools = [tool[DefaultInfo].files_to_run for i in plugin_infos for tool in i.tools] + non_default_plugin_infos = [plugin[GhcPluginInfo] for plugin in ctx.attr.non_default_plugins] + non_default_plugin_tools = [tool[DefaultInfo].files_to_run for i in non_default_plugin_infos for tool in i.tools] + preprocessors = _resolve_preprocessors(ctx.attr.tools) user_compile_flags = haskell_library_expand_make_variables("ghcopts", ctx, ctx.attr.ghcopts) c = hs.toolchain.actions.compile_library( hs, @@ -488,8 +483,10 @@ def haskell_library_impl(ctx): objects_dir = objects_dir, my_pkg_id = my_pkg_id, extra_ldflags_file = extra_ldflags_file, - plugins = plugins, - non_default_plugins = non_default_plugins, + plugin_infos = plugin_infos, + plugin_tools = plugin_tools, + non_default_plugin_infos = non_default_plugin_infos, + non_default_plugin_tools = non_default_plugin_tools, preprocessors = preprocessors, ) diff --git a/haskell/private/plugins.bzl b/haskell/private/plugins.bzl deleted file mode 100644 index 02cab6306..000000000 --- a/haskell/private/plugins.bzl +++ /dev/null @@ -1,12 +0,0 @@ -"""Utilities for GHC plugins.""" - -def resolve_plugin_tools(ctx, plugin_info): - """Convert a plugin provider to a struct with tools resolved to inputs.""" - (tool_inputs, tool_input_manifests) = ctx.resolve_tools(tools = plugin_info.tools) - return struct( - module = plugin_info.module, - deps = plugin_info.deps, - args = plugin_info.args, - tool_inputs = tool_inputs, - tool_input_manifests = tool_input_manifests, - ) diff --git a/haskell/private/runghc.bzl b/haskell/private/runghc.bzl index 37e87fb39..64bdd3aac 100644 --- a/haskell/private/runghc.bzl +++ b/haskell/private/runghc.bzl @@ -24,21 +24,32 @@ def _runghc_wrapper_impl(ctx): content = """\ #!/usr/bin/env python3 +import os import subprocess import sys from python.runfiles import runfiles r = runfiles.Create() -subprocess.run([r.Rlocation("{runghc}")] + sys.argv[1:], check=True) +# Get the correct location first +ghc_location = r.Rlocation("{runghc}") + +# Clear out the environment so that downstream tools don't use the wrong +# runfiles environment. See the comment in cabal_wrapper.py for more details. +if "RUNFILES_DIR" in os.environ: + del os.environ["RUNFILES_DIR"] +if "RUNFILES_MANIFEST_FILE" in os.environ: + del os.environ["RUNFILES_MANIFEST_FILE"] + +subprocess.run([ghc_location] + sys.argv[1:], check=True) """.format(runghc = runghc_runfile_path), is_executable = True, ) return [DefaultInfo( executable = runghc_wrapper_file, - runfiles = hs_toolchain.cc_wrapper.runfiles.merge( - ctx.runfiles(files = [runghc_wrapper_file, hs_toolchain.tools.runghc]), + runfiles = ctx.runfiles( + files = [runghc_wrapper_file, hs_toolchain.tools.runghc, hs_toolchain.cc_wrapper.executable], ), )] diff --git a/haskell/protobuf.bzl b/haskell/protobuf.bzl index fd6979793..237ebb403 100644 --- a/haskell/protobuf.bzl +++ b/haskell/protobuf.bzl @@ -147,13 +147,12 @@ def _haskell_proto_aspect_impl(target, ctx): ]) ctx.actions.run( - inputs = depset(inputs, transitive = [pb.plugin.inputs, pb.protoc.inputs]), - input_manifests = pb.protoc.input_manifests + pb.plugin.input_manifests, + inputs = inputs, outputs = hs_files, mnemonic = "HaskellProtoc", - executable = pb.protoc.executable, + executable = pb.protoc, arguments = [args], - tools = [pb.plugin.executable], + tools = [pb.plugin], env = { "RULES_HASKELL_GHC_PATH": hs.tools.ghc.path, "RULES_HASKELL_GHC_PKG_PATH": hs.tools.ghc_pkg.path, @@ -351,21 +350,13 @@ registered. """, ) -def _wrap_tool(ctx, exe, tool): - inputs, input_manifests = ctx.resolve_tools(tools = [tool]) - return struct( - executable = exe, - inputs = inputs, - input_manifests = input_manifests, - ) - def _protobuf_toolchain_impl(ctx): return [ platform_common.ToolchainInfo( name = ctx.label.name, tools = struct( - plugin = _wrap_tool(ctx, ctx.executable.plugin, ctx.attr.plugin), - protoc = _wrap_tool(ctx, ctx.executable.protoc, ctx.attr.protoc), + plugin = ctx.attr.plugin[DefaultInfo].files_to_run, + protoc = ctx.attr.protoc[DefaultInfo].files_to_run, ), deps = ctx.attr.deps, ), diff --git a/haskell/toolchain.bzl b/haskell/toolchain.bzl index 5e033af84..aa6457ba0 100644 --- a/haskell/toolchain.bzl +++ b/haskell/toolchain.bzl @@ -62,26 +62,27 @@ def _run_ghc( interface_inputs = [], extra_name = "", hi_file = None, - abi_file = None): + abi_file = None, + extra_tools = []): args = hs.actions.args() extra_inputs = [] # Detect persistent worker support flagsfile_prefix = "" execution_requirements = {} - tools = [] + tools = extra_tools + [cc.tools.cc.as_tool] if hs.worker != None: flagsfile_prefix = "@" execution_requirements = {"supports-workers": "1"} args.add(hs.worker.path) - tools = [hs.worker] + tools = extra_tools + [hs.worker] else: args.add(hs.tools.ghc) extra_inputs.append(hs.tools.ghc) # XXX: We should also tether Bazel's CC toolchain to GHC's, so that we can properly mix Bazel-compiled # C libraries with Haskell targets. - args.add_all(ghc_cc_program_args(hs, cc.tools.cc, cc.tools.ld)) + args.add_all(ghc_cc_program_args(hs, cc.tools.cc.executable.path, cc.tools.ld)) compile_flags_file = hs.actions.declare_file("compile_flags_%s_%s_%s" % (hs.name, extra_name, mnemonic)) extra_args_file = hs.actions.declare_file("extra_args_%s_%s_%s" % (hs.name, extra_name, mnemonic)) @@ -129,7 +130,7 @@ def _run_ghc( extra_inputs += [ compile_flags_file, extra_args_file, - ] + cc.files + hs.toolchain.bindir + hs.toolchain.libdir + ] + hs.toolchain.bindir + hs.toolchain.libdir if hs.toolchain.locale_archive != None: extra_inputs.append(hs.toolchain.locale_archive) @@ -141,11 +142,6 @@ def _run_ghc( inputs = depset(extra_inputs, transitive = [inputs]) - if input_manifests != None: - input_manifests = input_manifests + cc.manifests - else: - input_manifests = cc.manifests - tools.extend(hs.tools_config.tools_for_ghc) append_to_path(env, hs.toolchain.is_windows, hs.tools_config.path_for_run_ghc) @@ -426,11 +422,8 @@ def _haskell_toolchain_impl(ctx): for lib in ctx.attr.libraries } - (cc_wrapper_inputs, cc_wrapper_manifest) = ctx.resolve_tools(tools = [ctx.attr._cc_wrapper]) cc_wrapper_info = ctx.attr._cc_wrapper[DefaultInfo] - cc_wrapper_runfiles = cc_wrapper_info.default_runfiles.merge( - cc_wrapper_info.data_runfiles, - ) + cc_wrapper_files_to_run = cc_wrapper_info.files_to_run if ctx.attr.asterius_binaries: tools_config = asterius_tools_config( @@ -449,8 +442,6 @@ def _haskell_toolchain_impl(ctx): supports_haddock = default_tools_config.supports_haddock, ) - (protoc_inputs, protoc_input_manifests) = ctx.resolve_tools(tools = [ctx.attr._protoc]) - return [ platform_common.ToolchainInfo( name = ctx.label.name, @@ -467,10 +458,9 @@ def _haskell_toolchain_impl(ctx): locale = ctx.attr.locale, locale_archive = locale_archive, cc_wrapper = struct( - executable = ctx.executable._cc_wrapper, - inputs = cc_wrapper_inputs, - manifests = cc_wrapper_manifest, - runfiles = cc_wrapper_runfiles, + executable = cc_wrapper_files_to_run.executable, + as_tool = cc_wrapper_files_to_run, + runfiles = cc_wrapper_info.default_runfiles, ), mode = ctx.var["COMPILATION_MODE"], actions = struct( @@ -491,11 +481,7 @@ def _haskell_toolchain_impl(ctx): version = ctx.attr.version, numeric_version = numeric_version, global_pkg_db = pkgdb_file, - protoc = struct( - executable = ctx.executable._protoc, - inputs = protoc_inputs, - input_manifests = protoc_input_manifests, - ), + protoc = ctx.attr._protoc[DefaultInfo].files_to_run, rule_info_proto = ctx.attr._rule_info_proto, tools_config = tools_config, ), diff --git a/rules_haskell_tests/tests/stackage_zlib_runpath/BUILD.bazel b/rules_haskell_tests/tests/stackage_zlib_runpath/BUILD.bazel index db2fb3aa2..3054be546 100644 --- a/rules_haskell_tests/tests/stackage_zlib_runpath/BUILD.bazel +++ b/rules_haskell_tests/tests/stackage_zlib_runpath/BUILD.bazel @@ -98,14 +98,14 @@ with open(libz_soname) as fh: (sodir, sobase) = os.path.split(sofile) # Locate test artifacts. -libHSzlib = r.Rlocation(os.path.join( +libHSzlib = r.Rlocation(os.path.normpath(os.path.join( os.environ["TEST_WORKSPACE"], sys.argv[2], -)) -cabal_binary = r.Rlocation(os.path.join( +))) +cabal_binary = r.Rlocation(os.path.normpath(os.path.join( os.environ["TEST_WORKSPACE"], sys.argv[3], -)) +))) def read_runpaths(binary, sobase): if platform.system() == "Darwin": From 2d4846c7cae15432690143b5dc2c68037d9c8510 Mon Sep 17 00:00:00 2001 From: Kyle Butt Date: Fri, 3 Apr 2026 17:06:24 -0600 Subject: [PATCH 2/9] WIP Pass cc_wrapper its path via env var The inherited RUNFILES_* environment variables aren't correct. Pass in a path to try and find the correct directory/manifest. Only prints currently. --- haskell/cc.bzl | 4 ++++ haskell/private/cc_wrapper.py.tpl | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/haskell/cc.bzl b/haskell/cc.bzl index 7cfe47c4b..f030d8616 100644 --- a/haskell/cc.bzl +++ b/haskell/cc.bzl @@ -147,8 +147,12 @@ def cc_interop_info(ctx, override_cc_toolchain = None): env["CC_WRAPPER_PLATFORM"] = "linux" env["CC_WRAPPER_CC_PATH"] = real_cc_path + env["CC_WRAPPER_PATH"] = cc_wrapper.executable.path env["CC_WRAPPER_CPU"] = cc_toolchain.cpu + if cc_wrapper.as_tool.runfiles_manifest: + env["CC_WRAPPER_MANIFEST"] = cc_wrapper.as_tool.runfiles_manifest.path + cc_libraries_info = deps_HaskellCcLibrariesInfo( ctx.attr.deps + getattr(ctx.attr, "plugins", []) + getattr(ctx.attr, "setup_deps", []), ) diff --git a/haskell/private/cc_wrapper.py.tpl b/haskell/private/cc_wrapper.py.tpl index 0b8e69ca0..57d40fa07 100644 --- a/haskell/private/cc_wrapper.py.tpl +++ b/haskell/private/cc_wrapper.py.tpl @@ -1026,6 +1026,13 @@ def find_cc(): # being called from a GHCi REPL then we need to find this wrapper # script using Bazel runfiles. r = bazel_runfiles.Create() + if r is None: + manifest_path = os.environ.get("CC_WRAPPER_MANIFEST", None) + exe_path = os.environ.get("CC_WRAPPER_PATH", None) + if manifest_path is not None: + r = bazel_runfiles.CreateManifestBased(manifest_path) + elif exe_path is not None: + r = bazel_runfiles.CreateDirectoryBased(exe_path + ".runfiles") cc = r.Rlocation("/".join([WORKSPACE, CC])) if cc is None and is_windows(): # We must use "/" instead of os.path.join on Windows, because the From a2cf64c5c2ff3af166b763d175876cf32d86e74b Mon Sep 17 00:00:00 2001 From: Kyle Butt Date: Sat, 4 Apr 2026 00:34:05 -0600 Subject: [PATCH 3/9] WIP Tweak ghc_wrapper runfiles Make sure that the runfiles for cc_wrapper are included in the runfiles for ghc_wrapper --- haskell/private/runghc.bzl | 1 + 1 file changed, 1 insertion(+) diff --git a/haskell/private/runghc.bzl b/haskell/private/runghc.bzl index 64bdd3aac..598039e89 100644 --- a/haskell/private/runghc.bzl +++ b/haskell/private/runghc.bzl @@ -50,6 +50,7 @@ subprocess.run([ghc_location] + sys.argv[1:], check=True) executable = runghc_wrapper_file, runfiles = ctx.runfiles( files = [runghc_wrapper_file, hs_toolchain.tools.runghc, hs_toolchain.cc_wrapper.executable], + transitive_files = hs_toolchain.cc_wrapper.runfiles.files, ), )] From 1c934743b1b12125a2898cd40af2982ea9d17561 Mon Sep 17 00:00:00 2001 From: Kyle Butt Date: Sat, 4 Apr 2026 00:48:32 -0600 Subject: [PATCH 4/9] WIP only use manifest/dir if they exist. --- haskell/private/cc_wrapper.py.tpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haskell/private/cc_wrapper.py.tpl b/haskell/private/cc_wrapper.py.tpl index 57d40fa07..be9fceb04 100644 --- a/haskell/private/cc_wrapper.py.tpl +++ b/haskell/private/cc_wrapper.py.tpl @@ -1029,9 +1029,9 @@ def find_cc(): if r is None: manifest_path = os.environ.get("CC_WRAPPER_MANIFEST", None) exe_path = os.environ.get("CC_WRAPPER_PATH", None) - if manifest_path is not None: + if manifest_path is not None and os.path.isfile(manifest_path): r = bazel_runfiles.CreateManifestBased(manifest_path) - elif exe_path is not None: + elif exe_path is not None and os.path.isfile(exe_path): r = bazel_runfiles.CreateDirectoryBased(exe_path + ".runfiles") cc = r.Rlocation("/".join([WORKSPACE, CC])) if cc is None and is_windows(): From 2339ba53daf5e66b73661aa57fd123945341f2f3 Mon Sep 17 00:00:00 2001 From: Kyle Butt Date: Sat, 4 Apr 2026 00:48:54 -0600 Subject: [PATCH 5/9] WIP canonicalize more paths from env vars --- haskell/private/cabal_wrapper.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/haskell/private/cabal_wrapper.py b/haskell/private/cabal_wrapper.py index fee5692b6..6e2a40e41 100755 --- a/haskell/private/cabal_wrapper.py +++ b/haskell/private/cabal_wrapper.py @@ -100,8 +100,9 @@ def canonicalize_path(path): os.environ["RULES_HASKELL_GHC_PKG_PATH"] = canonicalize_path(os.getenv("RULES_HASKELL_GHC_PKG_PATH", "")) os.environ["RULES_HASKELL_LIBDIR_PATH"] = canonicalize_path(os.getenv("RULES_HASKELL_LIBDIR_PATH", "")) os.environ["RULES_HASKELL_DOCDIR_PATH"] = canonicalize_path(os.getenv("RULES_HASKELL_DOCDIR_PATH", "")) -if "LOCALE_ARCHIVE" in os.environ: - os.environ["LOCALE_ARCHIVE"] = canonicalize_path(os.getenv("LOCALE_ARCHIVE")) +for path in ["LOCALE_ARCHIVE", "CC_WRAPPER_PATH", "CC_WRAPPER_MANIFEST"]: + if path in os.environ: + os.environ[path] = canonicalize_path(os.getenv(path)) component = json_args["component"] name = json_args["pkg_name"] From 7bb12b1da869e13eb788d5008b0b2396bea469a5 Mon Sep 17 00:00:00 2001 From: Kyle Butt Date: Sat, 4 Apr 2026 01:10:45 -0600 Subject: [PATCH 6/9] WIP Pass cc env to hsc actions This will allow the CC_* env vars to reach cc_wrapper if it is invoked during hsc2hs's run. --- haskell/private/actions/process_hsc_file.bzl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/haskell/private/actions/process_hsc_file.bzl b/haskell/private/actions/process_hsc_file.bzl index 52c474517..709714790 100644 --- a/haskell/private/actions/process_hsc_file.bzl +++ b/haskell/private/actions/process_hsc_file.bzl @@ -1,5 +1,6 @@ """Action processing hsc files""" +load("@bazel_skylib//lib:dicts.bzl", "dicts") load("@bazel_skylib//lib:paths.bzl", "paths") load("@bazel_skylib//lib:sets.bzl", "sets") load(":private/path_utils.bzl", "declare_compiled") @@ -51,14 +52,16 @@ def process_hsc_file(hs, cc, hsc_flags, hsc_inputs, hsc_file): args.add_all(hsc_flags) + env = dicts.add(hs.env, cc.env) + # Add an empty PATH variable if not already specified in hs.env. # Needed to avoid a "Couldn't read PATH" error on Windows. # # On Unix platforms, though, we mustn't set PATH as it is automatically set up # by the run action, unless already set in the env parameter. This triggers # build errors when using GHC bindists on Linux. - if hs.env.get("PATH") == None and hs.toolchain.is_windows: - hs.env["PATH"] = "" + if env.get("PATH") == None and hs.toolchain.is_windows: + env["PATH"] = "" hs.actions.run_shell( inputs = depset(transitive = [ @@ -87,7 +90,7 @@ def process_hsc_file(hs, cc, hsc_flags, hsc_inputs, hsc_file): hsc2hs = hs.tools.hsc2hs.path, ), arguments = [args], - env = hs.env, + env = env, tools = [cc.tools.cc.as_tool], ) From 8a0ef6648a55020ac0c27958527bd1e7840d0f07 Mon Sep 17 00:00:00 2001 From: Kyle Butt Date: Tue, 14 Apr 2026 12:34:08 -0600 Subject: [PATCH 7/9] WIP Pass cc env to module actions --- haskell/experimental/private/module.bzl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/haskell/experimental/private/module.bzl b/haskell/experimental/private/module.bzl index 3e77c9c3e..e94f2bd2d 100644 --- a/haskell/experimental/private/module.bzl +++ b/haskell/experimental/private/module.bzl @@ -1,3 +1,4 @@ +load("@bazel_skylib//lib:dicts.bzl", "dicts") load("@bazel_skylib//lib:paths.bzl", "paths") load("@bazel_skylib//lib:sets.bzl", "sets") load( @@ -320,6 +321,8 @@ def _build_haskell_module( args.add("-optl@{}".format(extra_ldflags_file.path)) input_files.append(extra_ldflags_file) + env = dicts.add(hs.env, cc.env) + # Compile the module hs.toolchain.actions.run_ghc( hs, @@ -352,7 +355,7 @@ def _build_haskell_module( outputs = outputs, mnemonic = "HaskellBuildObject" + ("Prof" if with_profiling else ""), progress_message = "HaskellBuildObject {} {}".format(hs.label, module.label), - env = hs.env, + env = env, arguments = args, interface_inputs = interface_inputs, extra_name = module.label.package.replace("/", "_") + "_" + module.label.name, From 8cb8ed637954519946274781aac5b1cc6660be98 Mon Sep 17 00:00:00 2001 From: Kyle Butt Date: Tue, 14 Apr 2026 12:51:44 -0600 Subject: [PATCH 8/9] WIP Pass FilesToRunProvider as tools for protoc call --- haskell/private/actions/info.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haskell/private/actions/info.bzl b/haskell/private/actions/info.bzl index efbd9c6e4..b4a5c4325 100644 --- a/haskell/private/actions/info.bzl +++ b/haskell/private/actions/info.bzl @@ -33,7 +33,7 @@ def write_proto_file(hs, output_name, proto_type, content): hs.actions.run_shell( outputs = [proto_pb], inputs = depset([proto_txt] + rule_info_protos), - tools = [protoc.executable], + tools = [protoc], command = "{protoc} {rule_info_proto} --encode {proto_type} < {proto_txt} > {proto_pb}" .format( From f5b2fe8c2548ae05d97a80d919669a254122a0de Mon Sep 17 00:00:00 2001 From: Kyle Butt Date: Tue, 14 Apr 2026 13:09:46 -0600 Subject: [PATCH 9/9] WIP Fix usage of cc.tools.cc as string vs struct --- haskell/c2hs.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haskell/c2hs.bzl b/haskell/c2hs.bzl index eeee9b724..7cbd74fc9 100644 --- a/haskell/c2hs.bzl +++ b/haskell/c2hs.bzl @@ -86,7 +86,7 @@ def _c2hs_library_impl(ctx): ( """ export PATH=$PATH:{mingw_bin} - """.format(mingw_bin = paths.dirname(cc.tools.cc)) if hs.toolchain.is_windows else "" + """.format(mingw_bin = paths.dirname(cc.tools.cc.executable.path)) if hs.toolchain.is_windows else "" ) + """ # Include libdir in include path just like hsc2hs does.