Skip to content

Commit 6303159

Browse files
committed
Add header_map rule
1 parent d260bcb commit 6303159

File tree

19 files changed

+3791
-2
lines changed

19 files changed

+3791
-2
lines changed

apple/header_map.bzl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright 2024 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""
16+
Rules for creating header maps.
17+
"""
18+
19+
load(
20+
"@build_bazel_rules_apple//apple/internal:header_map.bzl",
21+
_header_map = "header_map",
22+
)
23+
24+
header_map = _header_map

apple/internal/header_map.bzl

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# Copyright 2024 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Rule for creating header_maps."""
16+
17+
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_common")
18+
19+
HeaderMapInfo = provider(
20+
doc = "Provides information about created `.hmap` (header map) files",
21+
fields = {
22+
"public_header_maps": "depset of paths of any public header maps",
23+
},
24+
)
25+
26+
def _write_header_map(actions, header_map_tool, output, namespace, hdrs_lists):
27+
"""Makes a binary hmap file by executing the header_map tool.
28+
29+
Args:
30+
actions: a ctx.actions struct
31+
header_map_tool: an executable pointing to @bazel_build_rules_ios//rules/hmap:hmaptool
32+
output: the output file that will contain the built hmap
33+
namespace: the prefix to be used for header imports
34+
hdrs_lists: an array of enumerables containing headers to be added to the hmap
35+
"""
36+
37+
args = actions.args()
38+
if namespace:
39+
args.add("--namespace", namespace)
40+
41+
args.add("--output", output)
42+
43+
for hdrs in hdrs_lists:
44+
args.add_all(hdrs)
45+
46+
args.set_param_file_format(format = "multiline")
47+
args.use_param_file("@%s")
48+
49+
actions.run(
50+
mnemonic = "HmapWrite",
51+
arguments = [args],
52+
executable = header_map_tool,
53+
outputs = [output],
54+
)
55+
56+
def _header_map_impl(ctx):
57+
"""Implementation of the header_map() rule.
58+
59+
It creates a text file with mappings and creates an action that calls out to the header_map tool
60+
to convert it to a binary header_map file.
61+
"""
62+
hdrs_lists = [ctx.files.hdrs] if ctx.files.hdrs else []
63+
64+
for dep in ctx.attr.deps:
65+
found_headers = []
66+
if apple_common.Objc in dep:
67+
found_headers.append(getattr(dep[apple_common.Objc], "direct_headers", []))
68+
if CcInfo in dep:
69+
found_headers.append(dep[CcInfo].compilation_context.direct_headers)
70+
if not found_headers:
71+
fail("Direct header provider: '%s' listed in 'deps' does not have any direct headers to provide." % dep)
72+
hdrs_lists.extend(found_headers)
73+
74+
hdrs_lists = [[h for h in hdrs if h.basename.endswith(".h")] for hdrs in hdrs_lists]
75+
76+
_write_header_map(
77+
actions = ctx.actions,
78+
header_map_tool = ctx.executable._hmaptool,
79+
output = ctx.outputs.header_map,
80+
namespace = ctx.attr.namespace,
81+
hdrs_lists = hdrs_lists,
82+
)
83+
84+
return [
85+
apple_common.new_objc_provider(),
86+
swift_common.create_swift_info(),
87+
CcInfo(
88+
compilation_context = cc_common.create_compilation_context(
89+
headers = depset([ctx.outputs.header_map]),
90+
),
91+
),
92+
HeaderMapInfo(
93+
public_header_maps = depset([ctx.outputs.header_map]),
94+
),
95+
]
96+
97+
header_map = rule(
98+
implementation = _header_map_impl,
99+
output_to_genfiles = True,
100+
attrs = {
101+
"namespace": attr.string(
102+
mandatory = False,
103+
doc = "The prefix to be used for header imports",
104+
),
105+
"hdrs": attr.label_list(
106+
mandatory = False,
107+
allow_files = True,
108+
doc = "The list of headers included in the header_map",
109+
),
110+
"deps": attr.label_list(
111+
mandatory = False,
112+
providers = [[apple_common.Objc], [CcInfo]],
113+
doc = "Targets whose direct headers should be added to the list of hdrs and rooted at the namespace",
114+
),
115+
"_hmaptool": attr.label(
116+
executable = True,
117+
cfg = "exec",
118+
default = Label("//tools/hmaptool:hmaptool_swift"),
119+
),
120+
},
121+
outputs = {
122+
"header_map": "%{name}.hmap",
123+
},
124+
doc = """\
125+
Creates a binary `.hmap` file from the given headers suitable for passing to clang.
126+
127+
Headermaps can be used in `-I` and `-iquote` compile flags (as well as in `includes`) to tell clang where to find headers.
128+
This can be used to allow headers to be imported at a consistent path regardless of the package structure being used.
129+
130+
For example, if you have a package structure like this:
131+
132+
```
133+
MyLib/
134+
headers/
135+
MyLib.h
136+
MyLib.c
137+
BUILD
138+
```
139+
140+
And you want to import `MyLib.h` from `MyLib.c` using angle bracket imports: `#import <MyLib/MyLib.h>`
141+
You can create a header map like this:
142+
143+
```bzl
144+
header_map(
145+
name = "MyLib.hmap",
146+
hdrs = ["headers/MyLib.h"],
147+
)
148+
```
149+
150+
This generates a binary headermap that looks like:
151+
152+
```
153+
MyLib.h -> headers/MyLib.h
154+
MyLib/MyLib.h -> headers/MyLib.h
155+
```
156+
157+
Then update `deps`, `copts` and `includes` to use the header map:
158+
159+
```bzl
160+
objc_library(
161+
name = "MyLib",
162+
module_name = "MyLib",
163+
srcs = ["MyLib.c"],
164+
hdrs = ["headers/MyLib.h"],
165+
deps = [":MyLib.hmap"],
166+
copts = ["-I.]
167+
includes = ["MyLib.hmap"]
168+
)
169+
```
170+
""",
171+
)

apple/internal/header_map_support.bzl

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright 2024 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Provides utilities for working with header_maps within macros and rules"""
16+
17+
load("//apple/internal:header_map.bzl", "header_map")
18+
19+
def _create_header_map_context(
20+
name,
21+
module_name,
22+
hdrs,
23+
deps):
24+
"""
25+
Creates header_map(s) for the target with the given name.
26+
27+
Args:
28+
name: The name of the target.
29+
module_name: The name of the module to use in the header map.
30+
hdrs: The public headers to include in the header mapm, these will be rooted
31+
under module_name and flattened.
32+
deps: The direct dependencies to include in the header map, any headers in the deps will be rooted
33+
under this `module_name` and flattened.
34+
35+
Returns a struct (or `None` if no headers) with the following attributes:
36+
copts: The compiler options to use when compiling a C family library with header maps.
37+
includes: The includes to use when compiling a C family library with header maps.
38+
swift_copts: The compiler options to use when compiling a Swift library with the header map.
39+
header_maps: The labels to any generated header maps, these should be the inputs used with the `copts`.
40+
"""
41+
42+
public_hdrs_filegroup = name + ".public.hmap_hdrs"
43+
public_hmap_name = name + ".public"
44+
45+
native.filegroup(
46+
name = public_hdrs_filegroup,
47+
srcs = hdrs,
48+
)
49+
50+
header_map(
51+
name = public_hmap_name,
52+
namespace = module_name,
53+
hdrs = [public_hdrs_filegroup],
54+
deps = deps,
55+
)
56+
57+
copts = [
58+
"-I.", # makes the package's bin dir available for use with #import <foo/foo.h>
59+
]
60+
includes = [
61+
"{}.hmap".format(public_hmap_name), # propogates the header map include to target and things that depend on it
62+
]
63+
header_maps = [
64+
":{}".format(public_hmap_name),
65+
]
66+
67+
swift_copts = []
68+
for copt in copts:
69+
swift_copts.extend(["-Xcc", copt])
70+
71+
return struct(
72+
copts = copts,
73+
includes = includes,
74+
swift_copts = swift_copts,
75+
header_maps = header_maps,
76+
)
77+
78+
header_map_support = struct(
79+
create_header_map_context = _create_header_map_context,
80+
)

examples/multi_platform/MixedLib/BUILD

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,41 @@ load(
33
"swift_library",
44
)
55
load("//apple:apple.bzl", "experimental_mixed_language_library")
6+
load("//apple:header_map.bzl", "header_map")
67
load("//apple:ios.bzl", "ios_unit_test")
78

9+
filegroup(
10+
name = "MixedAnswer.public_headers.h",
11+
srcs = [
12+
"MixedAnswer.h",
13+
],
14+
)
15+
816
experimental_mixed_language_library(
917
name = "MixedAnswer",
1018
srcs = [
1119
"MixedAnswer.m",
1220
"MixedAnswer.swift",
1321
],
14-
hdrs = ["MixedAnswer.h"],
22+
hdrs = [
23+
":MixedAnswer.public_headers.h",
24+
],
1525
enable_modules = True,
26+
includes = [
27+
"MixedAnswerHeaderMap.hmap",
28+
],
29+
objc_copts = ["-I."],
30+
deps = [
31+
":MixedAnswerHeaderMap",
32+
],
33+
)
34+
35+
header_map(
36+
name = "MixedAnswerHeaderMap",
37+
hdrs = [
38+
":MixedAnswer.public_headers.h",
39+
],
40+
namespace = "MixedAnswer",
1641
)
1742

1843
swift_library(
@@ -23,6 +48,19 @@ swift_library(
2348
deps = [":MixedAnswer"],
2449
)
2550

51+
objc_library(
52+
name = "ObjcLibDependingOnMixedLib",
53+
srcs = [
54+
"ObjcLibDependingOnMixedLib.m",
55+
],
56+
hdrs = [
57+
"ObjcLibDependingOnMixedLib.h",
58+
],
59+
copts = ["-I."],
60+
enable_modules = True,
61+
deps = [":MixedAnswer"],
62+
)
63+
2664
experimental_mixed_language_library(
2765
name = "MixedTestsLib",
2866
testonly = True,

examples/multi_platform/MixedLib/MixedAnswer.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
#import "examples/multi_platform/MixedLib/MixedAnswer.h"
1+
#import <MixedAnswer/MixedAnswer.h>
2+
23
#import "examples/multi_platform/MixedLib/MixedAnswer-Swift.h"
34

45
@implementation MixedAnswerObjc
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@import Foundation;
2+
3+
@interface ObjcLibDependingOnMixedLib : NSObject
4+
5+
+ (void)doSomething;
6+
7+
@end
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@import Foundation;
2+
3+
#import <MixedAnswer/MixedAnswer.h>
4+
5+
#import "ObjcLibDependingOnMixedLib.h"
6+
7+
@implementation ObjcLibDependingOnMixedLib
8+
9+
+ (void)doSomething {
10+
MixedAnswerObjc *objcAnswer __unused = [[MixedAnswerObjc alloc] init];
11+
return;
12+
}
13+
14+
@end

0 commit comments

Comments
 (0)