From 43eb4e010ad3329e7d5236b181ad0b6a006f9adb Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Mon, 8 Jan 2024 13:42:10 +0100 Subject: [PATCH 1/7] Remove `haskell_toolchain_libraries` rule This was only needed as a workaround, but toolchain transitions have been implemented and it is not needed anymore. --- haskell/BUILD.bazel | 8 -- haskell/defs.bzl | 3 - haskell/private/haskell_impl.bzl | 151 +----------------------------- haskell/toolchain.bzl | 153 ++++++++++++++++++++++++++++++- 4 files changed, 154 insertions(+), 161 deletions(-) diff --git a/haskell/BUILD.bazel b/haskell/BUILD.bazel index 17b92b65f..a16ccded1 100644 --- a/haskell/BUILD.bazel +++ b/haskell/BUILD.bazel @@ -1,9 +1,5 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("@rules_python//python:defs.bzl", "py_binary", "py_library") -load( - "@rules_haskell//haskell:private/haskell_impl.bzl", - "haskell_toolchain_libraries", -) load( "@rules_haskell//haskell:private/cc_wrapper.bzl", "cc_wrapper", @@ -167,10 +163,6 @@ toolchain_type( # implemented, yet. See # https://github.com/bazelbuild/proposals/blob/master/designs/2019-02-12-toolchain-transitions.md # This will need to be revisited once that proposal is implemented. -haskell_toolchain_libraries( - name = "toolchain-libraries", - visibility = ["//visibility:public"], -) config_setting( name = "use_worker", diff --git a/haskell/defs.bzl b/haskell/defs.bzl index 95ea07077..394e57bb8 100644 --- a/haskell/defs.bzl +++ b/haskell/defs.bzl @@ -670,9 +670,6 @@ haskell_toolchain_library = rule( package = attr.string( doc = "The name of a GHC package not built by Bazel. Defaults to the name of the rule.", ), - _toolchain_libraries = attr.label( - default = Label("@rules_haskell//haskell:toolchain-libraries"), - ), ), toolchains = [ "@rules_haskell//haskell:toolchain", diff --git a/haskell/private/haskell_impl.bzl b/haskell/private/haskell_impl.bzl index ef4bc402a..bf8c82c40 100644 --- a/haskell/private/haskell_impl.bzl +++ b/haskell/private/haskell_impl.bzl @@ -795,7 +795,8 @@ def haskell_toolchain_library_impl(ctx): else: package = ctx.label.name - libraries = ctx.attr._toolchain_libraries[HaskellToolchainLibraries].libraries + libraries = hs.toolchain.new_libraries.libraries + target = libraries.get(package) if not target: @@ -823,154 +824,6 @@ The following toolchain libraries are available: )), ] -def _toolchain_library_symlink(dynamic_library): - prefix = dynamic_library.owner.workspace_root.replace("_", "_U").replace("/", "_S") - basename = dynamic_library.basename - return paths.join(prefix, basename) - -def haskell_toolchain_libraries_impl(ctx): - hs = haskell_context(ctx) - with_profiling = is_profiling_enabled(hs) - with_threaded = "-threaded" in hs.toolchain.ghcopts - - cc_toolchain = find_cc_toolchain(ctx) - feature_configuration = cc_common.configure_features( - ctx = ctx, - cc_toolchain = cc_toolchain, - requested_features = ctx.features, - unsupported_features = ctx.disabled_features, - ) - - libraries = hs.toolchain.libraries - - # List of library in left-to-right post-ordering - # Meaning, if package B depends on package A, then A will appear before B. - ordered = depset(transitive = [ - target[HaskellImportHack].transitive_depends - for target in hs.toolchain.libraries.values() - ]) - - library_dict = {} - for package in ordered.to_list(): - target = libraries[package] - - # Construct CcInfo - if with_profiling: - # GHC does not provide dynamic profiling mode libraries. The dynamic - # libraries that are available are missing profiling symbols, that - # other profiling mode build results will reference. Therefore, we - # don't import dynamic libraries in profiling mode. - libs = { - get_static_hs_lib_name(hs.toolchain.version, lib): {"static": lib} - for lib in target[HaskellImportHack].static_profiling_libraries.to_list() - } - else: - # Workaround for https://github.com/tweag/rules_haskell/issues/881 - # Static and dynamic libraries don't necessarily pair up 1 to 1. - # E.g. the rts package in the Unix GHC bindist contains the - # dynamic libHSrts and the static libCffi and libHSrts. - libs = {} - for lib in target[HaskellImportHack].dynamic_libraries.to_list(): - libname = get_dynamic_hs_lib_name(hs.toolchain.version, lib) - if libname == "ffi" and libname in libs: - # Make sure that the file of libffi matching its soname - # ends up in target runfiles. Otherwise, execution will - # fail with "cannot open shared object file" errors. - # On Linux libffi comes in three shapes: - # libffi.so, libffi.so.7, libffi.so.7.1.0 - # (version numbers may vary) - # The soname is then libffi.so.7, meaning, at runtime the - # dynamic linker will look for libffi.so.7. So, that file - # should be the LibraryToLink.dynamic_library. - ext_components = get_lib_extension(lib).split(".") - if len(ext_components) == 2 and ext_components[0] == "so": - libs[libname]["dynamic"] = lib - else: - libs[libname] = {"dynamic": lib} - for lib in target[HaskellImportHack].static_libraries.to_list(): - name = get_static_hs_lib_name(with_profiling, lib) - entry = libs.get(name, {}) - entry["static"] = lib - libs[name] = entry - - # Avoid duplicate runtime and ffi libraries. These libraries come - # in threaded and non-threaded flavors. Depending on the - # compilation mode we want to forward only one or the other. - # XXX: Threaded mode should be a per-target property. Use Bazel - # build configurations and transitions to select the threaded or - # non-threaded runtime and ffi on a per-target basis. - if "HSrts_thr" in libs: - if with_threaded: - libs["HSrts"] = libs["HSrts_thr"] - libs.pop("HSrts_thr") - if "Cffi_thr" in libs: - if with_threaded: - libs["ffi"]["static"] = libs["Cffi_thr"]["static"] - libs.pop("Cffi_thr") - linker_inputs = [ - cc_common.create_linker_input( - owner = ctx.label, - libraries = depset(direct = [ - cc_common.create_library_to_link( - actions = ctx.actions, - feature_configuration = feature_configuration, - dynamic_library = lib.get("dynamic", None), - dynamic_library_symlink_path = - _toolchain_library_symlink(lib["dynamic"]) if lib.get("dynamic") else "", - static_library = lib.get("static", None), - cc_toolchain = cc_toolchain, - ) - for lib in libs.values() - ]), - user_link_flags = depset(direct = target[HaskellImportHack].linkopts), - ), - ] - compilation_context = cc_common.create_compilation_context( - headers = target[HaskellImportHack].headers, - includes = target[HaskellImportHack].includes, - ) - linking_context = cc_common.create_linking_context( - linker_inputs = depset(direct = linker_inputs), - ) - cc_info = CcInfo( - compilation_context = compilation_context, - linking_context = linking_context, - ) - library_dict[package] = struct( - default_info = target[DefaultInfo], - hs_info = target[HaskellInfo], - hs_lib_info = target[HaskellLibraryInfo], - cc_info = cc_common.merge_cc_infos(cc_infos = [cc_info] + [ - library_dict[dep].cc_info - for dep in target[HaskellImportHack].depends - ]), - haddock_info = target[HaddockInfo], - ) - - return [HaskellToolchainLibraries(libraries = library_dict)] - -haskell_toolchain_libraries = rule( - haskell_toolchain_libraries_impl, - attrs = { - "_cc_toolchain": attr.label( - default = Label("@rules_cc//cc:current_cc_toolchain"), - ), - }, - toolchains = use_cc_toolchain() + [ - "@rules_haskell//haskell:toolchain", - ], - fragments = ["cpp"], -) -"""Generate Haskell toolchain libraries. - -This is an internal rule and should not be user facing. - -This rule is a work-around for toolchain transitions not being implemented, -yet. See -https://github.com/bazelbuild/proposals/blob/master/designs/2019-02-12-toolchain-transitions.md -This will need to be revisited once that proposal is implemented. -""" - def haskell_import_impl(ctx): # The `allow_files` attribute of `rule` cannot define patterns of accepted # file extensions like `.so.*`. Instead, we check for the correct file diff --git a/haskell/toolchain.bzl b/haskell/toolchain.bzl index 91c0aa854..3fcea49a8 100644 --- a/haskell/toolchain.bzl +++ b/haskell/toolchain.bzl @@ -24,9 +24,38 @@ load( "ASTERIUS_BINARIES", "asterius_tools_config", ) +load( + ":providers.bzl", + "HaddockInfo", + "HaskellCcLibrariesInfo", + "HaskellInfo", + "HaskellLibraryInfo", + "HaskellProtobufInfo", +) +load( + ":private/path_utils.bzl", + "determine_module_names", + "get_dynamic_hs_lib_name", + "get_lib_extension", + "get_static_hs_lib_name", + "infer_main_module", + "ln", + "match_label", + "parse_pattern", +) +load( + ":private/haskell_impl.bzl", + "HaskellImportHack", + "HaskellToolchainLibraries", +) _GHC_BINARIES = ["ghc", "ghc-pkg", "hsc2hs", "haddock", "ghci", "runghc", "hpc"] +def _toolchain_library_symlink(dynamic_library): + prefix = dynamic_library.owner.workspace_root.replace("_", "_U").replace("/", "_S") + basename = dynamic_library.basename + return paths.join(prefix, basename) + def _run_ghc( hs, cc, @@ -174,6 +203,125 @@ def _lookup_binaries(names, files, version = ""): fail("Cannot find {} in {}".format(tool, files)) return binaries +def _haskell_toolchain_libraries(ctx, libraries): + with_profiling = ctx.var["COMPILATION_MODE"] == "dbg" # TODO is_profiling_enabled(hs) + with_threaded = "-threaded" in ctx.attr.ghcopts + + cc_toolchain = find_cc_toolchain(ctx) + feature_configuration = cc_common.configure_features( + ctx = ctx, + cc_toolchain = cc_toolchain, + requested_features = ctx.features, + unsupported_features = ctx.disabled_features, + ) + + # List of library in left-to-right post-ordering + # Meaning, if package B depends on package A, then A will appear before B. + ordered = depset(transitive = [ + target[HaskellImportHack].transitive_depends + for target in libraries.values() + ]) + + library_dict = {} + for package in ordered.to_list(): + target = libraries[package] + + # Construct CcInfo + additional_link_inputs = [] + if with_profiling: + # GHC does not provide dynamic profiling mode libraries. The dynamic + # libraries that are available are missing profiling symbols, that + # other profiling mode build results will reference. Therefore, we + # don't import dynamic libraries in profiling mode. + libs = { + get_static_hs_lib_name(ctx.attr.version, lib): {"static": lib} + for lib in target[HaskellImportHack].static_profiling_libraries.to_list() + } + else: + # Workaround for https://github.com/tweag/rules_haskell/issues/881 + # Static and dynamic libraries don't necessarily pair up 1 to 1. + # E.g. the rts package in the Unix GHC bindist contains the + # dynamic libHSrts and the static libCffi and libHSrts. + libs = {} + for lib in target[HaskellImportHack].dynamic_libraries.to_list(): + libname = get_dynamic_hs_lib_name(ctx.attr.version, lib) + if libname == "ffi" and libname in libs: + # Make sure that the file of libffi matching its soname + # ends up in target runfiles. Otherwise, execution will + # fail with "cannot open shared object file" errors. + # On Linux libffi comes in three shapes: + # libffi.so, libffi.so.7, libffi.so.7.1.0 + # (version numbers may vary) + # The soname is then libffi.so.7, meaning, at runtime the + # dynamic linker will look for libffi.so.7. So, that file + # should be the LibraryToLink.dynamic_library. + ext_components = get_lib_extension(lib).split(".") + if len(ext_components) == 2 and ext_components[0] == "so": + libs[libname]["dynamic"] = lib + else: + libs[libname] = {"dynamic": lib} + for lib in target[HaskellImportHack].static_libraries.to_list(): + name = get_static_hs_lib_name(with_profiling, lib) + entry = libs.get(name, {}) + entry["static"] = lib + libs[name] = entry + + # Avoid duplicate runtime and ffi libraries. These libraries come + # in threaded and non-threaded flavors. Depending on the + # compilation mode we want to forward only one or the other. + # XXX: Threaded mode should be a per-target property. Use Bazel + # build configurations and transitions to select the threaded or + # non-threaded runtime and ffi on a per-target basis. + if "HSrts_thr" in libs: + if with_threaded: + libs["HSrts"] = libs["HSrts_thr"] + libs.pop("HSrts_thr") + if "Cffi_thr" in libs: + if with_threaded: + libs["ffi"]["static"] = libs["Cffi_thr"]["static"] + libs.pop("Cffi_thr") + linker_inputs = [ + cc_common.create_linker_input( + owner = ctx.label, + libraries = depset(direct = [ + cc_common.create_library_to_link( + actions = ctx.actions, + feature_configuration = feature_configuration, + dynamic_library = lib.get("dynamic", None), + dynamic_library_symlink_path = + _toolchain_library_symlink(lib["dynamic"]) if lib.get("dynamic") else "", + static_library = lib.get("static", None), + cc_toolchain = cc_toolchain, + ) + for lib in libs.values() + ]), + user_link_flags = depset(direct = target[HaskellImportHack].linkopts), + ), + ] + compilation_context = cc_common.create_compilation_context( + headers = target[HaskellImportHack].headers, + includes = target[HaskellImportHack].includes, + ) + linking_context = cc_common.create_linking_context( + linker_inputs = depset(direct = linker_inputs), + ) + cc_info = CcInfo( + compilation_context = compilation_context, + linking_context = linking_context, + ) + library_dict[package] = struct( + default_info = target[DefaultInfo], + hs_info = target[HaskellInfo], + hs_lib_info = target[HaskellLibraryInfo], + cc_info = cc_common.merge_cc_infos(cc_infos = [cc_info] + [ + library_dict[dep].cc_info + for dep in target[HaskellImportHack].depends + ]), + haddock_info = target[HaddockInfo], + ) + + return HaskellToolchainLibraries(libraries = library_dict) + def _haskell_toolchain_impl(ctx): numeric_version = [int(x) for x in ctx.attr.version.split(".")] if numeric_version == [8, 10, 1] or numeric_version == [8, 10, 2]: @@ -313,7 +461,8 @@ def _haskell_toolchain_impl(ctx): package = package, run_ghc = _run_ghc, ), - libraries = libraries, + old_libraries = libraries, + new_libraries = _haskell_toolchain_libraries(ctx, libraries), is_darwin = ctx.attr.is_darwin, is_windows = ctx.attr.is_windows, static_runtime = ctx.attr.static_runtime, @@ -420,6 +569,8 @@ _haskell_toolchain = rule( attrs = dict( common_attrs, ), + toolchains = use_cc_toolchain(), + fragments = ["cpp"], ) def haskell_toolchain( From b7c06af4e15153d59c7ab6df0cfe4cb4410c25a2 Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Mon, 8 Jan 2024 14:07:53 +0100 Subject: [PATCH 2/7] buildifier --- haskell/private/haskell_impl.bzl | 3 --- haskell/toolchain.bzl | 7 ------- 2 files changed, 10 deletions(-) diff --git a/haskell/private/haskell_impl.bzl b/haskell/private/haskell_impl.bzl index bf8c82c40..c242b3298 100644 --- a/haskell/private/haskell_impl.bzl +++ b/haskell/private/haskell_impl.bzl @@ -1,7 +1,6 @@ """Implementation of core Haskell rules""" load("@bazel_skylib//lib:dicts.bzl", "dicts") -load("@rules_cc//cc:find_cc_toolchain.bzl", "use_cc_toolchain") load( ":providers.bzl", "C2hsLibraryInfo", @@ -35,9 +34,7 @@ load(":private/mode.bzl", "is_profiling_enabled") load( ":private/path_utils.bzl", "determine_module_names", - "get_dynamic_hs_lib_name", "get_lib_extension", - "get_static_hs_lib_name", "infer_main_module", "match_label", "parse_pattern", diff --git a/haskell/toolchain.bzl b/haskell/toolchain.bzl index 3fcea49a8..307f73552 100644 --- a/haskell/toolchain.bzl +++ b/haskell/toolchain.bzl @@ -27,21 +27,14 @@ load( load( ":providers.bzl", "HaddockInfo", - "HaskellCcLibrariesInfo", "HaskellInfo", "HaskellLibraryInfo", - "HaskellProtobufInfo", ) load( ":private/path_utils.bzl", - "determine_module_names", "get_dynamic_hs_lib_name", "get_lib_extension", "get_static_hs_lib_name", - "infer_main_module", - "ln", - "match_label", - "parse_pattern", ) load( ":private/haskell_impl.bzl", From 04545440aecf2cc1424addfd7cde263e91a906f0 Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Mon, 8 Jan 2024 14:10:01 +0100 Subject: [PATCH 3/7] Add compatibility `_cc_toolchain` attribute to `_haskell_toolchain` rule --- haskell/toolchain.bzl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/haskell/toolchain.bzl b/haskell/toolchain.bzl index 307f73552..948b6a9bf 100644 --- a/haskell/toolchain.bzl +++ b/haskell/toolchain.bzl @@ -561,6 +561,11 @@ _haskell_toolchain = rule( _haskell_toolchain_impl, attrs = dict( common_attrs, + _cc_toolchain = attr.label( + default = Label( + "@rules_cc//cc:current_cc_toolchain", + ), + ), ), toolchains = use_cc_toolchain(), fragments = ["cpp"], From cee83b1457d616e7ec87b6d01aed484f30c74108 Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Mon, 8 Jan 2024 14:15:19 +0100 Subject: [PATCH 4/7] Remove unused variable --- haskell/toolchain.bzl | 1 - 1 file changed, 1 deletion(-) diff --git a/haskell/toolchain.bzl b/haskell/toolchain.bzl index 948b6a9bf..0abcb0319 100644 --- a/haskell/toolchain.bzl +++ b/haskell/toolchain.bzl @@ -220,7 +220,6 @@ def _haskell_toolchain_libraries(ctx, libraries): target = libraries[package] # Construct CcInfo - additional_link_inputs = [] if with_profiling: # GHC does not provide dynamic profiling mode libraries. The dynamic # libraries that are available are missing profiling symbols, that From b10973c4e37d16b944c838ba7fb386d0086ba77a Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Mon, 8 Jan 2024 14:38:33 +0100 Subject: [PATCH 5/7] Use new rules_nixpkgs name in start script --- start | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start b/start index d74866fa8..17c806b5f 100755 --- a/start +++ b/start @@ -449,8 +449,8 @@ if [ "${MODE}" = "nix" ]; then cat >> .bazelrc <<-EOF # This project uses a GHC provisioned via nix. # We need to use the rules_haskell nix toolchain accordingly: - build --host_platform=@io_tweag_rules_nixpkgs//nixpkgs/platforms:host - run --host_platform=@io_tweag_rules_nixpkgs//nixpkgs/platforms:host + build --host_platform=@rules_nixpkgs_core//platforms:host + run --host_platform=@rules_nixpkgs_core//platforms:host EOF fi From 96a109522b2e062642b0563fa46821cfc26e2e4f Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Mon, 8 Jan 2024 14:52:03 +0100 Subject: [PATCH 6/7] Add cc toolchain to `_ahc_haskell_toolchain` rule --- haskell/toolchain.bzl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/haskell/toolchain.bzl b/haskell/toolchain.bzl index 0abcb0319..1eeb280cb 100644 --- a/haskell/toolchain.bzl +++ b/haskell/toolchain.bzl @@ -541,6 +541,11 @@ _ahc_haskell_toolchain = rule( _haskell_toolchain_impl, attrs = dict( common_attrs, + _cc_toolchain = attr.label( + default = Label( + "@rules_cc//cc:current_cc_toolchain", + ), + ), _exec_nodejs_toolchain = attr.label( default = Label("@rules_haskell//haskell:current_nodejs_toolchain"), cfg = "exec", @@ -554,6 +559,8 @@ _ahc_haskell_toolchain = rule( cfg = "exec", ), ), + toolchains = use_cc_toolchain(), + fragments = ["cpp"], ) _haskell_toolchain = rule( From f9b29bf885704f100998214704d6012f1f60abe6 Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Mon, 8 Jan 2024 17:02:32 +0100 Subject: [PATCH 7/7] Make cc toolchains mandatory --- haskell/toolchain.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haskell/toolchain.bzl b/haskell/toolchain.bzl index 1eeb280cb..1fe85f9b3 100644 --- a/haskell/toolchain.bzl +++ b/haskell/toolchain.bzl @@ -559,7 +559,7 @@ _ahc_haskell_toolchain = rule( cfg = "exec", ), ), - toolchains = use_cc_toolchain(), + toolchains = use_cc_toolchain(mandatory = True), fragments = ["cpp"], ) @@ -573,7 +573,7 @@ _haskell_toolchain = rule( ), ), ), - toolchains = use_cc_toolchain(), + toolchains = use_cc_toolchain(mandatory = True), fragments = ["cpp"], )