daml/bazel_tools/fat_cc_library.bzl

144 lines
5.3 KiB
Python
Raw Normal View History

# Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2019-04-04 11:33:38 +03:00
# SPDX-License-Identifier: Apache-2.0
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load("@os_info//:os_info.bzl", "is_darwin", "is_windows")
2019-04-04 11:33:38 +03:00
def _fat_cc_library_impl(ctx):
input_lib = ctx.attr.input_lib
cc_info = input_lib[CcInfo]
static_libs = []
2019-04-04 11:33:38 +03:00
# For now we assume that we have static PIC libs for all libs.
# It should be possible to extend this but we do not have a need
# for it so far and it would complicate things.
for input in cc_info.linking_context.linker_inputs.to_list():
for lib in input.libraries:
static_lib = None
if lib.pic_static_library:
static_lib = lib.pic_static_library
elif is_windows and lib.static_library:
# On Windows we don't seem to have `pic_static_library`s available.
static_lib = lib.static_library
else:
fail("No (PIC) static library found for '{}'.".format(
str(lib.dynamic_library.path),
))
static_libs += [static_lib]
2019-04-04 11:33:38 +03:00
dyn_lib = ctx.outputs.dynamic_library
static_lib = ctx.outputs.static_library
toolchain = find_cpp_toolchain(ctx)
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features,
)
2019-04-04 11:33:38 +03:00
compiler = cc_common.get_tool_for_action(
feature_configuration = feature_configuration,
action_name = ACTION_NAMES.c_compile,
)
2019-04-04 11:33:38 +03:00
ctx.actions.run(
mnemonic = "CppLinkFatDynLib",
outputs = [dyn_lib],
executable = compiler,
tools = toolchain.all_files.to_list(),
2019-04-04 11:33:38 +03:00
arguments =
["-o", dyn_lib.path, "-shared"] +
ctx.attr.whole_archive_flag +
[f.path for f in static_libs] +
ctx.attr.no_whole_archive_flag +
2019-04-04 11:33:38 +03:00
# Some libs seems to depend on libstdc++ implicitely
["-lstdc++"] +
2019-07-18 14:32:17 +03:00
(["-framework", "CoreFoundation"] if is_darwin else []) +
# On Windows we have some extra deps.
(["-lws2_32"] if is_windows else []),
inputs = static_libs,
env = {"PATH": ""},
2019-04-04 11:33:38 +03:00
)
mri_script_content = "\n".join(
["create {}".format(static_lib.path)] +
["addlib {}".format(lib.path) for lib in static_libs] +
["save", "end"],
2019-04-04 11:33:38 +03:00
) + "\n"
mri_script = ctx.actions.declare_file(ctx.label.name + "_mri")
ctx.actions.write(mri_script, mri_script_content)
ar = toolchain.ar_executable
2019-04-04 11:33:38 +03:00
if ar.find("libtool") >= 0:
# We are on MacOS where ar_executable is actually libtool, see
# https://github.com/bazelbuild/bazel/issues/5127.
ctx.actions.run(
mnemonic = "CppLinkFatStaticLib",
outputs = [static_lib],
executable = ar,
inputs = static_libs,
2019-04-04 11:33:38 +03:00
arguments =
["-no_warning_for_no_symbols", "-static", "-o", static_lib.path] +
[f.path for f in static_libs],
2019-04-04 11:33:38 +03:00
)
else:
ctx.actions.run_shell(
mnemonic = "CppLinkFatStaticLib",
outputs = [static_lib],
inputs = [mri_script] + static_libs,
2019-04-04 11:33:38 +03:00
command = "{ar} -M < {mri_script}".format(ar = ar, mri_script = mri_script.path),
)
fat_lib = cc_common.create_library_to_link(
actions = ctx.actions,
feature_configuration = feature_configuration,
cc_toolchain = toolchain,
dynamic_library = dyn_lib,
static_library = static_lib,
)
linker_input = cc_common.create_linker_input(
libraries = depset([fat_lib]),
owner = ctx.label,
)
2019-04-04 11:33:38 +03:00
new_linking_context = cc_common.create_linking_context(
linker_inputs = depset([linker_input]),
2019-04-04 11:33:38 +03:00
)
new_cc_info = CcInfo(
linking_context = new_linking_context,
compilation_context = cc_info.compilation_context,
)
return [new_cc_info]
2019-04-04 11:33:38 +03:00
# Shared libraries built with Bazel do not declare their dependencies on other libraries properly.
# Instead that dependency is tracked in Bazel internally. This breaks the GHCi linker if
# RTLD_LAZY doesnt work which happens quite often. To make matters worse, we also cannot use
# linkstatic = True, since the GHCi linker cannot handle some relocations.
# To work around this mess, we create fat libraries that do not have additional dependencies.
# See https://github.com/tweag/rules_haskell/issues/720
fat_cc_library = rule(
_fat_cc_library_impl,
attrs = dict({
"input_lib": attr.label(),
"_cc_toolchain": attr.label(
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
),
"whole_archive_flag": attr.string_list(
# ld on MacOS doesnt understand --whole-archive
default = ["-Wl,-all_load"] if is_darwin else ["-Wl,--whole-archive"],
),
"no_whole_archive_flag": attr.string_list(
default = [] if is_darwin else ["-Wl,--no-whole-archive"],
),
}),
fragments = ["cpp"],
2019-04-04 11:33:38 +03:00
outputs = {
"dynamic_library": "lib%{name}.dll" if is_windows else "lib%{name}.so",
2019-04-04 11:33:38 +03:00
"static_library": "lib%{name}.a",
},
)