Skip to content

Commit 2000428

Browse files
authored
Fix includes attribute resolution in apple_static_xcframework_import (#2869)
1 parent 46a85f1 commit 2000428

File tree

4 files changed

+142
-1
lines changed

4 files changed

+142
-1
lines changed

apple/internal/apple_xcframework_import.bzl

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,16 @@ def _apple_static_xcframework_import_impl(ctx):
690690
linkopts = sdk_linkopts + linkopts,
691691
swiftinterface_imports = [xcframework_library.swift_module_interface] if xcframework_library.swift_module_interface else [],
692692
swiftmodule_imports = xcframework_library.swiftmodule,
693-
includes = xcframework_library.includes + ctx.attr.includes,
693+
# User-specified includes are relative to the platform directory inside the xcframework.
694+
# For framework XCFrameworks, binary is inside .framework bundle, so go up one level.
695+
# For library XCFrameworks, binary is directly in the platform directory.
696+
includes = xcframework_library.includes + [
697+
paths.join(
698+
paths.dirname(xcframework_library.binary.dirname) if xcframework_library.framework_includes else xcframework_library.binary.dirname,
699+
inc,
700+
)
701+
for inc in ctx.attr.includes
702+
],
694703
)
695704
providers.append(cc_info)
696705

test/starlark_tests/apple_xcframework_import_tests.bzl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ load(
2222
"//test/starlark_tests/rules:analysis_target_outputs_test.bzl",
2323
"analysis_target_outputs_test",
2424
)
25+
load(
26+
"//test/starlark_tests/rules:analysis_xcframework_includes_test.bzl",
27+
"analysis_xcframework_includes_test",
28+
)
2529
load(
2630
"//test/starlark_tests/rules:apple_verification_test.bzl",
2731
"apple_verification_test",
@@ -249,6 +253,34 @@ def apple_xcframework_import_test_suite(name):
249253
tags = [name],
250254
)
251255

256+
# Test that includes attribute is correctly resolved for library-style static XCFrameworks.
257+
# The expected include path should contain the xcframework's platform directory + "Headers".
258+
analysis_xcframework_includes_test(
259+
name = "{}_static_xcfw_library_style_includes_resolved".format(name),
260+
target_under_test = "//test/starlark_tests/targets_under_test/apple:ios_imported_static_xcframework_old",
261+
expected_includes = [
262+
# The path should be: .../ios_static_xcframework/Headers
263+
"ios_static_xcframework/Headers",
264+
],
265+
tags = [name],
266+
)
267+
268+
# Test that includes attribute is correctly resolved for framework-style static XCFrameworks.
269+
# Includes are relative to the platform directory, not the .framework bundle.
270+
analysis_xcframework_includes_test(
271+
name = "{}_static_xcfw_framework_style_includes_resolved".format(name),
272+
target_under_test = "//test/starlark_tests/targets_under_test/apple:ios_imported_xcframework_bundling_static_fmwks_with_includes",
273+
expected_includes = [
274+
"ios_imported_xcframework_bundling_static_fmwks_with_includes-intermediates/Headers",
275+
],
276+
# The include should NOT be inside the .framework bundle - this ensures the path
277+
# was correctly computed to go up one level from the .framework directory.
278+
not_expected_includes = [
279+
".framework/Headers",
280+
],
281+
tags = [name],
282+
)
283+
252284
native.test_suite(
253285
name = name,
254286
tags = [name],
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Copyright 2026 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+
"""Analysis test for verifying XCFramework include paths in CcInfo provider."""
16+
17+
load(
18+
"@bazel_skylib//lib:unittest.bzl",
19+
"analysistest",
20+
"unittest",
21+
)
22+
load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
23+
24+
def _analysis_xcframework_includes_test_impl(ctx):
25+
"""Implementation of analysis_xcframework_includes_test."""
26+
env = analysistest.begin(ctx)
27+
target_under_test = analysistest.target_under_test(env)
28+
29+
# Get CcInfo provider from the target
30+
if not CcInfo in target_under_test:
31+
unittest.fail(env, "Target does not provide CcInfo")
32+
return analysistest.end(env)
33+
34+
cc_info = target_under_test[CcInfo]
35+
compilation_context = cc_info.compilation_context
36+
37+
# Get all include directories as strings
38+
includes = [inc for inc in compilation_context.includes.to_list()]
39+
system_includes = [inc for inc in compilation_context.system_includes.to_list()]
40+
quote_includes = [inc for inc in compilation_context.quote_includes.to_list()]
41+
42+
all_includes = includes + system_includes + quote_includes
43+
44+
# Check that expected includes are present
45+
for expected_include in ctx.attr.expected_includes:
46+
found = False
47+
for inc in all_includes:
48+
if expected_include in inc:
49+
found = True
50+
break
51+
if not found:
52+
unittest.fail(
53+
env,
54+
"Expected include path '{}' not found in CcInfo includes.\nActual includes: {}".format(
55+
expected_include,
56+
all_includes,
57+
),
58+
)
59+
return analysistest.end(env)
60+
61+
# Check that not_expected includes are absent
62+
for not_expected_include in ctx.attr.not_expected_includes:
63+
for inc in all_includes:
64+
if not_expected_include in inc:
65+
unittest.fail(
66+
env,
67+
"Include path '{}' should NOT be present but was found in CcInfo includes.\nActual includes: {}".format(
68+
not_expected_include,
69+
all_includes,
70+
),
71+
)
72+
return analysistest.end(env)
73+
74+
return analysistest.end(env)
75+
76+
analysis_xcframework_includes_test = analysistest.make(
77+
_analysis_xcframework_includes_test_impl,
78+
attrs = {
79+
"expected_includes": attr.string_list(
80+
doc = """
81+
A list of strings that should be substrings of paths in the CcInfo includes.
82+
Each expected include must match at least one path in the includes.""",
83+
),
84+
"not_expected_includes": attr.string_list(
85+
doc = """
86+
A list of strings that should NOT be substrings of any paths in the CcInfo includes.
87+
If any of these are found, the test fails.""",
88+
),
89+
},
90+
)

test/starlark_tests/targets_under_test/apple/BUILD

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,16 @@ apple_static_xcframework_import(
628628
xcframework_imports = [":generated_ios_xcframework_bundling_static_fmwks"],
629629
)
630630

631+
# Framework-style static xcframework with includes attribute for testing include path resolution.
632+
# Unlike library-style xcframeworks where the binary is directly in the platform dir,
633+
# framework-style xcframeworks have the binary inside a .framework bundle.
634+
apple_static_xcframework_import(
635+
name = "ios_imported_xcframework_bundling_static_fmwks_with_includes",
636+
includes = ["Headers"],
637+
tags = ["manual"],
638+
xcframework_imports = [":generated_ios_xcframework_bundling_static_fmwks"],
639+
)
640+
631641
apple_static_xcframework_import(
632642
name = "ios_imported_static_xcframework_with_module_map",
633643
tags = ["manual"],

0 commit comments

Comments
 (0)