mongo/bazel/mongo_src_rules.bzl

1885 lines
64 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Common mongo-specific bazel build rules intended to be used in individual
BUILD files in the "src/" subtree.
"""
load("//bazel/toolchains/cc:mongo_defines.bzl", "MONGO_GLOBAL_DEFINES")
load(
"//bazel/toolchains/cc:mongo_errors.bzl",
"REQUIRED_SETTINGS_LIBUNWIND_ERROR_MESSAGE",
)
load(
"//bazel/toolchains/cc:mongo_compiler_flags.bzl",
"get_copts",
"get_linkopts",
)
load("@bazel_skylib//lib:selects.bzl", "selects")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load("@com_github_grpc_grpc//bazel:generate_cc.bzl", "generate_cc")
load("@poetry//:dependencies.bzl", "dependency")
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
load("@rules_proto//proto:defs.bzl", "proto_library")
load(
"//bazel:separate_debug.bzl",
"CC_SHARED_LIBRARY_SUFFIX",
"SHARED_ARCHIVE_SUFFIX",
"WITH_DEBUG_SUFFIX",
"extract_debuginfo",
"extract_debuginfo_binary",
"extract_debuginfo_test",
)
load("@local_host_values//:local_host_values_set.bzl", "NUM_CPUS")
load("@evergreen_variables//:evergreen_variables.bzl", "UNSAFE_COMPILE_VARIANT", "UNSAFE_VERSION_ID")
load("//bazel/toolchains/cc/mongo_windows:mongo_windows_cc_toolchain_config.bzl", "MIN_VER_MAP")
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load("//bazel/config:generate_config_header.bzl", "generate_config_header")
load("//bazel/auto_header:auto_header.bzl", "binary_srcs_with_all_headers", "build_selects_and_flat_files", "concat_selects", "dedupe_preserve_order", "maybe_all_headers", "maybe_compute_auto_headers", "strings_only")
# These will throw an error if the following condition is not met:
# (libunwind == on && os == linux) || libunwind == off || libunwind == auto
LIBUNWIND_DEPS = select({
"//bazel/config:_libunwind_disabled_by_auto": [],
"//bazel/config:_libunwind_off": [],
"//bazel/config:libunwind_enabled": ["//src/third_party/unwind:unwind"],
}, no_match_error = REQUIRED_SETTINGS_LIBUNWIND_ERROR_MESSAGE)
REQUIRED_SETTINGS_DYNAMIC_LINK_ERROR_MESSAGE = """
Error:
linking mongo dynamically is not currently supported on Windows
"""
# This is a hack to work around the fact that the cc_library flag
# additional_compiler_inputs doesn't exist in cc_binary. Instead, we add the
# denylists to srcs as header files to make them visible to the compiler
# executable.
SANITIZER_DENYLIST_HEADERS = select({
"//bazel/config:asan_enabled": ["//etc:asan_denylist_h"],
"//conditions:default": [],
}) + select({
"//bazel/config:msan_enabled": ["//etc:msan_denylist_h"],
"//conditions:default": [],
}) + select({
"//bazel/config:tsan_enabled": ["//etc:tsan_denylist_h"],
"//conditions:default": [],
}) + select({
"//bazel/config:ubsan_enabled": ["//etc:ubsan_denylist_h"],
"//conditions:default": [],
})
ASAN_OPTIONS = [
"detect_leaks=1",
"check_initialization_order=true",
"strict_init_order=true",
"abort_on_error=1",
"disable_coredump=0",
"handle_abort=1",
"strict_string_checks=true",
"detect_invalid_pointer_pairs=1",
]
LSAN_OPTIONS = [
"report_objects=1",
"suppressions=$(location //etc:lsan.suppressions)",
]
MSAN_OPTIONS = []
UBSAN_OPTIONS = [
"print_stacktrace=1",
]
TSAN_OPTIONS = [
"abort_on_error=1",
"disable_coredump=0",
"handle_abort=1",
"halt_on_error=1",
"report_thread_leaks=0",
"die_after_fork=0",
"history_size=4",
"suppressions=$(location //etc:tsan.suppressions)",
]
LLVM_SYMBOLIZER_OPTION = [
"external_symbolizer_path=$(location //:llvm_symbolizer)",
]
ASAN_ENV = select({
"//bazel/config:asan_enabled": {
"ASAN_OPTIONS": ":".join(ASAN_OPTIONS),
"LSAN_OPTIONS": ":".join(LSAN_OPTIONS),
},
"//bazel/config:asan_enabled_clang": {
"ASAN_OPTIONS": ":".join(ASAN_OPTIONS + LLVM_SYMBOLIZER_OPTION),
"LSAN_OPTIONS": ":".join(LSAN_OPTIONS + LLVM_SYMBOLIZER_OPTION),
},
"//conditions:default": {},
})
MSAN_ENV = select({
"//bazel/config:msan_enabled": {
"MSAN_OPTIONS": ":".join(MSAN_OPTIONS),
},
"//bazel/config:msan_enabled_clang": {
"MSAN_OPTIONS": ":".join(MSAN_OPTIONS + LLVM_SYMBOLIZER_OPTION),
},
"//conditions:default": {},
})
TSAN_ENV = select({
"//bazel/config:tsan_enabled": {
"TSAN_OPTIONS": ":".join(TSAN_OPTIONS),
},
"//bazel/config:tsan_enabled_clang": {
"TSAN_OPTIONS": ":".join(TSAN_OPTIONS + LLVM_SYMBOLIZER_OPTION),
},
"//conditions:default": {},
})
UBSAN_ENV = select({
"//bazel/config:ubsan_enabled": {
"UBSAN_OPTIONS": ":".join(UBSAN_OPTIONS),
},
"//bazel/config:ubsan_enabled_clang": {
"UBSAN_OPTIONS": ":".join(UBSAN_OPTIONS + LLVM_SYMBOLIZER_OPTION),
},
"//conditions:default": {},
})
ASAN_DATA = select({
"//bazel/config:asan_enabled": [
"//etc:lsan.suppressions",
],
"//conditions:default": [],
})
TSAN_DATA = select({
"//bazel/config:tsan_enabled": [
"//etc:tsan.suppressions",
],
"//conditions:default": [],
})
ANY_SAN_DATA = select({
"//bazel/config:any_sanitizer_clang": [
"//:llvm_symbolizer",
"//:llvm_symbolizer_libs",
],
"//conditions:default": [],
})
SANITIZER_ENV = ASAN_ENV | MSAN_ENV | TSAN_ENV | UBSAN_ENV
SANITIZER_DATA = ASAN_DATA + TSAN_DATA + ANY_SAN_DATA
LINKSTATIC_ENABLED = select({
"//bazel/config:linkdynamic_required_settings": False,
"//bazel/config:linkstatic_enabled": True,
}, no_match_error = REQUIRED_SETTINGS_DYNAMIC_LINK_ERROR_MESSAGE)
SKIP_ARCHIVE_ENABLED = select({
"//bazel/config:skip_archive_linkstatic_not_windows": True,
"//conditions:default": False,
})
SKIP_ARCHIVE_FEATURE = select({
"//bazel/config:skip_archive_linkstatic_not_windows": ["supports_start_end_lib"],
"//conditions:default": [],
})
SEPARATE_DEBUG_ENABLED = select({
"//bazel/config:separate_debug_enabled": True,
"//conditions:default": False,
})
PDB_GENERATION_ENABLED = select({
"//bazel/config:debug_symbols_disabled": False,
"//conditions:default": True,
})
TCMALLOC_ERROR_MESSAGE = """
Error:\n" +
Build failed due to unsupported platform for current allocator selection:
'--allocator=tcmalloc-google' is supported on linux with
aarch64 or x86_64
'--allocator=tcmalloc-gperf' is supported on windows or
linux, but not macos
'--allocator=system' can be used on any platform
"""
TCMALLOC_DEPS = select({
"//bazel/config:system_allocator_enabled": [],
"//bazel/config:tcmalloc_google_enabled": [
"//src/third_party/tcmalloc:tcmalloc",
"//src/third_party/tcmalloc:tcmalloc_internal_percpu_tcmalloc",
"//src/third_party/tcmalloc:tcmalloc_internal_sysinfo",
],
"//bazel/config:tcmalloc_gperf_enabled": [
"//src/third_party/gperftools:tcmalloc_minimal",
],
}, no_match_error = TCMALLOC_ERROR_MESSAGE)
SYMBOL_ORDER_FILES = [
"//buildscripts:symbols.orderfile",
"//buildscripts:symbols-al2023.orderfile",
]
# These are warnings are disabled globally at the toolchain level to allow external repository compilation.
# Re-enable them for MongoDB source code.
RE_ENABLE_DISABLED_3RD_PARTY_WARNINGS_FEATURES = select({
"//bazel/config:compiler_type_clang": [
"-disable_warnings_for_third_party_libraries_clang",
"thread_safety_warnings",
],
"//bazel/config:compiler_type_gcc": [
"-disable_warnings_for_third_party_libraries_gcc",
],
"//conditions:default": [],
})
MONGO_GLOBAL_SRC_DEPS = [
"//src/third_party/abseil-cpp:absl_base",
"//src/third_party/boost:headers",
"//src/third_party/croaring:croaring",
"//src/third_party/fmt:fmt",
"//src/third_party/libstemmer_c:stemmer",
"//src/third_party/murmurhash3:murmurhash3",
"//src/third_party/tomcrypt-1.18.2:tomcrypt",
"//src/third_party/immer:headers",
"//src/third_party/SafeInt:headers",
"//src/third_party/sasl:windows_sasl",
"//src/third_party/valgrind:headers",
"//src/third_party/abseil-cpp:absl_local_repo_deps",
]
MONGO_GLOBAL_ADDITIONAL_LINKER_INPUTS = SYMBOL_ORDER_FILES
def hex32(val):
"""Returns zero-padded 8-character lowercase hex string of 32-bit hash."""
v = val & 0xFFFFFFFF # wrap to 32-bit unsigned
s = "%x" % v
return ("0" * (8 - len(s))) + s
def force_includes_hdr(package_name, name):
if package_name.startswith("src/mongo"):
return select({
"@platforms//os:windows": [
"//src/mongo/platform:basic.h",
"//src/mongo/platform:windows_basic.h",
],
"//conditions:default": ["//src/mongo/platform:basic.h"],
})
if name in ["scripting", "scripting_mozjs_test", "encrypted_dbclient"]:
return select({
"//bazel/config:linux_aarch64": ["//src/third_party/mozjs:platform/aarch64/linux/build/js-config.h"],
"//bazel/config:linux_ppc64le": ["//src/third_party/mozjs:platform/ppc64le/linux/build/js-config.h"],
"//bazel/config:linux_s390x": ["//src/third_party/mozjs:platform/s390x/linux/build/js-config.h"],
"//bazel/config:linux_x86_64": ["//src/third_party/mozjs:platform/x86_64/linux/build/js-config.h"],
"//bazel/config:macos_aarch64": ["//src/third_party/mozjs:platform/aarch64/macOS/build/js-config.h"],
"//bazel/config:macos_x86_64": ["//src/third_party/mozjs:platform/x86_64/macOS/build/js-config.h"],
"//bazel/config:windows_x86_64": ["//src/third_party/mozjs:/platform/x86_64/windows/build/js-config.h"],
})
return []
def remap_linker_inputs_ownership_impl(ctx):
cc_toolchain = find_cpp_toolchain(ctx)
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features,
)
linker_inputs = []
for linker_input in ctx.attr.input[CcInfo].linking_context.linker_inputs.to_list():
linker_input = cc_common.create_linker_input(
owner = Label(ctx.attr.new_owner),
libraries = depset(linker_input.libraries),
user_link_flags = linker_input.user_link_flags,
additional_inputs = depset(linker_input.additional_inputs),
)
linker_inputs += [linker_input]
linking_context = cc_common.create_linking_context(linker_inputs = depset(direct = linker_inputs, transitive = []))
output = [DefaultInfo(files = ctx.attr.input.files), CcInfo(
compilation_context = ctx.attr.input[CcInfo].compilation_context,
linking_context = linking_context,
)]
return output
# Bazel cc_shared_library's implementation ignores static linker inputs that
# are owned by a different target than the cc_shared_library itself. Since we
# need to transitively collect the list of static linker inputs for the shared
# archive implementation, we need to transtiively remap ownership of each linker
# input to make Bazel actually link them in.
#
# Ex:
# mongo_crypt_v1.so
# -> libserver_base.a (linker input owned by mongo_crypt_v1.so)
# -> libbase.a (linker input owned by libserver_base.a, will be ignored normally)
#
# Since we effectively want to flatten this down into:
# mongo_crypt_v1.so
# -> libserver_base.a, libbase.a
#
# We need to the remap libbase.a linker input to be owned by mongo_crypt_v1.so
remap_linker_inputs_ownership = rule(
remap_linker_inputs_ownership_impl,
attrs = {
"input": attr.label(
providers = [CcInfo],
),
"new_owner": attr.string(),
},
provides = [CcInfo],
toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
fragments = ["cpp"],
)
def tidy_config_filegroup():
if native.existing_rule("clang_tidy_config") == None:
native.filegroup(
name = "clang_tidy_config",
srcs = native.glob(
[".clang-tidy"],
allow_empty = True,
),
visibility = ["//visibility:public"],
)
def mongo_cc_library(
name,
srcs = [],
hdrs = [],
textual_hdrs = [],
deps = [],
cc_deps = [],
private_hdrs = [],
testonly = False,
visibility = None,
data = [],
tags = [],
copts = [],
cxxopts = [],
linkopts = [],
includes = [],
linkstatic = False,
local_defines = [],
mongo_api_name = None,
target_compatible_with = [],
skip_global_deps = [],
non_transitive_dyn_linkopts = [],
defines = [],
additional_linker_inputs = [],
features = [],
exec_properties = {},
no_undefined_ref_DO_NOT_USE = True,
linkshared = False,
skip_windows_crt_flags = False,
shared_lib_name = "",
win_def_file = None,
auto_header = True,
srcs_select = None,
**kwargs):
"""Wrapper around cc_library.
Args:
name: The name of the library the target is compiling.
srcs: The source files to build.
hdrs: The headers files of the target library.
textual_hdrs: Textual headers. Might be used to include cpp files without
compiling them.
deps: The targets the library depends on.
cc_deps: Same as deps, but doesn't get added as shared library dep.
testonly: Whether or not the target is purely for tests.
visibility: The visibility of the target library.
data: Data targets the library depends on.
tags: Tags to add to the rule.
copts: Any extra compiler options to pass in.
linkopts: Any extra link options to pass in. These are applied
transitively to all targets that depend on this target.
includes: Any directory which should be exported to dependents, will be
prefixed with the package path
linkstatic: Whether or not linkstatic should be passed to the native bazel
cc_test rule. This argument is currently not supported. The mongo build
must link entirely statically or entirely dynamically. This can be
configured via //config/bazel:linkstatic.
local_defines: macro definitions added to the compile line when building
any source in this target, but not to the compile line of targets that
depend on this.
skip_global_deps: Globally injected dependencies to skip adding as a
dependency (options: "libunwind", "allocator").
non_transitive_dyn_linkopts: Any extra link options to pass in when
linking dynamically. Unlike linkopts these are not applied transitively
to all targets depending on this target, and are only used when linking
this target itself.
See https://jira.mongodb.org/browse/SERVER-89047 for motivation.
defines: macro definitions added to the compile line when building any
source in this target, as well as the compile line of targets that
depend on this.
additional_linker_inputs: Any additional files that you may want to pass
to the linker, for example, linker scripts.
linkshared: force this library to be linked dynamically, regardless of
configuration. This should only be used for shared archive support,
aka. a shared library with all of its dependencies linked to it statically.
"""
if linkstatic == True:
fail("""Linking specific targets statically is not supported.
The mongo build must link entirely statically or entirely dynamically.
This can be configured via //config/bazel:linkstatic.""")
if "libunwind" not in skip_global_deps:
deps += LIBUNWIND_DEPS
if "allocator" not in skip_global_deps:
deps += TCMALLOC_DEPS
# 0) Build real select(...) objects + a flat list of files (strings)
_select_objs, _select_flat_files = build_selects_and_flat_files(
srcs_select,
lib_name = name,
debug = False,
)
# 1) What cc_* should see: plain srcs, then fold in each select(...) via '+'
_final_srcs_for_cc = concat_selects(srcs, _select_objs)
pkg = native.package_name()
is_mongo_src = pkg.startswith("src/mongo")
in_third_party = "third_party" in pkg
if is_mongo_src:
if auto_header and not in_third_party:
# Introspection list for auto-headers (strings only!)
_all_concrete_srcs = dedupe_preserve_order(strings_only(srcs) + _select_flat_files)
_ah = maybe_compute_auto_headers(_all_concrete_srcs)
if _ah != None and _ah:
# dedupe only the _ah strings if you want, NOT the selector expression
srcs = _final_srcs_for_cc + dedupe_preserve_order(_ah)
else:
srcs = _final_srcs_for_cc + private_hdrs
elif not in_third_party:
srcs = binary_srcs_with_all_headers(name, _final_srcs_for_cc, private_hdrs)
else:
srcs = _final_srcs_for_cc + private_hdrs
if name != "mongoca" and name != "cyrus_sasl_windows_test_plugin":
deps += MONGO_GLOBAL_SRC_DEPS
features = features + RE_ENABLE_DISABLED_3RD_PARTY_WARNINGS_FEATURES
else:
srcs = _final_srcs_for_cc + private_hdrs
if "modules/enterprise" in native.package_name():
target_compatible_with += select({
"//bazel/config:build_enterprise_enabled": [],
"//conditions:default": ["@platforms//:incompatible"],
})
elif "modules/atlas" in native.package_name():
target_compatible_with += select({
"//bazel/config:build_atlas_enabled": [],
"//conditions:default": ["@platforms//:incompatible"],
})
if "third_party" in native.package_name():
tags = tags + ["third_party"]
copts = get_copts(name, native.package_name(), copts, skip_windows_crt_flags)
fincludes_hdr = force_includes_hdr(native.package_name(), name)
linkopts = get_linkopts(native.package_name(), linkopts)
if mongo_api_name:
visibility_support_defines_list = ["MONGO_USE_VISIBILITY", "MONGO_API_" + mongo_api_name]
visibility_support_shared_lib_flags_list = ["-fvisibility=hidden"]
else:
visibility_support_defines_list = ["MONGO_USE_VISIBILITY"]
visibility_support_shared_lib_flags_list = []
visibility_support_defines = select({
"//bazel/config:visibility_support_enabled_dynamic_linking_setting": visibility_support_defines_list,
"//conditions:default": [],
})
visibility_support_shared_flags = select({
"//bazel/config:visibility_support_enabled_dynamic_linking_non_windows_setting": visibility_support_shared_lib_flags_list,
"//conditions:default": [],
})
linux_rpath_flags = [
"-Wl,-z,origin",
"-Wl,--enable-new-dtags",
"-Wl,-rpath,\\$ORIGIN/../lib",
"-Wl,-h,lib" + name + ".so",
]
macos_rpath_flags = [
"-Wl,-rpath,\\$ORIGIN/../lib",
"-Wl,-install_name,@rpath/lib" + name + ".dylib",
]
rpath_flags = select({
"//bazel/config:linux_aarch64": linux_rpath_flags,
"//bazel/config:linux_ppc64le": linux_rpath_flags,
"//bazel/config:linux_s390x": linux_rpath_flags,
"//bazel/config:linux_x86_64": linux_rpath_flags,
"//bazel/config:macos_aarch64": macos_rpath_flags,
"//bazel/config:macos_x86_64": macos_rpath_flags,
"//bazel/config:windows_x86_64": [],
})
if no_undefined_ref_DO_NOT_USE:
undefined_ref_flag = select({
"//bazel/config:sanitize_address_required_settings": [],
"//bazel/config:sanitize_thread_required_settings": [],
"@platforms//os:macos": [],
"@platforms//os:windows": [],
"//conditions:default": ["-Wl,-z,defs"],
})
else:
undefined_ref_flag = []
tags = tags + ["skip_symbol_check"]
tidy_config_filegroup()
# Create a cc_library entry to generate a shared archive of the target.
cc_library(
name = name + SHARED_ARCHIVE_SUFFIX,
srcs = srcs + SANITIZER_DENYLIST_HEADERS,
hdrs = hdrs + fincludes_hdr,
deps = deps + cc_deps,
textual_hdrs = textual_hdrs,
visibility = visibility,
testonly = testonly,
copts = copts,
cxxopts = cxxopts,
data = data,
tags = tags + ["mongo_library"],
linkopts = linkopts,
linkstatic = True,
local_defines = MONGO_GLOBAL_DEFINES + visibility_support_defines + local_defines,
defines = defines,
includes = includes,
features = features,
target_compatible_with = select({
"//bazel/config:shared_archive_enabled": [],
"//conditions:default": ["@platforms//:incompatible"],
}) + target_compatible_with,
additional_linker_inputs = additional_linker_inputs + MONGO_GLOBAL_ADDITIONAL_LINKER_INPUTS,
exec_properties = exec_properties,
**kwargs
)
# Did not want to expose alwayslink for cc_library as it ends up getting
# modified in extract_debuginfo
if "alwayslink" not in kwargs:
kwargs["alwayslink"] = SKIP_ARCHIVE_ENABLED
cc_library(
name = name + WITH_DEBUG_SUFFIX,
srcs = srcs + SANITIZER_DENYLIST_HEADERS,
hdrs = hdrs + fincludes_hdr,
deps = deps + cc_deps,
textual_hdrs = textual_hdrs,
visibility = visibility,
testonly = testonly,
copts = copts,
cxxopts = cxxopts,
data = data,
tags = tags + ["mongo_library", "check_symbol_target"],
linkopts = linkopts,
linkstatic = True,
local_defines = MONGO_GLOBAL_DEFINES + local_defines,
defines = defines,
includes = includes,
features = SKIP_ARCHIVE_FEATURE + features,
target_compatible_with = target_compatible_with,
additional_linker_inputs = additional_linker_inputs + MONGO_GLOBAL_ADDITIONAL_LINKER_INPUTS,
exec_properties = exec_properties,
**kwargs
)
dynamic_deps = deps
shared_library_compatible_with = select({
"//bazel/config:linkstatic_disabled": [],
"//conditions:default": ["@platforms//:incompatible"],
})
# Always build shared if specified & remove dynamic deps to allow
# for static linking dependencies.
if linkshared:
shared_library_compatible_with = []
dynamic_deps = []
remap_linker_inputs_ownership(
name = name + WITH_DEBUG_SUFFIX + "_ownership_remapped",
input = name + WITH_DEBUG_SUFFIX,
new_owner = "//" + native.package_name() + ":" + name + WITH_DEBUG_SUFFIX,
)
# Creates a shared library version of our target only if
# //bazel/config:linkstatic_disabled is true. This uses the
# CcSharedLibraryInfo provided from extract_debuginfo to allow it to declare
# all dependencies in dynamic_deps.
native.cc_shared_library(
name = name + CC_SHARED_LIBRARY_SUFFIX + WITH_DEBUG_SUFFIX,
deps = [name + WITH_DEBUG_SUFFIX + "_ownership_remapped"] if linkshared else [name + WITH_DEBUG_SUFFIX],
visibility = visibility,
tags = tags + ["mongo_library"],
user_link_flags = get_linkopts(native.package_name()) + undefined_ref_flag + non_transitive_dyn_linkopts + rpath_flags + visibility_support_shared_flags + select({
"//bazel/config:simple_build_id_enabled": ["-Wl,--build-id=0x" +
hex32(hash(name)) +
hex32(hash(name)) +
hex32(hash(str(UNSAFE_VERSION_ID) + str(UNSAFE_COMPILE_VARIANT)))],
"//conditions:default": [],
}),
target_compatible_with = shared_library_compatible_with + target_compatible_with,
dynamic_deps = dynamic_deps,
shared_lib_name = shared_lib_name,
features = select({
"//bazel/config:windows_debug_symbols_enabled": ["generate_pdb_file"],
"//conditions:default": [],
}) + select({
"//bazel/config:simple_build_id_enabled": ["-build_id"],
"//conditions:default": [],
}),
additional_linker_inputs = additional_linker_inputs + MONGO_GLOBAL_ADDITIONAL_LINKER_INPUTS,
exec_properties = exec_properties,
win_def_file = win_def_file,
)
shared_library = select({
"//bazel/config:linkstatic_disabled": ":" + name + CC_SHARED_LIBRARY_SUFFIX + WITH_DEBUG_SUFFIX,
"//conditions:default": None,
})
shared_archive = select({
"//bazel/config:shared_archive_enabled": ":" + name + SHARED_ARCHIVE_SUFFIX,
"//conditions:default": None,
})
if linkshared:
shared_library = name + CC_SHARED_LIBRARY_SUFFIX + WITH_DEBUG_SUFFIX
shared_archive = None
extract_debuginfo(
name = name,
binary_with_debug = ":" + name + WITH_DEBUG_SUFFIX,
type = "library",
tags = tags + ["mongo_library"],
enabled = SEPARATE_DEBUG_ENABLED,
enable_pdb = PDB_GENERATION_ENABLED,
cc_shared_library = shared_library,
shared_archive = shared_archive,
skip_archive = SKIP_ARCHIVE_ENABLED,
visibility = visibility,
deps = deps + cc_deps,
exec_properties = exec_properties,
)
def write_sources_impl(ctx):
out = ctx.actions.declare_file(ctx.label.name + ".sources_list")
ctx.actions.write(
out,
"\n".join(ctx.attr.sources),
)
return [
DefaultInfo(
files = depset([out]),
),
]
write_sources = rule(
write_sources_impl,
attrs = {
"sources": attr.string_list(
doc = "the sources used to build the binary",
),
},
)
def _mongo_cc_binary_and_test(
name,
srcs = [],
deps = [],
private_hdrs = [],
testonly = False,
visibility = None,
data = [],
tags = [],
copts = [],
linkopts = [],
includes = [],
linkstatic = False,
local_defines = [],
target_compatible_with = [],
defines = [],
additional_linker_inputs = [],
features = [],
exec_properties = {},
skip_global_deps = [],
env = {},
_program_type = "",
skip_windows_crt_flags = False,
auto_header = True,
srcs_select = None,
**kwargs):
if linkstatic == True:
fail("""Linking specific targets statically is not supported.
The mongo build must link entirely statically or entirely dynamically.
This can be configured via //config/bazel:linkstatic.""")
# 0) Build real select(...) objects + gather a flat, introspectable list of files
_select_objs, _select_flat_files = build_selects_and_flat_files(
srcs_select,
lib_name = name,
debug = False,
)
# 1) What we actually pass to cc_binary as srcs: (plain srcs) + (real select(...)s)
_final_srcs_for_cc = concat_selects(srcs, _select_objs)
pkg = native.package_name()
is_mongo_src = pkg.startswith("src/mongo")
in_third_party = "third_party" in pkg
if is_mongo_src:
if auto_header and not in_third_party:
# What we use for *introspection* (auto-header computation): a plain list of strings
_all_concrete_srcs = dedupe_preserve_order((srcs or []) + _select_flat_files)
# Use the concrete list so the tool can iterate even if _final_srcs_for_cc contains selects
_ah = maybe_compute_auto_headers(_all_concrete_srcs)
if _ah != None:
# Add transitive auto-headers to *srcs* (binary path)
srcs = _final_srcs_for_cc + dedupe_preserve_order(_ah)
else:
# Couldnt compute auto-headers → fall back to adding private_hdrs to srcs
srcs = _final_srcs_for_cc + private_hdrs
elif not in_third_party:
# all_headers mode (binary flavor): returns a srcs list
srcs = binary_srcs_with_all_headers(name, _final_srcs_for_cc, private_hdrs)
else:
# third_party inside src/mongo: append private headers as sources
srcs = _final_srcs_for_cc + private_hdrs
deps += MONGO_GLOBAL_SRC_DEPS
features = features + RE_ENABLE_DISABLED_3RD_PARTY_WARNINGS_FEATURES
else:
# Non-mongo pkgs: append private headers as sources
srcs = _final_srcs_for_cc + private_hdrs
if "modules/enterprise" in native.package_name():
target_compatible_with += select({
"//bazel/config:build_enterprise_enabled": [],
"//conditions:default": ["@platforms//:incompatible"],
})
if "modules/enterprise/src/fle" not in native.package_name():
target_compatible_with += select({
"//bazel/config:ssl_enabled": [],
"//conditions:default": ["@platforms//:incompatible"],
})
copts = get_copts(name, native.package_name(), copts, skip_windows_crt_flags)
fincludes_hdr = force_includes_hdr(native.package_name(), name)
linkopts = get_linkopts(native.package_name(), linkopts)
all_deps = deps
if "libunwind" not in skip_global_deps:
all_deps += LIBUNWIND_DEPS
if "allocator" not in skip_global_deps:
all_deps += TCMALLOC_DEPS
linux_rpath_flags = [
"-Wl,-z,origin",
"-Wl,--enable-new-dtags",
"-Wl,-rpath,\\$$ORIGIN/../lib",
]
macos_rpath_flags = ["-Wl,-rpath,\\$$ORIGIN/../lib"]
rpath_flags = select({
"//bazel/config:linux_aarch64": linux_rpath_flags,
"//bazel/config:linux_ppc64le": linux_rpath_flags,
"//bazel/config:linux_s390x": linux_rpath_flags,
"//bazel/config:linux_x86_64": linux_rpath_flags,
"//bazel/config:macos_aarch64": macos_rpath_flags,
"//bazel/config:macos_x86_64": macos_rpath_flags,
"//bazel/config:windows_x86_64": [],
})
exec_properties |= select({
"//bazel/config:link_timeout_enabled": {
"cpp_link.timeout": "600",
},
"//conditions:default": {},
})
# This is used as a tool in part of the shared archive build, so it needs to be marked
# as compatible with a shared archive build.
if name in ["grpc_cpp_plugin", "protobuf_compiler"]:
features = features + ["-pie", "pic"]
else:
target_compatible_with += select({
"//bazel/config:shared_archive_enabled": ["@platforms//:incompatible"],
"//conditions:default": [],
})
args = {
"name": name + WITH_DEBUG_SUFFIX,
"srcs": srcs + fincludes_hdr + SANITIZER_DENYLIST_HEADERS,
"deps": all_deps,
"visibility": visibility,
"testonly": testonly,
"copts": copts,
"data": data + SANITIZER_DATA + select({
"//bazel/platforms:use_mongo_toolchain": ["//:gdb"],
"//conditions:default": [],
}),
"tags": tags,
"linkopts": linkopts + rpath_flags + select({
"//bazel/config:thin_lto_enabled": ["-Wl,--threads=" + str(NUM_CPUS)],
"//conditions:default": [],
}) + select({
"//bazel/config:simple_build_id_enabled": ["-Wl,--build-id=0x" +
hex32(hash(name)) +
hex32(hash(name)) +
hex32(hash(str(UNSAFE_VERSION_ID) + str(UNSAFE_COMPILE_VARIANT)))],
"//conditions:default": [],
}),
"linkstatic": LINKSTATIC_ENABLED,
"local_defines": MONGO_GLOBAL_DEFINES + local_defines,
"defines": defines,
"includes": includes,
"features": SKIP_ARCHIVE_FEATURE + ["-pic", "pie"] + features + select({
"//bazel/config:windows_debug_symbols_enabled": ["generate_pdb_file"],
"//conditions:default": [],
}) + select({
"//bazel/config:simple_build_id_enabled": ["-build_id"],
"//conditions:default": [],
}),
"dynamic_deps": select({
"//bazel/config:linkstatic_disabled": deps,
"//conditions:default": [],
}),
"target_compatible_with": target_compatible_with,
"additional_linker_inputs": additional_linker_inputs + MONGO_GLOBAL_ADDITIONAL_LINKER_INPUTS,
"exec_properties": exec_properties | select({
"//bazel/config:remote_link_enabled": {},
"//bazel/config:dtlto_enabled": {},
"@platforms//os:windows": {"cpp_link.coefficient": "1.0"},
"//conditions:default": {"cpp_link.coefficient": "18.0"},
}) | select({
"//bazel/config:thin_lto_enabled": {"cpp_link.cpus": str(NUM_CPUS)},
"//conditions:default": {},
}) | select({
"//bazel/config:remote_link_arm_linux_linkstatic": {"cpp_link.Pool": "arm_linker"},
"//conditions:default": {},
}),
"env": env | SANITIZER_ENV,
} | kwargs
# we dont want the intermediate build targets to be picked up by tags
# so we empty it out
original_tags = list(args["tags"])
args["tags"] = ["intermediate_debug"] + [tag + "_debug" for tag in original_tags]
if _program_type == "binary":
cc_binary(**args)
extract_debuginfo_binary(
name = name,
binary_with_debug = ":" + name + WITH_DEBUG_SUFFIX,
type = "program",
tags = original_tags + ["final_target"],
enabled = SEPARATE_DEBUG_ENABLED,
enable_pdb = PDB_GENERATION_ENABLED,
deps = all_deps,
visibility = visibility,
exec_properties = exec_properties,
)
else:
native.cc_test(**args)
extract_debuginfo_test(
name = name,
binary_with_debug = ":" + name + WITH_DEBUG_SUFFIX,
type = "program",
tags = original_tags + ["final_target"],
enabled = SEPARATE_DEBUG_ENABLED,
enable_pdb = PDB_GENERATION_ENABLED,
deps = all_deps,
visibility = visibility,
exec_properties = exec_properties,
)
native.sh_test(
name = name + "_ci_wrapper",
srcs = [
"//bazel:test_wrapper",
],
tags = original_tags + ["wrapper_target"],
args = [
"$(location " + name + ")",
],
data = args["data"] + [name],
env = args["env"],
target_compatible_with = target_compatible_with,
visibility = visibility,
exec_properties = exec_properties,
)
def mongo_cc_binary(
name,
srcs = [],
deps = [],
private_hdrs = [],
testonly = False,
visibility = None,
data = [],
tags = [],
copts = [],
linkopts = [],
includes = [],
linkstatic = False,
local_defines = [],
target_compatible_with = [],
defines = [],
additional_linker_inputs = [],
features = [],
exec_properties = {},
skip_global_deps = [],
env = {},
**kwargs):
"""Wrapper around cc_binary.
Args:
name: The name of the library the target is compiling.
srcs: The source files to build.
deps: The targets the library depends on.
testonly: Whether or not the target is purely for tests.
visibility: The visibility of the target library.
data: Data targets the library depends on.
tags: Tags to add to the rule.
copts: Any extra compiler options to pass in.
linkopts: Any extra link options to pass in.
includes: Any directory which should be exported to dependents, will be
prefixed with the package path
linkstatic: Whether or not linkstatic should be passed to the native bazel
cc_test rule. This argument is currently not supported. The mongo build
must link entirely statically or entirely dynamically. This can be
configured via //config/bazel:linkstatic.
local_defines: macro definitions passed to all source and header files.
defines: macro definitions added to the compile line when building any
source in this target, as well as the compile line of targets that
depend on this.
additional_linker_inputs: Any additional files that you may want to pass
to the linker, for example, linker scripts.
skip_global_deps: Globally injected dependencies to skip adding as a
dependency (options: "libunwind", "allocator").
env: environment variables to pass to the binary when running through
bazel.
"""
_mongo_cc_binary_and_test(
name,
srcs,
deps,
private_hdrs,
testonly,
visibility,
data,
tags + ["mongo_binary"],
copts,
linkopts,
includes,
linkstatic,
local_defines,
target_compatible_with,
defines,
additional_linker_inputs,
features,
exec_properties,
skip_global_deps,
env,
_program_type = "binary",
**kwargs
)
def mongo_cc_test(
name,
srcs = [],
deps = [],
private_hdrs = [],
visibility = None,
data = [],
tags = [],
copts = [],
linkopts = [],
includes = [],
linkstatic = False,
local_defines = [],
target_compatible_with = [],
defines = [],
additional_linker_inputs = [],
features = [],
exec_properties = {},
skip_global_deps = [],
env = {},
minimum_test_resources = {},
**kwargs):
"""Wrapper around cc_test.
Args:
name: The name of the test target.
srcs: The source files to build.
deps: The targets the library depends on.
visibility: The visibility of the target library.
data: Data targets the library depends on.
tags: Tags to add to the rule.
copts: Any extra compiler options to pass in.
linkopts: Any extra link options to pass in.
includes: Any directory which should be exported to dependents, will be
prefixed with the package path
linkstatic: Whether or not linkstatic should be passed to the native bazel
cc_test rule. This argument is currently not supported. The mongo build
must link entirely statically or entirely dynamically. This can be
configured via //config/bazel:linkstatic.
local_defines: macro definitions passed to all source and header files.
defines: macro definitions added to the compile line when building any
source in this target, as well as the compile line of targets that
depend on this.
additional_linker_inputs: Any additional files that you may want to pass
to the linker, for example, linker scripts.
skip_global_deps: Globally injected dependencies to skip adding as a
dependency (options: "libunwind", "allocator").
env: environment variables to pass to the binary when running through
bazel.
minimum_test_resources: a dict of key/value pairs defining execution
requirements for the test. The only currently supported key is "cpu_cores".
"""
minimum_core_count = 1
if "cpu_cores" in minimum_test_resources:
minimum_core_count = minimum_test_resources["cpu_cores"]
if minimum_core_count == 2:
exec_properties = exec_properties | select({
"@platforms//cpu:x86_64": {
"test.Pool": "large_mem_2core_x86_64",
},
"@platforms//cpu:aarch64": {
"test.Pool": "large_memory_2core_arm64",
},
"//conditions:default": {},
})
elif minimum_core_count > 2:
fail("minimum_test_resources[\"cpu_cores\"] > 2 is not supported")
else:
# TSAN will use more memory and EngFlow currently does not surface a good
# error message to users when an OOM occurs.
# TOOD(SERVER-112889): Remove this once OOM errors are better surfaced by EngFlow
exec_properties = exec_properties | select({
"//bazel/config:tsan_enabled_x86_64": {
"test.Pool": "large_mem_x86_64",
},
"//bazel/config:tsan_enabled_arm64": {
"test.Pool": "large_memory_arm64",
},
"//conditions:default": {},
})
_mongo_cc_binary_and_test(
name,
srcs,
deps,
private_hdrs,
True,
visibility,
data,
tags,
copts,
linkopts,
includes,
linkstatic,
local_defines,
target_compatible_with,
defines,
additional_linker_inputs,
features,
exec_properties,
skip_global_deps,
env | {
# This flag is already always set when running bazel test. Setting it
# here ensures that it is also set when running bazel run. This avoids
# test-setup.sh piping stdout through tee, so that the binary will be
# directly connected to the terminal and able to detect color support.
# We can remove this once we are on bazel 9 because it has removed the
# logic that looks for this var always behaves as if it is set.
"EXPERIMENTAL_SPLIT_XML_GENERATION": "1",
} | select({
"//bazel/config:dev_stacktrace_enabled": {
# Forcing bazel's test environment setup script to run from the
# unsandboxed directory allows access to split DWARF files and source
# files.
"RUNTEST_PRESERVE_CWD": "1",
},
"//conditions:default": {},
}),
_program_type = "test",
**kwargs
)
def mongo_cc_unit_test(
name,
srcs = [],
deps = [],
private_hdrs = [],
visibility = ["//visibility:public"],
data = [],
tags = [],
copts = [],
linkopts = [],
includes = [],
linkstatic = False,
local_defines = [],
target_compatible_with = [],
defines = [],
additional_linker_inputs = [],
features = [],
exec_properties = {},
has_custom_mainline = False,
**kwargs):
mongo_cc_test(
name = name,
srcs = srcs,
deps = deps + ([] if has_custom_mainline else ["//src/mongo/unittest:unittest_main"]),
private_hdrs = private_hdrs,
visibility = visibility,
data = data,
tags = tags + ["mongo_unittest"],
copts = copts,
linkopts = linkopts,
includes = includes,
linkstatic = linkstatic,
local_defines = local_defines,
target_compatible_with = target_compatible_with,
defines = defines,
additional_linker_inputs = additional_linker_inputs,
features = features,
exec_properties = exec_properties,
**kwargs
)
IdlInfo = provider(
fields = {
"header_output": "header output of the idl",
"idl_deps": "depset of idl files",
},
)
def idl_generator_impl(ctx):
base = ctx.attr.src.files.to_list()[0].basename.removesuffix(".idl")
gen_source = ctx.actions.declare_file(base + "_gen.cpp")
gen_header = ctx.actions.declare_file(base + "_gen.h")
python = ctx.toolchains["@bazel_tools//tools/python:toolchain_type"].py3_runtime
dep_depsets = [dep[IdlInfo].idl_deps for dep in ctx.attr.deps]
# Transitive headers from deps + explicit hdrs attr
transitive_header_outputs = (
[dep[IdlInfo].header_output for dep in ctx.attr.deps] +
[hdr[DefaultInfo].files for hdr in ctx.attr.hdrs]
)
# collect deps from python modules and setup the corresponding
# path so all modules can be found by the toolchain.
python_path = []
for py_dep in ctx.attr.py_deps:
for path in py_dep[PyInfo].imports.to_list():
if path not in python_path:
python_path.append(ctx.expand_make_variables(
"python_library_imports",
"$(BINDIR)/external/" + path,
ctx.var,
))
py_depsets = [py_dep[PyInfo].transitive_sources for py_dep in ctx.attr.py_deps]
inputs = depset(transitive = [
ctx.attr.src.files,
ctx.attr.idlc.files,
python.files,
] + dep_depsets + py_depsets)
include_directives = ["--include", "src"]
if "src/mongo/db/modules/enterprise/src" in ctx.attr.src.files.to_list()[0].path:
include_directives += ["--include", "src/mongo/db/modules/enterprise/src"]
ctx.actions.run(
executable = python.interpreter.path,
outputs = [gen_source, gen_header],
inputs = inputs,
arguments = [
"buildscripts/idl/idlc.py",
"--base_dir",
ctx.bin_dir.path + "/src",
"--target_arch",
ctx.var["TARGET_CPU"],
"--header",
gen_header.path,
"--output",
gen_source.path,
ctx.attr.src.files.to_list()[0].path,
] + include_directives,
mnemonic = "IdlcGenerator",
env = {"PYTHONPATH": ctx.configuration.host_path_separator.join(python_path)},
)
# Depsets well publish
header_ds = depset([gen_header], transitive = transitive_header_outputs)
all_files = depset([gen_source, gen_header], transitive = transitive_header_outputs)
return [
# Keep DefaultInfo as-is so :*_gen works in cc_library(srcs/hdrs)
DefaultInfo(files = all_files),
# Your custom provider (unchanged)
IdlInfo(
idl_deps = depset(
ctx.attr.src.files.to_list(),
transitive = [dep[IdlInfo].idl_deps for dep in ctx.attr.deps],
),
header_output = header_ds,
),
# NEW: expose header-only view for wrappers in the shadow BUILD
OutputGroupInfo(
# Most consumers use one of these two names—publish both:
hdrs = header_ds,
header_files = header_ds,
# Optional: a cpp-only view if you ever want it
srcs = depset([gen_source]),
cpps = depset([gen_source]),
# (You can omit srcs/cpps if you don't need them.)
),
]
idl_generator_rule = rule(
idl_generator_impl,
attrs = {
"deps": attr.label_list(
doc = "Other idl files that need to be imported.",
providers = [IdlInfo],
),
"idlc": attr.label(
doc = "The idlc generator to use.",
default = "//buildscripts/idl:idlc",
),
"py_deps": attr.label_list(
doc = "Python modules that should be imported.",
providers = [PyInfo],
default = [
dependency("pyyaml", group = "core"),
dependency("pymongo", group = "core"),
],
),
"src": attr.label(
doc = "The idl file to generate cpp/h files from.",
allow_single_file = True,
),
"hdrs": attr.label_list(
doc = "Dependent headers required by this IDL target",
allow_files = True,
default = [],
),
},
outputs = {
# These create addressable file labels:
"gen_hdr": "%{name}.h",
"gen_src": "%{name}.cpp",
},
doc = "Generates header/source files from IDL files.",
toolchains = ["@bazel_tools//tools/python:toolchain_type"],
fragments = ["py"],
)
def idl_generator(name, tags = [], hdrs = [], deps = [], idl_self_dep = False, **kwargs):
# Extra headers always pulled by IDL
if not idl_self_dep:
idl_deps = deps + ["//src/mongo/db/query:explain_verbosity_gen"]
else:
idl_deps = deps
idl_generator_rule(
name = name,
tags = tags + ["gen_source"],
hdrs = hdrs + ["//src/mongo:idl_headers"],
deps = idl_deps,
**kwargs
)
def symlink_impl(ctx):
ctx.actions.symlink(
output = ctx.outputs.output,
target_file = ctx.attr.input.files.to_list()[0],
)
return [DefaultInfo(files = depset([ctx.outputs.output]))]
symlink_rule = rule(
symlink_impl,
attrs = {
"input": attr.label(
doc = "The File that the output symlink will point to.",
allow_single_file = True,
),
"output": attr.output(
doc = "The output of this rule.",
),
},
)
def symlink(name, tags = [], **kwargs):
symlink_rule(
name = name,
tags = tags + ["gen_source"],
**kwargs
)
def strip_deps_impl(ctx):
cc_toolchain = find_cpp_toolchain(ctx)
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features,
)
linker_input = ctx.attr.input[CcInfo].linking_context.linker_inputs.to_list()[0]
linking_context = cc_common.create_linking_context(linker_inputs = depset(direct = [linker_input], transitive = []))
return [DefaultInfo(files = ctx.attr.input.files), CcInfo(
compilation_context = ctx.attr.input[CcInfo].compilation_context,
linking_context = linking_context,
)]
strip_deps = rule(
strip_deps_impl,
attrs = {
"input": attr.label(
providers = [CcInfo],
),
"linkstatic": attr.bool(),
},
provides = [CcInfo],
toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
fragments = ["cpp"],
)
def dummy_file_impl(ctx):
ctx.actions.write(
output = ctx.outputs.output,
content = "",
)
return [DefaultInfo(files = depset([ctx.outputs.output]))]
dummy_file = rule(
dummy_file_impl,
attrs = {
"output": attr.output(
doc = "The output of this rule.",
),
},
)
def mongo_proto_library(
name,
srcs,
tags = [],
**kwargs):
features = kwargs.pop("features", [])
proto_library(
name = name,
srcs = srcs,
tags = tags + ["gen_source"],
features = features,
**kwargs
)
def mongo_cc_proto_library(
name,
deps,
tags = [],
**kwargs):
native.cc_proto_library(
name = name + "_raw",
deps = deps,
**kwargs
)
strip_deps(
name = name,
input = name + "_raw",
tags = tags + ["gen_source"],
)
def mongo_cc_grpc_library(
name,
srcs,
cc_proto,
deps = [],
grpc_only = True,
proto_only = False,
well_known_protos = False,
generate_mocks = False,
tags = [],
no_undefined_ref_DO_NOT_USE = True,
**kwargs):
codegen_grpc_target = "_" + name + "_grpc_codegen"
# TODO(SERVER-100148): Re-enable sandboxing on protobuf compilation
# once we can rely on //external:grpc_cpp_plugin.
#
# TSAN is currently being applied to protoc which is failing to run
# under Bazel's sandbox due to the system call to disable ASLR
# failing.
#
# To workaround this issue, disable the sandbox only when compiling
# protobufs, since we don't care about threading issues in the
# proto compiler itself.
generate_cc(
name = codegen_grpc_target,
srcs = srcs,
plugin = "//src/third_party/grpc:grpc_cpp_plugin",
well_known_protos = well_known_protos,
generate_mocks = generate_mocks,
tags = tags + ["gen_source"],
disable_sandbox = select({
"//bazel/config:tsan_enabled": True,
"//conditions:default": False,
}),
**kwargs
)
# cc_proto_library tacks on unnecessary link-time dependencies to
# @com_google_protobuf and @com_google_absl, forcefully remove them
# to avoid intefering with thin targets link line generation.
cc_proto_target = "_" + name + "_cc_proto_stripped_deps"
strip_deps(
name = cc_proto_target,
input = cc_proto,
)
mongo_cc_library(
name = name,
srcs = [":" + codegen_grpc_target],
hdrs = [":" + codegen_grpc_target],
deps = deps +
["//src/third_party/grpc:grpc++_codegen_proto"],
cc_deps = [":" + cc_proto_target],
no_undefined_ref_DO_NOT_USE = no_undefined_ref_DO_NOT_USE,
**kwargs
)
def mongo_idl_library(
name,
src,
idl_deps = [],
idl_hdrs = [],
deps = [],
**kwargs):
"""
Args:
name: The name of the IDL library.
src: The IDL src.
idl_deps: The idl_generator deps.
idl_hdrs: The idl_generator hdrs.
deps: The mongo_cc_library deps.
"""
idl_gen_name = name + "_gen"
idl_generator(
name = idl_gen_name,
src = src,
hdrs = idl_hdrs,
deps = idl_deps,
)
mongo_cc_library(
name = name,
srcs = [idl_gen_name],
deps = deps,
auto_header = False,
**kwargs
)
def mongo_cc_benchmark(
name,
srcs = [],
deps = [],
private_hdrs = [],
visibility = None,
data = [],
tags = [],
copts = [],
linkopts = [],
includes = [],
linkstatic = False,
local_defines = [],
target_compatible_with = [],
defines = [],
additional_linker_inputs = [],
features = [],
exec_properties = {},
has_custom_mainline = False,
**kwargs):
mongo_cc_test(
name = name,
srcs = srcs,
deps = deps + ([] if has_custom_mainline else ["//src/mongo/unittest:benchmark_main"]),
private_hdrs = private_hdrs,
visibility = visibility,
data = data,
tags = tags + ["mongo_benchmark"],
copts = copts,
linkopts = linkopts,
includes = includes,
linkstatic = linkstatic,
local_defines = local_defines,
target_compatible_with = target_compatible_with,
defines = defines,
additional_linker_inputs = additional_linker_inputs,
features = features,
exec_properties = exec_properties,
**kwargs
)
def mongo_cc_integration_test(
name,
srcs = [],
deps = [],
private_hdrs = [],
visibility = None,
data = [],
tags = [],
copts = [],
linkopts = [],
includes = [],
linkstatic = False,
local_defines = [],
target_compatible_with = [],
defines = [],
additional_linker_inputs = [],
features = [],
exec_properties = {},
has_custom_mainline = False,
**kwargs):
mongo_cc_test(
name = name,
srcs = srcs,
deps = deps + ([] if has_custom_mainline else ["//src/mongo/unittest:integration_test_main"]),
private_hdrs = private_hdrs,
visibility = visibility,
data = data,
tags = tags + ["mongo_integration_test"],
copts = copts,
linkopts = linkopts,
includes = includes,
linkstatic = linkstatic,
local_defines = local_defines,
target_compatible_with = target_compatible_with,
defines = defines,
additional_linker_inputs = additional_linker_inputs,
features = features,
exec_properties = exec_properties,
**kwargs
)
def mongo_cc_fuzzer_test(
name,
srcs = [],
deps = [],
private_hdrs = [],
visibility = None,
data = [],
tags = [],
copts = [],
linkopts = [],
includes = [],
linkstatic = False,
local_defines = [],
target_compatible_with = [],
defines = [],
additional_linker_inputs = [],
features = [],
exec_properties = {},
has_custom_mainline = False,
**kwargs):
mongo_cc_test(
name = name,
srcs = srcs,
deps = deps,
private_hdrs = private_hdrs,
visibility = visibility,
data = data,
tags = tags + ["mongo_fuzzer_test"],
copts = copts,
linkopts = linkopts + ["-fsanitize=fuzzer"],
includes = includes,
linkstatic = linkstatic,
local_defines = local_defines,
target_compatible_with = target_compatible_with + select({
"//bazel/config:fsan_enabled": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
defines = defines,
additional_linker_inputs = additional_linker_inputs,
features = features,
exec_properties = exec_properties,
**kwargs
)
# Note: For these extensions to load successfully in the server, they must be built with
# --allocator=system. Otherwise, the extensions will get a local instance of tcmalloc which
# fails to run properly because there isn't enough TLS space available for both the host and
# extension's tcmalloc. In transitions.bzl, we define a Bazel transition for managing the allocator
# and other extension-specific options.
def mongo_cc_extension_shared_library(
name,
srcs = [],
deps = [],
private_hdrs = [],
visibility = None,
data = [],
tags = [],
copts = [],
linkopts = [],
includes = [],
linkstatic = False,
local_defines = [],
target_compatible_with = [],
defines = [],
additional_linker_inputs = [],
features = [],
exec_properties = {},
**kwargs):
mongo_cc_library(
name = name,
srcs = srcs,
deps = deps + [
"//src/mongo/db/extension/public:extensions_api_public",
"//src/mongo/db/extension/sdk:sdk_cpp",
],
private_hdrs = private_hdrs,
visibility = visibility,
data = data,
tags = tags,
copts = copts,
linkopts = linkopts,
includes = includes,
linkstatic = linkstatic,
local_defines = local_defines,
defines = defines,
features = features,
exec_properties = exec_properties,
additional_linker_inputs = additional_linker_inputs + select({
"@platforms//os:linux": [
":test_extensions.version_script.lds",
],
"//conditions:default": [],
}) + select({
"@platforms//os:macos": [
":test_extensions.exported_symbols_list.lds",
],
"//conditions:default": [],
}),
# linkshared produces a shared library as the output.
# TODO SERVER-109255 Make sure the test extensions are statically linked, as we expect
# all extensions to be.
linkshared = True,
non_transitive_dyn_linkopts = select({
"@platforms//os:linux": [
"-Wl,--version-script=$(location :test_extensions.version_script.lds)",
],
"//conditions:default": [],
}) + select({
"@platforms//os:macos": [
"-Wl,-exported_symbols_list,$(location :test_extensions.exported_symbols_list.lds)",
],
"//conditions:default": [],
}),
skip_global_deps = [
# This is a globally injected dependency. We don't want a special allocator linked
# here. Instead, the allocator should be overriden at load time.
"allocator",
"libunwind",
],
target_compatible_with = target_compatible_with + select({
"//bazel/config:shared_archive_or_link_dynamic": [],
"//conditions:default": ["@platforms//:incompatible"],
}) + select({
"@platforms//os:linux": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
)
def _compute_win_defines(ver):
if ver not in MIN_VER_MAP:
fail("Unsupported windows_version_minimal=%r; supported: %r" %
(ver, sorted(MIN_VER_MAP.keys())))
m = MIN_VER_MAP[ver]
return [
"_WIN32_WINNT=%s" % m["win"],
"BOOST_USE_WINAPI_VERSION=%s" % m["win"],
"NTDDI_VERSION=%s" % m["ddi"],
]
def _uniq_dirs(files):
d = {}
for f in files:
d[f.dirname] = True
return sorted(d.keys())
def _rc_impl(ctx):
# No-op on non-Windows
if not ctx.target_platform_has_constraint(
ctx.attr._os_windows[platform_common.ConstraintValueInfo],
):
li = cc_common.create_linker_input(
owner = ctx.label,
user_link_flags = [],
additional_inputs = depset(), # and declare it as a link input
)
new_cc_shared_info = CcSharedLibraryInfo(
dynamic_deps = depset(),
exports = [],
linker_input = li,
link_once_static_libs = {},
)
return [DefaultInfo(files = depset([])), CcInfo(), new_cc_shared_info]
new_cc_shared_info = CcSharedLibraryInfo(
dynamic_deps = depset(),
exports = [],
linker_input = None,
link_once_static_libs = {},
)
# On Windows we need an rc executable
if ctx.executable.rc == None:
fail("windows_rc: 'rc' tool not provided. Pass rc = '@mongo_windows_toolchain//:rc' (or your wrapper).")
out = ctx.actions.declare_file(ctx.label.name + ".res")
defines = []
if ctx.attr.windows_version_minimal:
ver = ctx.attr.windows_version_minimal[BuildSettingInfo].value
defines += _compute_win_defines(ver)
defines += ctx.attr.defines
include_dirs = ["src", ctx.file.src.dirname]
# Add $(GENDIR)/src (use backslashes for rc.exe friendliness)
gen_src = ctx.var["GENDIR"] + "\\src"
include_dirs.append(gen_src)
args = ctx.actions.args()
args.add("/nologo")
for inc in include_dirs:
args.add("/I", inc)
for d in defines:
args.add("/d", d)
args.add("/fo" + out.path) # /fo must be joined
args.add(ctx.file.src.path)
ctx.actions.run(
executable = ctx.executable.rc, # your wrapper
arguments = [args],
inputs = [ctx.file.src] + ctx.files.resources,
outputs = [out],
mnemonic = "WindowsRC",
)
li = cc_common.create_linker_input(
owner = ctx.label,
user_link_flags = [out.path], # put .res on the link line
additional_inputs = depset([out]), # and declare it as a link input
)
lc = cc_common.create_linking_context(linker_inputs = depset([li]))
new_cc_shared_info = CcSharedLibraryInfo(
dynamic_deps = depset(),
exports = [],
linker_input = li,
link_once_static_libs = {},
)
return [DefaultInfo(files = depset([out])), CcInfo(linking_context = lc), new_cc_shared_info]
windows_rc_rule = rule(
implementation = _rc_impl,
attrs = {
"src": attr.label(mandatory = True, allow_single_file = [".rc"]),
"resources": attr.label_list(allow_files = True),
"defines": attr.string_list(),
"rc": attr.label(executable = True, cfg = "exec", allow_files = True),
"windows_version_minimal": attr.label(),
"_os_windows": attr.label(
default = Label("@platforms//os:windows"),
providers = [platform_common.ConstraintValueInfo],
),
},
provides = [CcInfo],
fragments = ["cpp"],
)
def windows_rc(name, src, manifest_in = None, icon = None):
if manifest_in:
# Turn "foo.manifest.in" into "foo.manifest"
out_manifest = manifest_in[:-3] if manifest_in.endswith(".in") else manifest_in
generate_config_header(
name = name + "_manifest_gen",
checks = "//src/mongo/util:version_constants_gen.py",
cpp_defines = [],
cpp_linkflags = [],
cpp_opts = [],
extra_definitions = {
"MONGO_DISTMOD": "$(MONGO_DISTMOD)",
"MONGO_VERSION": "$(MONGO_VERSION)",
"GIT_COMMIT_HASH": "$(GIT_COMMIT_HASH)",
} | select({
"//bazel/config:js_engine_mozjs": {"js_engine_ver": "mozjs"},
"//conditions:default": {"js_engine_ver": "none"},
}) | select({
"//bazel/config:tcmalloc_google_enabled": {"MONGO_ALLOCATOR": "tcmalloc-google"},
"//bazel/config:tcmalloc_gperf_enabled": {"MONGO_ALLOCATOR": "tcmalloc-gperf"},
"//conditions:default": {"MONGO_ALLOCATOR": "system"},
}) | select({
"//bazel/config:build_enterprise_enabled": {"build_enterprise_enabled": "1"},
"//conditions:default": {},
}),
logfile = name + "_manifest_gen.log",
output = out_manifest,
template = manifest_in,
)
resources = ["//src/mongo/util:rc_constants_gen"]
if manifest_in:
resources.append(name + "_manifest_gen")
if icon:
resources.append(icon)
windows_rc_rule(
name = name,
src = src,
resources = resources,
rc = select({
"@platforms//os:windows": "@mongo_windows_toolchain//:rc",
"//conditions:default": None,
}),
windows_version_minimal = "//bazel/config:win_min_version",
)