blob: 6343db98651d649655f48b2258137d7cc48b549d [file] [log] [blame]
# Copyright 2020 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Common functionality for Objc rules."""
load(":common/cc/cc_info.bzl", "CcInfo")
load(":common/objc/providers.bzl", "J2ObjcEntryClassInfo", "J2ObjcMappingFileInfo")
objc_internal = _builtins.internal.objc_internal
apple_common = _builtins.toplevel.apple_common
cc_internal = _builtins.internal.cc_internal
CPP_SOURCES = [".cc", ".cpp", ".mm", ".cxx", ".C"]
NON_CPP_SOURCES = [".m", ".c"]
ASSEMBLY_SOURCES = [".s", ".S", ".asm"]
OBJECT_FILE_SOURCES = [".o"]
HEADERS = [".h", ".inc", ".hpp", ".hh"]
COMPILABLE_SRCS = CPP_SOURCES + NON_CPP_SOURCES + ASSEMBLY_SOURCES
SRCS = COMPILABLE_SRCS + OBJECT_FILE_SOURCES + HEADERS
NON_ARC_SRCS = [".m", ".mm"]
ios_cpus = struct(
IOS_SIMULATOR_TARGET_CPUS = ["ios_x86_64", "ios_i386", "ios_sim_arm64"],
IOS_DEVICE_TARGET_CPUS = ["ios_armv6", "ios_arm64", "ios_armv7", "ios_armv7s", "ios_arm64e"],
VISIONOS_SIMULATOR_TARGET_CPUS = ["visionos_x86_64", "visionos_sim_arm64"],
VISIONOS_DEVICE_TARGET_CPUS = ["visionos_arm64"],
WATCHOS_SIMULATOR_TARGET_CPUS = ["watchos_i386", "watchos_x86_64", "watchos_arm64"],
WATCHOS_DEVICE_TARGET_CPUS = ["watchos_armv7k", "watchos_arm64_32", "watchos_device_arm64", "watchos_device_arm64e"],
TVOS_SIMULATOR_TARGET_CPUS = ["tvos_x86_64", "tvos_sim_arm64"],
TVOS_DEVICE_TARGET_CPUS = ["tvos_arm64"],
CATALYST_TARGET_CPUS = ["catalyst_x86_64"],
MACOS_TARGET_CPUS = ["darwin_x86_64", "darwin_arm64", "darwin_arm64e"],
)
extensions = struct(
CPP_SOURCES = CPP_SOURCES,
NON_CPP_SOURCES = NON_CPP_SOURCES,
ASSEMBLY_SOURCES = ASSEMBLY_SOURCES,
HEADERS = HEADERS,
SRCS = SRCS,
NON_ARC_SRCS = NON_ARC_SRCS,
)
def _create_context_and_provider(
ctx,
compilation_attributes,
compilation_artifacts,
intermediate_artifacts,
has_module_map,
deps,
implementation_deps,
attr_linkopts,
direct_cc_compilation_contexts = [],
includes = [],
is_aspect = False):
objc_providers = []
cc_compilation_contexts = []
cc_linking_contexts = []
for dep in deps:
if apple_common.Objc in dep:
objc_providers.append(dep[apple_common.Objc])
if CcInfo in dep:
cc_compilation_contexts.append(dep[CcInfo].compilation_context)
cc_linking_contexts.append(dep[CcInfo].linking_context)
implementation_cc_compilation_contexts = []
for impl_dep in implementation_deps:
implementation_cc_compilation_contexts.append(impl_dep[CcInfo].compilation_context)
cc_linking_contexts.append(impl_dep[CcInfo].linking_context)
sdk_linking_info = {
"sdk_dylib": [],
"sdk_framework": [],
"weak_sdk_framework": [],
}
objc_provider_kwargs = {
"providers": objc_providers,
"umbrella_header": [],
"module_map": [],
"source": [],
}
objc_compilation_context_kwargs = {
"providers": objc_providers,
"cc_compilation_contexts": cc_compilation_contexts,
"implementation_cc_compilation_contexts": implementation_cc_compilation_contexts,
"public_hdrs": [],
"private_hdrs": [],
"public_textual_hdrs": [],
"defines": [],
"includes": list(includes),
"direct_cc_compilation_contexts": direct_cc_compilation_contexts,
}
all_non_sdk_linkopts = []
non_sdk_linkopts = _add_linkopts(
sdk_linking_info,
objc_internal.expand_and_tokenize(ctx = ctx, attr = "linkopts", flags = attr_linkopts),
)
all_non_sdk_linkopts.extend(non_sdk_linkopts)
if compilation_attributes != None:
sdk_dir = apple_common.apple_toolchain().sdk_dir()
usr_include_dir = sdk_dir + "/usr/include/"
sdk_includes = []
for sdk_include in compilation_attributes.sdk_includes.to_list():
sdk_includes.append(usr_include_dir + sdk_include)
sdk_linking_info["sdk_framework"].extend(
compilation_attributes.sdk_frameworks.to_list(),
)
sdk_linking_info["weak_sdk_framework"].extend(
compilation_attributes.weak_sdk_frameworks.to_list(),
)
sdk_linking_info["sdk_dylib"].extend(compilation_attributes.sdk_dylibs.to_list())
objc_compilation_context_kwargs["public_hdrs"].extend(compilation_attributes.hdrs.to_list())
objc_compilation_context_kwargs["public_textual_hdrs"].extend(
compilation_attributes.textual_hdrs.to_list(),
)
objc_compilation_context_kwargs["defines"].extend(compilation_attributes.defines)
objc_compilation_context_kwargs["includes"].extend(sdk_includes)
if compilation_artifacts != None:
all_sources = _filter_out_by_extension(compilation_artifacts.srcs, OBJECT_FILE_SOURCES) + \
compilation_artifacts.non_arc_srcs
if compilation_artifacts.archive != None:
if is_aspect:
if ctx.rule.kind in ["j2objc_library", "java_library", "java_import", "java_proto_library"]:
objc_provider_kwargs["j2objc_library"] = [compilation_artifacts.archive]
objc_provider_kwargs["source"].extend(all_sources)
objc_compilation_context_kwargs["public_hdrs"].extend(
compilation_artifacts.additional_hdrs,
)
objc_compilation_context_kwargs["private_hdrs"].extend(
_filter_by_extension(compilation_artifacts.srcs, HEADERS),
)
if has_module_map:
module_map = intermediate_artifacts.swift_module_map
umbrella_header = module_map.umbrella_header()
if umbrella_header != None:
objc_provider_kwargs["umbrella_header"].append(umbrella_header)
objc_provider_kwargs["module_map"].append(module_map.file())
objc_provider_kwargs_built = {}
for k, v in objc_provider_kwargs.items():
if k == "providers":
objc_provider_kwargs_built[k] = v
else:
objc_provider_kwargs_built[k] = depset(v)
objc_compilation_context = objc_internal.create_compilation_context(
**objc_compilation_context_kwargs
)
all_linkopts = all_non_sdk_linkopts
for sdk_framework in depset(sdk_linking_info["sdk_framework"]).to_list():
all_linkopts.append("-framework")
all_linkopts.append(sdk_framework)
for weak_sdk_framework in depset(sdk_linking_info["weak_sdk_framework"]).to_list():
all_linkopts.append("-weak_framework")
all_linkopts.append(weak_sdk_framework)
for sdk_dylib in depset(sdk_linking_info["sdk_dylib"]).to_list():
if sdk_dylib.startswith("lib"):
sdk_dylib = sdk_dylib[3:]
all_linkopts.append("-l%s" % sdk_dylib)
objc_linking_context = struct(
cc_linking_contexts = cc_linking_contexts,
linkopts = all_linkopts,
)
return (
apple_common.new_objc_provider(**objc_provider_kwargs_built),
objc_compilation_context,
objc_linking_context,
)
def _filter_by_extension(file_list, extensions):
return [file for file in file_list if "." + file.extension in extensions]
def _filter_out_by_extension(file_list, extensions):
return [file for file in file_list if "." + file.extension not in extensions]
def _add_linkopts(sdk_linking_info, linkopts):
non_sdk_linkopts = []
i = 0
skip_next = False
for arg in linkopts:
if skip_next:
skip_next = False
i += 1
continue
if arg == "-framework" and i < len(linkopts) - 1:
sdk_linking_info["sdk_framework"].append(linkopts[i + 1])
skip_next = True
elif arg == "-weak_framework" and i < len(linkopts) - 1:
sdk_linking_info["weak_sdk_framework"].append(linkopts[i + 1])
skip_next = True
elif arg.startswith("-Wl,-framework,"):
sdk_linking_info["sdk_framework"].append(arg[len("-Wl,-framework,"):])
elif arg.startswith("-Wl,-weak_framework,"):
sdk_linking_info["weak_sdk_framework"].append(arg[len("-Wl,-weak_framework,"):])
elif arg.startswith("-l"):
sdk_linking_info["sdk_dylib"].append(arg[2:])
else:
non_sdk_linkopts.append(arg)
i += 1
return non_sdk_linkopts
def _is_apple_platform(cpu):
return cpu in ios_cpus.IOS_SIMULATOR_TARGET_CPUS or \
cpu in ios_cpus.IOS_DEVICE_TARGET_CPUS or \
cpu in ios_cpus.VISIONOS_SIMULATOR_TARGET_CPUS or \
cpu in ios_cpus.VISIONOS_DEVICE_TARGET_CPUS or \
cpu in ios_cpus.WATCHOS_SIMULATOR_TARGET_CPUS or \
cpu in ios_cpus.WATCHOS_DEVICE_TARGET_CPUS or \
cpu in ios_cpus.TVOS_SIMULATOR_TARGET_CPUS or \
cpu in ios_cpus.TVOS_DEVICE_TARGET_CPUS or \
cpu in ios_cpus.CATALYST_TARGET_CPUS or \
cpu in ios_cpus.MACOS_TARGET_CPUS
# Returns the string representation of this dotted version, padded to a minimum number of
# components if the string representation does not already contain that many components.
# For example, a dotted version of "7.3" will return "7.3" with either one or two components
# requested, "7.3.0" if three are requested, and "7.3.0.0" if four are requested.
# Trailing zero components at the end of a string representation will not be removed. For
# example, a dotted version of "1.0.0" will return "1.0.0" if only one or two components are
# requested.
def _to_string_with_minimum_components(version, min_components):
components = version.split(".")
num_components = max(len(components), min_components)
if num_components == 0:
fail("Can't serialize as a version with " + str(num_components) + " components")
if num_components <= len(components):
return ".".join(components[:num_components])
else:
for _ in range(len(components), num_components):
components.append("0")
return ".".join(components)
def _sdk_framework_dir(target_platform, xcode_config):
if target_platform == apple_common.platform.ios_device or \
target_platform == apple_common.platform.ios_simulator:
if xcode_config.sdk_version_for_platform(target_platform).compare_to(apple_common.dotted_version("9.0")) >= 0:
relative_path = "/System/Library/Frameworks"
else:
relative_path = "/Developer/Library/Frameworks"
return "__BAZEL_XCODE_SDKROOT__" + relative_path
if target_platform == apple_common.platform.macos or \
target_platform == apple_common.platform.visionos_device or \
target_platform == apple_common.platform.visionos_simulator or \
target_platform == apple_common.platform.watchos_device or \
target_platform == apple_common.platform.watchos_simulator or \
target_platform == apple_common.platform.tvos_device or \
target_platform == apple_common.platform.tvos_simulator or \
target_platform == apple_common.platform.catalyst:
relative_path = "/System/Library/Frameworks"
return "__BAZEL_XCODE_SDKROOT__" + relative_path
fail("Unhandled platform " + str(target_platform))
def _platform_developer_framework_dir(platform):
platform_dir = "__BAZEL_XCODE_DEVELOPER_DIR__" + "/Platforms/" + platform.name_in_plist + ".platform"
return platform_dir + "/Developer/Library/Frameworks"
def _platform_name_from_apple_target_cpu(cpu):
if cpu in ios_cpus.IOS_SIMULATOR_TARGET_CPUS:
return "iPhoneSimulator"
elif cpu in ios_cpus.IOS_DEVICE_TARGET_CPUS:
return "iPhoneOS"
elif cpu in ios_cpus.VISIONOS_SIMULATOR_TARGET_CPUS:
return "XRSimulator"
elif cpu in ios_cpus.VISIONOS_DEVICE_TARGET_CPUS:
return "XROS"
elif cpu in ios_cpus.WATCHOS_SIMULATOR_TARGET_CPUS:
return "WatchSimulator"
elif cpu in ios_cpus.WATCHOS_DEVICE_TARGET_CPUS:
return "WatchOS"
elif cpu in ios_cpus.TVOS_SIMULATOR_TARGET_CPUS:
return "AppleTVSimulator"
elif cpu in ios_cpus.TVOS_DEVICE_TARGET_CPUS:
return "AppleTVOS"
elif cpu in ios_cpus.CATALYST_TARGET_CPUS:
return "MacOSX"
elif cpu in ios_cpus.MACOS_TARGET_CPUS:
return "MacOSX"
else:
fail("No supported apple platform registered for target cpu " + cpu)
def _sdk_version_for_platform(xcode_config, platform_name):
if platform_name == "iPhoneOS" or platform_name == "iPhoneSimulator":
return xcode_config.ios_sdk_version()
elif platform_name == "AppleTVOS" or platform_name == "AppleTVSimulator":
return xcode_config.tvos_sdk_version()
elif platform_name == "XROS" or platform_name == "XRSimulator":
return xcode_config.visionos_sdk_version()
elif platform_name == "WatchOS" or platform_name == "WatchSimulator":
return xcode_config.watchos_sdk_version()
elif platform_name == "MacOSX":
return xcode_config.macos_sdk_version()
else:
fail("Unhandled platform: " + platform_name)
def _get_apple_env_build_variables(xcode_config, cpu):
env = {}
if xcode_config.xcode_version() != None:
env["XCODE_VERSION_OVERRIDE"] = str(xcode_config.xcode_version())
if _is_apple_platform(cpu):
platform_name = _platform_name_from_apple_target_cpu(cpu)
sdk_version = _to_string_with_minimum_components(str(_sdk_version_for_platform(xcode_config, platform_name)), 2)
env["APPLE_SDK_VERSION_OVERRIDE"] = sdk_version
env["APPLE_SDK_PLATFORM"] = platform_name
return env
def _get_common_vars(cpp_config, sysroot):
variables = {}
min_os_version = cpp_config.minimum_os_version()
if min_os_version != None:
variables["minimum_os_version"] = min_os_version
if sysroot != None:
variables["sysroot"] = sysroot
return variables
def _apple_cc_toolchain_build_variables(xcode_config):
def apple_cc_toolchain_build_variables(platform, cpu, cpp_config, sysroot):
variables = _get_common_vars(cpp_config, sysroot)
apple_env = _get_apple_env_build_variables(xcode_config, cpu)
variables["xcode_version"] = _to_string_with_minimum_components(str(xcode_config.xcode_version()), 2)
variables["ios_sdk_version"] = _to_string_with_minimum_components(str(xcode_config.sdk_version_for_platform(apple_common.platform.ios_simulator)), 2)
variables["macos_sdk_version"] = _to_string_with_minimum_components(str(xcode_config.sdk_version_for_platform(apple_common.platform.macos)), 2)
variables["tvos_sdk_version"] = _to_string_with_minimum_components(str(xcode_config.sdk_version_for_platform(apple_common.platform.tvos_simulator)), 2)
variables["visionos_sdk_version"] = _to_string_with_minimum_components(str(xcode_config.sdk_version_for_platform(apple_common.platform.visionos_simulator)), 2)
variables["watchos_sdk_version"] = _to_string_with_minimum_components(str(xcode_config.sdk_version_for_platform(apple_common.platform.watchos_simulator)), 2)
variables["sdk_dir"] = "__BAZEL_XCODE_SDKROOT__"
variables["sdk_framework_dir"] = _sdk_framework_dir(platform, xcode_config)
variables["platform_developer_framework_dir"] = _platform_developer_framework_dir(platform)
variables["xcode_version_override_value"] = apple_env.get("XCODE_VERSION_OVERRIDE", "")
variables["apple_sdk_version_override_value"] = apple_env.get("APPLE_SDK_VERSION_OVERRIDE", "")
variables["apple_sdk_platform_value"] = apple_env.get("APPLE_SDK_PLATFORM", "")
variables["version_min"] = str(xcode_config.minimum_os_for_platform_type(platform.platform_type))
return cc_internal.cc_toolchain_variables(vars = variables)
return apple_cc_toolchain_build_variables
# TODO(bazel-team): Delete this function when MultiArchBinarySupport is starlarkified.
def _j2objc_mapping_file_info_union(providers):
transitive_header_mapping_files = []
transitive_class_mapping_files = []
transitive_dependency_mapping_files = []
transitive_archive_source_mapping_files = []
for provider in providers:
transitive_header_mapping_files.append(provider.header_mapping_files)
transitive_class_mapping_files.append(provider.class_mapping_files)
transitive_dependency_mapping_files.append(provider.dependency_mapping_files)
transitive_archive_source_mapping_files.append(provider.archive_source_mapping_files)
return J2ObjcMappingFileInfo(
header_mapping_files = depset([], transitive = transitive_header_mapping_files),
class_mapping_files = depset([], transitive = transitive_class_mapping_files),
dependency_mapping_files = depset([], transitive = transitive_dependency_mapping_files),
archive_source_mapping_files = depset([], transitive = transitive_archive_source_mapping_files),
)
# TODO(bazel-team): Delete this function when MultiArchBinarySupport is starlarkified.
def _j2objc_entry_class_info_union(providers):
transitive_entry_classes = []
for provider in providers:
transitive_entry_classes.append(provider.entry_classes)
return J2ObjcEntryClassInfo(
entry_classes = depset([], transitive = transitive_entry_classes),
)
objc_common = struct(
create_context_and_provider = _create_context_and_provider,
to_string_with_minimum_components = _to_string_with_minimum_components,
sdk_framework_dir = _sdk_framework_dir,
platform_developer_framework_dir = _platform_developer_framework_dir,
apple_cc_toolchain_build_variables = _apple_cc_toolchain_build_variables,
is_apple_platform = _is_apple_platform,
get_common_vars = _get_common_vars,
j2objc_mapping_file_info_union = _j2objc_mapping_file_info_union,
j2objc_entry_class_info_union = _j2objc_entry_class_info_union,
)