diff options
Diffstat (limited to 'third_party/bazel/rules_haskell/haskell/private/dependencies.bzl')
-rw-r--r-- | third_party/bazel/rules_haskell/haskell/private/dependencies.bzl | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/third_party/bazel/rules_haskell/haskell/private/dependencies.bzl b/third_party/bazel/rules_haskell/haskell/private/dependencies.bzl new file mode 100644 index 000000000000..6a2a797872fe --- /dev/null +++ b/third_party/bazel/rules_haskell/haskell/private/dependencies.bzl @@ -0,0 +1,222 @@ +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 |