Skip to content

Commit

Permalink
Merge pull request #1914 from tweag/ylecornec/bindist_extension
Browse files Browse the repository at this point in the history
haskell_toolchains extension
  • Loading branch information
mergify[bot] committed Jun 29, 2023
2 parents cd23a0c + eefde79 commit 7600541
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 69 deletions.
46 changes: 25 additions & 21 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -83,6 +80,31 @@ 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",
)

# 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",
)

# Setup node toolchain and install webpack for asterius.
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")

Expand Down Expand Up @@ -165,24 +187,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(
Expand Down
7 changes: 7 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ load("//extensions:rules_haskell_dependencies.bzl", _repositories_3 = "repositor

_repositories_3(bzlmod = False)

load(
"@rules_haskell//haskell:ghc_bindist.bzl",
"haskell_register_ghc_bindists",
)

haskell_register_ghc_bindists()

load(
"@rules_haskell//haskell/asterius:repositories.bzl",
"asterius_dependencies_bindist",
Expand Down
162 changes: 162 additions & 0 deletions extensions/haskell_toolchains.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
""" 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,
),
)

if module.tags.bindists and not found_bindists:
# We only consider the first `bindists` tag accross all modules, because subsequent
# ones would have the same constraints and lower priority.
found_bindists = True
bindists_tag = module.tags.bindists[0]
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,
},
)
3 changes: 0 additions & 3 deletions extensions/rules_haskell_dependencies.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
43 changes: 33 additions & 10 deletions haskell/ghc_bindist.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,8 @@ _ghc_bindist = repository_rule(
},
)

def _ghc_bindist_toolchain_impl(ctx):
os, _, arch = ctx.attr.target.partition("_")
def ghc_bindist_toolchain_declaration(target, bindist_name, toolchain_name):
os, _, arch = target.partition("_")
os_constraint = {
"darwin": "osx",
"linux": "linux",
Expand All @@ -290,21 +290,29 @@ def _ghc_bindist_toolchain_impl(ctx):
"@platforms//cpu:{}".format(cpu_constraint),
]
target_constraints = exec_constraints
ctx.file(
"BUILD",
executable = False,
content = """
return """
toolchain(
name = "toolchain",
name = "{toolchain_name}",
toolchain_type = "@rules_haskell//haskell:toolchain",
toolchain = "@{bindist_name}//:toolchain-impl",
exec_compatible_with = {exec_constraints},
target_compatible_with = {target_constraints},
)
""".format(
""".format(
toolchain_name = toolchain_name,
bindist_name = bindist_name,
exec_constraints = exec_constraints,
target_constraints = target_constraints,
)

def _ghc_bindist_toolchain_impl(ctx):
ctx.file(
"BUILD",
executable = False,
content = ghc_bindist_toolchain_declaration(
target = ctx.attr.target,
bindist_name = ctx.attr.bindist_name,
exec_constraints = exec_constraints,
target_constraints = target_constraints,
toolchain_name = "toolchain",
),
)

Expand Down Expand Up @@ -342,6 +350,21 @@ _windows_cc_toolchain = repository_rule(
},
)

# Toolchains declarations for bindists used by the `haskell_toolchains` module
# extension to register all the haskell toolchains in the same BUILD file
def ghc_bindists_toolchain_declarations(version):
version = version or _GHC_DEFAULT_VERSION
if not GHC_BINDIST.get(version):
fail("Binary distribution of GHC {} not available.".format(version))
return [
ghc_bindist_toolchain_declaration(
target = target,
bindist_name = "rules_haskell_ghc_{}".format(target),
toolchain_name = "rules_haskell_ghc_{}".format(target),
)
for target in GHC_BINDIST[version]
]

def ghc_bindist(
name,
version,
Expand Down
8 changes: 0 additions & 8 deletions non_module_dev_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ load(
"@rules_haskell//haskell:nixpkgs.bzl",
"haskell_register_ghc_nixpkgs",
)
load(
"@rules_haskell//haskell:ghc_bindist.bzl",
"haskell_register_ghc_bindists",
)
load(
"@rules_haskell//docs/pandoc:pandoc.bzl",
"import_pandoc_bindists",
Expand Down Expand Up @@ -85,10 +81,6 @@ def repositories(*, bzlmod):
register = not bzlmod,
)

haskell_register_ghc_bindists(
register = not bzlmod,
)

nixpkgs_python_configure(
repository = "@nixpkgs_default",
register = not bzlmod,
Expand Down
Loading

0 comments on commit 7600541

Please sign in to comment.