blob: fab9f885d3745a26435c40e71eddc50eb1fc8a94 [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.
"""Utility methods used for creating objc_* rules actions"""
load("@_builtins//:common/cc/cc_helper.bzl", "cc_helper")
load("@_builtins//:common/objc/objc_common.bzl", "objc_common")
objc_internal = _builtins.internal.objc_internal
cc_common = _builtins.toplevel.cc_common
def _build_variable_extensions(
common_variables,
ctx,
intermediate_artifacts,
variable_categories,
arc_enabled):
extensions = {}
if hasattr(ctx.attr, "pch") and ctx.attr.pch != None:
extensions["pch_file"] = ctx.file.pch.path
extensions["module_maps_dir"] = intermediate_artifacts.swift_module_map.file().path
extensions["modules_cache_path"] = ctx.genfiles_dir.path + "/" + "_objc_module_cache"
if "ARCHIVE_VARIABLE" in variable_categories:
extensions["obj_list_path"] = intermediate_artifacts.archive_obj_list.path
if arc_enabled:
extensions["objc_arc"] = ""
else:
extensions["no_objc_arc"] = ""
return extensions
def _build_common_variables(
ctx,
toolchain,
use_pch,
disable_layering_check,
disable_parse_hdrs,
empty_compilation_artifacts,
deps,
runtime_deps,
extra_import_libraries,
linkopts):
compilation_attributes = objc_internal.create_compilation_attributes(ctx = ctx)
intermediate_artifacts = objc_internal.create_intermediate_artifacts(ctx = ctx)
if empty_compilation_artifacts:
compilation_artifacts = objc_internal.create_compilation_artifacts()
else:
compilation_artifacts = objc_internal.create_compilation_artifacts(ctx = ctx)
(objc_provider, objc_compilation_context) = objc_common.create_context_and_provider(
purpose = "COMPILE_AND_LINK",
ctx = ctx,
compilation_attributes = compilation_attributes,
compilation_artifacts = compilation_artifacts,
deps = deps,
runtime_deps = runtime_deps,
intermediate_artifacts = intermediate_artifacts,
alwayslink = ctx.attr.alwayslink,
has_module_map = True,
extra_import_libraries = extra_import_libraries,
linkopts = linkopts,
)
return struct(
ctx = ctx,
intermediate_artifacts = intermediate_artifacts,
compilation_attributes = compilation_attributes,
compilation_artifacts = compilation_artifacts,
objc_compilation_context = objc_compilation_context,
toolchain = toolchain,
use_pch = use_pch,
disable_layering_check = disable_layering_check,
disable_parse_headers = disable_parse_hdrs,
objc_config = ctx.fragments.objc,
objc_provider = objc_provider,
)
def _build_feature_configuration(common_variables, for_swift_module_map, support_parse_headers):
activated_crosstool_selectables = []
ctx = common_variables.ctx
OBJC_ACTIONS = [
"objc-compile",
"objc++-compile",
"objc-archive",
"objc-fully-link",
"objc-executable",
"objc++-executable",
]
activated_crosstool_selectables.extend(ctx.features)
activated_crosstool_selectables.extend(OBJC_ACTIONS)
activated_crosstool_selectables.append("lang_objc")
if common_variables.objc_config.should_strip_binary:
activated_crosstool_selectables.append("dead_strip")
if common_variables.objc_config.generate_linkmap:
activated_crosstool_selectables.append("generate_linkmap")
disabled_features = []
disabled_features.extend(ctx.disabled_features)
if common_variables.disable_parse_headers:
disabled_features.append("parse_headers")
if common_variables.disable_layering_check:
disabled_features.append("layering_check")
if not support_parse_headers:
disabled_features.append("parse_headers")
if for_swift_module_map:
activated_crosstool_selectables.append("module_maps")
activated_crosstool_selectables.append("compile_all_modules")
activated_crosstool_selectables.append("only_doth_headers_in_module_maps")
activated_crosstool_selectables.append("exclude_private_headers_in_module_maps")
activated_crosstool_selectables.append("module_map_without_extern_module")
disabled_features.append("generate_submodules")
return cc_common.configure_features(
ctx = common_variables.ctx,
cc_toolchain = common_variables.toolchain,
requested_features = activated_crosstool_selectables,
unsupported_features = disabled_features,
)
def _compile(
common_variables,
feature_configuration,
extension,
extra_compile_args,
priority_headers,
srcs,
private_hdrs,
public_hdrs,
pch_hdr,
module_map,
purpose,
generate_module_map,
should_process_headers):
objc_compilation_context = common_variables.objc_compilation_context
includes = []
includes.extend(priority_headers)
includes.extend(objc_compilation_context.includes)
user_compile_flags = []
user_compile_flags.extend(_get_compile_rule_copts(common_variables))
user_compile_flags.extend(common_variables.objc_config.copts_for_current_compilation_mode)
user_compile_flags.extend(extra_compile_args)
user_compile_flags.extend(_paths_to_include_args(objc_compilation_context.strict_dependency_includes))
textual_hdrs = []
textual_hdrs.extend(objc_compilation_context.public_textual_hdrs)
if pch_hdr != None:
textual_hdrs.append(pch_hdr)
return cc_common.compile(
actions = common_variables.ctx.actions,
feature_configuration = feature_configuration,
cc_toolchain = common_variables.toolchain,
name = common_variables.ctx.label.name,
srcs = srcs,
public_hdrs = public_hdrs,
private_hdrs = private_hdrs,
textual_hdrs = textual_hdrs,
defines = objc_compilation_context.defines,
includes = objc_compilation_context.includes,
system_includes = objc_compilation_context.system_includes,
quote_includes = objc_compilation_context.quote_includes,
compilation_contexts = objc_compilation_context.cc_compilation_contexts,
user_compile_flags = user_compile_flags,
grep_includes = common_variables.ctx.executable._grep_includes,
module_map = module_map,
propagate_module_map_to_compile_action = True,
variables_extension = extension,
language = "objc",
code_coverage_enabled = cc_helper.is_code_coverage_enabled(ctx = common_variables.ctx),
hdrs_checking_mode = "strict",
do_not_generate_module_map = module_map.file().is_source or not generate_module_map,
purpose = purpose,
)
def _validate_attributes(common_variables):
for include in common_variables.compilation_attributes.includes.to_list():
if include.startswith("/"):
cc_helper.rule_error("The path '{}' is absolute, but only relative paths are allowed.".format(include))
ctx = common_variables.ctx
if hasattr(ctx.attr, "srcs"):
srcs = {}
for src in ctx.files.srcs:
srcs[src.path] = True
for src in ctx.files.non_arc_srcs:
if src.path in srcs:
cc_helper.attribute_error(
"srcs",
"File '{}' is present in both srcs and non_arc_srcs which is forbidden.".format(src.path),
)
if ctx.attr.module_name != "" and ctx.attr.module_map != None:
cc_helper.attribute_error("module_name", "Specifying both module_name and module_map is invalid, please remove one of them.")
def _get_compile_rule_copts(common_variables):
attributes = common_variables.compilation_attributes
copts = []
copts.extend(common_variables.objc_config.copts)
copts.extend(attributes.copts)
if attributes.enable_modules and common_variables.ctx.attr.module_map == None:
copts.append("-fmodules")
if "-fmodules" in copts:
cache_path = common_variables.ctx.genfiles_dir.path + "/" + "_objc_module_cache"
copts.append("-fmodules-cache-path=" + cache_path)
return copts
def _register_obj_file_list_action(common_variables, obj_files, obj_list):
args = common_variables.ctx.actions.args()
args.set_param_file_format("multiline")
args.add_all(obj_files)
common_variables.ctx.actions.write(obj_list, args)
def _paths_to_include_args(paths):
new_paths = []
for path in paths:
new_paths.append("-I" + path)
return new_paths
def _register_compile_and_archive_actions(
common_variables,
extra_compile_args,
priority_headers):
compilation_result = None
if common_variables.compilation_artifacts.archive != None:
obj_list = common_variables.intermediate_artifacts.archive_obj_list
compilation_result = _cc_compile_and_link(
common_variables,
extra_compile_args,
priority_headers,
"OBJC_ARCHIVE",
obj_list,
["ARCHIVE_VARIABLE"],
)
_register_obj_file_list_action(
common_variables,
compilation_result[1].objects,
obj_list,
)
else:
compilation_result = _cc_compile_and_link(
common_variables,
extra_compile_args,
priority_headers,
None,
None,
[],
)
return compilation_result
def _cc_compile_and_link(
common_variables,
extra_compile_args,
priority_headers,
link_type,
link_action_input,
variable_categories):
compilation_artifacts = common_variables.compilation_artifacts
intermediate_artifacts = common_variables.intermediate_artifacts
compilation_attributes = common_variables.compilation_attributes
ctx = common_variables.ctx
(objects, pic_objects) = _get_object_files(common_variables.ctx)
public_hdrs = []
public_hdrs.extend(compilation_attributes.hdrs.to_list())
public_hdrs.extend(compilation_artifacts.additional_hdrs.to_list())
pch_header = _get_pch_file(common_variables)
feature_configuration = _build_feature_configuration(common_variables, False, True)
# Generate up to two module maps, while minimizing the number of actions created. If
# module_map feature is off, generate a swift module map. If module_map feature is on,
# generate a layering check and a swift module map. In the latter case, the layering check
# module map must be the primary one.
#
# TODO(waltl): Delete this logic when swift module map is migrated to swift_library.
primary_module_map = None
arc_primary_module_map_fc = None
non_arc_primary_module_map_fc = None
extra_module_map = None
extra_module_map_fc = None
fc_for_swift_module_map = _build_feature_configuration(
common_variables,
True,
True,
)
if cc_common.is_enabled(feature_configuration = feature_configuration, feature_name = "module_maps"):
primary_module_map = intermediate_artifacts.internal_module_map
arc_primary_module_map_fc = feature_configuration
non_arc_primary_module_map_fc = _build_feature_configuration(
common_variables,
True,
False,
)
extra_module_map = intermediate_artifacts.swift_module_map
extra_module_map_fc = fc_for_swift_module_map
else:
primary_module_map = intermediate_artifacts.swift_module_map
arc_primary_module_map_fc = fc_for_swift_module_map
non_arc_primary_module_map_fc = _build_feature_configuration(
common_variables,
True,
False,
)
extra_module_map = None
extra_module_map_fc = None
purpose = "%s_objc_arc".format(_get_purpose(common_variables))
arc_extensions = _build_variable_extensions(
common_variables,
ctx,
intermediate_artifacts,
variable_categories,
True,
)
(arc_compilation_context, arc_compilation_outputs) = _compile(
common_variables,
arc_primary_module_map_fc,
arc_extensions,
extra_compile_args,
priority_headers,
compilation_artifacts.srcs,
compilation_artifacts.private_hdrs,
public_hdrs,
pch_header,
primary_module_map,
purpose,
True,
True,
)
purpose = "%s_non_objc_arc".format(_get_purpose(common_variables))
non_arc_extensions = _build_variable_extensions(
common_variables,
ctx,
intermediate_artifacts,
variable_categories,
False,
)
(non_arc_compilation_context, non_arc_compilation_outputs) = _compile(
common_variables,
non_arc_primary_module_map_fc,
non_arc_extensions,
extra_compile_args,
priority_headers,
compilation_artifacts.non_arc_srcs,
compilation_artifacts.private_hdrs,
public_hdrs,
pch_header,
primary_module_map,
purpose,
False,
False,
)
objc_compilation_context = common_variables.objc_compilation_context
if extra_module_map != None and not extra_module_map.file().is_source:
_generate_extra_module_map(
common_variables,
extra_module_map,
public_hdrs,
compilation_artifacts.private_hdrs,
objc_compilation_context.public_textual_hdrs,
pch_header,
objc_compilation_context.cc_compilation_contexts,
extra_module_map_fc,
)
if link_type == "OBJC_ARCHIVE":
language = "objc"
else:
language = "c++"
additional_inputs = []
if link_action_input != None:
additional_inputs.append(link_action_input)
cc_compilation_context = cc_common.merge_compilation_contexts(
compilation_contexts = [arc_compilation_context, non_arc_compilation_context],
)
precompiled_compilation_outputs = cc_common.create_compilation_outputs(
pic_objects = depset(pic_objects),
objects = depset(objects),
)
compilation_outputs = cc_common.merge_compilation_outputs(
compilation_outputs = [
precompiled_compilation_outputs,
arc_compilation_outputs,
non_arc_compilation_outputs,
],
)
cc_common.create_linking_context_from_compilation_outputs(
actions = ctx.actions,
feature_configuration = feature_configuration,
cc_toolchain = common_variables.toolchain,
compilation_outputs = compilation_outputs,
linking_contexts = cc_helper.get_linking_contexts_from_deps(common_variables.ctx.attr.deps),
name = common_variables.ctx.label.name + intermediate_artifacts.archive_file_name_suffix,
language = language,
disallow_dynamic_library = True,
additional_inputs = additional_inputs,
grep_includes = ctx.executable._grep_includes,
variables_extension = non_arc_extensions,
)
arc_output_groups = cc_helper.build_output_groups_for_emitting_compile_providers(
arc_compilation_outputs,
arc_compilation_context,
ctx.fragments.cpp,
common_variables.toolchain,
feature_configuration,
ctx,
True,
)
non_arc_output_groups = cc_helper.build_output_groups_for_emitting_compile_providers(
non_arc_compilation_outputs,
non_arc_compilation_context,
ctx.fragments.cpp,
common_variables.toolchain,
feature_configuration,
ctx,
True,
)
merged_output_groups = cc_helper.merge_output_groups(
[arc_output_groups, non_arc_output_groups],
)
return (cc_compilation_context, compilation_outputs, OutputGroupInfo(**merged_output_groups))
def _get_object_files(ctx):
if not hasattr(ctx.attr, "srcs"):
return ([], [])
pic_objects = []
for src in ctx.files.srcs:
path = src.path
if path.endswith(".pic.o") or path.endswith(".o") and not path.endswith(".nopic.o"):
pic_objects.append(src)
objects = []
for src in ctx.files.srcs:
path = src.path
if path.endswith(".o") and not path.endswith(".pic.o"):
objects.append(src)
return (objects, pic_objects)
def _get_pch_file(common_variables):
if not common_variables.use_pch:
return None
pch_hdr = None
if hasattr(common_variables.ctx.attr, "pch"):
pch_hdr = common_variables.ctx.file.pch
return pch_hdr
def _get_purpose(common_variables):
suffix = common_variables.intermediate_artifacts.archive_file_name_suffix
config = common_variables.ctx.bin_dir.path.split("/")[1]
return "Objc_build_arch_" + config + "_with_suffix_" + suffix
def _generate_extra_module_map(
common_variables,
module_map,
public_hdrs,
private_hdrs,
textual_hdrs,
pch_header,
compilation_contexts,
feature_configuration):
purpose = "%s_extra_module_map".format(_get_purpose(common_variables))
all_textual_hdrs = []
all_textual_hdrs.extend(textual_hdrs)
if pch_header != None:
all_textual_hdrs.append(pch_header)
cc_common.compile(
actions = common_variables.ctx.actions,
feature_configuration = feature_configuration,
cc_toolchain = common_variables.toolchain,
public_hdrs = public_hdrs,
textual_hdrs = textual_hdrs,
private_hdrs = private_hdrs,
compilation_contexts = compilation_contexts,
module_map = module_map,
purpose = purpose,
name = common_variables.ctx.label.name,
grep_includes = common_variables.ctx.executable._grep_includes,
)
compilation_support = struct(
register_compile_and_archive_actions = _register_compile_and_archive_actions,
build_common_variables = _build_common_variables,
build_feature_configuration = _build_feature_configuration,
validate_attributes = _validate_attributes,
)