Skip to content
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

[Prototype] Adding bridging header as module handling #1403

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
34 changes: 33 additions & 1 deletion Sources/SwiftDriver/Driver/Driver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@ public struct Driver {
/// The path to the pch for the imported Objective-C header.
let bridgingPrecompiledHeader: VirtualPath.Handle?

/// The path to the module map for imported Objective-C header.
let bridgingModuleMap: VirtualPath.Handle?

/// Path to the dependencies file.
let dependenciesFilePath: VirtualPath.Handle?

Expand Down Expand Up @@ -758,6 +761,9 @@ public struct Driver {
compilerMode: compilerMode,
importedObjCHeader: importedObjCHeader,
outputFileMap: outputFileMap)
self.bridgingModuleMap = try Self.generateModuleMapForObjCHeader(&parsedOptions,
fileSystem: fileSystem,
importedObjCHeader: importedObjCHeader)

self.supportedFrontendFlags =
try Self.computeSupportedCompilerArgs(of: self.toolchain,
Expand Down Expand Up @@ -2739,7 +2745,8 @@ extension Driver {
outputFileMap: OutputFileMap?) throws -> VirtualPath.Handle? {
guard compilerMode.supportsBridgingPCH,
let input = importedObjCHeader,
parsedOptions.hasFlag(positive: .enableBridgingPch, negative: .disableBridgingPch, default: true) else {
parsedOptions.hasFlag(positive: .enableBridgingPch, negative: .disableBridgingPch, default: true),
!parsedOptions.hasArgument(.experimentalBridgingHeaderAsModule) else {
return nil
}

Expand All @@ -2755,6 +2762,31 @@ extension Driver {
return VirtualPath.createUniqueTemporaryFile(RelativePath(pchFileName)).intern()
}
}

/// Write the module map for bridging header.
static func generateModuleMapForObjCHeader(_ parsedOptions: inout ParsedOptions,
fileSystem: FileSystem,
importedObjCHeader: VirtualPath.Handle?) throws -> VirtualPath.Handle? {
guard let header = importedObjCHeader,
parsedOptions.hasArgument(.experimentalBridgingHeaderAsModule) else {
return nil
}
guard let moduleMapContent = """
module __ObjC {
requires swift
header \"\(VirtualPath.lookup(header))\"
export *
}
""".data(using: .utf8) else { return nil }
// Write the modulemap inside -pch-output-dir if specified, otherwise in temporary directory.
if let outputDir = parsedOptions.getLastArgument(.pchOutputDir)?.asSingle {
let moduleMap = try VirtualPath(path: outputDir).appending(components: "module.modulemap")
try fileSystem.writeFileContents(moduleMap, bytes: ByteString(moduleMapContent), atomically: true)
return moduleMap.intern()
}
return VirtualPath.createUniqueTemporaryFileWithKnownContents(.init("module.modulemap"),
moduleMapContent).intern()
}
}

extension Diagnostic.Message {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,10 @@ public extension Driver {
var commandLine: [Job.ArgTemplate] = swiftCompilerPrefixArgs.map { Job.ArgTemplate.flag($0) }
commandLine.appendFlag("-frontend")
commandLine.appendFlag("-scan-dependencies")

let bridgingHandling: BridgingHeaderHandling = parsedOptions.hasArgument(.experimentalBridgingHeaderAsModule) ? .module : .parsed
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .scanDependencies,
bridgingHeaderHandling: .parsed,
bridgingHeaderHandling: bridgingHandling,
moduleDependencyGraphUse: .dependencyScan)
// FIXME: MSVC runtime flags

Expand Down
3 changes: 2 additions & 1 deletion Sources/SwiftDriver/Jobs/CompileJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,8 @@ extension Driver {
commandLine.appendFlag(.disableObjcAttrRequiresFoundationModule)
}

try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .compile)
let bridgingHandling: BridgingHeaderHandling = parsedOptions.hasArgument(.experimentalBridgingHeaderAsModule) ? .module : .precompiled
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .compile, bridgingHeaderHandling: bridgingHandling)

// FIXME: MSVC runtime flags

Expand Down
26 changes: 20 additions & 6 deletions Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ extension Driver {

/// Use the precompiled bridging header.
case precompiled

/// Use module for bridging header.
case module
}
/// Whether the driver has already constructed a module dependency graph or is in the process
/// of doing so
Expand Down Expand Up @@ -364,15 +367,17 @@ extension Driver {
try commandLine.appendAll(.Xcc, from: &parsedOptions)
}

if let importedObjCHeader = importedObjCHeader,
bridgingHeaderHandling != .ignored {
commandLine.appendFlag(.importObjcHeader)
if bridgingHeaderHandling == .precompiled,
let pch = bridgingPrecompiledHeader {
if let importedObjCHeader = importedObjCHeader {
switch bridgingHeaderHandling {
case .ignored:
break
case .precompiled:
guard let pch = bridgingPrecompiledHeader else { break }
// For explicit module build, we directly pass the compiled pch as
// `-import-objc-header`, rather than rely on swift-frontend to locate
// the pch in the pchOutputDir and can start an implicit build in case
// of a lookup failure.
commandLine.appendFlag(.importObjcHeader)
if parsedOptions.contains(.pchOutputDir) &&
!parsedOptions.contains(.driverExplicitModuleBuild) {
commandLine.appendPath(VirtualPath.lookup(importedObjCHeader))
Expand All @@ -383,8 +388,17 @@ extension Driver {
} else {
commandLine.appendPath(VirtualPath.lookup(pch))
}
} else {
case .parsed:
commandLine.appendFlag(.importObjcHeader)
commandLine.appendPath(VirtualPath.lookup(importedObjCHeader))
case .module:
commandLine.appendFlag(.experimentalBridgingHeaderAsModule)
// Tell clang importer where to look for the module map during dependency scanning.
guard let moduleMapFile = bridgingModuleMap, kind == .scanDependencies else { break }
commandLine.appendFlag(.clangModuleMap)
commandLine.appendPath(VirtualPath.lookup(moduleMapFile))
inputs.append(TypedVirtualPath(file: moduleMapFile,
type: .clangModuleMap))
}
}

Expand Down
6 changes: 6 additions & 0 deletions Sources/SwiftOptions/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ extension Option {
public static let bsdk: Option = Option("-bsdk", .joinedOrSeparate, attributes: [.noDriver, .argumentIsPath], helpText: "path to the baseline SDK to import frameworks")
public static let buildModuleFromParseableInterface: Option = Option("-build-module-from-parseable-interface", .flag, alias: Option.compileModuleFromInterface, attributes: [.helpHidden, .frontend, .noDriver], group: .modes)
public static let bypassBatchModeChecks: Option = Option("-bypass-batch-mode-checks", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Bypass checks for batch-mode errors.")
public static let bypassResilience: Option = Option("-bypass-resilience-checks", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Ignore all checks for module resilience.")
public static let cacheCompileJob: Option = Option("-cache-compile-job", .flag, attributes: [.frontend], helpText: "Enable compiler caching")
public static let cacheDisableReplay: Option = Option("-cache-disable-replay", .flag, attributes: [.frontend], helpText: "Skip loading the compilation result from cache")
public static let candidateModuleFile: Option = Option("-candidate-module-file", .separate, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "<path>", helpText: "Specify Swift module may be ready to use for an interface")
Expand All @@ -74,6 +75,7 @@ extension Option {
public static let clangHeaderExposeModule: Option = Option("-clang-header-expose-module", .separate, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "<imported-module-name>=<generated-header-name>", helpText: "Allow the compiler to assume that APIs from the specified module are exposed to C/C++/Objective-C in another generated header, so that APIs in the current module that depend on declarations from the specified module can be exposed in the generated header.")
public static let clangIncludeTreeRoot: Option = Option("-clang-include-tree-root", .separate, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "<cas-id>", helpText: "Clang Include Tree CASID")
public static let clangIncludeTree: Option = Option("-clang-include-tree", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Use clang include tree")
public static let clangModuleMap: Option = Option("-clang-module-map", .separate, attributes: [.frontend, .argumentIsPath], metaVar: "<path>", helpText: "clang module map path")
public static let clangTarget: Option = Option("-clang-target", .separate, attributes: [.frontend], helpText: "Separately set the target we should use for internal Clang instance")
public static let codeCompleteCallPatternHeuristics: Option = Option("-code-complete-call-pattern-heuristics", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Use heuristics to guess whether we want call pattern completions")
public static let codeCompleteInitsInPostfixExpr: Option = Option("-code-complete-inits-in-postfix-expr", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Include initializers when completing a postfix expression")
Expand Down Expand Up @@ -431,6 +433,7 @@ extension Option {
public static let enforceExclusivityEQ: Option = Option("-enforce-exclusivity=", .joined, attributes: [.frontend, .moduleInterface], metaVar: "<enforcement>", helpText: "Enforce law of exclusivity")
public static let entryPointFunctionName: Option = Option("-entry-point-function-name", .separate, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "<string>", helpText: "Name of the entry point function")
public static let experimentalAllowModuleWithCompilerErrors: Option = Option("-experimental-allow-module-with-compiler-errors", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Attempt to output .swiftmodule, regardless of compilation errors")
public static let experimentalBridgingHeaderAsModule: Option = Option("-experimental-bridging-header-as-module", .flag, attributes: [.frontend], helpText: "Import bridging header as module")
public static let experimentalCForeignReferenceTypes: Option = Option("-experimental-c-foreign-reference-types", .flag, attributes: [.helpHidden, .frontend, .moduleInterface], helpText: "Enable experimental C foreign references types (with reference coutning).")
public static let experimentalCxxStdlib: Option = Option("-experimental-cxx-stdlib", .separate, attributes: [.helpHidden], helpText: "C++ standard library to use; forwarded to Clang's -stdlib flag")
public static let emitModuleSeparately: Option = Option("-experimental-emit-module-separately", .flag, attributes: [.helpHidden], helpText: "Emit module files as a distinct job")
Expand Down Expand Up @@ -853,6 +856,7 @@ extension Option {
Option.bsdk,
Option.buildModuleFromParseableInterface,
Option.bypassBatchModeChecks,
Option.bypassResilience,
Option.cacheCompileJob,
Option.cacheDisableReplay,
Option.candidateModuleFile,
Expand All @@ -867,6 +871,7 @@ extension Option {
Option.clangHeaderExposeModule,
Option.clangIncludeTreeRoot,
Option.clangIncludeTree,
Option.clangModuleMap,
Option.clangTarget,
Option.codeCompleteCallPatternHeuristics,
Option.codeCompleteInitsInPostfixExpr,
Expand Down Expand Up @@ -1224,6 +1229,7 @@ extension Option {
Option.enforceExclusivityEQ,
Option.entryPointFunctionName,
Option.experimentalAllowModuleWithCompilerErrors,
Option.experimentalBridgingHeaderAsModule,
Option.experimentalCForeignReferenceTypes,
Option.experimentalCxxStdlib,
Option.emitModuleSeparately,
Expand Down
6 changes: 6 additions & 0 deletions TestInputs/ExplicitModuleBuilds/CHeaders/BridgingModule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "A.h"

@interface A
@end

void bridgingA(A *a);
Loading