Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions swift/toolchains/config/compile_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -2005,8 +2005,19 @@ def _dependencies_swiftmodules_configurator(prerequisites, args):
uniquify = True,
)

# Include both swiftmodule and swiftinterface files as inputs to ensure
# they are available in the sandbox for compilation
transitive_inputs = []
for module in prerequisites.transitive_modules:
swift_module = module.swift
if swift_module:
if swift_module.swiftmodule:
transitive_inputs.append(swift_module.swiftmodule)
if swift_module.swiftinterface:
transitive_inputs.append(swift_module.swiftinterface)

return ConfigResultInfo(
inputs = prerequisites.transitive_swiftmodules,
inputs = transitive_inputs,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make it so prerequisites.transitive_swiftmodules has the right things (and probably rename it to transitive_included_modules... though maybe we don't do that for now to keep cherry-picks easier). Also, we should only add one or the other. We should add swift_module.swiftmodule if it exists, otherwise swift_module.private_swiftinterface, otherwise swift_module.swiftinterface.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am running into issues if I pick only one of those files since -swiftmodule is getting generated even though it is not explicitly passed. I am assuming that .swiftmodule is produced as a result of building swift_import target with .swiftinterface.
Basically we need to keep logic as is.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am assuming that .swiftmodule is produced as a result of building swift_import target with .swiftinterface

Ideally we wouldn't compile .swiftinterface and just pass it along as an importable module. You should only need to compile a (private) interface into a module if you needed access to package/protected types, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not really familiar with how swift_import rule is implemented. But essentially I am building https://github.com/wesprint-io/swift-syntax-prebuilt/releases and it only exposes swift_import targets with no .swiftmodule files yet they are produced at some point and if I pick either .swiftmodule or .swiftinterface the build fails because it won't pick up the .swiftinterface since .swiftmodule appears and it gets selected. Only way that I was able to make it work is by including both of them like in this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brentleyjones given the following swift_import target

swift_import(
    name = "SwiftBasicFormat",
    archives = select({":darwin_arm64": ["arm64/libSwiftBasicFormat.a"]}),
    module_name = "SwiftBasicFormat",
    swiftdoc = select({":darwin_arm64": "arm64/SwiftBasicFormat.swiftdoc"}),
    swiftinterface = select({":darwin_arm64": "arm64/SwiftBasicFormat.swiftinterface"}),
    visibility = ["//visibility:public"],
    deps = [":SwiftSyntax"],
)

after executing build bazel build :SwiftBasicFormat I see the following files produced

SwiftSyntax601.swiftmodule-0.params
SwiftBasicFormat.swiftmodule
SwiftBasicFormat.swiftmodule-0.params
SwiftSyntax.swiftmodule
SwiftSyntax.swiftmodule-0.params
SwiftSyntax509.swiftmodule
SwiftSyntax509.swiftmodule-0.params
SwiftSyntax510.swiftmodule
SwiftSyntax510.swiftmodule-0.params
SwiftSyntax600.swiftmodule
SwiftSyntax600.swiftmodule-0.params
SwiftSyntax601.swiftmodule

I also added print staments to track this while build is in progress

DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2015:22: Adding swiftmodule: <generated file SwiftSyntax509.swiftmodule>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2018:22: Adding swiftinterface: <source file arm64/SwiftSyntax509.swiftinterface>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2015:22: Adding swiftmodule: <generated file SwiftSyntax510.swiftmodule>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2018:22: Adding swiftinterface: <source file arm64/SwiftSyntax510.swiftinterface>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2015:22: Adding swiftmodule: <generated file SwiftSyntax600.swiftmodule>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2018:22: Adding swiftinterface: <source file arm64/SwiftSyntax600.swiftinterface>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2015:22: Adding swiftmodule: <generated file SwiftSyntax601.swiftmodule>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2018:22: Adding swiftinterface: <source file arm64/SwiftSyntax601.swiftinterface>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2015:22: Adding swiftmodule: <generated file SwiftSyntax509.swiftmodule>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2018:22: Adding swiftinterface: <source file arm64/SwiftSyntax509.swiftinterface>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2015:22: Adding swiftmodule: <generated file SwiftSyntax510.swiftmodule>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2018:22: Adding swiftinterface: <source file arm64/SwiftSyntax510.swiftinterface>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2015:22: Adding swiftmodule: <generated file SwiftSyntax600.swiftmodule>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2018:22: Adding swiftinterface: <source file arm64/SwiftSyntax600.swiftinterface>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2015:22: Adding swiftmodule: <generated file SwiftSyntax601.swiftmodule>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2018:22: Adding swiftinterface: <source file arm64/SwiftSyntax601.swiftinterface>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2015:22: Adding swiftmodule: <generated file SwiftSyntax.swiftmodule>
DEBUG: /private/var/tmp/_bazel_adincebic/636060455adfb7fc752026ce1a8908d3/external/rules_swift+/swift/toolchains/config/compile_config.bzl:2018:22: Adding swiftinterface: <source file arm64/SwiftSyntax.private.swiftinterface>

)

def _module_aliases_configurator(prerequisites, args):
Expand Down Expand Up @@ -2064,7 +2075,6 @@ def _plugin_search_paths_configurator(prerequisites, args):

def _dependencies_swiftmodules_vfsoverlay_configurator(prerequisites, args, is_frontend = False):
"""Provides a single `.swiftmodule` search path using a VFS overlay."""
swiftmodules = prerequisites.transitive_swiftmodules

# Bug: `swiftc` doesn't pass its `-vfsoverlay` arg to the frontend.
# Workaround: Pass `-vfsoverlay` directly via `-Xfrontend`.
Expand All @@ -2076,8 +2086,19 @@ def _dependencies_swiftmodules_vfsoverlay_configurator(prerequisites, args, is_f
"-I{}".format(prerequisites.vfsoverlay_search_path),
)

# Include both swiftmodule and swiftinterface files as inputs to ensure
# they are available in the sandbox for compilation
transitive_inputs = [prerequisites.vfsoverlay_file]
for module in prerequisites.transitive_modules:
swift_module = module.swift
if swift_module:
if swift_module.swiftmodule:
transitive_inputs.append(swift_module.swiftmodule)
if swift_module.swiftinterface:
transitive_inputs.append(swift_module.swiftinterface)

return ConfigResultInfo(
inputs = swiftmodules + [prerequisites.vfsoverlay_file],
inputs = transitive_inputs,
)

def _explicit_swift_module_map_configurator(prerequisites, args, is_frontend = False):
Expand Down
12 changes: 12 additions & 0 deletions test/module_interface_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ load(
"//test/rules:action_command_line_test.bzl",
"make_action_command_line_test_rule",
)
load("//test/rules:action_inputs_test.bzl", "action_inputs_test")
load("//test/rules:provider_test.bzl", "provider_test")

explicit_swift_module_map_test = make_action_command_line_test_rule(
Expand Down Expand Up @@ -113,6 +114,17 @@ def module_interface_test_suite(name, tags = []):
target_under_test = "//test/fixtures/module_interface:toy_module",
)

# Test that dependency swiftinterface files are included as action inputs
action_inputs_test(
name = "{}_dependencies_included_as_inputs".format(name),
tags = all_tags,
mnemonic = "SwiftCompileModuleInterface",
expected_inputs = [
"ToyModule.swiftinterface",
],
target_under_test = "//test/fixtures/module_interface:toy_module",
)

native.test_suite(
name = name,
tags = all_tags,
Expand Down
115 changes: 115 additions & 0 deletions test/rules/action_inputs_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
"""Rules for testing action inputs contain expected files."""

load("@bazel_skylib//lib:collections.bzl", "collections")
load("@bazel_skylib//lib:unittest.bzl", "analysistest", "unittest")

def _action_inputs_test_impl(ctx):
env = analysistest.begin(ctx)
target_under_test = analysistest.target_under_test(env)

actions = analysistest.target_actions(env)
mnemonic = ctx.attr.mnemonic
matching_actions = [
action
for action in actions
if action.mnemonic == mnemonic
]
if not matching_actions:
actual_mnemonics = collections.uniq(
[action.mnemonic for action in actions],
)
unittest.fail(
env,
("Target '{}' registered no actions with the mnemonic '{}' " +
"(it had {}).").format(
str(target_under_test.label),
mnemonic,
actual_mnemonics,
),
)
return analysistest.end(env)
if len(matching_actions) != 1:
unittest.fail(
env,
("Expected exactly one action with the mnemonic '{}', " +
"but found {}.").format(
mnemonic,
len(matching_actions),
),
)
return analysistest.end(env)

action = matching_actions[0]
message_prefix = "In {} action for target '{}', ".format(
mnemonic,
str(target_under_test.label),
)

input_paths = [input.short_path for input in action.inputs.to_list()]

for expected_input in ctx.attr.expected_inputs:
found = False
for path in input_paths:
if expected_input in path:
found = True
break
if not found:
unittest.fail(
env,
"{}expected inputs to contain file matching '{}', but it did not. Inputs: {}".format(
message_prefix,
expected_input,
input_paths,
),
)

for not_expected_input in ctx.attr.not_expected_inputs:
found = False
for path in input_paths:
if not_expected_input in path:
found = True
break
if found:
unittest.fail(
env,
"{}expected inputs to not contain file matching '{}', but it did. Inputs: {}".format(
message_prefix,
not_expected_input,
input_paths,
),
)

return analysistest.end(env)

def make_action_inputs_test_rule(config_settings = {}):
"""A `action_inputs_test`-like rule with custom configs.

Args:
config_settings: A dictionary of configuration settings and their values
that should be applied during tests.

Returns:
A rule returned by `analysistest.make` that has the `action_inputs_test`
interface and the given config settings.
"""
return analysistest.make(
_action_inputs_test_impl,
attrs = {
"mnemonic": attr.string(
mandatory = True,
doc = "The mnemonic of the action to test.",
),
"expected_inputs": attr.string_list(
default = [],
doc = "List of file patterns that should be present in action inputs.",
),
"not_expected_inputs": attr.string_list(
default = [],
doc = "List of file patterns that should not be present in action inputs.",
),
},
config_settings = config_settings,
)

# A default instantiation of the rule when no custom config settings are needed.
action_inputs_test = make_action_inputs_test_rule()