summary refs log tree commit diff
path: root/third_party/bazel/rules_haskell/haskell/cc.bzl
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/bazel/rules_haskell/haskell/cc.bzl')
-rw-r--r--third_party/bazel/rules_haskell/haskell/cc.bzl353
1 files changed, 353 insertions, 0 deletions
diff --git a/third_party/bazel/rules_haskell/haskell/cc.bzl b/third_party/bazel/rules_haskell/haskell/cc.bzl
new file mode 100644
index 000000000000..1ec803764aab
--- /dev/null
+++ b/third_party/bazel/rules_haskell/haskell/cc.bzl
@@ -0,0 +1,353 @@
+"""Interop with cc_* rules
+
+These rules are deprecated.
+"""
+
+load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
+load(
+    "@bazel_tools//tools/build_defs/cc:action_names.bzl",
+    "CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME",
+    "C_COMPILE_ACTION_NAME",
+)
+load(":private/path_utils.bzl", "ln")
+load("@bazel_skylib//lib:paths.bzl", "paths")
+load(":private/set.bzl", "set")
+load(
+    "@io_tweag_rules_haskell//haskell:providers.bzl",
+    "HaskellInfo",
+)
+
+CcInteropInfo = provider(
+    doc = "Information needed for interop with cc rules.",
+    fields = {
+        "tools": "Tools from the CC toolchain",
+        # See the following for why this is needed:
+        # https://stackoverflow.com/questions/52769846/custom-c-rule-with-the-cc-common-api
+        "files": "Files for all tools (input to any action that uses tools)",
+        "hdrs": "CC headers",
+        "cpp_flags": "Preprocessor flags",
+        "compiler_flags": "Flags for compilation",
+        "linker_flags": "Flags to forward to the linker",
+        "include_args": "Extra include dirs",
+    },
+)
+
+def cc_interop_info(ctx):
+    """Gather information from any CC dependencies.
+
+    *Internal function - do not use.*
+
+    Args:
+      ctx: Rule context.
+
+    Returns:
+      CcInteropInfo: Information needed for CC interop.
+    """
+    ccs = [dep[CcInfo] for dep in ctx.attr.deps if CcInfo in dep and HaskellInfo not in dep]
+
+    hdrs = []
+    include_args = []
+    cpp_flags = []
+    for cc in ccs:
+        cc_ctx = cc.compilation_context
+        hdrs.append(cc_ctx.headers)
+        include_args.extend(["-I" + include for include in cc_ctx.includes])
+        cpp_flags.extend(
+            [
+                "-D" + define
+                for define in cc_ctx.defines
+            ] + [
+                f
+                for include in cc_ctx.quote_includes
+                for f in ["-iquote", include]
+            ] + [
+                f
+                for include in cc_ctx.system_includes
+                for f in ["-isystem", include]
+            ],
+        )
+
+    hdrs = depset(transitive = hdrs)
+
+    # 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,
+    )
+    compile_variables = cc_common.create_compile_variables(
+        feature_configuration = feature_configuration,
+        cc_toolchain = cc_toolchain,
+    )
+    compiler_flags = cc_common.get_memory_inefficient_command_line(
+        feature_configuration = feature_configuration,
+        action_name = C_COMPILE_ACTION_NAME,
+        variables = compile_variables,
+    )
+    link_variables = cc_common.create_link_variables(
+        feature_configuration = feature_configuration,
+        cc_toolchain = cc_toolchain,
+        is_linking_dynamic_library = False,
+        is_static_linking_mode = True,
+    )
+    linker_flags = cc_common.get_memory_inefficient_command_line(
+        feature_configuration = feature_configuration,
+        action_name = CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME,
+        variables = link_variables,
+    )
+
+    # Generate cc wrapper script on Darwin that adjusts load commands.
+    hs_toolchain = ctx.toolchains["@io_tweag_rules_haskell//haskell:toolchain"]
+    if hs_toolchain.is_darwin:
+        cc_wrapper = ctx.actions.declare_file("osx_cc_wrapper")
+        cc = cc_wrapper.path
+        ctx.actions.expand_template(
+            template = hs_toolchain.osx_cc_wrapper_tpl,
+            output = cc_wrapper,
+            substitutions = {
+                "%{cc}": cc_toolchain.compiler_executable(),
+            },
+        )
+        cc_files = ctx.files._cc_toolchain + [
+            cc_wrapper,
+        ]
+    else:
+        cc = cc_toolchain.compiler_executable()
+        cc_files = ctx.files._cc_toolchain
+
+    # XXX Workaround https://github.com/bazelbuild/bazel/issues/6876.
+    linker_flags = [flag for flag in linker_flags if flag not in ["-shared"]]
+
+    tools = {
+        "ar": cc_toolchain.ar_executable(),
+        "cc": cc,
+        "ld": cc_toolchain.ld_executable(),
+        "cpp": cc_toolchain.preprocessor_executable(),
+        "nm": cc_toolchain.nm_executable(),
+    }
+
+    # If running on darwin but XCode is not installed (i.e., only the Command
+    # Line Tools are available), then Bazel will make ar_executable point to
+    # "/usr/bin/libtool". Since we call ar directly, override it.
+    # TODO: remove this if Bazel fixes its behavior.
+    # Upstream ticket: https://github.com/bazelbuild/bazel/issues/5127.
+    if tools["ar"].find("libtool") >= 0:
+        tools["ar"] = "/usr/bin/ar"
+
+    return CcInteropInfo(
+        tools = struct(**tools),
+        files = cc_files,
+        hdrs = hdrs.to_list(),
+        cpp_flags = cpp_flags,
+        include_args = include_args,
+        compiler_flags = compiler_flags,
+        # XXX this might not be the right set of flags for all situations,
+        # but this will anyways all be replaced (once implemented) by
+        # https://github.com/bazelbuild/bazel/issues/4571.
+        linker_flags = linker_flags,
+    )
+
+def _cc_import_impl(ctx):
+    strip_prefix = ctx.attr.strip_include_prefix
+
+    # cc_library's strip_include_prefix attribute accepts both absolute and
+    # relative paths.  For simplicity we currently only implement absolute
+    # paths.
+    if strip_prefix.startswith("/"):
+        prefix = strip_prefix[1:]
+    else:
+        prefix = paths.join(ctx.label.workspace_root, ctx.label.package, strip_prefix)
+
+    roots = set.empty()
+    for f in ctx.files.hdrs:
+        # If it's a generated file, strip off the bin or genfiles prefix.
+        path = f.path
+        if path.startswith(ctx.bin_dir.path):
+            path = paths.relativize(path, ctx.bin_dir.path)
+        elif path.startswith(ctx.genfiles_dir.path):
+            path = paths.relativize(path, ctx.genfiles_dir.path)
+
+        if not path.startswith(prefix):
+            fail("Header {} does not have expected prefix {}".format(
+                path,
+                prefix,
+            ))
+        roots = set.insert(roots, f.root.path if f.root.path else ".")
+
+    include_directories = [paths.join(root, prefix) for root in set.to_list(roots)]
+
+    cc_toolchain = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo]
+    feature_configuration = cc_common.configure_features(cc_toolchain = cc_toolchain)
+
+    compilation_context = cc_common.create_compilation_context(
+        headers = depset(transitive = [l.files for l in ctx.attr.hdrs]),
+        includes = depset(direct = include_directories),
+    )
+    linking_context = cc_common.create_linking_context(
+        libraries_to_link = [
+            cc_common.create_library_to_link(
+                actions = ctx.actions,
+                feature_configuration = feature_configuration,
+                cc_toolchain = cc_toolchain,
+                dynamic_library = f,
+            )
+            for f in ctx.attr.shared_library.files
+        ],
+    )
+
+    return [
+        CcInfo(
+            compilation_context = compilation_context,
+            linking_context = linking_context,
+        ),
+    ]
+
+haskell_cc_import = rule(
+    _cc_import_impl,
+    attrs = {
+        "shared_library": attr.label(
+            # NOTE We do not list all extensions here because .so libraries may
+            # have numeric suffixes like foo.so.1.2.3, and if they also have
+            # SONAME with numeric suffix, matching file must be provided, so this
+            # attributes must accept libraries with almost arbitrary extensions.
+            # It would be easier if Skylark supported regexps.
+            allow_files = True,
+            doc = """A single precompiled shared library.
+
+Bazel ensures it is available to the binary that depends on it
+during runtime.
+""",
+        ),
+        "hdrs": attr.label_list(
+            allow_files = [".h"],
+            doc = """
+
+The list of header files published by this precompiled library to be
+directly included by sources in dependent rules.
+""",
+        ),
+        "strip_include_prefix": attr.string(
+            doc = """
+The prefix to strip from the paths of the headers of this rule.
+When set, the headers in the `hdrs` attribute of this rule are
+accessible at their path (relative to the repository) with this
+prefix cut off.
+
+If it's a relative path, it's taken as a package-relative one. If it's an
+absolute one, it's understood as a repository-relative path.
+""",
+        ),
+        "_cc_toolchain": attr.label(
+            default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
+        ),
+    },
+)
+"""Imports a prebuilt shared library.
+
+Use this to make `.so`, `.dll`, `.dylib` files residing in external
+[external repositories][bazel-ext-repos] available to Haskell rules.
+
+*This rule is temporary replacement for [cc_import][cc_import] and is
+deprecated. Use [cc_library][cc_library] instead as shown in the example.*
+
+Example:
+  ```bzl
+  # Deprecated, use cc_library instead.
+  # haskell_cc_import(name = "zlib", shared_library = "@zlib//:lib")
+
+  cc_library(name = "zlib", srcs = ["@zlib//:lib"])
+
+  haskell_import(
+    name = "base_pkg",
+    package = "base",
+  )
+
+  haskell_binary(
+    name = "crc32sum",
+    srcs = ["Main.hs"],
+    deps = [
+      "bazel_pkg",
+      ":zlib",
+    ],
+  )
+  ```
+
+[bazel-ext-repos]: https://docs.bazel.build/versions/master/external.html
+[cc_import]: https://docs.bazel.build/versions/master/be/c-cpp.html#cc_import
+[cc_library]: https://docs.bazel.build/versions/master/be/c-cpp.html#cc_library
+"""
+
+def _cc_haskell_import(ctx):
+    dyn_libs = set.empty()
+
+    if HaskellInfo in ctx.attr.dep:
+        set.mutable_union(dyn_libs, ctx.attr.dep[HaskellInfo].dynamic_libraries)
+    else:
+        fail("{0} has to provide `HaskellInfo`".format(ctx.attr.dep.label.name))
+
+    return [
+        DefaultInfo(
+            files = set.to_depset(dyn_libs),
+            default_runfiles = ctx.runfiles(
+                files = ctx.attr.dep.default_runfiles.files.to_list(),
+                collect_default = True,
+            ),
+            data_runfiles = ctx.runfiles(
+                files = ctx.attr.dep.data_runfiles.files.to_list(),
+                collect_data = True,
+            ),
+        ),
+    ]
+
+cc_haskell_import = rule(
+    _cc_haskell_import,
+    attrs = {
+        "dep": attr.label(
+            doc = """
+Target providing a `HaskellInfo` such as `haskell_library` or
+`haskell_binary`.
+""",
+        ),
+    },
+    toolchains = ["@io_tweag_rules_haskell//haskell:toolchain"],
+)
+"""Exports a Haskell library as a CC library.
+
+Given a [haskell_library](#haskell_library) or
+[haskell_binary](#haskell_binary) input, outputs the shared object files
+produced as well as the object files it depends on directly and
+transitively. This is very useful if you want to link in a Haskell shared
+library from `cc_library`.
+
+There is a caveat: this will not provide any shared libraries that
+aren't explicitly given to it. This means that if you're using
+`prebuilt_dependencies` and relying on GHC to provide those objects,
+they will not be present here. You will have to provide those
+separately to your `cc_library`. If you're getting
+`prebuilt_dependencies` from your toolchain, you will likely want to
+extract those and pass them in as well.
+
+*This rule is deprecated.*
+
+Example:
+  ```bzl
+  haskell_library(
+    name = "my-lib",
+    ...
+  )
+
+  cc_haskell_import(
+    name = "my-lib-objects",
+    dep = ":my-lib",
+  )
+
+  cc_library(
+    name = "my-cc",
+    srcs = ["main.c", ":my-lib-objects"],
+  )
+  ```
+
+[bazel-cpp-sandwich]: https://github.com/bazelbuild/bazel/issues/2163
+"""