Skip to content

Commit

Permalink
Add header_map rule
Browse files Browse the repository at this point in the history
  • Loading branch information
luispadron committed Jan 2, 2024
1 parent 071463e commit da35ed4
Show file tree
Hide file tree
Showing 14 changed files with 3,167 additions and 2 deletions.
24 changes: 24 additions & 0 deletions apple/header_map.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2024 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.

"""
Rules for creating header maps.
"""

load(
"@build_bazel_rules_apple//apple/internal:header_map.bzl",
_header_map = "header_map",
)

header_map = _header_map
129 changes: 129 additions & 0 deletions apple/internal/header_map.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Copyright 2024 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.

"""Rule for creating header_maps."""

load("@build_bazel_rules_swift//swift:swift.bzl", "swift_common")

HeaderMapInfo = provider(
doc = "Provides information about created `.hmap` (header map) files",
fields = {
"files": "depset of paths of any header_maps",
},
)

def _write_header_map(actions, header_map_tool, output, namespace, hdrs_lists):
"""Makes a binary hmap file by executing the header_map tool.
Args:
actions: a ctx.actions struct
header_map_tool: an executable pointing to @bazel_build_rules_ios//rules/hmap:hmaptool
output: the output file that will contain the built hmap
namespace: the prefix to be used for header imports
hdrs_lists: an array of enumerables containing headers to be added to the hmap
"""

args = actions.args()
if namespace:
args.add("--namespace", namespace)

args.add("--output", output)

for hdrs in hdrs_lists:
args.add_all(hdrs)

args.set_param_file_format(format = "multiline")
args.use_param_file("@%s")

actions.run(
mnemonic = "HmapWrite",
arguments = [args],
executable = header_map_tool,
outputs = [output],
)

def _header_map_impl(ctx):
"""Implementation of the header_map() rule.
It creates a text file with mappings and creates an action that calls out to the header_map tool
to convert it to a binary header_map file.
"""
hdrs_lists = [ctx.files.hdrs] if ctx.files.hdrs else []

for dep in ctx.attr.deps:
found_headers = []
if apple_common.Objc in dep:
found_headers.append(getattr(dep[apple_common.Objc], "direct_headers", []))
if CcInfo in dep:
found_headers.append(dep[CcInfo].compilation_context.direct_headers)
if not found_headers:
fail("Direct header provider: '%s' listed in 'deps' does not have any direct headers to provide." % dep)
hdrs_lists.extend(found_headers)

hdrs_lists = [[h for h in hdrs if h.basename.endswith(".h")] for hdrs in hdrs_lists]

_write_header_map(
actions = ctx.actions,
header_map_tool = ctx.executable._hmaptool,
output = ctx.outputs.header_map,
namespace = ctx.attr.namespace,
hdrs_lists = hdrs_lists,
)

return [
apple_common.new_objc_provider(),
swift_common.create_swift_info(),
CcInfo(
compilation_context = cc_common.create_compilation_context(
headers = depset([ctx.outputs.header_map]),
),
),
HeaderMapInfo(
files = depset([ctx.outputs.header_map]),
),
]

header_map = rule(
implementation = _header_map_impl,
output_to_genfiles = True,
attrs = {
"namespace": attr.string(
mandatory = False,
doc = "The prefix to be used for header imports",
),
"hdrs": attr.label_list(
mandatory = False,
allow_files = True,
doc = "The list of headers included in the header_map",
),
"deps": attr.label_list(
mandatory = False,
providers = [[apple_common.Objc], [CcInfo]],
doc = "Targets whose direct headers should be added to the list of hdrs",
),
"_hmaptool": attr.label(
executable = True,
cfg = "exec",
default = Label("//tools/hmaptool:hmaptool"),
),
},
outputs = {
"header_map": "%{name}.hmap",
},
doc = """\
Creates a binary header_map file from the given headers suitable for passing to clang.
This can be used to allow headers to be imported at a consistent path regardless of the package structure being used.
""",
)
99 changes: 99 additions & 0 deletions apple/internal/header_map_support.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Copyright 2024 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.

"""Provides utilities for working with header_maps within macros and rules"""

load("//Rules/apple/header_map:header_map.bzl", "header_map")

def _create_header_map_context(
name,
module_name,
hdrs,
private_hdrs,
deps):
"""
Creates header_map(s) for the target with the given name.
Args:
name: The name of the target.
module_name: The name of the module to use in the header map.
hdrs: The public headers to include in the header map.
private_hdrs: The private headers to include in the header map.
deps: The dependencies to include in the header map.
Returns a struct (or `None` if no headers) with the following attributes:
objc_copts: The compiler options to use when compiling an Objective-C library with the header map.
swift_copts: The compiler options to use when compiling a Swift library with the header map.
header_maps: The labels to any generated header maps, these should be the inputs used with the `copts`.
"""

header_maps = []
copts = []

if hdrs:
public_hmap_name = name + "_public_hmap"
public_hdrs_filegroup = name + "_public_hdrs"
native.filegroup(
name = public_hdrs_filegroup,
srcs = hdrs,
)
header_map(
name = public_hmap_name,
namespace = module_name,
hdrs = [public_hdrs_filegroup],
direct_hdr_providers = deps,
)
header_maps.append(":{}".format(public_hmap_name))
copts.append("-I$(execpath :{})".format(public_hmap_name))
copts.append("-I.")

if private_hdrs:
private_hmap_name = name + "_private_angled_hmap"
private_hdrs_filegroup = name + "_private_angled_hdrs"
native.filegroup(
name = private_hdrs_filegroup,
srcs = private_hdrs,
)
header_map(
name = private_hmap_name,
namespace = module_name,
hdrs = [private_hdrs_filegroup],
)
header_maps.extend([
":{}".format(private_hmap_name),
":{}".format(private_hdrs_filegroup),
])
copts.extend([
"-I$(execpath :{})".format(private_hmap_name),
"-I$(execpath :{})".format(private_hmap_name),
"-iquote",
"$(execpath :{})".format(private_hmap_name),
])

if not header_maps:
return None

swift_copts = []
for copt in copts:
swift_copts.extend(["-Xcc", copt])

return struct(
objc_copts = copts,
swift_copts = swift_copts,
header_maps = header_maps,
)

header_map_support = struct(
create_header_map_context = _create_header_map_context,
)
16 changes: 15 additions & 1 deletion examples/multi_platform/MixedLib/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ load(
"swift_library",
)
load("//apple:apple.bzl", "experimental_mixed_language_library")
load("//apple:header_map.bzl", "header_map")
load("//apple:ios.bzl", "ios_unit_test")

experimental_mixed_language_library(
Expand All @@ -11,8 +12,21 @@ experimental_mixed_language_library(
"MixedAnswer.m",
"MixedAnswer.swift",
],
hdrs = ["MixedAnswer.h"],
hdrs = [
"MixedAnswer.h",
":MixedAnswerHeaderMap",
],
enable_modules = True,
objc_copts = [
"-I$(execpath :MixedAnswerHeaderMap)",
"-I.",
],
)

header_map(
name = "MixedAnswerHeaderMap",
hdrs = ["MixedAnswer.h"],
namespace = "MixedAnswer",
)

swift_library(
Expand Down
3 changes: 2 additions & 1 deletion examples/multi_platform/MixedLib/MixedAnswer.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#import "examples/multi_platform/MixedLib/MixedAnswer.h"
#import <MixedAnswer/MixedAnswer.h>

#import "examples/multi_platform/MixedLib/MixedAnswer-Swift.h"

@implementation MixedAnswerObjc
Expand Down
48 changes: 48 additions & 0 deletions test/starlark_tests/targets_under_test/apple/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ load(
"dummy_test_runner",
)
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("//apple:header_map.bzl", "header_map")

licenses(["notice"])

Expand Down Expand Up @@ -1405,3 +1406,50 @@ swift_apple_core_ml_library(
mlmodel = "//test/testdata/resources:sample.mlmodel",
tags = common.fixture_tags,
)

# ---------------------------------------------------------------------------------------
# Targets for header map rule tests.

objc_library(
name = "header_map_objc_lib",
srcs = [
"//test/starlark_tests/resources:shared.m",
],
hdrs = [
"//test/starlark_tests/resources:shared.h",
],
tags = common.fixture_tags,
)

swift_library(
name = "header_map_swift_lib",
srcs = ["DummyFmwk.swift"],
generates_header = True,
tags = common.fixture_tags,
)

header_map(
name = "header_map_with_header",
hdrs = [
"//test/starlark_tests/resources:shared.h",
],
tags = common.fixture_tags,
)

header_map(
name = "header_map_with_objc_lib_dep",
hdrs = [],
tags = common.fixture_tags,
deps = [
":header_map_objc_lib",
],
)

header_map(
name = "header_map_with_swift_lib_dep",
hdrs = [],
tags = common.fixture_tags,
deps = [
":header_map_swift_lib",
],
)
38 changes: 38 additions & 0 deletions tools/hmaptool/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package(default_visibility = ["//apple/internal:__subpackages__"])

HMAP_COPTS = [
"-DHASH_FUNCTION=HASH_MUR",
"-DHASH_USING_NO_STRICT_ALIASING",
"-fno-strict-aliasing",
]

cc_library(
name = "lines",
srcs = ["lines.c"],
hdrs = ["lines.h"],
copts = ["-Wno-parentheses"],
)

cc_library(
name = "hmap",
srcs = ["hmap.c"],
hdrs = ["hmap.h"],
copts = HMAP_COPTS,
)

cc_binary(
name = "hmaptool",
srcs = [
"hmaptool.c",
"uthash.h",
],
copts = HMAP_COPTS,
deps = [
":hmap",
":lines",
],
# Used by the rule implementations, so it needs to be public; but
# should be considered an implementation detail of the rules and
# not used by other things.
visibility = ["//visibility:public"],
)
Loading

0 comments on commit da35ed4

Please sign in to comment.