diff --git a/Sources/CSwiftScan/include/swiftscan_header.h b/Sources/CSwiftScan/include/swiftscan_header.h index 75eecfdf2..6d6d27e91 100644 --- a/Sources/CSwiftScan/include/swiftscan_header.h +++ b/Sources/CSwiftScan/include/swiftscan_header.h @@ -18,7 +18,7 @@ #include #define SWIFTSCAN_VERSION_MAJOR 0 -#define SWIFTSCAN_VERSION_MINOR 6 +#define SWIFTSCAN_VERSION_MINOR 10 //=== Public Scanner Data Types -------------------------------------------===// @@ -41,6 +41,7 @@ typedef enum { typedef struct swiftscan_module_details_s *swiftscan_module_details_t; typedef struct swiftscan_dependency_info_s *swiftscan_dependency_info_t; +typedef struct swiftscan_link_library_info_s *swiftscan_link_library_info_t; typedef struct swiftscan_dependency_graph_s *swiftscan_dependency_graph_t; typedef struct swiftscan_import_set_s *swiftscan_import_set_t; typedef struct swiftscan_diagnostic_info_s *swiftscan_diagnostic_info_t; @@ -60,6 +61,10 @@ typedef struct { swiftscan_dependency_info_t *modules; size_t count; } swiftscan_dependency_set_t; +typedef struct { + swiftscan_link_library_info_t *link_libraries; + size_t count; +} swiftscan_link_library_set_t; //=== Batch Scan Input Specification --------------------------------------===// @@ -110,9 +115,19 @@ typedef struct { (*swiftscan_module_info_get_source_files)(swiftscan_dependency_info_t); swiftscan_string_set_t * (*swiftscan_module_info_get_direct_dependencies)(swiftscan_dependency_info_t); + swiftscan_link_library_set_t * + (*swiftscan_module_info_get_link_libraries)(swiftscan_dependency_graph_t); swiftscan_module_details_t (*swiftscan_module_info_get_details)(swiftscan_dependency_info_t); + //=== Link Library Info Functions ------------------------------------===// + swiftscan_string_ref_t + (*swiftscan_link_library_info_get_link_name)(swiftscan_link_library_info_t); + bool + (*swiftscan_link_library_info_get_is_framework)(swiftscan_link_library_info_t); + bool + (*swiftscan_link_library_info_get_should_force_load)(swiftscan_link_library_info_t); + //=== Dependency Module Info Details Functions ----------------------------===// swiftscan_dependency_info_kind_t (*swiftscan_module_detail_get_kind)(swiftscan_module_details_t); diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index 19279bbcc..59130ead0 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -3076,6 +3076,14 @@ extension Driver { diagnosticsEngine.emit(.error_hermetic_seal_requires_lto) } } + + if parsedOptions.hasArgument(.explicitAutoLinking) { + if !parsedOptions.hasArgument(.driverExplicitModuleBuild) { + diagnosticsEngine.emit(.error(Error.optionRequiresAnother(Option.explicitAutoLinking.spelling, + Option.driverExplicitModuleBuild.spelling)), + location: nil) + } + } } private static func validateSanitizerAddressUseOdrIndicatorFlag( diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift index ee80d45bc..877b2ec37 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/ExplicitDependencyBuildPlanner.swift @@ -34,7 +34,7 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT /// that specify said explicit module dependencies. @_spi(Testing) public struct ExplicitDependencyBuildPlanner { /// The module dependency graph. - private let dependencyGraph: InterModuleDependencyGraph + @_spi(Testing) public let dependencyGraph: InterModuleDependencyGraph /// A set of direct and transitive dependencies for every module in the dependency graph private let reachabilityMap: [ModuleDependencyId : Set] @@ -421,6 +421,29 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT } } + public func getLinkLibraryLoadCommandFlags(_ commandLine: inout [Job.ArgTemplate]) throws { + var allLinkLibraries: [LinkLibraryInfo] = [] + for (_, moduleInfo) in dependencyGraph.modules { + guard let moduleLinkLibraries = moduleInfo.linkLibraries else { + continue + } + for linkLibrary in moduleLinkLibraries { + allLinkLibraries.append(linkLibrary) + } + } + + for linkLibrary in allLinkLibraries { + if !linkLibrary.isFramework { + commandLine.appendFlag("-l\(linkLibrary.linkName)") + } else { + commandLine.appendFlag(.Xlinker) + commandLine.appendFlag("-framework") + commandLine.appendFlag(.Xlinker) + commandLine.appendFlag(linkLibrary.linkName) + } + } + } + /// Resolve all module dependencies of the main module and add them to the lists of /// inputs and command line flags. public mutating func resolveMainModuleDependencies(inputs: inout [TypedVirtualPath], diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/CommonDependencyOperations.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/CommonDependencyOperations.swift index eaad3543d..c9145ea51 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/CommonDependencyOperations.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/CommonDependencyOperations.swift @@ -27,24 +27,26 @@ import func TSCBasic.topologicalSort if let currentInfo = modules[swiftModuleId], externalModuleId.moduleName != mainModuleName { let newExternalModuleDetails = - try SwiftPrebuiltExternalModuleDetails(compiledModulePath: - TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()), - isFramework: externalModuleDetails.isFramework) + SwiftPrebuiltExternalModuleDetails(compiledModulePath: + TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()), + isFramework: externalModuleDetails.isFramework) let newInfo = ModuleInfo(modulePath: TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()), sourceFiles: [], directDependencies: currentInfo.directDependencies, + linkLibraries: currentInfo.linkLibraries, details: .swiftPrebuiltExternal(newExternalModuleDetails)) Self.replaceModule(originalId: swiftModuleId, replacementId: prebuiltModuleId, replacementInfo: newInfo, in: &modules) } else if let currentPrebuiltInfo = modules[prebuiltModuleId] { // Just update the isFramework bit on this prebuilt module dependency let newExternalModuleDetails = - try SwiftPrebuiltExternalModuleDetails(compiledModulePath: - TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()), - isFramework: externalModuleDetails.isFramework) + SwiftPrebuiltExternalModuleDetails(compiledModulePath: + TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()), + isFramework: externalModuleDetails.isFramework) let newInfo = ModuleInfo(modulePath: TextualVirtualPath(path: VirtualPath.absolute(externalModulePath).intern()), sourceFiles: [], directDependencies: currentPrebuiltInfo.directDependencies, + linkLibraries: currentPrebuiltInfo.linkLibraries, details: .swiftPrebuiltExternal(newExternalModuleDetails)) Self.replaceModule(originalId: prebuiltModuleId, replacementId: prebuiltModuleId, replacementInfo: newInfo, in: &modules) @@ -231,6 +233,9 @@ extension InterModuleDependencyGraph { let firstModuleDependencies = firstInfo.directDependencies ?? [] let secondModuleDependencies = secondInfo.directDependencies ?? [] let combinedDependencies = Array(Set(firstModuleDependencies + secondModuleDependencies)) + let firstLinkLibraries = firstInfo.linkLibraries ?? [] + let secondLinkLibraries = secondInfo.linkLibraries ?? [] + let combinedLinkLibraries = Array(Set(firstLinkLibraries + secondLinkLibraries)) let firstModuleCapturedPCMArgs = firstDetails.capturedPCMArgs ?? Set<[String]>() let secondModuleCapturedPCMArgs = secondDetails.capturedPCMArgs ?? Set<[String]>() @@ -245,6 +250,7 @@ extension InterModuleDependencyGraph { return ModuleInfo(modulePath: firstInfo.modulePath, sourceFiles: combinedSourceFiles, directDependencies: combinedDependencies, + linkLibraries: combinedLinkLibraries, details: .clang(combinedModuleDetails)) } } diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift index e45b6c765..e30bdbb4a 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift @@ -94,6 +94,13 @@ public struct BridgingHeader: Codable, Hashable { var moduleDependencies: [String] } +/// Linked Library +public struct LinkLibraryInfo: Codable, Hashable { + public var linkName: String + public var isFramework: Bool + public var shouldForceLoad: Bool +} + /// Details specific to Swift modules. public struct SwiftModuleDetails: Codable, Hashable { /// The module interface from which this module was built, if any. @@ -203,6 +210,9 @@ public struct ModuleInfo: Codable, Hashable { /// The set of direct module dependencies of this module. public var directDependencies: [ModuleDependencyId]? + /// The set of libraries that need to be linked + public var linkLibraries: [LinkLibraryInfo]? + /// Specific details of a particular kind of module. public var details: Details @@ -226,10 +236,12 @@ public struct ModuleInfo: Codable, Hashable { public init(modulePath: TextualVirtualPath, sourceFiles: [String]?, directDependencies: [ModuleDependencyId]?, + linkLibraries: [LinkLibraryInfo]?, details: Details) { self.modulePath = modulePath self.sourceFiles = sourceFiles self.directDependencies = directDependencies + self.linkLibraries = linkLibraries self.details = details } } @@ -306,7 +318,7 @@ public struct InterModuleDependencyGraph: Codable { public var mainModule: ModuleInfo { modules[.swift(mainModuleName)]! } } -internal extension InterModuleDependencyGraph { +@_spi(Testing) public extension InterModuleDependencyGraph { func toJSONData() throws -> Data { let encoder = JSONEncoder() #if os(Linux) || os(Android) diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift index ec8fc1702..04ee22e40 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift @@ -174,6 +174,13 @@ public class InterModuleDependencyOracle { return swiftScan.supportsDiagnosticSourceLocations } + @_spi(Testing) public func supportsLinkLibraries() throws -> Bool { + guard let swiftScan = swiftScanLibInstance else { + fatalError("Attempting to query supported scanner API with no scanner instance.") + } + return swiftScan.supportsLinkLibraries + } + @_spi(Testing) public func getScannerDiagnostics() throws -> [ScannerDiagnosticPayload]? { guard let swiftScan = swiftScanLibInstance else { fatalError("Attempting to reset scanner cache with no scanner instance.") diff --git a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift index 2be237734..1c9868e8d 100644 --- a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift +++ b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift @@ -472,6 +472,12 @@ extension Driver { commandLine.appendFlag("-frontend-parseable-output") } + // If explicit auto-linking is enabled, ensure that compiler tasks do not produce + // auto-link load commands in resulting object files. + if parsedOptions.hasArgument(.explicitAutoLinking) { + commandLine.appendFlag(.disableAllAutolinking) + } + savedUnknownDriverFlagsForSwiftFrontend.forEach { commandLine.appendFlag($0) } diff --git a/Sources/SwiftDriver/Jobs/LinkJob.swift b/Sources/SwiftDriver/Jobs/LinkJob.swift index b5efd0df2..fa7d40eb5 100644 --- a/Sources/SwiftDriver/Jobs/LinkJob.swift +++ b/Sources/SwiftDriver/Jobs/LinkJob.swift @@ -75,6 +75,10 @@ extension Driver { targetInfo: frontendTargetInfo ) + if parsedOptions.hasArgument(.explicitAutoLinking) { + try explicitDependencyBuildPlanner?.getLinkLibraryLoadCommandFlags(&commandLine) + } + return Job( moduleName: moduleOutputInfo.name, kind: .link, diff --git a/Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift b/Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift index 44cf74f18..007bd8c9b 100644 --- a/Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift +++ b/Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift @@ -120,6 +120,24 @@ private extension SwiftScan { directDependencies = nil } + var linkLibraries: [LinkLibraryInfo] = [] + if supportsLinkLibraries { + let linkLibrarySetRefOrNull = api.swiftscan_module_info_get_link_libraries(moduleInfoRef) + guard let linkLibrarySetRef = linkLibrarySetRefOrNull else { + throw DependencyScanningError.missingField("dependency_graph.link_libraries") + } + // Turn the `swiftscan_dependency_set_t` into an array of `swiftscan_dependency_info_t` + // references we can iterate through in order to construct `ModuleInfo` objects. + let linkLibraryRefArray = Array(UnsafeBufferPointer(start: linkLibrarySetRef.pointee.link_libraries, + count: Int(linkLibrarySetRef.pointee.count))) + for linkLibraryRefOrNull in linkLibraryRefArray { + guard let linkLibraryRef = linkLibraryRefOrNull else { + throw DependencyScanningError.missingField("dependency_set_t.link_libraries[_]") + } + linkLibraries.append(try constructLinkLibrayInfo(from: linkLibraryRef)) + } + } + guard let moduleDetailsRef = api.swiftscan_module_info_get_details(moduleInfoRef) else { throw DependencyScanningError.missingField("modules[\(moduleId)].details") } @@ -128,9 +146,16 @@ private extension SwiftScan { return (moduleId, ModuleInfo(modulePath: modulePath, sourceFiles: sourceFiles, directDependencies: directDependencies, + linkLibraries: linkLibraries, details: details)) } + func constructLinkLibrayInfo(from linkLibraryInfoRef: swiftscan_link_library_info_t) throws -> LinkLibraryInfo { + return LinkLibraryInfo(linkName: try toSwiftString(api.swiftscan_link_library_info_get_link_name(linkLibraryInfoRef)), + isFramework: api.swiftscan_link_library_info_get_is_framework(linkLibraryInfoRef), + shouldForceLoad: api.swiftscan_link_library_info_get_should_force_load(linkLibraryInfoRef)) + } + /// From a reference to a binary-format module info details object info returned by libSwiftScan, /// construct an instance of an `ModuleInfo`.Details as used by the driver. /// The object returned by libSwiftScan is a union so ensure to execute dependency-specific queries. diff --git a/Sources/SwiftDriver/SwiftScan/SwiftScan.swift b/Sources/SwiftDriver/SwiftScan/SwiftScan.swift index 7bb02a472..c95a42e68 100644 --- a/Sources/SwiftDriver/SwiftScan/SwiftScan.swift +++ b/Sources/SwiftDriver/SwiftScan/SwiftScan.swift @@ -364,6 +364,13 @@ private extension String { api.swiftscan_source_location_get_column_number != nil } + @_spi(Testing) public var supportsLinkLibraries : Bool { + return api.swiftscan_module_info_get_link_libraries != nil && + api.swiftscan_link_library_info_get_link_name != nil && + api.swiftscan_link_library_info_get_is_framework != nil && + api.swiftscan_link_library_info_get_should_force_load != nil + } + func serializeScannerCache(to path: AbsolutePath) { api.swiftscan_scanner_cache_serialize(scanner, path.description.cString(using: String.Encoding.utf8)) @@ -636,6 +643,11 @@ private extension swiftscan_functions_t { self.swiftscan_source_location_get_line_number = try loadOptional("swiftscan_source_location_get_line_number") self.swiftscan_source_location_get_column_number = try loadOptional("swiftscan_source_location_get_column_number") + self.swiftscan_module_info_get_link_libraries = try loadOptional("swiftscan_module_info_get_link_libraries") + self.swiftscan_link_library_info_get_link_name = try loadOptional("swiftscan_link_library_info_get_link_name") + self.swiftscan_link_library_info_get_is_framework = try loadOptional("swiftscan_link_library_info_get_is_framework") + self.swiftscan_link_library_info_get_should_force_load = try loadOptional("swiftscan_link_library_info_get_should_force_load") + // Swift Overlay Dependencies self.swiftscan_swift_textual_detail_get_swift_overlay_dependencies = try loadOptional("swiftscan_swift_textual_detail_get_swift_overlay_dependencies") diff --git a/Sources/SwiftOptions/Options.swift b/Sources/SwiftOptions/Options.swift index 38327c5e8..3365d6713 100644 --- a/Sources/SwiftOptions/Options.swift +++ b/Sources/SwiftOptions/Options.swift @@ -165,6 +165,7 @@ extension Option { public static let disableColocateTypeDescriptors: Option = Option("-disable-colocate-type-descriptors", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable colocate type descriptors") public static let disableConcreteTypeMetadataMangledNameAccessors: Option = Option("-disable-concrete-type-metadata-mangled-name-accessors", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable concrete type metadata access by mangled name") public static let disableConstraintSolverPerformanceHacks: Option = Option("-disable-constraint-solver-performance-hacks", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable all the hacks in the constraint solver") + public static let disableCrossImportOverlaySearch: Option = Option("-disable-cross-import-overlay-search", .flag, attributes: [.frontend, .noDriver], helpText: "Disable searching for cross import overlay file") public static let disableCrossImportOverlays: Option = Option("-disable-cross-import-overlays", .flag, attributes: [.frontend, .noDriver], helpText: "Do not automatically import declared cross-import overlays.") public static let cxxInteropDisableRequirementAtImport: Option = Option("-disable-cxx-interop-requirement-at-import", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Do not require C++ interoperability to be enabled when importing a Swift module that enables C++ interoperability") public static let disableDebuggerShadowCopies: Option = Option("-disable-debugger-shadow-copies", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable debugger shadow copies of local variables.This option is only useful for testing the compiler.") @@ -180,10 +181,12 @@ extension Option { public static let disableExperimentalStringProcessing: Option = Option("-disable-experimental-string-processing", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable experimental string processing") public static let disableFailOnError: Option = Option("-disable-fail-on-error", .flag, attributes: [.noDriver], helpText: "Don't exit with a nonzero status if errors are emitted") public static let disableFailOnError_: Option = Option("--disable-fail-on-error", .flag, alias: Option.disableFailOnError, attributes: [.noDriver], helpText: "Don't exit with a nonzero status if errors are emitted") + public static let disableForceLoadSymbols: Option = Option("-disable-force-load-symbols", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable generation of all Swift _FORCE_LOAD symbols") public static let disableFragileResilientProtocolWitnesses: Option = Option("-disable-fragile-relative-protocol-tables", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable relative protocol witness tables") public static let disableGenericMetadataPrespecialization: Option = Option("-disable-generic-metadata-prespecialization", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Do not statically specialize metadata for generic types at types that are known to be used in source.") public static let disableImplicitBacktracingModuleImport: Option = Option("-disable-implicit-backtracing-module-import", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable the implicit import of the _Backtracing module.") public static let disableImplicitConcurrencyModuleImport: Option = Option("-disable-implicit-concurrency-module-import", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable the implicit import of the _Concurrency module.") + public static let disableImplicitCxxModuleImport: Option = Option("-disable-implicit-cxx-module-import", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable the implicit import of the C++ Standard Library module.") public static let disableImplicitStringProcessingModuleImport: Option = Option("-disable-implicit-string-processing-module-import", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable the implicit import of the _StringProcessing module.") public static let disableImplicitSwiftModules: Option = Option("-disable-implicit-swift-modules", .flag, attributes: [.frontend, .noDriver], helpText: "Disable building Swift modules implicitly by the compiler") public static let disableImportPtrauthFieldFunctionPointers: Option = Option("-disable-import-ptrauth-field-function-pointers", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable import of custom ptrauth qualified field function pointers") @@ -487,13 +490,13 @@ extension Option { public static let experimentalPrintFullConvention: Option = Option("-experimental-print-full-convention", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "When emitting a module interface or SIL, emit additional @convention arguments, regardless of whether they were written in the source. Also requires -use-clang-function-types to be enabled.") public static let experimentalSkipAllFunctionBodies: Option = Option("-experimental-skip-all-function-bodies", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Skip type-checking function bodies and all SIL generation") public static let experimentalSkipNonExportableDecls: Option = Option("-experimental-skip-non-exportable-decls", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Skip decls that are not exported to clients") - public static let experimentalSkipNonInlinableFunctionBodiesIsLazy: Option = Option("-experimental-skip-non-inlinable-function-bodies-is-lazy", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Infer lazy typechecking for -experimental-skip-non-inlinable-function-bodies") public static let experimentalSkipNonInlinableFunctionBodiesWithoutTypes: Option = Option("-experimental-skip-non-inlinable-function-bodies-without-types", .flag, attributes: [.helpHidden, .frontend], helpText: "Skip work on non-inlinable function bodies that do not declare nested types") public static let experimentalSkipNonInlinableFunctionBodies: Option = Option("-experimental-skip-non-inlinable-function-bodies", .flag, attributes: [.helpHidden, .frontend], helpText: "Skip type-checking and SIL generation for non-inlinable function bodies") public static let experimentalSpiImports: Option = Option("-experimental-spi-imports", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enable experimental support for SPI imports") public static let experimentalSpiOnlyImports: Option = Option("-experimental-spi-only-imports", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enable use of @_spiOnly imports") public static let enableExperimentalSwiftBasedClosureSpecialization: Option = Option("-experimental-swift-based-closure-specialization", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Use the experimental Swift based closure-specialization optimization pass instead of the existing C++ one") public static let explainModuleDependency: Option = Option("-explain-module-dependency", .separate, attributes: [], helpText: "Emit remark/notes describing why compilation may depend on a module with a given name.") + public static let explicitAutoLinking: Option = Option("-explicit-auto-linking", .flag, attributes: [], helpText: "Instead of linker-load directives, have the driver specify all link dependencies on the linker invocation. Requires '-explicit-module-build'.") public static let explicitDependencyGraphFormat: Option = Option("-explicit-dependency-graph-format=", .joined, attributes: [.helpHidden, .doesNotAffectIncrementalBuild], helpText: "Specify the explicit dependency graph output format to either 'json' or 'dot'") public static let explicitInterfaceModuleBuild: Option = Option("-explicit-interface-module-build", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Use the specified command-line to build the module from interface, instead of flags specified in the interface") public static let driverExplicitModuleBuild: Option = Option("-explicit-module-build", .flag, attributes: [.helpHidden], helpText: "Prebuild module dependencies to make them explicit") @@ -604,6 +607,8 @@ extension Option { public static let moduleAbiName: Option = Option("-module-abi-name", .separate, attributes: [.frontend, .moduleInterface], helpText: "ABI name to use for the contents of this module") public static let moduleAlias: Option = Option("-module-alias", .separate, attributes: [.frontend, .moduleInterface], metaVar: "", helpText: "If a source file imports or references module , the is used for the contents of the file") public static let moduleCachePath: Option = Option("-module-cache-path", .separate, attributes: [.frontend, .doesNotAffectIncrementalBuild, .argumentIsPath], helpText: "Specifies the module cache path") + public static let moduleCanImportVersion: Option = Option("-module-can-import-version", .multiArg, attributes: [.frontend, .noDriver], metaVar: " ", helpText: "Specify canImport module and versions", numArgs: 3) + public static let moduleCanImport: Option = Option("-module-can-import", .separate, attributes: [.frontend, .noDriver], metaVar: "", helpText: "Specify canImport module name") public static let moduleInterfacePreserveTypesAsWritten: Option = Option("-module-interface-preserve-types-as-written", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "When emitting a module interface, preserve types as they were written in the source") public static let moduleLinkNameEQ: Option = Option("-module-link-name=", .joined, alias: Option.moduleLinkName, attributes: [.frontend]) public static let moduleLinkName: Option = Option("-module-link-name", .separate, attributes: [.frontend, .moduleInterface], helpText: "Library to link against when using this module") @@ -776,6 +781,7 @@ extension Option { public static let suppressStaticExclusivitySwap: Option = Option("-suppress-static-exclusivity-swap", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Suppress static violations of exclusive access with swap()") public static let suppressWarnings: Option = Option("-suppress-warnings", .flag, attributes: [.frontend], helpText: "Suppress all warnings") public static let swiftAsyncFramePointerEQ: Option = Option("-swift-async-frame-pointer=", .joined, attributes: [.helpHidden, .frontend, .noDriver], helpText: "One of 'auto', 'always' or 'never'") + public static let swiftModuleCrossImport: Option = Option("-swift-module-cross-import", .multiArg, attributes: [.frontend, .noDriver], metaVar: " ", helpText: "Specify the cross import module", numArgs: 2) public static let swiftModuleFile: Option = Option("-swift-module-file=", .joined, attributes: [.frontend, .noDriver], metaVar: "=", helpText: "Specify Swift module input explicitly built from textual interface") public static let swiftOnly: Option = Option("-swift-only", .flag, attributes: [.noDriver], helpText: "Only include APIs defined from Swift source") public static let swiftOnly_: Option = Option("--swift-only", .flag, alias: Option.swiftOnly, attributes: [.noDriver], helpText: "Only include APIs defined from Swift source") @@ -1022,6 +1028,7 @@ extension Option { Option.disableColocateTypeDescriptors, Option.disableConcreteTypeMetadataMangledNameAccessors, Option.disableConstraintSolverPerformanceHacks, + Option.disableCrossImportOverlaySearch, Option.disableCrossImportOverlays, Option.cxxInteropDisableRequirementAtImport, Option.disableDebuggerShadowCopies, @@ -1037,10 +1044,12 @@ extension Option { Option.disableExperimentalStringProcessing, Option.disableFailOnError, Option.disableFailOnError_, + Option.disableForceLoadSymbols, Option.disableFragileResilientProtocolWitnesses, Option.disableGenericMetadataPrespecialization, Option.disableImplicitBacktracingModuleImport, Option.disableImplicitConcurrencyModuleImport, + Option.disableImplicitCxxModuleImport, Option.disableImplicitStringProcessingModuleImport, Option.disableImplicitSwiftModules, Option.disableImportPtrauthFieldFunctionPointers, @@ -1344,13 +1353,13 @@ extension Option { Option.experimentalPrintFullConvention, Option.experimentalSkipAllFunctionBodies, Option.experimentalSkipNonExportableDecls, - Option.experimentalSkipNonInlinableFunctionBodiesIsLazy, Option.experimentalSkipNonInlinableFunctionBodiesWithoutTypes, Option.experimentalSkipNonInlinableFunctionBodies, Option.experimentalSpiImports, Option.experimentalSpiOnlyImports, Option.enableExperimentalSwiftBasedClosureSpecialization, Option.explainModuleDependency, + Option.explicitAutoLinking, Option.explicitDependencyGraphFormat, Option.explicitInterfaceModuleBuild, Option.driverExplicitModuleBuild, @@ -1461,6 +1470,8 @@ extension Option { Option.moduleAbiName, Option.moduleAlias, Option.moduleCachePath, + Option.moduleCanImportVersion, + Option.moduleCanImport, Option.moduleInterfacePreserveTypesAsWritten, Option.moduleLinkNameEQ, Option.moduleLinkName, @@ -1633,6 +1644,7 @@ extension Option { Option.suppressStaticExclusivitySwap, Option.suppressWarnings, Option.swiftAsyncFramePointerEQ, + Option.swiftModuleCrossImport, Option.swiftModuleFile, Option.swiftOnly, Option.swiftOnly_, diff --git a/Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift b/Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift index a54a5063a..2c5e1d596 100644 --- a/Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift +++ b/Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift @@ -344,6 +344,93 @@ final class ExplicitModuleBuildTests: XCTestCase { } } + func testExplicitLinkLibraries() throws { + try withTemporaryDirectory { path in + let (_, _, toolchain, _) = try getDriverArtifactsForScanning() + + let main = path.appending(component: "testExplicitLinkLibraries.swift") + try localFileSystem.writeFileContents(main, bytes: + """ + import C;import E;import G; + """ + ) + + let cHeadersPath: AbsolutePath = + try testInputsPath.appending(component: "ExplicitModuleBuilds") + .appending(component: "CHeaders") + let bridgingHeaderpath: AbsolutePath = + cHeadersPath.appending(component: "Bridging.h") + let swiftModuleInterfacesPath: AbsolutePath = + try testInputsPath.appending(component: "ExplicitModuleBuilds") + .appending(component: "Swift") + let sdkArgumentsForTesting = (try? Driver.sdkArgumentsForTesting()) ?? [] + + // 2. Run a dependency scan to find the just-built module + let dependencyOracle = InterModuleDependencyOracle() + let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib()) + try dependencyOracle.verifyOrCreateScannerInstance(fileSystem: localFileSystem, + swiftScanLibPath: scanLibPath) + guard try dependencyOracle.supportsLinkLibraries() else { + throw XCTSkip("libSwiftScan does not support link library reporting.") + } + + var driver = try Driver(args: ["swiftc", + "-I", cHeadersPath.nativePathString(escaped: true), + "-I", swiftModuleInterfacesPath.nativePathString(escaped: true), + "-explicit-module-build", + "-import-objc-header", bridgingHeaderpath.nativePathString(escaped: true), + main.nativePathString(escaped: true)] + sdkArgumentsForTesting) + let _ = try driver.planBuild() + let dependencyGraph = try XCTUnwrap(driver.explicitDependencyBuildPlanner?.dependencyGraph) + + let checkForLinkLibrary = { (info: ModuleInfo, linkName: String, isFramework: Bool, shouldForceLoad: Bool) in + let linkLibraries = try XCTUnwrap(info.linkLibraries) + XCTAssertEqual(linkLibraries.count, 1) + let linkLibrary = try XCTUnwrap(linkLibraries.first) + XCTAssertEqual(linkLibrary.linkName, linkName) + XCTAssertEqual(linkLibrary.isFramework, isFramework) + XCTAssertEqual(linkLibrary.shouldForceLoad, shouldForceLoad) + } + + for (depId, depInfo) in dependencyGraph.modules { + switch depId { + case .swiftPrebuiltExternal("Swift"): + fallthrough + case .swift("Swift"): + try checkForLinkLibrary(depInfo, "swiftCore", false, false) + break + + case .swiftPrebuiltExternal("_StringProcessing"): + fallthrough + case .swift("_StringProcessing"): + try checkForLinkLibrary(depInfo, "swift_StringProcessing", false, false) + break + + case .swiftPrebuiltExternal("SwiftOnoneSupport"): + fallthrough + case .swift("SwiftOnoneSupport"): + try checkForLinkLibrary(depInfo, "swiftSwiftOnoneSupport", false, false) + break + + case .swiftPrebuiltExternal("_Concurrency"): + fallthrough + case .swift("_Concurrency"): + try checkForLinkLibrary(depInfo, "swift_Concurrency", false, false) + break + + case .swift("testExplicitLinkLibraries"): + let linkLibraries = try XCTUnwrap(depInfo.linkLibraries) + if driver.targetTriple.isDarwin { + XCTAssertTrue(!linkLibraries.isEmpty) + XCTAssertTrue(linkLibraries.contains { $0.linkName == "objc" }) + } + default: + continue + } + } + } + } + /// Test generation of explicit module build jobs for dependency modules when the driver /// is invoked with -explicit-module-build func testExplicitModuleBuildJobs() throws {