@@ -34,6 +34,8 @@ public struct Driver {
3434 case missingProfilingData( String )
3535 case conditionalCompilationFlagHasRedundantPrefix( String )
3636 case conditionalCompilationFlagIsNotValidIdentifier( String )
37+ case baselineGenerationRequiresTopLevelModule( String )
38+ case optionRequiresAnother( String , String )
3739 // Explicit Module Build Failures
3840 case malformedModuleDependency( String , String )
3941 case missingPCMArguments( String )
@@ -100,6 +102,10 @@ public struct Driver {
100102 return " unable to load output file map ' \( path) ': no such file or directory "
101103 case . missingExternalDependency( let moduleName) :
102104 return " Missing External dependency info for module: \( moduleName) "
105+ case . baselineGenerationRequiresTopLevelModule( let arg) :
106+ return " generating a baseline with ' \( arg) ' is only supported with '-emit-module' or '-emit-module-path' "
107+ case . optionRequiresAnother( let first, let second) :
108+ return " ' \( first) ' cannot be specified if ' \( second) ' is not present "
103109 }
104110 }
105111 }
@@ -288,6 +294,12 @@ public struct Driver {
288294 /// Path to the Swift module source information file.
289295 let moduleSourceInfoPath : VirtualPath . Handle ?
290296
297+ /// Path to the module's digester baseline file.
298+ let digesterBaselinePath : VirtualPath . Handle ?
299+
300+ /// The mode the API digester should run in.
301+ let digesterMode : DigesterMode
302+
291303 /// Force the driver to emit the module first and then run compile jobs. This could be used to unblock
292304 /// dependencies in parallel builds.
293305 var forceEmitModuleBeforeCompile : Bool = false
@@ -535,6 +547,16 @@ public struct Driver {
535547 self . numThreads = Self . determineNumThreads ( & parsedOptions, compilerMode: compilerMode, diagnosticsEngine: diagnosticEngine)
536548 self . numParallelJobs = Self . determineNumParallelJobs ( & parsedOptions, diagnosticsEngine: diagnosticEngine, env: env)
537549
550+ var mode = DigesterMode . api
551+ if let modeArg = parsedOptions. getLastArgument ( . digesterMode) ? . asSingle {
552+ if let digesterMode = DigesterMode ( rawValue: modeArg) {
553+ mode = digesterMode
554+ } else {
555+ diagnosticsEngine. emit ( Error . invalidArgumentValue ( Option . digesterMode. spelling, modeArg) )
556+ }
557+ }
558+ self . digesterMode = mode
559+
538560 Self . validateWarningControlArgs ( & parsedOptions, diagnosticEngine: diagnosticEngine)
539561 Self . validateProfilingArgs ( & parsedOptions,
540562 fileSystem: fileSystem,
@@ -587,7 +609,7 @@ public struct Driver {
587609 diagnosticEngine: diagnosticEngine,
588610 toolchain: toolchain,
589611 targetInfo: frontendTargetInfo)
590-
612+
591613 Self . validateSanitizerAddressUseOdrIndicatorFlag ( & parsedOptions, diagnosticEngine: diagnosticsEngine, addressSanitizerEnabled: enabledSanitizers. contains ( . address) )
592614
593615 Self . validateSanitizerRecoverArgValues ( & parsedOptions, diagnosticEngine: diagnosticsEngine, enabledSanitizers: enabledSanitizers)
@@ -663,6 +685,15 @@ public struct Driver {
663685 outputFileMap: self . outputFileMap,
664686 moduleName: moduleOutputInfo. name,
665687 projectDirectory: projectDirectory)
688+ self . digesterBaselinePath = try Self . computeDigesterBaselineOutputPath (
689+ & parsedOptions,
690+ moduleOutputPath: self . moduleOutputInfo. output? . outputPath,
691+ mode: self . digesterMode,
692+ compilerOutputType: compilerOutputType,
693+ compilerMode: compilerMode,
694+ outputFileMap: self . outputFileMap,
695+ moduleName: moduleOutputInfo. name,
696+ projectDirectory: projectDirectory)
666697 self . swiftInterfacePath = try Self . computeSupplementaryOutputPath (
667698 & parsedOptions, type: . swiftInterface, isOutputOptions: [ . emitModuleInterface] ,
668699 outputPath: . emitModuleInterfacePath,
@@ -700,6 +731,12 @@ public struct Driver {
700731 outputFileMap: self . outputFileMap,
701732 moduleName: moduleOutputInfo. name)
702733
734+ Self . validateDigesterArgs ( & parsedOptions,
735+ moduleOutputInfo: moduleOutputInfo,
736+ digesterMode: self . digesterMode,
737+ swiftInterfacePath: self . swiftInterfacePath,
738+ diagnosticEngine: diagnosticsEngine)
739+
703740 try verifyOutputOptions ( )
704741 }
705742
@@ -2203,6 +2240,36 @@ extension Driver {
22032240 }
22042241 }
22052242
2243+ static func validateDigesterArgs( _ parsedOptions: inout ParsedOptions ,
2244+ moduleOutputInfo: ModuleOutputInfo ,
2245+ digesterMode: DigesterMode ,
2246+ swiftInterfacePath: VirtualPath . Handle ? ,
2247+ diagnosticEngine: DiagnosticsEngine ) {
2248+ if moduleOutputInfo. output? . isTopLevel != true {
2249+ for arg in parsedOptions. arguments ( for: . emitDigesterBaseline, . emitDigesterBaselinePath, . compareToBaselinePath) {
2250+ diagnosticEngine. emit ( Error . baselineGenerationRequiresTopLevelModule ( arg. option. spelling) )
2251+ }
2252+ }
2253+
2254+ if parsedOptions. hasArgument ( . serializeBreakingChangesPath) && !parsedOptions. hasArgument ( . compareToBaselinePath) {
2255+ diagnosticEngine. emit ( Error . optionRequiresAnother ( Option . serializeBreakingChangesPath. spelling,
2256+ Option . compareToBaselinePath. spelling) )
2257+ }
2258+ if parsedOptions. hasArgument ( . digesterBreakageAllowlistPath) && !parsedOptions. hasArgument ( . compareToBaselinePath) {
2259+ diagnosticEngine. emit ( Error . optionRequiresAnother ( Option . digesterBreakageAllowlistPath. spelling,
2260+ Option . compareToBaselinePath. spelling) )
2261+ }
2262+ if digesterMode == . abi && !parsedOptions. hasArgument ( . enableLibraryEvolution) {
2263+ diagnosticEngine. emit ( Error . optionRequiresAnother ( " \( Option . digesterMode. spelling) abi " ,
2264+ Option . enableLibraryEvolution. spelling) )
2265+ }
2266+ if digesterMode == . abi && swiftInterfacePath == nil {
2267+ diagnosticEngine. emit ( Error . optionRequiresAnother ( " \( Option . digesterMode. spelling) abi " ,
2268+ Option . emitModuleInterface. spelling) )
2269+ }
2270+ }
2271+
2272+
22062273 static func validateProfilingArgs( _ parsedOptions: inout ParsedOptions ,
22072274 fileSystem: FileSystem ,
22082275 workingDirectory: AbsolutePath ? ,
@@ -2657,6 +2724,31 @@ extension Driver {
26572724 projectDirectory: projectDirectory)
26582725 }
26592726
2727+ static func computeDigesterBaselineOutputPath(
2728+ _ parsedOptions: inout ParsedOptions ,
2729+ moduleOutputPath: VirtualPath . Handle ? ,
2730+ mode: DigesterMode ,
2731+ compilerOutputType: FileType ? ,
2732+ compilerMode: CompilerMode ,
2733+ outputFileMap: OutputFileMap ? ,
2734+ moduleName: String ,
2735+ projectDirectory: VirtualPath . Handle ?
2736+ ) throws -> VirtualPath . Handle ? {
2737+ // Only emit a baseline if at least of the arguments was provided.
2738+ guard parsedOptions. hasArgument ( . emitDigesterBaseline, . emitDigesterBaselinePath) else { return nil }
2739+ return try computeModuleAuxiliaryOutputPath ( & parsedOptions,
2740+ moduleOutputPath: moduleOutputPath,
2741+ type: mode. baselineFileType,
2742+ isOutput: . emitDigesterBaseline,
2743+ outputPath: . emitDigesterBaselinePath,
2744+ compilerOutputType: compilerOutputType,
2745+ compilerMode: compilerMode,
2746+ outputFileMap: outputFileMap,
2747+ moduleName: moduleName,
2748+ projectDirectory: projectDirectory)
2749+ }
2750+
2751+
26602752
26612753 /// Determine the output path for a module auxiliary output.
26622754 static func computeModuleAuxiliaryOutputPath(
0 commit comments