222 lines
8.4 KiB
Python
222 lines
8.4 KiB
Python
load("@bazel_skylib//lib:dicts.bzl", "dicts")
|
|
load("@bazel_skylib//lib:paths.bzl", "paths")
|
|
load(
|
|
"@io_tweag_rules_haskell//haskell:providers.bzl",
|
|
"HaskellCcInfo",
|
|
"HaskellInfo",
|
|
"HaskellLibraryInfo",
|
|
"HaskellPrebuiltPackageInfo",
|
|
"empty_HaskellCcInfo",
|
|
"merge_HaskellCcInfo",
|
|
)
|
|
load(
|
|
":private/path_utils.bzl",
|
|
"get_lib_name",
|
|
"is_shared_library",
|
|
"is_static_library",
|
|
"ln",
|
|
)
|
|
load(":private/set.bzl", "set")
|
|
|
|
def _cc_get_static_lib(lib_info):
|
|
"""Return the library to use in static linking mode.
|
|
|
|
This returns the first available library artifact in the following order:
|
|
- static_library
|
|
- pic_static_library
|
|
- dynamic_library
|
|
- interface_library
|
|
|
|
Args:
|
|
lib_info: LibraryToLink provider.
|
|
|
|
Returns:
|
|
File: The library to link against in static mode.
|
|
"""
|
|
if lib_info.static_library:
|
|
return lib_info.static_library
|
|
elif lib_info.pic_static_library:
|
|
return lib_info.pic_static_library
|
|
elif lib_info.dynamic_library:
|
|
return lib_info.dynamic_library
|
|
else:
|
|
return lib_info.interface_library
|
|
|
|
def _cc_get_dynamic_lib(lib_info):
|
|
"""Return the library to use in dynamic linking mode.
|
|
|
|
This returns the first available library artifact in the following order:
|
|
- dynamic_library
|
|
- interface_library
|
|
- pic_static_library
|
|
- static_library
|
|
|
|
Args:
|
|
lib_info: LibraryToLink provider.
|
|
|
|
Returns:
|
|
File: The library to link against in dynamic mode.
|
|
"""
|
|
if lib_info.dynamic_library:
|
|
return lib_info.dynamic_library
|
|
elif lib_info.interface_library:
|
|
return lib_info.interface_library
|
|
elif lib_info.pic_static_library:
|
|
return lib_info.pic_static_library
|
|
else:
|
|
return lib_info.static_library
|
|
|
|
def _HaskellCcInfo_from_CcInfo(ctx, cc_info):
|
|
libs_to_link = cc_info.linking_context.libraries_to_link
|
|
static_libs_to_link = []
|
|
dynamic_libs_to_link = []
|
|
static_libs_for_runtime = []
|
|
dynamic_libs_for_runtime = []
|
|
for l in libs_to_link:
|
|
_static_lib = _cc_get_static_lib(l)
|
|
dynamic_lib = _cc_get_dynamic_lib(l)
|
|
|
|
# Bazel itself only mangles dynamic libraries, not static libraries.
|
|
# However, we need the library name of the static and dynamic version
|
|
# of a library to match so that we can refer to both with one entry in
|
|
# the package configuration file. Here we rename any static archives
|
|
# with mismatching mangled dynamic library name.
|
|
static_name = get_lib_name(_static_lib)
|
|
dynamic_name = get_lib_name(dynamic_lib)
|
|
if static_name != dynamic_name:
|
|
ext = _static_lib.extension
|
|
static_lib = ctx.actions.declare_file(
|
|
"lib%s.%s" % (dynamic_name, ext),
|
|
)
|
|
ln(ctx, _static_lib, static_lib)
|
|
else:
|
|
static_lib = _static_lib
|
|
|
|
static_libs_to_link.append(static_lib)
|
|
if is_shared_library(static_lib):
|
|
static_libs_for_runtime.append(static_lib)
|
|
dynamic_libs_to_link.append(dynamic_lib)
|
|
if is_shared_library(dynamic_lib):
|
|
dynamic_libs_for_runtime.append(dynamic_lib)
|
|
|
|
return HaskellCcInfo(
|
|
static_linking = struct(
|
|
libraries_to_link = depset(
|
|
direct = static_libs_to_link,
|
|
order = "topological",
|
|
),
|
|
dynamic_libraries_for_runtime = depset(
|
|
direct = static_libs_for_runtime,
|
|
order = "topological",
|
|
),
|
|
user_link_flags = depset(
|
|
direct = cc_info.linking_context.user_link_flags,
|
|
order = "topological",
|
|
),
|
|
),
|
|
dynamic_linking = struct(
|
|
libraries_to_link = depset(
|
|
direct = dynamic_libs_to_link,
|
|
order = "topological",
|
|
),
|
|
dynamic_libraries_for_runtime = depset(
|
|
direct = dynamic_libs_for_runtime,
|
|
order = "topological",
|
|
),
|
|
user_link_flags = depset(
|
|
direct = cc_info.linking_context.user_link_flags,
|
|
order = "topological",
|
|
),
|
|
),
|
|
)
|
|
|
|
def gather_dep_info(ctx, deps):
|
|
"""Collapse dependencies into a single `HaskellInfo`.
|
|
|
|
Note that the field `prebuilt_dependencies` also includes
|
|
prebuilt_dependencies of current target.
|
|
|
|
Args:
|
|
ctx: Rule context.
|
|
deps: deps attribute.
|
|
|
|
Returns:
|
|
HaskellInfo: Unified information about all dependencies.
|
|
"""
|
|
|
|
acc = HaskellInfo(
|
|
package_ids = set.empty(),
|
|
package_databases = set.empty(),
|
|
version_macros = set.empty(),
|
|
static_libraries = [],
|
|
static_libraries_prof = [],
|
|
dynamic_libraries = set.empty(),
|
|
interface_dirs = set.empty(),
|
|
prebuilt_dependencies = set.empty(),
|
|
direct_prebuilt_deps = set.empty(),
|
|
cc_dependencies = empty_HaskellCcInfo(),
|
|
transitive_cc_dependencies = empty_HaskellCcInfo(),
|
|
)
|
|
|
|
for dep in deps:
|
|
if HaskellInfo in dep:
|
|
binfo = dep[HaskellInfo]
|
|
package_ids = acc.package_ids
|
|
if HaskellLibraryInfo not in dep:
|
|
fail("Target {0} cannot depend on binary".format(ctx.attr.name))
|
|
if HaskellLibraryInfo in dep:
|
|
set.mutable_insert(package_ids, dep[HaskellLibraryInfo].package_id)
|
|
acc = HaskellInfo(
|
|
package_ids = package_ids,
|
|
package_databases = set.mutable_union(acc.package_databases, binfo.package_databases),
|
|
version_macros = set.mutable_union(acc.version_macros, binfo.version_macros),
|
|
static_libraries = acc.static_libraries + binfo.static_libraries,
|
|
static_libraries_prof = acc.static_libraries_prof + binfo.static_libraries_prof,
|
|
dynamic_libraries = set.mutable_union(acc.dynamic_libraries, binfo.dynamic_libraries),
|
|
interface_dirs = set.mutable_union(acc.interface_dirs, binfo.interface_dirs),
|
|
prebuilt_dependencies = set.mutable_union(acc.prebuilt_dependencies, binfo.prebuilt_dependencies),
|
|
direct_prebuilt_deps = acc.direct_prebuilt_deps,
|
|
cc_dependencies = acc.cc_dependencies,
|
|
transitive_cc_dependencies = merge_HaskellCcInfo(acc.transitive_cc_dependencies, binfo.transitive_cc_dependencies),
|
|
)
|
|
elif HaskellPrebuiltPackageInfo in dep:
|
|
pkg = dep[HaskellPrebuiltPackageInfo]
|
|
acc = HaskellInfo(
|
|
package_ids = acc.package_ids,
|
|
package_databases = acc.package_databases,
|
|
version_macros = set.mutable_insert(acc.version_macros, pkg.version_macros_file),
|
|
static_libraries = acc.static_libraries,
|
|
static_libraries_prof = acc.static_libraries_prof,
|
|
dynamic_libraries = acc.dynamic_libraries,
|
|
interface_dirs = acc.interface_dirs,
|
|
prebuilt_dependencies = set.mutable_insert(acc.prebuilt_dependencies, pkg),
|
|
direct_prebuilt_deps = set.mutable_insert(acc.direct_prebuilt_deps, pkg),
|
|
cc_dependencies = acc.cc_dependencies,
|
|
transitive_cc_dependencies = acc.transitive_cc_dependencies,
|
|
)
|
|
elif CcInfo in dep and HaskellInfo not in dep:
|
|
# The final link of a binary must include all static libraries we
|
|
# depend on, including transitives ones. Theses libs are provided
|
|
# in the `CcInfo` provider.
|
|
hs_cc_info = _HaskellCcInfo_from_CcInfo(ctx, dep[CcInfo])
|
|
acc = HaskellInfo(
|
|
package_ids = acc.package_ids,
|
|
package_databases = acc.package_databases,
|
|
version_macros = acc.version_macros,
|
|
static_libraries = acc.static_libraries,
|
|
static_libraries_prof = acc.static_libraries_prof,
|
|
dynamic_libraries = acc.dynamic_libraries,
|
|
interface_dirs = acc.interface_dirs,
|
|
prebuilt_dependencies = acc.prebuilt_dependencies,
|
|
direct_prebuilt_deps = acc.direct_prebuilt_deps,
|
|
cc_dependencies = merge_HaskellCcInfo(
|
|
acc.cc_dependencies,
|
|
hs_cc_info,
|
|
),
|
|
transitive_cc_dependencies = merge_HaskellCcInfo(
|
|
acc.transitive_cc_dependencies,
|
|
hs_cc_info,
|
|
),
|
|
)
|
|
|
|
return acc
|