@@ -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
@@ -2196,6 +2233,36 @@ extension Driver {
21962233 }
21972234 }
21982235
2236+ static func validateDigesterArgs( _ parsedOptions: inout ParsedOptions ,
2237+ moduleOutputInfo: ModuleOutputInfo ,
2238+ digesterMode: DigesterMode ,
2239+ swiftInterfacePath: VirtualPath . Handle ? ,
2240+ diagnosticEngine: DiagnosticsEngine ) {
2241+ if moduleOutputInfo. output? . isTopLevel != true {
2242+ for arg in parsedOptions. arguments ( for: . emitDigesterBaseline, . emitDigesterBaselinePath, . compareToBaselinePath) {
2243+ diagnosticEngine. emit ( Error . baselineGenerationRequiresTopLevelModule ( arg. option. spelling) )
2244+ }
2245+ }
2246+
2247+ if parsedOptions. hasArgument ( . serializeBreakingChangesPath) && !parsedOptions. hasArgument ( . compareToBaselinePath) {
2248+ diagnosticEngine. emit ( Error . optionRequiresAnother ( Option . serializeBreakingChangesPath. spelling,
2249+ Option . compareToBaselinePath. spelling) )
2250+ }
2251+ if parsedOptions. hasArgument ( . digesterBreakageAllowlistPath) && !parsedOptions. hasArgument ( . compareToBaselinePath) {
2252+ diagnosticEngine. emit ( Error . optionRequiresAnother ( Option . digesterBreakageAllowlistPath. spelling,
2253+ Option . compareToBaselinePath. spelling) )
2254+ }
2255+ if digesterMode == . abi && !parsedOptions. hasArgument ( . enableLibraryEvolution) {
2256+ diagnosticEngine. emit ( Error . optionRequiresAnother ( " \( Option . digesterMode. spelling) abi " ,
2257+ Option . enableLibraryEvolution. spelling) )
2258+ }
2259+ if digesterMode == . abi && swiftInterfacePath == nil {
2260+ diagnosticEngine. emit ( Error . optionRequiresAnother ( " \( Option . digesterMode. spelling) abi " ,
2261+ Option . emitModuleInterface. spelling) )
2262+ }
2263+ }
2264+
2265+
21992266 static func validateProfilingArgs( _ parsedOptions: inout ParsedOptions ,
22002267 fileSystem: FileSystem ,
22012268 workingDirectory: AbsolutePath ? ,
@@ -2650,6 +2717,31 @@ extension Driver {
26502717 projectDirectory: projectDirectory)
26512718 }
26522719
2720+ static func computeDigesterBaselineOutputPath(
2721+ _ parsedOptions: inout ParsedOptions ,
2722+ moduleOutputPath: VirtualPath . Handle ? ,
2723+ mode: DigesterMode ,
2724+ compilerOutputType: FileType ? ,
2725+ compilerMode: CompilerMode ,
2726+ outputFileMap: OutputFileMap ? ,
2727+ moduleName: String ,
2728+ projectDirectory: VirtualPath . Handle ?
2729+ ) throws -> VirtualPath . Handle ? {
2730+ // Only emit a baseline if at least of the arguments was provided.
2731+ guard parsedOptions. hasArgument ( . emitDigesterBaseline, . emitDigesterBaselinePath) else { return nil }
2732+ return try computeModuleAuxiliaryOutputPath ( & parsedOptions,
2733+ moduleOutputPath: moduleOutputPath,
2734+ type: mode. baselineFileType,
2735+ isOutput: . emitDigesterBaseline,
2736+ outputPath: . emitDigesterBaselinePath,
2737+ compilerOutputType: compilerOutputType,
2738+ compilerMode: compilerMode,
2739+ outputFileMap: outputFileMap,
2740+ moduleName: moduleName,
2741+ projectDirectory: projectDirectory)
2742+ }
2743+
2744+
26532745
26542746 /// Determine the output path for a module auxiliary output.
26552747 static func computeModuleAuxiliaryOutputPath(
0 commit comments