Skip to content

Commit

Permalink
Adding bridging header as module handling
Browse files Browse the repository at this point in the history
  • Loading branch information
cachemeifyoucan committed Jul 26, 2023
1 parent 893f014 commit 1fbf112
Show file tree
Hide file tree
Showing 8 changed files with 407 additions and 9 deletions.
33 changes: 32 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,30 @@ 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 {
umbrella 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

0 comments on commit 1fbf112

Please sign in to comment.