feat(third_party/bazel): Check in rules_haskell from Tweag
This commit is contained in:
parent
2eb1dc26e4
commit
f723b8b878
479 changed files with 51484 additions and 0 deletions
668
third_party/bazel/rules_haskell/haskell/private/haskell_impl.bzl
vendored
Normal file
668
third_party/bazel/rules_haskell/haskell/private/haskell_impl.bzl
vendored
Normal file
|
|
@ -0,0 +1,668 @@
|
|||
"""Implementation of core Haskell rules"""
|
||||
|
||||
load(
|
||||
"@io_tweag_rules_haskell//haskell:providers.bzl",
|
||||
"C2hsLibraryInfo",
|
||||
"HaskellInfo",
|
||||
"HaskellLibraryInfo",
|
||||
"HaskellPrebuiltPackageInfo",
|
||||
)
|
||||
load(":cc.bzl", "cc_interop_info")
|
||||
load(
|
||||
":private/actions/link.bzl",
|
||||
"link_binary",
|
||||
"link_library_dynamic",
|
||||
"link_library_static",
|
||||
)
|
||||
load(":private/actions/package.bzl", "package")
|
||||
load(":private/actions/repl.bzl", "build_haskell_repl")
|
||||
load(":private/actions/runghc.bzl", "build_haskell_runghc")
|
||||
load(":private/context.bzl", "haskell_context")
|
||||
load(":private/dependencies.bzl", "gather_dep_info")
|
||||
load(":private/java.bzl", "java_interop_info")
|
||||
load(":private/mode.bzl", "is_profiling_enabled")
|
||||
load(
|
||||
":private/path_utils.bzl",
|
||||
"ln",
|
||||
"match_label",
|
||||
"parse_pattern",
|
||||
"target_unique_name",
|
||||
)
|
||||
load(":private/pkg_id.bzl", "pkg_id")
|
||||
load(":private/set.bzl", "set")
|
||||
load(":private/version_macros.bzl", "generate_version_macros")
|
||||
load(":providers.bzl", "GhcPluginInfo", "HaskellCoverageInfo")
|
||||
load("@bazel_skylib//lib:paths.bzl", "paths")
|
||||
load("@bazel_skylib//lib:collections.bzl", "collections")
|
||||
load("@bazel_skylib//lib:shell.bzl", "shell")
|
||||
|
||||
def _prepare_srcs(srcs):
|
||||
srcs_files = []
|
||||
import_dir_map = {}
|
||||
|
||||
for src in srcs:
|
||||
# If it has the "files" attribute, it must be a Target
|
||||
if hasattr(src, "files"):
|
||||
if C2hsLibraryInfo in src:
|
||||
srcs_files += src.files.to_list()
|
||||
for f in src.files.to_list():
|
||||
import_dir_map[f] = src[C2hsLibraryInfo].import_dir
|
||||
else:
|
||||
srcs_files += src.files.to_list()
|
||||
|
||||
# otherwise it's just a file
|
||||
|
||||
else:
|
||||
srcs_files.append(src)
|
||||
|
||||
return srcs_files, import_dir_map
|
||||
|
||||
def haskell_test_impl(ctx):
|
||||
return _haskell_binary_common_impl(ctx, is_test = True)
|
||||
|
||||
def haskell_binary_impl(ctx):
|
||||
return _haskell_binary_common_impl(ctx, is_test = False)
|
||||
|
||||
def _should_inspect_coverage(ctx, hs, is_test):
|
||||
return hs.coverage_enabled and is_test
|
||||
|
||||
def _coverage_enabled_for_target(coverage_source_patterns, label):
|
||||
for pat in coverage_source_patterns:
|
||||
if match_label(pat, label):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
# Mix files refer to genfile srcs including their root. Therefore, we
|
||||
# must condition the src filepaths passed in for coverage to match.
|
||||
def _condition_coverage_src(hs, src):
|
||||
if not src.path.startswith(hs.genfiles_dir.path):
|
||||
return src
|
||||
|
||||
""" Genfiles have the genfile directory as part of their path,
|
||||
so declaring a file with the sample path actually makes the new
|
||||
file double-qualified by the genfile directory.
|
||||
|
||||
This is necessary because mix files capture the genfile
|
||||
path before compilation, and then expect those files to be
|
||||
qualified by the genfile directory when `hpc report` or
|
||||
`hpc markup` are used. But, genfiles included as runfiles
|
||||
are no longer qualified. So, double-qualifying them results in
|
||||
only one level of qualification as runfiles.
|
||||
"""
|
||||
conditioned_src = hs.actions.declare_file(src.path)
|
||||
hs.actions.run_shell(
|
||||
inputs = [src],
|
||||
outputs = [conditioned_src],
|
||||
arguments = [
|
||||
src.path,
|
||||
conditioned_src.path,
|
||||
],
|
||||
command = """
|
||||
mkdir -p $(dirname "$2") && cp "$1" "$2"
|
||||
""",
|
||||
)
|
||||
|
||||
return conditioned_src
|
||||
|
||||
def _haskell_binary_common_impl(ctx, is_test):
|
||||
hs = haskell_context(ctx)
|
||||
dep_info = gather_dep_info(ctx, ctx.attr.deps)
|
||||
plugin_dep_info = gather_dep_info(
|
||||
ctx,
|
||||
[dep for plugin in ctx.attr.plugins for dep in plugin[GhcPluginInfo].deps],
|
||||
)
|
||||
|
||||
# Add any interop info for other languages.
|
||||
cc = cc_interop_info(ctx)
|
||||
java = java_interop_info(ctx)
|
||||
|
||||
with_profiling = is_profiling_enabled(hs)
|
||||
srcs_files, import_dir_map = _prepare_srcs(ctx.attr.srcs)
|
||||
inspect_coverage = _should_inspect_coverage(ctx, hs, is_test)
|
||||
|
||||
c = hs.toolchain.actions.compile_binary(
|
||||
hs,
|
||||
cc,
|
||||
java,
|
||||
dep_info,
|
||||
plugin_dep_info,
|
||||
srcs = srcs_files,
|
||||
ls_modules = ctx.executable._ls_modules,
|
||||
import_dir_map = import_dir_map,
|
||||
extra_srcs = depset(ctx.files.extra_srcs),
|
||||
user_compile_flags = ctx.attr.compiler_flags,
|
||||
dynamic = False if hs.toolchain.is_windows else not ctx.attr.linkstatic,
|
||||
with_profiling = False,
|
||||
main_function = ctx.attr.main_function,
|
||||
version = ctx.attr.version,
|
||||
inspect_coverage = inspect_coverage,
|
||||
plugins = ctx.attr.plugins,
|
||||
)
|
||||
|
||||
# gather intermediary code coverage instrumentation data
|
||||
coverage_data = c.coverage_data
|
||||
for dep in ctx.attr.deps:
|
||||
if HaskellCoverageInfo in dep:
|
||||
coverage_data += dep[HaskellCoverageInfo].coverage_data
|
||||
|
||||
c_p = None
|
||||
|
||||
if with_profiling:
|
||||
c_p = hs.toolchain.actions.compile_binary(
|
||||
hs,
|
||||
cc,
|
||||
java,
|
||||
dep_info,
|
||||
plugin_dep_info,
|
||||
srcs = srcs_files,
|
||||
ls_modules = ctx.executable._ls_modules,
|
||||
import_dir_map = import_dir_map,
|
||||
# NOTE We must make the object files compiled without profiling
|
||||
# available to this step for TH to work, presumably because GHC is
|
||||
# linked against RTS without profiling.
|
||||
extra_srcs = depset(transitive = [
|
||||
depset(ctx.files.extra_srcs),
|
||||
depset([c.objects_dir]),
|
||||
]),
|
||||
user_compile_flags = ctx.attr.compiler_flags,
|
||||
# NOTE We can't have profiling and dynamic code at the
|
||||
# same time, see:
|
||||
# https://ghc.haskell.org/trac/ghc/ticket/15394
|
||||
dynamic = False,
|
||||
with_profiling = True,
|
||||
main_function = ctx.attr.main_function,
|
||||
version = ctx.attr.version,
|
||||
plugins = ctx.attr.plugins,
|
||||
)
|
||||
|
||||
(binary, solibs) = link_binary(
|
||||
hs,
|
||||
cc,
|
||||
dep_info,
|
||||
ctx.files.extra_srcs,
|
||||
ctx.attr.compiler_flags,
|
||||
c_p.objects_dir if with_profiling else c.objects_dir,
|
||||
dynamic = False if hs.toolchain.is_windows else not ctx.attr.linkstatic,
|
||||
with_profiling = with_profiling,
|
||||
version = ctx.attr.version,
|
||||
)
|
||||
|
||||
hs_info = HaskellInfo(
|
||||
package_ids = dep_info.package_ids,
|
||||
package_databases = dep_info.package_databases,
|
||||
version_macros = set.empty(),
|
||||
source_files = c.source_files,
|
||||
extra_source_files = c.extra_source_files,
|
||||
import_dirs = c.import_dirs,
|
||||
static_libraries = dep_info.static_libraries,
|
||||
static_libraries_prof = dep_info.static_libraries_prof,
|
||||
dynamic_libraries = dep_info.dynamic_libraries,
|
||||
interface_dirs = dep_info.interface_dirs,
|
||||
compile_flags = c.compile_flags,
|
||||
prebuilt_dependencies = dep_info.prebuilt_dependencies,
|
||||
cc_dependencies = dep_info.cc_dependencies,
|
||||
transitive_cc_dependencies = dep_info.transitive_cc_dependencies,
|
||||
)
|
||||
cc_info = cc_common.merge_cc_infos(
|
||||
cc_infos = [dep[CcInfo] for dep in ctx.attr.deps if CcInfo in dep],
|
||||
)
|
||||
|
||||
target_files = depset([binary])
|
||||
|
||||
build_haskell_repl(
|
||||
hs,
|
||||
ghci_script = ctx.file._ghci_script,
|
||||
ghci_repl_wrapper = ctx.file._ghci_repl_wrapper,
|
||||
user_compile_flags = ctx.attr.compiler_flags,
|
||||
repl_ghci_args = ctx.attr.repl_ghci_args,
|
||||
output = ctx.outputs.repl,
|
||||
package_databases = dep_info.package_databases,
|
||||
version = ctx.attr.version,
|
||||
hs_info = hs_info,
|
||||
)
|
||||
|
||||
# XXX Temporary backwards compatibility hack. Remove eventually.
|
||||
# See https://github.com/tweag/rules_haskell/pull/460.
|
||||
ln(hs, ctx.outputs.repl, ctx.outputs.repl_deprecated)
|
||||
|
||||
build_haskell_runghc(
|
||||
hs,
|
||||
runghc_wrapper = ctx.file._ghci_repl_wrapper,
|
||||
extra_args = ctx.attr.runcompile_flags,
|
||||
user_compile_flags = ctx.attr.compiler_flags,
|
||||
output = ctx.outputs.runghc,
|
||||
package_databases = dep_info.package_databases,
|
||||
version = ctx.attr.version,
|
||||
hs_info = hs_info,
|
||||
)
|
||||
|
||||
executable = binary
|
||||
extra_runfiles = []
|
||||
|
||||
if inspect_coverage:
|
||||
binary_path = paths.join(ctx.workspace_name, binary.short_path)
|
||||
hpc_path = paths.join(ctx.workspace_name, hs.toolchain.tools.hpc.short_path)
|
||||
tix_file_path = hs.label.name + ".tix"
|
||||
mix_file_paths = [
|
||||
paths.join(ctx.workspace_name, datum.mix_file.short_path)
|
||||
for datum in coverage_data
|
||||
]
|
||||
mix_file_paths = collections.uniq(mix_file_paths) # remove duplicates
|
||||
|
||||
# find which modules to exclude from coverage analysis, by using the specified source patterns
|
||||
raw_coverage_source_patterns = ctx.attr.experimental_coverage_source_patterns
|
||||
coverage_source_patterns = [parse_pattern(ctx, pat) for pat in raw_coverage_source_patterns]
|
||||
modules_to_exclude = [paths.split_extension(datum.mix_file.basename)[0] for datum in coverage_data if not _coverage_enabled_for_target(coverage_source_patterns, datum.target_label)]
|
||||
modules_to_exclude = collections.uniq(modules_to_exclude) # remove duplicates
|
||||
|
||||
expected_covered_expressions_percentage = ctx.attr.expected_covered_expressions_percentage
|
||||
expected_uncovered_expression_count = ctx.attr.expected_uncovered_expression_count
|
||||
strict_coverage_analysis = ctx.attr.strict_coverage_analysis
|
||||
coverage_report_format = ctx.attr.coverage_report_format
|
||||
|
||||
if coverage_report_format != "text" and coverage_report_format != "html":
|
||||
fail("""haskell_test attribute "coverage_report_format" must be one of "text" or "html".""")
|
||||
|
||||
wrapper = hs.actions.declare_file("{}_coverage/coverage_wrapper.sh".format(ctx.label.name))
|
||||
ctx.actions.expand_template(
|
||||
template = ctx.file._coverage_wrapper_template,
|
||||
output = wrapper,
|
||||
substitutions = {
|
||||
"{binary_path}": shell.quote(binary_path),
|
||||
"{hpc_path}": shell.quote(hpc_path),
|
||||
"{tix_file_path}": shell.quote(tix_file_path),
|
||||
"{expected_covered_expressions_percentage}": str(expected_covered_expressions_percentage),
|
||||
"{expected_uncovered_expression_count}": str(expected_uncovered_expression_count),
|
||||
"{mix_file_paths}": shell.array_literal(mix_file_paths),
|
||||
"{modules_to_exclude}": shell.array_literal(modules_to_exclude),
|
||||
"{strict_coverage_analysis}": str(strict_coverage_analysis),
|
||||
"{coverage_report_format}": shell.quote(ctx.attr.coverage_report_format),
|
||||
"{package_path}": shell.quote(ctx.label.package),
|
||||
},
|
||||
is_executable = True,
|
||||
)
|
||||
executable = wrapper
|
||||
mix_runfiles = [datum.mix_file for datum in coverage_data]
|
||||
srcs_runfiles = [_condition_coverage_src(hs, datum.src_file) for datum in coverage_data]
|
||||
extra_runfiles = [
|
||||
ctx.file._bash_runfiles,
|
||||
hs.toolchain.tools.hpc,
|
||||
binary,
|
||||
] + mix_runfiles + srcs_runfiles
|
||||
|
||||
return [
|
||||
hs_info,
|
||||
cc_info,
|
||||
DefaultInfo(
|
||||
executable = executable,
|
||||
files = target_files,
|
||||
runfiles = ctx.runfiles(
|
||||
files =
|
||||
solibs +
|
||||
extra_runfiles,
|
||||
collect_data = True,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
def haskell_library_impl(ctx):
|
||||
hs = haskell_context(ctx)
|
||||
dep_info = gather_dep_info(ctx, ctx.attr.deps)
|
||||
plugin_dep_info = gather_dep_info(
|
||||
ctx,
|
||||
[dep for plugin in ctx.attr.plugins for dep in plugin[GhcPluginInfo].deps],
|
||||
)
|
||||
version = ctx.attr.version if ctx.attr.version else None
|
||||
my_pkg_id = pkg_id.new(ctx.label, version)
|
||||
with_profiling = is_profiling_enabled(hs)
|
||||
with_shared = False if hs.toolchain.is_windows else not ctx.attr.linkstatic
|
||||
|
||||
# Add any interop info for other languages.
|
||||
cc = cc_interop_info(ctx)
|
||||
java = java_interop_info(ctx)
|
||||
|
||||
srcs_files, import_dir_map = _prepare_srcs(ctx.attr.srcs)
|
||||
other_modules = ctx.attr.hidden_modules
|
||||
exposed_modules_reexports = _exposed_modules_reexports(ctx.attr.exports)
|
||||
|
||||
c = hs.toolchain.actions.compile_library(
|
||||
hs,
|
||||
cc,
|
||||
java,
|
||||
dep_info,
|
||||
plugin_dep_info,
|
||||
srcs = srcs_files,
|
||||
ls_modules = ctx.executable._ls_modules,
|
||||
other_modules = other_modules,
|
||||
exposed_modules_reexports = exposed_modules_reexports,
|
||||
import_dir_map = import_dir_map,
|
||||
extra_srcs = depset(ctx.files.extra_srcs),
|
||||
user_compile_flags = ctx.attr.compiler_flags,
|
||||
with_shared = with_shared,
|
||||
with_profiling = False,
|
||||
my_pkg_id = my_pkg_id,
|
||||
plugins = ctx.attr.plugins,
|
||||
)
|
||||
|
||||
c_p = None
|
||||
|
||||
if with_profiling:
|
||||
c_p = hs.toolchain.actions.compile_library(
|
||||
hs,
|
||||
cc,
|
||||
java,
|
||||
dep_info,
|
||||
plugin_dep_info,
|
||||
srcs = srcs_files,
|
||||
ls_modules = ctx.executable._ls_modules,
|
||||
other_modules = other_modules,
|
||||
exposed_modules_reexports = exposed_modules_reexports,
|
||||
import_dir_map = import_dir_map,
|
||||
# NOTE We must make the object files compiled without profiling
|
||||
# available to this step for TH to work, presumably because GHC is
|
||||
# linked against RTS without profiling.
|
||||
extra_srcs = depset(transitive = [
|
||||
depset(ctx.files.extra_srcs),
|
||||
depset([c.objects_dir]),
|
||||
]),
|
||||
user_compile_flags = ctx.attr.compiler_flags,
|
||||
# NOTE We can't have profiling and dynamic code at the
|
||||
# same time, see:
|
||||
# https://ghc.haskell.org/trac/ghc/ticket/15394
|
||||
with_shared = False,
|
||||
with_profiling = True,
|
||||
my_pkg_id = my_pkg_id,
|
||||
plugins = ctx.attr.plugins,
|
||||
)
|
||||
|
||||
static_library = link_library_static(
|
||||
hs,
|
||||
cc,
|
||||
dep_info,
|
||||
c.objects_dir,
|
||||
my_pkg_id,
|
||||
with_profiling = False,
|
||||
)
|
||||
|
||||
if with_shared:
|
||||
dynamic_library = link_library_dynamic(
|
||||
hs,
|
||||
cc,
|
||||
dep_info,
|
||||
depset(ctx.files.extra_srcs),
|
||||
c.objects_dir,
|
||||
my_pkg_id,
|
||||
)
|
||||
dynamic_libraries = set.insert(
|
||||
dep_info.dynamic_libraries,
|
||||
dynamic_library,
|
||||
)
|
||||
else:
|
||||
dynamic_library = None
|
||||
dynamic_libraries = dep_info.dynamic_libraries
|
||||
|
||||
static_library_prof = None
|
||||
if with_profiling:
|
||||
static_library_prof = link_library_static(
|
||||
hs,
|
||||
cc,
|
||||
dep_info,
|
||||
c_p.objects_dir,
|
||||
my_pkg_id,
|
||||
with_profiling = True,
|
||||
)
|
||||
|
||||
conf_file, cache_file = package(
|
||||
hs,
|
||||
dep_info,
|
||||
c.interfaces_dir,
|
||||
c_p.interfaces_dir if c_p != None else None,
|
||||
static_library,
|
||||
dynamic_library,
|
||||
c.exposed_modules_file,
|
||||
other_modules,
|
||||
my_pkg_id,
|
||||
static_library_prof = static_library_prof,
|
||||
)
|
||||
|
||||
static_libraries_prof = dep_info.static_libraries_prof
|
||||
|
||||
if static_library_prof != None:
|
||||
static_libraries_prof = [static_library_prof] + dep_info.static_libraries_prof
|
||||
|
||||
interface_dirs = set.union(
|
||||
dep_info.interface_dirs,
|
||||
set.singleton(c.interfaces_dir),
|
||||
)
|
||||
|
||||
if c_p != None:
|
||||
interface_dirs = set.mutable_union(
|
||||
interface_dirs,
|
||||
set.singleton(c_p.interfaces_dir),
|
||||
)
|
||||
|
||||
version_macros = set.empty()
|
||||
if version != None:
|
||||
version_macros = set.singleton(
|
||||
generate_version_macros(ctx, hs.name, version),
|
||||
)
|
||||
|
||||
hs_info = HaskellInfo(
|
||||
package_ids = set.insert(dep_info.package_ids, pkg_id.to_string(my_pkg_id)),
|
||||
package_databases = set.insert(dep_info.package_databases, cache_file),
|
||||
version_macros = version_macros,
|
||||
source_files = c.source_files,
|
||||
extra_source_files = c.extra_source_files,
|
||||
import_dirs = c.import_dirs,
|
||||
# NOTE We have to use lists for static libraries because the order is
|
||||
# important for linker. Linker searches for unresolved symbols to the
|
||||
# left, i.e. you first feed a library which has unresolved symbols and
|
||||
# then you feed the library which resolves the symbols.
|
||||
static_libraries = [static_library] + dep_info.static_libraries,
|
||||
static_libraries_prof = static_libraries_prof,
|
||||
dynamic_libraries = dynamic_libraries,
|
||||
interface_dirs = interface_dirs,
|
||||
compile_flags = c.compile_flags,
|
||||
prebuilt_dependencies = dep_info.prebuilt_dependencies,
|
||||
cc_dependencies = dep_info.cc_dependencies,
|
||||
transitive_cc_dependencies = dep_info.transitive_cc_dependencies,
|
||||
)
|
||||
lib_info = HaskellLibraryInfo(
|
||||
package_id = pkg_id.to_string(my_pkg_id),
|
||||
version = version,
|
||||
)
|
||||
|
||||
dep_coverage_data = []
|
||||
for dep in ctx.attr.deps:
|
||||
if HaskellCoverageInfo in dep:
|
||||
dep_coverage_data += dep[HaskellCoverageInfo].coverage_data
|
||||
|
||||
coverage_info = HaskellCoverageInfo(
|
||||
coverage_data = dep_coverage_data + c.coverage_data,
|
||||
)
|
||||
|
||||
target_files = depset([file for file in [static_library, dynamic_library] if file])
|
||||
|
||||
if hasattr(ctx, "outputs"):
|
||||
build_haskell_repl(
|
||||
hs,
|
||||
ghci_script = ctx.file._ghci_script,
|
||||
ghci_repl_wrapper = ctx.file._ghci_repl_wrapper,
|
||||
repl_ghci_args = ctx.attr.repl_ghci_args,
|
||||
user_compile_flags = ctx.attr.compiler_flags,
|
||||
output = ctx.outputs.repl,
|
||||
package_databases = dep_info.package_databases,
|
||||
version = ctx.attr.version,
|
||||
hs_info = hs_info,
|
||||
lib_info = lib_info,
|
||||
)
|
||||
|
||||
# XXX Temporary backwards compatibility hack. Remove eventually.
|
||||
# See https://github.com/tweag/rules_haskell/pull/460.
|
||||
ln(hs, ctx.outputs.repl, ctx.outputs.repl_deprecated)
|
||||
|
||||
build_haskell_runghc(
|
||||
hs,
|
||||
runghc_wrapper = ctx.file._ghci_repl_wrapper,
|
||||
extra_args = ctx.attr.runcompile_flags,
|
||||
user_compile_flags = ctx.attr.compiler_flags,
|
||||
output = ctx.outputs.runghc,
|
||||
package_databases = dep_info.package_databases,
|
||||
version = ctx.attr.version,
|
||||
hs_info = hs_info,
|
||||
lib_info = lib_info,
|
||||
)
|
||||
|
||||
default_info = None
|
||||
|
||||
if hasattr(ctx, "runfiles"):
|
||||
default_info = DefaultInfo(
|
||||
files = target_files,
|
||||
runfiles = ctx.runfiles(collect_data = True),
|
||||
)
|
||||
else:
|
||||
default_info = DefaultInfo(
|
||||
files = target_files,
|
||||
)
|
||||
|
||||
# Create a CcInfo provider so that CC rules can work with
|
||||
# a haskell library as if it was a regular CC one.
|
||||
|
||||
# XXX Workaround https://github.com/bazelbuild/bazel/issues/6874.
|
||||
# Should be find_cpp_toolchain() instead.
|
||||
cc_toolchain = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo]
|
||||
feature_configuration = cc_common.configure_features(
|
||||
cc_toolchain = cc_toolchain,
|
||||
requested_features = ctx.features,
|
||||
unsupported_features = ctx.disabled_features,
|
||||
)
|
||||
library_to_link = cc_common.create_library_to_link(
|
||||
actions = ctx.actions,
|
||||
feature_configuration = feature_configuration,
|
||||
dynamic_library = dynamic_library,
|
||||
static_library = static_library,
|
||||
cc_toolchain = cc_toolchain,
|
||||
)
|
||||
compilation_context = cc_common.create_compilation_context()
|
||||
linking_context = cc_common.create_linking_context(
|
||||
libraries_to_link = [library_to_link],
|
||||
)
|
||||
cc_info = cc_common.merge_cc_infos(
|
||||
cc_infos = [
|
||||
CcInfo(
|
||||
compilation_context = compilation_context,
|
||||
linking_context = linking_context,
|
||||
),
|
||||
] + [dep[CcInfo] for dep in ctx.attr.deps if CcInfo in dep],
|
||||
)
|
||||
|
||||
return [
|
||||
hs_info,
|
||||
cc_info,
|
||||
coverage_info,
|
||||
default_info,
|
||||
lib_info,
|
||||
]
|
||||
|
||||
def haskell_toolchain_library_impl(ctx):
|
||||
hs = haskell_context(ctx)
|
||||
|
||||
if ctx.attr.package:
|
||||
package = ctx.attr.package
|
||||
else:
|
||||
package = ctx.label.name
|
||||
|
||||
id_file = hs.actions.declare_file(target_unique_name(hs, "id"))
|
||||
hs.actions.run_shell(
|
||||
inputs = [hs.tools.ghc_pkg],
|
||||
outputs = [id_file],
|
||||
command = """
|
||||
"$1" --simple-output -v1 field "$2" id > "$3"
|
||||
""",
|
||||
arguments = [
|
||||
hs.tools.ghc_pkg.path,
|
||||
package,
|
||||
id_file.path,
|
||||
],
|
||||
)
|
||||
|
||||
version_macros_file = hs.actions.declare_file("{}_version_macros.h".format(hs.name))
|
||||
hs.actions.run_shell(
|
||||
inputs = [hs.tools.ghc_pkg, ctx.executable._version_macros],
|
||||
outputs = [version_macros_file],
|
||||
command = """
|
||||
"$1" \\
|
||||
`"$2" --simple-output -v1 field "$3" name` \\
|
||||
`"$2" --simple-output -v1 field "$3" version` \\
|
||||
> "$4"
|
||||
""",
|
||||
arguments = [
|
||||
ctx.executable._version_macros.path,
|
||||
hs.tools.ghc_pkg.path,
|
||||
package,
|
||||
version_macros_file.path,
|
||||
],
|
||||
)
|
||||
|
||||
prebuilt_package_info = HaskellPrebuiltPackageInfo(
|
||||
package = package,
|
||||
id_file = id_file,
|
||||
version_macros_file = version_macros_file,
|
||||
)
|
||||
|
||||
return [prebuilt_package_info]
|
||||
|
||||
def _exposed_modules_reexports(exports):
|
||||
"""Creates a ghc-pkg-compatible list of reexport declarations.
|
||||
|
||||
A ghc-pkg registration file declares reexports as part of the
|
||||
exposed-modules field in the following format:
|
||||
|
||||
exposed-modules: A, B, C from pkg-c:C, D from pkg-d:Original.D
|
||||
|
||||
Here, the Original.D module from pkg-d is renamed by virtue of a
|
||||
different name being used before the "from" keyword.
|
||||
|
||||
This function creates a ghc-pkg-compatible list of reexport declarations
|
||||
(as shown above) from a dictionary mapping package targets to "Cabal-style"
|
||||
reexported-modules declarations. That is, something like:
|
||||
|
||||
{
|
||||
":pkg-c": "C",
|
||||
":pkg-d": "Original.D as D",
|
||||
":pkg-e": "E1, Original.E2 as E2",
|
||||
}
|
||||
|
||||
Args:
|
||||
exports: a dictionary mapping package targets to "Cabal-style"
|
||||
reexported-modules declarations.
|
||||
|
||||
Returns:
|
||||
a ghc-pkg-compatible list of reexport declarations.
|
||||
"""
|
||||
exposed_reexports = []
|
||||
for dep, cabal_decls in exports.items():
|
||||
for cabal_decl in cabal_decls.split(","):
|
||||
stripped_cabal_decl = cabal_decl.strip()
|
||||
cabal_decl_parts = stripped_cabal_decl.split(" as ")
|
||||
original = cabal_decl_parts[0]
|
||||
if len(cabal_decl_parts) == 2:
|
||||
reexported = cabal_decl_parts[1]
|
||||
else:
|
||||
reexported = cabal_decl_parts[0]
|
||||
|
||||
if HaskellPrebuiltPackageInfo in dep:
|
||||
pkg = dep[HaskellPrebuiltPackageInfo].package
|
||||
elif HaskellLibraryInfo in dep:
|
||||
pkg = dep[HaskellLibraryInfo].package_id
|
||||
|
||||
exposed_reexport = "{reexported} from {pkg}:{original}".format(
|
||||
reexported = reexported,
|
||||
pkg = pkg,
|
||||
original = original,
|
||||
)
|
||||
|
||||
exposed_reexports.append(exposed_reexport)
|
||||
|
||||
return exposed_reexports
|
||||
Loading…
Add table
Add a link
Reference in a new issue