Skip to content

[6.0] Symbol graph cherry picks #7659

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

Merged
merged 2 commits into from
Jun 13, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,24 @@ public final class ClangTargetBuildDescription {
}
}

/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// this module.
package func symbolGraphExtractArguments() throws -> [String] {
var args = [String]()
if self.clangTarget.isCXX {
args += ["-cxx-interoperability-mode=default"]
}
if let cxxLanguageStandard = self.clangTarget.cxxLanguageStandard {
args += ["-Xcc", "-std=\(cxxLanguageStandard)"]
}
args += ["-I", self.clangTarget.includeDir.pathString]
args += self.additionalFlags.asSwiftcCCompilerFlags()
// Unconditionally use clang modules with swift tools.
args += try self.clangModuleArguments().asSwiftcCCompilerFlags()
args += try self.currentModuleMapFileArguments().asSwiftcCCompilerFlags()
return args
}

/// Builds up basic compilation arguments for a source file in this target; these arguments may be different for C++
/// vs non-C++.
/// NOTE: The parameter to specify whether to get C++ semantics is currently optional, but this is only for revlock
Expand Down Expand Up @@ -249,7 +267,7 @@ public final class ClangTargetBuildDescription {
// clang modules aren't fully supported in C++ mode in the current Darwin SDKs.
let enableModules = triple.isDarwin() && !isCXX
if enableModules {
args += ["-fmodules", "-fmodule-name=" + target.c99name]
args += try self.clangModuleArguments()
}

// Only add the build path to the framework search path if there are binary frameworks to link against.
Expand All @@ -259,9 +277,7 @@ public final class ClangTargetBuildDescription {

args += ["-I", clangTarget.includeDir.pathString]
args += additionalFlags
if enableModules {
args += try moduleCacheArgs
}

args += buildParameters.sanitizers.compileCFlags()

// Add arguments from declared build settings.
Expand Down Expand Up @@ -407,11 +423,22 @@ public final class ClangTargetBuildDescription {
return compilationConditions
}

/// Module cache arguments.
private var moduleCacheArgs: [String] {
get throws {
try ["-fmodules-cache-path=\(buildParameters.moduleCache.pathString)"]
/// Enable Clang module flags.
private func clangModuleArguments() throws -> [String] {
let cachePath = try self.buildParameters.moduleCache.pathString
return [
"-fmodules",
"-fmodule-name=\(self.target.c99name)",
"-fmodules-cache-path=\(cachePath)",
]
}

private func currentModuleMapFileArguments() throws -> [String] {
// Pass the path to the current module's module map if present.
if let moduleMap = self.moduleMap {
return ["-fmodule-map-file=\(moduleMap.pathString)"]
}
return []
}

/// Generate the resource bundle accessor, if appropriate.
Expand Down
99 changes: 79 additions & 20 deletions Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -531,26 +531,8 @@ public final class SwiftTargetBuildDescription {
args += ["-color-diagnostics"]
}

// If this is a generated test discovery target or a test entry point, it might import a test
// target that is built with C++ interop enabled. In that case, the test
// discovery target must enable C++ interop as well
switch testTargetRole {
case .discovery, .entryPoint:
for dependency in try self.target.recursiveTargetDependencies() {
let dependencyScope = self.buildParameters.createScope(for: dependency)
let dependencySwiftFlags = dependencyScope.evaluate(.OTHER_SWIFT_FLAGS)
if let interopModeFlag = dependencySwiftFlags.first(where: { $0.hasPrefix("-cxx-interoperability-mode=") }) {
args += [interopModeFlag]
if interopModeFlag != "-cxx-interoperability-mode=off" {
if let cxxStandard = self.package.manifest.cxxLanguageStandard {
args += ["-Xcc", "-std=\(cxxStandard)"]
}
}
break
}
}
default: break
}
args += try self.cxxInteroperabilityModeArguments(
propagateFromCurrentModuleOtherSwiftFlags: false)

// Add arguments from declared build settings.
args += try self.buildSettingsFlags()
Expand Down Expand Up @@ -628,6 +610,83 @@ public final class SwiftTargetBuildDescription {

return args
}

/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// this module.
package func symbolGraphExtractArguments() throws -> [String] {
var args = [String]()
args += try self.cxxInteroperabilityModeArguments(
propagateFromCurrentModuleOtherSwiftFlags: true)

args += self.buildParameters.toolchain.extraFlags.swiftCompilerFlags

// Include search paths determined during planning
args += self.additionalFlags
// FIXME: only pass paths to the actual dependencies of the module
// Include search paths for swift module dependencies.
args += ["-I", self.modulesPath.pathString]

// FIXME: Only include valid args
// This condition should instead only include args which are known to be
// compatible instead of filtering out specific unknown args.
//
// swift-symbolgraph-extract does not support parsing `-use-ld=lld` and
// will silently error failing the operation.
args = args.filter { !$0.starts(with: "-use-ld=") }
return args
}

// FIXME: this function should operation on a strongly typed buildSetting
// Move logic from PackageBuilder here.
/// Determines the arguments needed for cxx interop for this module.
func cxxInteroperabilityModeArguments(
// FIXME: Remove argument
// This argument is added as a stop gap to support generating arguments
// for tools which currently don't leverage "OTHER_SWIFT_FLAGS". In the
// fullness of time this function should operate on a strongly typed
// "interopMode" property of SwiftTargetBuildDescription instead of
// digging through "OTHER_SWIFT_FLAGS" manually.
propagateFromCurrentModuleOtherSwiftFlags: Bool
) throws -> [String] {
func cxxInteroperabilityModeAndStandard(
for module: ResolvedModule
) -> [String]? {
let scope = self.buildParameters.createScope(for: module)
let flags = scope.evaluate(.OTHER_SWIFT_FLAGS)
let mode = flags.first { $0.hasPrefix("-cxx-interoperability-mode=") }
guard let mode else { return nil }
// FIXME: Use a stored self.cxxLanguageStandard property
// It definitely should _never_ reach back into the manifest
if let cxxStandard = self.package.manifest.cxxLanguageStandard {
return [mode, "-Xcc", "-std=\(cxxStandard)"]
} else {
return [mode]
}
}

if propagateFromCurrentModuleOtherSwiftFlags {
// Look for cxx interop mode in the current module, if set exit early,
// the flag is already present.
if let args = cxxInteroperabilityModeAndStandard(for: self.target) {
return args
}
}

// Implicitly propagate cxx interop flags for generated test targets.
// If the current module doesn't have cxx interop mode set, search
// through the module's dependencies looking for the a module that
// enables cxx interop and copy it's flag.
switch self.testTargetRole {
case .discovery, .entryPoint:
for module in try self.target.recursiveTargetDependencies() {
if let args = cxxInteroperabilityModeAndStandard(for: module) {
return args
}
}
default: break
}
return []
}

/// When `scanInvocation` argument is set to `true`, omit the side-effect producing arguments
/// such as emitting a module or supplementary outputs.
Expand Down
9 changes: 9 additions & 0 deletions Sources/Build/BuildDescription/TargetBuildDescription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,13 @@ public enum TargetBuildDescription {
return clangTargetBuildDescription.toolsVersion
}
}

/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// this module.
package func symbolGraphExtractArguments() throws -> [String] {
switch self {
case .swift(let target): try target.symbolGraphExtractArguments()
case .clang(let target): try target.symbolGraphExtractArguments()
}
}
}
9 changes: 9 additions & 0 deletions Sources/Build/BuildPlan/BuildPlan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,15 @@ public class BuildPlan: SPMBuildCore.BuildPlan {
try binaryTarget.parseXCFrameworks(for: triple, fileSystem: self.fileSystem)
}
}

/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// a particular module.
public func symbolGraphExtractArguments(for module: ResolvedModule) throws -> [String] {
guard let description = self.targetMap[module.id] else {
throw InternalError("Expected description for module \(module)")
}
return try description.symbolGraphExtractArguments()
}
}

extension Basics.Diagnostic {
Expand Down
4 changes: 3 additions & 1 deletion Sources/Commands/Utilities/SymbolGraphExtract.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ public struct SymbolGraphExtract {

// Construct arguments for extracting symbols for a single target.
var commandLine = [self.tool.pathString]
commandLine += try buildPlan.symbolGraphExtractArguments(for: module)

// FIXME: everything here should be in symbolGraphExtractArguments
commandLine += ["-module-name", module.c99name]
commandLine += try buildParameters.tripleArgs(for: module)
commandLine += try buildPlan.createAPIToolCommonArgs(includeLibrarySearchPaths: true)
commandLine += ["-module-cache-path", try buildParameters.moduleCache.pathString]
if verboseOutput {
commandLine += ["-v"]
Expand Down
4 changes: 4 additions & 0 deletions Sources/SPMBuildCore/BuildSystem/BuildSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ public protocol BuildPlan {

func createAPIToolCommonArgs(includeLibrarySearchPaths: Bool) throws -> [String]
func createREPLArguments() throws -> [String]

/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// a particular module.
func symbolGraphExtractArguments(for module: ResolvedModule) throws -> [String]
}

public protocol BuildSystemFactory {
Expand Down
Loading