# This file is licensed under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
"""LLVM libc starlark rules for building individual functions."""
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_skylib//lib:selects.bzl", "selects")
load(":libc_configure_options.bzl", "LIBC_CONFIGURE_OPTIONS")
load(":libc_namespace.bzl", "LIBC_NAMESPACE")
load(":platforms.bzl", "PLATFORM_CPU_ARM64", "PLATFORM_CPU_X86_64")
def libc_internal_target(name):
return name + ".__internal__"
def libc_common_copts():
root_label = Label(":libc")
libc_include_path = paths.join(root_label.workspace_root, root_label.package)
return [
"-I" + libc_include_path,
"-I" + paths.join(libc_include_path, "include"),
"-DLIBC_NAMESPACE=" + LIBC_NAMESPACE,
]
def _libc_library(name, hidden, copts = [], deps = [], local_defines = [], **kwargs):
"""Internal macro to serve as a base for all other libc library rules.
Args:
name: Target name.
copts: The special compiler options for the target.
deps: The list of target dependencies if any.
local_defines: The list of target local_defines if any.
hidden: Whether the symbols should be explicitly hidden or not.
**kwargs: All other attributes relevant for the cc_library rule.
"""
# We want all libc sources to be compiled with "hidden" visibility.
# The public symbols will be given "default" visibility explicitly.
# See src/__support/common.h for more information.
if hidden:
copts = copts + ["-fvisibility=hidden"]
native.cc_library(
name = name,
copts = copts + libc_common_copts(),
local_defines = local_defines + LIBC_CONFIGURE_OPTIONS,
deps = deps,
linkstatic = 1,
**kwargs
)
# A convenience function which should be used to list all libc support libraries.
# Any library which does not define a public function should be listed with
# libc_support_library.
def libc_support_library(name, **kwargs):
_libc_library(name = name, hidden = False, **kwargs)
def libc_function(
name,
srcs,
weak = False,
copts = None,
local_defines = None,
**kwargs):
"""Add target for a libc function.
The libc function is eventually available as a cc_library target by name
"name". LLVM libc implementations of libc functions are in C++. So, this
rule internally generates a C wrapper for the C++ implementation and adds
it to the source list of the cc_library. This way, the C++ implementation
and the C wrapper are both available in the cc_library.
Args:
name: Target name. It is normally the name of the function this target is
for.
srcs: The .cpp files which contain the function implementation.
weak: Make the symbol corresponding to the libc function "weak".
deps: The list of target dependencies if any.
copts: The list of options to add to the C++ compilation command.
local_defines: The preprocessor defines which will be prepended with -D
and passed to the compile command of this target but not
its deps.
**kwargs: Other attributes relevant for a cc_library. For example, deps.
"""
# We use the explicit equals pattern here because append and += mutate the
# original list, where this creates a new list and stores it in deps.
copts = copts or []
copts = copts + [
"-O3",
"-fno-builtin",
"-fno-lax-vector-conversions",
"-ftrivial-auto-var-init=pattern",
"-fno-omit-frame-pointer",
"-fstack-protector-strong",
]
# x86 targets have -mno-omit-leaf-frame-pointer.
platform_copts = selects.with_or({
PLATFORM_CPU_X86_64: ["-mno-omit-leaf-frame-pointer"],
"//conditions:default": [],
})
copts = copts + platform_copts
# We compile the code twice, the first target is suffixed with ".__internal__" and contains the
# C++ functions in the "LIBC_NAMESPACE" namespace. This allows us to test the function in the
# presence of another libc.
libc_support_library(
name = libc_internal_target(name),
srcs = srcs,
copts = copts,
**kwargs
)
# This second target is the llvm libc C function with either a default or hidden visibility.
# All other functions are hidden.
func_attrs = ["__attribute__((visibility(\"default\")))"]
if weak:
func_attrs = func_attrs + ["__attribute__((weak))"]
local_defines = local_defines or ["LIBC_COPT_PUBLIC_PACKAGING"]
local_defines = local_defines + ["LLVM_LIBC_FUNCTION_ATTR='%s'" % " ".join(func_attrs)]
_libc_library(
name = name,
hidden = True,
srcs = srcs,
copts = copts,
local_defines = local_defines,
**kwargs
)
def libc_math_function(
name,
additional_deps = None):
"""Add a target for a math function.
Args:
name: The name of the function.
specializations: List of machine specializations available for this
function. Possible specializations are "generic",
"aarch64" and "x86_64".
additional_deps: Other deps like helper cc_library targes used by the
math function.
"""
additional_deps = additional_deps or []
#TODO(michaelrj): Fix the floating point dependencies
OLD_FPUTIL_DEPS = [
":__support_fputil_basic_operations",
":__support_fputil_division_and_remainder_operations",
":__support_fputil_fenv_impl",
":__support_fputil_fp_bits",
":__support_fputil_hypot",
":__support_fputil_manipulation_functions",
":__support_fputil_nearest_integer_operations",
":__support_fputil_normal_float",
":__support_math_extras",
":__support_fputil_except_value_utils",
]
libc_function(
name = name,
srcs = ["src/math/generic/" + name + ".cpp"],
hdrs = ["src/math/" + name + ".h"],
deps = [":__support_common"] + OLD_FPUTIL_DEPS + additional_deps,
)