Skip to content

[Dependency Scanning] By-default do not specify '-fmodule-map-file' inputs on Swift interface dependency compilation jobs #72599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 29, 2024
Merged
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
21 changes: 14 additions & 7 deletions lib/DependencyScan/ScanDependencies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,20 @@ static llvm::Error resolveExplicitModuleInputs(
: binaryDepDetails->moduleCacheKey;
commandLine.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" +
path);
// If this binary module was built with a header, the header's module
// dependencies must also specify a .modulemap to the compilation, in
// order to resolve the header's own header include directives.
for (const auto &bridgingHeaderDepName :
binaryDepDetails->headerModuleDependencies) {
auto optionalBridgingHeaderDepModuleInfo = cache.findDependency(
{bridgingHeaderDepName, ModuleDependencyKind::Clang});
assert(optionalDepInfo.has_value());
const auto bridgingHeaderDepModuleDetails =
optionalBridgingHeaderDepModuleInfo.value()->getAsClangModule();
commandLine.push_back(
"-fmodule-map-file=" +
remapPath(bridgingHeaderDepModuleDetails->moduleMapFile));
}
} break;
case swift::ModuleDependencyKind::SwiftPlaceholder: {
auto placeholderDetails = depInfo->getAsPlaceholderDependencyModule();
Expand All @@ -278,13 +292,6 @@ static llvm::Error resolveExplicitModuleInputs(
commandLine.push_back("-Xcc");
commandLine.push_back("-fmodule-file=" + depModuleID.ModuleName + "=" +
clangDepDetails->mappedPCMPath);
if (!instance.getInvocation()
.getClangImporterOptions()
.UseClangIncludeTree) {
commandLine.push_back("-Xcc");
commandLine.push_back("-fmodule-map-file=" +
remapPath(clangDepDetails->moduleMapFile));
}
}
if (!clangDepDetails->moduleCacheKey.empty()) {
commandLine.push_back("-Xcc");
Expand Down
115 changes: 115 additions & 0 deletions test/ScanDependencies/bridging_header_dep_module_map.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// REQUIRES: objc_interop
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/FooInputs)
// RUN: %empty-directory(%t/BridgingHeaderDir)
// RUN: %empty-directory(%t/TestCHeaders)
// RUN: %empty-directory(%t/TestSwiftInterfaces)
// RUN: %empty-directory(%t/FooModuleDir)
// RUN: split-file %s %t

// - Fixup the input module file map
// RUN: sed -e "s|INPUTSDIR|%/t/FooInputs|g" %t/map.json.template > %t/map.json.template1
// RUN: sed -e "s|STDLIBMOD|%/stdlib_module|g" %t/map.json.template1 > %t/map.json.template2
// RUN: sed -e "s|ONONEMOD|%/ononesupport_module|g" %t/map.json.template2 > %t/map.json.template3
// RUN: sed -e "s|SWIFTLIBDIR|%swift-lib-dir|g" %t/map.json.template3 > %t/map.json

// - Set up explicit dependencies for Foo
// RUN: %target-swift-emit-pcm -module-name SwiftShims %swift-lib-dir/swift/shims/module.modulemap -o %t/FooInputs/SwiftShims.pcm
// - Build Foo module dependency, explicitly, non-resiliently
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/FooModuleDir/Foo.swiftmodule %t/foo.swift -module-name Foo -import-objc-header %t/BridgingHeaderDir/foo.h -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -disable-implicit-swift-modules -explicit-swift-module-map-file %t/map.json -I %S/Inputs/CHeaders

// - Scan main module and ensure that the "FooClient" recipe includes the modulemap for Foo's briding header's module dependencies
// but not other dependencies
// RUN: %target-swift-frontend -scan-dependencies %t/bridging_header_dep_module_map.swift -I %t/FooModuleDir -I %t/TestSwiftInterfaces -I %t/TestCHeaders -I %S/Inputs/CHeaders -o %t/deps.json
// RUN: %validate-json %t/deps.json | %FileCheck %s

// Given the following dependency graph:
//
// main
// |
// FooClient (.swiftinterface)
// | \
// Foo(.swiftmodule) Dart (.pcm)
//
// Given that 'Foo.swiftmodule' is built with a bridging header which imports 'X.h' ('X' clang module)
// We expect that 'Foo' will have a dependency on module 'X', and the scanner will ensure that 'FooClient' is built
// with the modulemap file for 'X' as an explicit input. 'Dart' Clang module however, must not result in an
// explicitly-specified modulemap file because no headers of this module will be ingested into the Swift
// compiler.

// Dependency of the main module
// CHECK: "swift": "FooClient"

// Definition of 'FooClient' in the dependency graph
// CHECK: "swift": "FooClient"
// CHECK: "modulePath": "{{.*}}FooClient-{{.*}}.swiftmodule",
// CHECK: "directDependencies": [
// CHECK-DAG: "swiftPrebuiltExternal": "Foo"
// CHECK-DAG: "swift": "SwiftOnoneSupport"
// CHECK-DAG: "clang": "Dart"
// CHECK: ],
// CHECK: "commandLine": [
// CHECK: "-fmodule-map-file={{.*}}{{/|\\}}CHeaders{{/|\\}}module.modulemap"
// CHECK-NOT: "-fmodule-map-file={{.*}}{{/|\\}}TestCHeaders{{/|\\}}module.modulemap"
// CHECK: ]

// Definition of 'Foo' in the dependency graph
// CHECK: "swiftPrebuiltExternal": "Foo"
// CHECK: "modulePath": "{{.*}}Foo.swiftmodule",
// CHECK-NEXT: "directDependencies": [
// CHECK-DAG: "swift": "Swift"
// CHECK-DAG: "swift": "SwiftOnoneSupport"
// CHECK-DAG: "clang": "X"
// CHECK: ],
// CHECK: "headerDependency": "{{.*}}{{/|\\}}BridgingHeaderDir{{/|\\}}foo.h"
// CHECK: "headerModuleDependencies": [
// CHECK-NEXT: "X"
// CHECK-NEXT: ],
// CHECK: "headerDependenciesSourceFiles": [
// CHECK-NEXT: "{{.*}}{{/|\\}}BridgingHeaderDir{{/|\\}}foo.h"
// CHECK-NEXT: ],

//--- foo.swift
extension Profiler {
public static let count: Int = 42
}

//--- BridgingHeaderDir/foo.h
#include "X.h"
struct Profiler { void* ptr; };

//--- TestCHeaders/Dart.h
struct Dart { void* ptr; };
//--- TestCHeaders/module.modulemap
module Dart {
header "Dart.h"
export *
}

//--- TestSwiftInterfaces/FooClient.swiftinterface
// swift-interface-format-version: 1.0
// swift-module-flags: -module-name FooClient
import Foo
import Dart

//--- map.json.template
[
{
"moduleName": "Swift",
"modulePath": "STDLIBMOD",
"isFramework": false
},
{
"moduleName": "SwiftOnoneSupport",
"modulePath": "ONONEMOD",
"isFramework": false
},
{
"moduleName": "SwiftShims",
"isFramework": false,
"clangModuleMapPath": "SWIFTLIBDIR/swift/shims/module.modulemap",
"clangModulePath": "INPUTSDIR/SwiftShims.pcm"
}]

//--- bridging_header_dep_module_map.swift
import FooClient
4 changes: 2 additions & 2 deletions test/ScanDependencies/explicit-swift-dependencies.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ import F
// CHECK-NEXT: "{{.*}}{{/|\\}}F-{{.*}}.swiftmodule"
// CHECK-DAG: "-swift-module-file=Swift={{.*}}{{/|\\}}Swift-{{.*}}.swiftmodule"
// CHECK-DAG: "-swift-module-file=SwiftOnoneSupport={{.*}}{{/|\\}}SwiftOnoneSupport-{{.*}}.swiftmodule"
// CHECK-DAG: "-fmodule-file=F={{.*}}{{/|\\}}F-{{.*}}.pcm",
// CHECK-DAG: "-fmodule-file=SwiftShims={{.*}}{{/|\\}}SwiftShims-{{.*}}.pcm",
// CHECK-DAG: "-fmodule-file=F={{.*}}{{/|\\}}F-{{.*}}.pcm"
// CHECK-DAG: "-fmodule-file=SwiftShims={{.*}}{{/|\\}}SwiftShims-{{.*}}.pcm"