From 3f8eedc54f3b31d0775b9faf30d43209a91bef76 Mon Sep 17 00:00:00 2001 From: Yves-Stan Le Cornec Date: Thu, 29 Jun 2023 14:19:56 +0200 Subject: [PATCH] Add haskell_toolchains module extension This extension is used to register the haskell bindists with bzlmod. --- MODULE.bazel | 48 ++++--- extensions/haskell_toolchains.bzl | 161 ++++++++++++++++++++++ extensions/rules_haskell_dependencies.bzl | 3 - rules_haskell_tests/MODULE.bazel | 82 +++++++++-- 4 files changed, 255 insertions(+), 39 deletions(-) create mode 100644 extensions/haskell_toolchains.bzl diff --git a/MODULE.bazel b/MODULE.bazel index cece35f8ad..038d276228 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -66,15 +66,12 @@ rules_haskell_dependencies = use_extension( use_repo( rules_haskell_dependencies, - "rules_haskell_python_local", "rules_haskell_worker_dependencies", "rules_haskell_stack_update", "rules_haskell_stack", "Cabal", ) -register_toolchains("@rules_haskell_python_local//:toolchain") - asterius = use_extension("@rules_haskell//haskell/asterius:extension.bzl", "rules_haskell_asterius") use_repo( @@ -83,6 +80,33 @@ use_repo( "rules_haskell_asterius_build_setting", ) +haskell_toolchains = use_extension( + "@rules_haskell//extensions:haskell_toolchains.bzl", + "haskell_toolchains", +) + +haskell_toolchains.bindists() + +use_repo( + haskell_toolchains, + "all_bindist_toolchains", + "rules_haskell_python_local", + "rules_haskell_sh_posix_local", +) + +# We need to register the nix toolchain before the bindist ones so it +# take precedence when we use the nixpkgs config. +register_toolchains( + "@rules_haskell_ghc_nixpkgs_toolchain//:toolchain", + dev_dependency = True, +) + +register_toolchains( + "@all_bindist_toolchains//:all", + "@rules_haskell_python_local//:toolchain", + "@rules_haskell_sh_posix_local//:all", +) + # Setup node toolchain and install webpack for asterius. node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node") @@ -165,24 +189,6 @@ use_repo( "rules_haskell_ghc_nixpkgs", "nixpkgs_default", "rules_haskell_ghc_nixpkgs_toolchain", - "rules_haskell_ghc_darwin_amd64-toolchain", - "rules_haskell_ghc_darwin_arm64-toolchain", - "rules_haskell_ghc_linux_amd64-toolchain", - "rules_haskell_ghc_windows_amd64-toolchain", - "rules_haskell_ghc_linux_arm64-toolchain", - "rules_haskell_ghc_windows_amd64_cc_toolchain", -) - -register_toolchains( - "@rules_haskell_ghc_nixpkgs_toolchain//:toolchain", - "@rules_haskell_ghc_darwin_amd64-toolchain//:toolchain", - "@rules_haskell_ghc_darwin_arm64-toolchain//:toolchain", - "@rules_haskell_ghc_linux_amd64-toolchain//:toolchain", - "@rules_haskell_ghc_linux_arm64-toolchain//:toolchain", - "@rules_haskell_ghc_windows_amd64-toolchain//:toolchain", - "@rules_haskell_ghc_windows_amd64-toolchain//:toolchain", - "@rules_haskell_ghc_windows_amd64_cc_toolchain//:windows_cc_toolchain", - dev_dependency = True, ) use_repo( diff --git a/extensions/haskell_toolchains.bzl b/extensions/haskell_toolchains.bzl new file mode 100644 index 0000000000..121f6ae9fc --- /dev/null +++ b/extensions/haskell_toolchains.bzl @@ -0,0 +1,161 @@ +""" Module extension to install bindist haskell toolchains""" + +load( + "@rules_haskell//haskell:ghc_bindist.bzl", + "ghc_bindist", + "ghc_bindist_toolchain_declaration", + "ghc_bindists_toolchain_declarations", + "haskell_register_ghc_bindists", +) + +_bindists_tag = tag_class( + attrs = { + "version": attr.string( + doc = "[see rules_haskell_toolchains](toolchain.html#rules_haskell_toolchains-version)", + ), + "ghcopts": attr.string_list( + doc = "[see rules_haskell_toolchains](toolchain.html#rules_haskell_toolchains-ghcopts)", + ), + "haddock_flags": attr.string_list( + doc = "haddock_flags: [see rules_haskell_toolchains](toolchain.html#rules_haskell_toolchains-haddock_flags)", + ), + "repl_ghci_args": attr.string_list( + doc = "[see rules_haskell_toolchains](toolchain.html#rules_haskell_toolchains-repl_ghci_args)", + ), + "cabalopts": attr.string_list( + doc = "[see rules_haskell_toolchains](toolchain.html#rules_haskell_toolchains-cabalopts)", + ), + "locale": attr.string( + doc = "[see rules_haskell_toolchains](toolchain.html#rules_haskell_toolchains-locale)", + ), + }, + doc = """See [rules_haskell_toolchains](toolchain.html#rules_haskell_toolchains). + Only the first `bindists` tag is taken into account (according to the iteration order over modules). + """, +) + +_bindist_tag = tag_class( + attrs = { + "version": attr.string( + mandatory = True, + doc = "The desired GHC version", + ), + "target": attr.string( + mandatory = True, + doc = "The desired architecture (See [ghc_bindist_generated.bzl](https://github.com/tweag/rules_haskell/blob/master/haskell/private/ghc_bindist_generated.bzl))", + ), + "ghcopts": attr.string_list( + doc = "[see rules_haskell_toolchains](toolchain.html#rules_haskell_toolchains-ghcopts)", + ), + "haddock_flags": attr.string_list( + doc = "[see rules_haskell_toolchains](toolchain.html#rules_haskell_toolchains-haddock_flags)", + ), + "repl_ghci_args": attr.string_list( + doc = "[see rules_haskell_toolchains](toolchain.html#rules_haskell_toolchains-repl_ghci_args) ", + ), + "cabalopts": attr.string_list( + doc = "[see rules_haskell_toolchains](toolchain.html#rules_haskell_toolchains-cabalopts)", + ), + "locale": attr.string( + doc = "[see rules_haskell_toolchains](toolchain.html#rules_haskell_toolchains-locale)", + ), + }, + doc = "Declares and configure a bindist haskell toolchain. See [ghc_bindist](ghc_bindist.html#ghc_bindist).", +) + +def _all_toolchains_impl(rctx): + content = "\n".join(rctx.attr.toolchains) + rctx.file("BUILD.bazel", content = content) + +_all_toolchains = repository_rule( + implementation = _all_toolchains_impl, + attrs = { + "toolchains": attr.string_list( + doc = "All the `toolchain(...)` declarations for the bindist toolchains as string", + ), + }, + doc = """ Used to generate the `all_bindist_toolchains` external repository. + We can then invoke `register_toolchains("@all_bindist_toolchains//:all")` in the MODULE.bazel file. + """, +) + +def _haskell_toolchains_impl(mctx): + # We gather the declarations of all the toolchains in the `toolchain_declarations` list + # in order to write them to the `@all_bindist_toolchains` repository. + + # The code could be simplified a bit by registering aliases to the + # `toolchain` rules, once the following issue is resolved + # https://github.com/bazelbuild/bazel/issues/16298 + toolchain_declarations = [] + + found_bindists = False + for module in mctx.modules: + bindist_targets = [] + for bindist_tag in module.tags.bindist: + name = "bindist_{}_{}_{}".format(module.name, module.version, bindist_tag.target) + if bindist_tag.target in bindist_targets: + fail( + """Module "{module}~{version}" used the "bindist" tag twice with the "{target}" target.""".format( + target = bindist_tag.target, + module = module.name, + version = module.version, + ), + ) + else: + bindist_targets.append(bindist_tag.target) + ghc_bindist( + name = name, + version = bindist_tag.version, + target = bindist_tag.target, + ghcopts = bindist_tag.ghcopts, + haddock_flags = bindist_tag.haddock_flags, + repl_ghci_args = bindist_tag.repl_ghci_args, + cabalopts = bindist_tag.cabalopts, + locale = bindist_tag.locale, + register = False, + ) + toolchain_declarations.append( + ghc_bindist_toolchain_declaration( + target = bindist_tag.target, + bindist_name = name, + toolchain_name = name, + ), + ) + + if len(module.tags.bindists) > 1: + fail( + """Module "{module}~{version}" used the "bindists" tag more than once.""".format( + module = module.name, + version = module.version, + ), + ) + for bindists_tag in module.tags.bindists: + # We only consider the first `bindists` tag accross all modules, because subsequent + # ones would have the same constraints and lower priority. + if not found_bindists: + found_bindists = True + haskell_register_ghc_bindists( + version = bindists_tag.version, + ghcopts = bindists_tag.ghcopts, + haddock_flags = bindists_tag.haddock_flags, + repl_ghci_args = bindists_tag.repl_ghci_args, + cabalopts = bindists_tag.cabalopts, + locale = bindists_tag.locale, + register = False, + ) + toolchain_declarations.extend( + ghc_bindists_toolchain_declarations(bindists_tag.version), + ) + + _all_toolchains( + name = "all_bindist_toolchains", + toolchains = toolchain_declarations, + ) + +haskell_toolchains = module_extension( + implementation = _haskell_toolchains_impl, + tag_classes = { + "bindist": _bindist_tag, + "bindists": _bindists_tag, + }, +) diff --git a/extensions/rules_haskell_dependencies.bzl b/extensions/rules_haskell_dependencies.bzl index 2d0e5073ca..11e46bf10b 100644 --- a/extensions/rules_haskell_dependencies.bzl +++ b/extensions/rules_haskell_dependencies.bzl @@ -12,9 +12,6 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") def repositories(*, bzlmod): rules_haskell_dependencies_bzlmod() - if LOCAL_PYTHON_REPO_NAME not in native.existing_rules(): - configure_python3_toolchain(name = LOCAL_PYTHON_REPO_NAME, register = not bzlmod) - # For persistent worker (tools/worker) # TODO: make this customizable via a module extension so that users # of persistant workers can use dependencies compatible with the diff --git a/rules_haskell_tests/MODULE.bazel b/rules_haskell_tests/MODULE.bazel index 61a748e284..6044f43619 100644 --- a/rules_haskell_tests/MODULE.bazel +++ b/rules_haskell_tests/MODULE.bazel @@ -124,14 +124,7 @@ use_repo( non_modules_deps_1, "glibc_locales", "nixpkgs_default", - "rules_haskell_ghc_darwin_amd64-toolchain", - "rules_haskell_ghc_darwin_arm64-toolchain", - "rules_haskell_ghc_linux_amd64-toolchain", - "rules_haskell_ghc_windows_amd64-toolchain", - "rules_haskell_ghc_linux_arm64-toolchain", - "rules_haskell_ghc_windows_amd64_cc_toolchain", "nixpkgs_python_toolchain", - "rules_haskell_python_local", "nixpkgs_config_cc", "nixpkgs_config_cc_info", "nixpkgs_config_cc_toolchains", @@ -155,7 +148,6 @@ register_toolchains( "@linux_amd64_asterius-toolchain//:toolchain", "@linux_amd64_asterius-toolchain//:asterius_toolchain", "@linux_amd64_asterius-toolchain//:wasm_cc_toolchain", - "@rules_haskell_python_local//:toolchain", "@nixpkgs_python_toolchain//:toolchain", ) @@ -195,13 +187,6 @@ use_repo( register_toolchains( "@rules_haskell_ghc_nixpkgs_toolchain//:toolchain", - "@rules_haskell_ghc_darwin_amd64-toolchain//:toolchain", - "@rules_haskell_ghc_darwin_arm64-toolchain//:toolchain", - "@rules_haskell_ghc_linux_amd64-toolchain//:toolchain", - "@rules_haskell_ghc_linux_arm64-toolchain//:toolchain", - "@rules_haskell_ghc_windows_amd64-toolchain//:toolchain", - "@rules_haskell_ghc_windows_amd64-toolchain//:toolchain", - "@rules_haskell_ghc_windows_amd64_cc_toolchain//:windows_cc_toolchain", ) [ @@ -308,3 +293,70 @@ use_repo( rules_haskell_dependencies, "zlib", ) + +haskell_toolchains = use_extension( + "@rules_haskell//extensions:haskell_toolchains.bzl", + "haskell_toolchains", +) + +test_ghc_version = "9.2.5" + +test_ghcopts = [ + "-XStandaloneDeriving", # Flag used at compile time + "-threaded", # Flag used at link time + # Used by `tests/repl-flags` + "-DTESTS_TOOLCHAIN_COMPILER_FLAGS", + # this is the default, so it does not harm other tests + "-XNoOverloadedStrings", +] + +test_haddock_flags = ["-U"] + +test_repl_ghci_args = [ + # The repl test will need this flag, but set by the local + # `repl_ghci_args`. + "-UTESTS_TOOLCHAIN_REPL_FLAGS", + # The repl test will need OverloadedString + "-XOverloadedStrings", +] + +test_cabalopts = [ + # Used by `tests/cabal-toolchain-flags` + "--ghc-option=-DTESTS_TOOLCHAIN_CABALOPTS", + "--haddock-option=--optghc=-DTESTS_TOOLCHAIN_CABALOPTS", +] + +cabalopts_windows = test_cabalopts + [ + # To avoid ghcide linking errors with heapsize on Windows of the form + # + # unknown symbol `heap_view_closurePtrs' + # + # See https://github.com/haskell/ghcide/pull/954 + "--disable-library-for-ghci", +] + +haskell_toolchains.bindists( + cabalopts = test_cabalopts, + ghcopts = test_ghcopts, + haddock_flags = test_haddock_flags, + repl_ghci_args = test_repl_ghci_args, +) + +# We cannot configure cabalopts depending on the platform before calling haskell_toolchains.bindists: +# https://github.com/bazelbuild/bazel/issues/17880 +# So we add toolchains for windows separately, they take precedence over the one generated by +# haskell_toolchains.bindists and use the `cabalopts_windows` variable. +[ + haskell_toolchains.bindist( + cabalopts = cabalopts_windows, + ghcopts = test_ghcopts, + haddock_flags = test_haddock_flags, + repl_ghci_args = test_repl_ghci_args, + target = target, + version = test_ghc_version, + ) + for target in [ + "windows_amd64", + "windows_arm64", + ] +]