diff --git a/lib/DependencyScan/ScanDependencies.cpp b/lib/DependencyScan/ScanDependencies.cpp index 5855cc521ba69..bcb262c90ef18 100644 --- a/lib/DependencyScan/ScanDependencies.cpp +++ b/lib/DependencyScan/ScanDependencies.cpp @@ -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(); @@ -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"); diff --git a/test/ScanDependencies/bridging_header_dep_module_map.swift b/test/ScanDependencies/bridging_header_dep_module_map.swift new file mode 100644 index 0000000000000..ac17bfba27eb8 --- /dev/null +++ b/test/ScanDependencies/bridging_header_dep_module_map.swift @@ -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 diff --git a/test/ScanDependencies/explicit-swift-dependencies.swift b/test/ScanDependencies/explicit-swift-dependencies.swift index 6c00f9024be12..746bf7f8416bf 100644 --- a/test/ScanDependencies/explicit-swift-dependencies.swift +++ b/test/ScanDependencies/explicit-swift-dependencies.swift @@ -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"